[flang] Fix some bugs exposed by testing new checks

Original-commit: flang-compiler/f18@9cc70dcad6
Reviewed-on: https://github.com/flang-compiler/f18/pull/782
Tree-same-pre-rewrite: false
This commit is contained in:
peter klausler 2019-10-16 09:39:37 -07:00
parent 4c37c06597
commit 3a4091b5e3
3 changed files with 57 additions and 46 deletions

View File

@ -412,7 +412,7 @@ Expr<Type<TypeCategory::Integer, KIND>> LBOUND(FoldingContext &context,
if (const auto *array{UnwrapExpr<Expr<SomeType>>(args[0])}) {
if (int rank{array->Rank()}; rank > 0) {
std::optional<int> dim;
if (args[1].has_value()) {
if (funcRef.Rank() == 0) {
// Optional DIM= argument is present: result is scalar.
if (auto dim64{GetInt64Arg(args[1])}) {
if (*dim64 < 1 || *dim64 > rank) {
@ -467,7 +467,7 @@ Expr<Type<TypeCategory::Integer, KIND>> UBOUND(FoldingContext &context,
if (auto *array{UnwrapExpr<Expr<SomeType>>(args[0])}) {
if (int rank{array->Rank()}; rank > 0) {
std::optional<int> dim;
if (args[1].has_value()) {
if (funcRef.Rank() == 0) {
// Optional DIM= argument is present: result is scalar.
if (auto dim64{GetInt64Arg(args[1])}) {
if (*dim64 < 1 || *dim64 > rank) {

View File

@ -477,9 +477,20 @@ auto GetShapeHelper::operator()(const ProcedureRef &call) const -> Result {
} else if (intrinsic->name == "reshape") {
if (call.arguments().size() >= 2 && call.arguments().at(1).has_value()) {
// SHAPE(RESHAPE(array,shape)) -> shape
const auto *shapeExpr{call.arguments().at(1).value().UnwrapExpr()};
auto shape{std::get<Expr<SomeInteger>>(DEREF(shapeExpr).u)};
return AsShape(context_, ConvertToType<ExtentType>(std::move(shape)));
if (const auto *shapeExpr{
call.arguments().at(1).value().UnwrapExpr()}) {
auto shape{std::get<Expr<SomeInteger>>(shapeExpr->u)};
return AsShape(context_, ConvertToType<ExtentType>(std::move(shape)));
}
}
} else if (intrinsic->name == "transpose") {
if (call.arguments().size() >= 1) {
if (auto shape{(*this)(call.arguments().at(0))}) {
if (shape->size() == 2) {
std::swap((*shape)[0], (*shape)[1]);
return shape;
}
}
}
} else if (intrinsic->characteristics.value().attrs.test(characteristics::
Procedure::Attr::NullPointer)) { // NULL(MOLD=)

View File

@ -307,34 +307,40 @@ static void CheckExplicitInterfaceArg(const evaluate::ActualArgument &arg,
const characteristics::Procedure &proc, evaluate::FoldingContext &context,
const Scope &scope) {
auto &messages{context.messages()};
if (const auto *object{
std::get_if<characteristics::DummyDataObject>(&dummy.u)}) {
if (const auto *expr{arg.UnwrapExpr()}) {
if (auto type{
characteristics::TypeAndShape::Characterize(*expr, context)}) {
CheckExplicitDataArg(*object, *expr, *type, proc, context, scope);
} else if (object->type.type().IsTypelessIntrinsicArgument() &&
std::holds_alternative<evaluate::BOZLiteralConstant>(expr->u)) {
// ok
} else {
messages.Say(
"Actual argument is not a variable or typed expression"_err_en_US);
}
} else if (const Symbol * assumed{arg.GetAssumedTypeDummy()}) {
// An assumed-type dummy is being forwarded.
if (!object->type.type().IsAssumedType()) {
messages.Say(
"Assumed-type TYPE(*) '%s' may be associated only with an assumed-TYPE(*) dummy argument"_err_en_US,
assumed->name());
}
} else {
messages.Say(
"Actual argument is not an expression or variable"_err_en_US);
}
} else {
// TODO check actual procedure compatibility
// TODO check alternate return
}
std::visit(
common::visitors{
[&](const characteristics::DummyDataObject &object) {
if (const auto *expr{arg.UnwrapExpr()}) {
if (auto type{characteristics::TypeAndShape::Characterize(
*expr, context)}) {
CheckExplicitDataArg(
object, *expr, *type, proc, context, scope);
} else if (object.type.type().IsTypelessIntrinsicArgument() &&
std::holds_alternative<evaluate::BOZLiteralConstant>(
expr->u)) {
// ok
} else {
messages.Say(
"Actual argument is not a variable or typed expression"_err_en_US);
}
} else if (const Symbol * assumed{arg.GetAssumedTypeDummy()}) {
// An assumed-type dummy is being forwarded.
if (!object.type.type().IsAssumedType()) {
messages.Say(
"Assumed-type TYPE(*) '%s' may be associated only with an assumed-TYPE(*) dummy argument"_err_en_US,
assumed->name());
}
} else {
messages.Say(
"Actual argument is not an expression or variable"_err_en_US);
}
},
[](const auto &) {
// TODO check actual procedure compatibility
// TODO check alternate return
},
},
dummy.u);
}
static void RearrangeArguments(const characteristics::Procedure &proc,
@ -427,26 +433,20 @@ void CheckArguments(const characteristics::Procedure &proc,
bool explicitInterface{proc.HasExplicitInterface()};
if (explicitInterface) {
auto buffer{CheckExplicitInterface(proc, actuals, context, scope)};
if (treatingExternalAsImplicit && !buffer.empty()) {
if (auto *msg{context.messages().Say(
"Warning: if the procedure's interface were explicit, this reference would be in error:"_en_US)}) {
buffer.AttachTo(*msg);
}
}
if (auto *msgs{context.messages().messages()}) {
msgs->Merge(std::move(buffer));
}
}
if (!explicitInterface || treatingExternalAsImplicit) {
parser::Messages buffer;
parser::ContextualMessages messages{context.messages().at(), &buffer};
for (auto &actual : actuals) {
if (actual.has_value()) {
CheckImplicitInterfaceArg(*actual, messages);
}
}
if (!buffer.empty()) {
if (treatingExternalAsImplicit) {
if (auto *msg{context.messages().Say(
"Warning: if the procedure's interface were explicit, this reference would be in error:"_en_US)}) {
buffer.AttachTo(*msg);
}
} else if (auto *msgs{context.messages().messages()}) {
msgs->Merge(std::move(buffer));
CheckImplicitInterfaceArg(*actual, context.messages());
}
}
}