Skip to content

Commit 89d5c31

Browse files
committed
[flang] Make per-argument intrinsic error messages more localized
A recent patch made it possible to emit more localized error messages pertaining to actual arguments in non-intrinsic procedure references. Use these new powers for good and make intrinsic error messages more precise, too. Differential Revision: https://reviews.llvm.org/D121126
1 parent 9fce696 commit 89d5c31

File tree

2 files changed

+50
-35
lines changed

2 files changed

+50
-35
lines changed

flang/include/flang/Parser/message.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,11 @@ class ContextualMessages {
296296
}
297297
}
298298

299+
template <typename... A>
300+
Message *Say(std::optional<CharBlock> at, A &&...args) {
301+
return Say(at.value_or(at_), std::forward<A>(args)...);
302+
}
303+
299304
template <typename... A> Message *Say(A &&...args) {
300305
return Say(at_, std::forward<A>(args)...);
301306
}

flang/lib/Evaluate/intrinsics.cpp

Lines changed: 45 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,7 +1243,7 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
12431243
if (!arg) {
12441244
++missingActualArguments;
12451245
} else if (arg->isAlternateReturn()) {
1246-
messages.Say(
1246+
messages.Say(arg->sourceLocation(),
12471247
"alternate return specifier not acceptable on call to intrinsic '%s'"_err_en_US,
12481248
name);
12491249
return std::nullopt;
@@ -1323,7 +1323,8 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
13231323
continue;
13241324
}
13251325
} else if (d.optionality == Optionality::missing) {
1326-
messages.Say("unexpected '%s=' argument"_err_en_US, d.keyword);
1326+
messages.Say(arg->sourceLocation(), "unexpected '%s=' argument"_err_en_US,
1327+
d.keyword);
13271328
return std::nullopt;
13281329
}
13291330
if (arg->GetAssumedTypeDummy()) {
@@ -1334,8 +1335,8 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
13341335
d.typePattern.kindCode == KindCode::addressable)) {
13351336
continue;
13361337
} else {
1337-
messages.Say("Assumed type TYPE(*) dummy argument not allowed "
1338-
"for '%s=' intrinsic argument"_err_en_US,
1338+
messages.Say(arg->sourceLocation(),
1339+
"Assumed type TYPE(*) dummy argument not allowed for '%s=' intrinsic argument"_err_en_US,
13391340
d.keyword);
13401341
return std::nullopt;
13411342
}
@@ -1352,11 +1353,11 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
13521353
const IntrinsicDummyArgument *nextParam{
13531354
j + 1 < dummies ? &dummy[j + 1] : nullptr};
13541355
if (nextParam && nextParam->rank == Rank::elementalOrBOZ) {
1355-
messages.Say(
1356+
messages.Say(arg->sourceLocation(),
13561357
"Typeless (BOZ) not allowed for both '%s=' & '%s=' arguments"_err_en_US, // C7109
13571358
d.keyword, nextParam->keyword);
13581359
} else {
1359-
messages.Say(
1360+
messages.Say(arg->sourceLocation(),
13601361
"Typeless (BOZ) not allowed for '%s=' argument"_err_en_US,
13611362
d.keyword);
13621363
}
@@ -1370,15 +1371,16 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
13701371
} else if (d.typePattern.kindCode == KindCode::nullPointerType) {
13711372
continue;
13721373
} else {
1373-
messages.Say(
1374+
messages.Say(arg->sourceLocation(),
13741375
"Actual argument for '%s=' may not be a procedure"_err_en_US,
13751376
d.keyword);
13761377
}
13771378
}
13781379
return std::nullopt;
13791380
} else if (!d.typePattern.categorySet.test(type->category())) {
1380-
messages.Say("Actual argument for '%s=' has bad type '%s'"_err_en_US,
1381-
d.keyword, type->AsFortran());
1381+
messages.Say(arg->sourceLocation(),
1382+
"Actual argument for '%s=' has bad type '%s'"_err_en_US, d.keyword,
1383+
type->AsFortran());
13821384
return std::nullopt; // argument has invalid type category
13831385
}
13841386
bool argOk{false};
@@ -1457,7 +1459,7 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
14571459
CRASH_NO_CASE;
14581460
}
14591461
if (!argOk) {
1460-
messages.Say(
1462+
messages.Say(arg->sourceLocation(),
14611463
"Actual argument for '%s=' has bad type or kind '%s'"_err_en_US,
14621464
d.keyword, type->AsFortran());
14631465
return std::nullopt;
@@ -1475,8 +1477,8 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
14751477
if (const ActualArgument * arg{actualForDummy[j]}) {
14761478
bool isAssumedRank{IsAssumedRank(*arg)};
14771479
if (isAssumedRank && d.rank != Rank::anyOrAssumedRank) {
1478-
messages.Say("Assumed-rank array cannot be forwarded to "
1479-
"'%s=' argument"_err_en_US,
1480+
messages.Say(arg->sourceLocation(),
1481+
"Assumed-rank array cannot be forwarded to '%s=' argument"_err_en_US,
14801482
d.keyword);
14811483
return std::nullopt;
14821484
}
@@ -1499,7 +1501,7 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
14991501
case Rank::shape:
15001502
CHECK(!shapeArgSize);
15011503
if (rank != 1) {
1502-
messages.Say(
1504+
messages.Say(arg->sourceLocation(),
15031505
"'shape=' argument must be an array of rank 1"_err_en_US);
15041506
return std::nullopt;
15051507
} else {
@@ -1512,7 +1514,7 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
15121514
}
15131515
}
15141516
if (!argOk) {
1515-
messages.Say(
1517+
messages.Say(arg->sourceLocation(),
15161518
"'shape=' argument must be a vector of known size"_err_en_US);
15171519
return std::nullopt;
15181520
}
@@ -1530,7 +1532,7 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
15301532
case Rank::coarray:
15311533
argOk = IsCoarray(*arg);
15321534
if (!argOk) {
1533-
messages.Say(
1535+
messages.Say(arg->sourceLocation(),
15341536
"'coarray=' argument must have corank > 0 for intrinsic '%s'"_err_en_US,
15351537
name);
15361538
return std::nullopt;
@@ -1556,11 +1558,11 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
15561558
if (std::optional<Shape> shape{GetShape(context, *arg)}) {
15571559
if (!shape->empty() && !shape->back().has_value()) {
15581560
if (strcmp(name, "shape") == 0) {
1559-
messages.Say(
1561+
messages.Say(arg->sourceLocation(),
15601562
"The '%s=' argument to the intrinsic function '%s' may not be assumed-size"_err_en_US,
15611563
d.keyword, name);
15621564
} else {
1563-
messages.Say(
1565+
messages.Say(arg->sourceLocation(),
15641566
"A dim= argument is required for '%s' when the array is assumed-size"_err_en_US,
15651567
name);
15661568
}
@@ -1606,8 +1608,9 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
16061608
d.keyword, name);
16071609
}
16081610
if (!argOk) {
1609-
messages.Say("'%s=' argument has unacceptable rank %d"_err_en_US,
1610-
d.keyword, rank);
1611+
messages.Say(arg->sourceLocation(),
1612+
"'%s=' argument has unacceptable rank %d"_err_en_US, d.keyword,
1613+
rank);
16111614
return std::nullopt;
16121615
}
16131616
}
@@ -2020,14 +2023,15 @@ bool CheckAndRearrangeArguments(ActualArguments &arguments,
20202023
return false;
20212024
}
20222025
} else if (anyKeywords) {
2023-
messages.Say(
2026+
messages.Say(arg ? arg->sourceLocation() : messages.at(),
20242027
"A positional actual argument may not appear after any keyword arguments"_err_en_US);
20252028
return false;
20262029
} else {
20272030
dummyIndex = position++;
20282031
}
20292032
if (rearranged[dummyIndex]) {
2030-
messages.Say("Dummy argument '%s=' appears more than once"_err_en_US,
2033+
messages.Say(arg ? arg->sourceLocation() : messages.at(),
2034+
"Dummy argument '%s=' appears more than once"_err_en_US,
20312035
dummyKeywords[dummyIndex]);
20322036
return false;
20332037
}
@@ -2081,7 +2085,7 @@ SpecificCall IntrinsicProcTable::Implementation::HandleNull(
20812085
"mold"s, characteristics::DummyDataObject{typeAndShape});
20822086
fResult.emplace(std::move(typeAndShape));
20832087
} else {
2084-
context.messages().Say(
2088+
context.messages().Say(arguments[0]->sourceLocation(),
20852089
"MOLD= argument to NULL() lacks type"_err_en_US);
20862090
}
20872091
if (goodProcPointer) {
@@ -2095,7 +2099,7 @@ SpecificCall IntrinsicProcTable::Implementation::HandleNull(
20952099
}
20962100
}
20972101
}
2098-
context.messages().Say(
2102+
context.messages().Say(arguments[0]->sourceLocation(),
20992103
"MOLD= argument to NULL() must be a pointer or allocatable"_err_en_US);
21002104
}
21012105
characteristics::Procedure::Attrs attrs;
@@ -2121,15 +2125,15 @@ IntrinsicProcTable::Implementation::HandleC_F_Pointer(
21212125
CHECK(arguments.size() == 3);
21222126
if (const auto *expr{arguments[0].value().UnwrapExpr()}) {
21232127
if (expr->Rank() > 0) {
2124-
context.messages().Say(
2128+
context.messages().Say(arguments[0]->sourceLocation(),
21252129
"CPTR= argument to C_F_POINTER() must be scalar"_err_en_US);
21262130
}
21272131
if (auto type{expr->GetType()}) {
21282132
if (type->category() != TypeCategory::Derived ||
21292133
type->IsPolymorphic() ||
21302134
type->GetDerivedTypeSpec().typeSymbol().name() !=
21312135
"__builtin_c_ptr") {
2132-
context.messages().Say(
2136+
context.messages().Say(arguments[0]->sourceLocation(),
21332137
"CPTR= argument to C_F_POINTER() must be a C_PTR"_err_en_US);
21342138
}
21352139
characteristics::DummyDataObject cptr{
@@ -2142,11 +2146,11 @@ IntrinsicProcTable::Implementation::HandleC_F_Pointer(
21422146
int fptrRank{expr->Rank()};
21432147
if (auto type{expr->GetType()}) {
21442148
if (type->HasDeferredTypeParameter()) {
2145-
context.messages().Say(
2149+
context.messages().Say(arguments[1]->sourceLocation(),
21462150
"FPTR= argument to C_F_POINTER() may not have a deferred type parameter"_err_en_US);
21472151
}
21482152
if (ExtractCoarrayRef(*expr)) {
2149-
context.messages().Say(
2153+
context.messages().Say(arguments[1]->sourceLocation(),
21502154
"FPTR= argument to C_F_POINTER() may not be a coindexed object"_err_en_US);
21512155
}
21522156
characteristics::DummyDataObject fptr{
@@ -2155,11 +2159,11 @@ IntrinsicProcTable::Implementation::HandleC_F_Pointer(
21552159
fptr.attrs.set(characteristics::DummyDataObject::Attr::Pointer);
21562160
dummies.emplace_back("fptr"s, std::move(fptr));
21572161
} else {
2158-
context.messages().Say(
2162+
context.messages().Say(arguments[1]->sourceLocation(),
21592163
"FPTR= argument to C_F_POINTER() must have a type"_err_en_US);
21602164
}
21612165
if (arguments[2] && fptrRank == 0) {
2162-
context.messages().Say(
2166+
context.messages().Say(arguments[2]->sourceLocation(),
21632167
"SHAPE= argument to C_F_POINTER() may not appear when FPTR= is scalar"_err_en_US);
21642168
} else if (!arguments[2] && fptrRank > 0) {
21652169
context.messages().Say(
@@ -2196,7 +2200,7 @@ static bool CheckAssociated(SpecificCall &call, FoldingContext &context) {
21962200
if (const auto *pointerExpr{pointerArg->UnwrapExpr()}) {
21972201
if (const Symbol * pointerSymbol{GetLastSymbol(*pointerExpr)}) {
21982202
if (!pointerSymbol->attrs().test(semantics::Attr::POINTER)) {
2199-
AttachDeclaration(context.messages().Say(
2203+
AttachDeclaration(context.messages().Say(pointerArg->sourceLocation(),
22002204
"POINTER= argument of ASSOCIATED() must be a "
22012205
"POINTER"_err_en_US),
22022206
*pointerSymbol);
@@ -2268,6 +2272,7 @@ static bool CheckAssociated(SpecificCall &call, FoldingContext &context) {
22682272
CHECK(!symbols.empty());
22692273
if (!GetLastTarget(symbols)) {
22702274
parser::Message *msg{context.messages().Say(
2275+
targetArg->sourceLocation(),
22712276
"TARGET= argument '%s' must have either the POINTER or the TARGET attribute"_err_en_US,
22722277
targetExpr->AsFortran())};
22732278
for (SymbolRef ref : symbols) {
@@ -2301,7 +2306,8 @@ static bool ApplySpecificChecks(SpecificCall &call, FoldingContext &context) {
23012306
bool ok{true};
23022307
const std::string &name{call.specificIntrinsic.name};
23032308
if (name == "allocated") {
2304-
if (const auto &arg{call.arguments[0]}) {
2309+
const auto &arg{call.arguments[0]};
2310+
if (arg) {
23052311
if (const auto *expr{arg->UnwrapExpr()}) {
23062312
if (const Symbol * symbol{GetLastSymbol(*expr)}) {
23072313
ok = symbol->attrs().test(semantics::Attr::ALLOCATABLE);
@@ -2310,20 +2316,23 @@ static bool ApplySpecificChecks(SpecificCall &call, FoldingContext &context) {
23102316
}
23112317
if (!ok) {
23122318
context.messages().Say(
2319+
arg ? arg->sourceLocation() : context.messages().at(),
23132320
"Argument of ALLOCATED() must be an ALLOCATABLE object or component"_err_en_US);
23142321
}
23152322
} else if (name == "associated") {
23162323
return CheckAssociated(call, context);
23172324
} else if (name == "loc") {
2318-
if (const auto &arg{call.arguments[0]}) {
2319-
ok = arg->GetAssumedTypeDummy() || GetLastSymbol(arg->UnwrapExpr());
2320-
}
2325+
const auto &arg{call.arguments[0]};
2326+
ok =
2327+
arg && (arg->GetAssumedTypeDummy() || GetLastSymbol(arg->UnwrapExpr()));
23212328
if (!ok) {
23222329
context.messages().Say(
2330+
arg ? arg->sourceLocation() : context.messages().at(),
23232331
"Argument of LOC() must be an object or procedure"_err_en_US);
23242332
}
23252333
} else if (name == "present") {
2326-
if (const auto &arg{call.arguments[0]}) {
2334+
const auto &arg{call.arguments[0]};
2335+
if (arg) {
23272336
if (const auto *expr{arg->UnwrapExpr()}) {
23282337
if (const Symbol * symbol{UnwrapWholeSymbolDataRef(*expr)}) {
23292338
ok = symbol->attrs().test(semantics::Attr::OPTIONAL);
@@ -2332,6 +2341,7 @@ static bool ApplySpecificChecks(SpecificCall &call, FoldingContext &context) {
23322341
}
23332342
if (!ok) {
23342343
context.messages().Say(
2344+
arg ? arg->sourceLocation() : context.messages().at(),
23352345
"Argument of PRESENT() must be the name of an OPTIONAL dummy argument"_err_en_US);
23362346
}
23372347
}

0 commit comments

Comments
 (0)