Skip to content

Commit cb1b846

Browse files
authored
[flang] Improve error reporting for procedures determined by usage (#88184)
When a symbol is known to be a procedure due to its being referenced as a function or subroutine, improve the error messages that appear if the symbol is also used as an object by attaching the source location of its procedural use. Also, for errors spotted in name resolution due to how a given symbol has been used, don't unconditionally set the symbol's error flag (which is otherwise generally a good idea, to prevent cascades of errors), so that more unrelated errors related to usage will appear.
1 parent e8572d0 commit cb1b846

File tree

3 files changed

+36
-19
lines changed

3 files changed

+36
-19
lines changed

flang/include/flang/Semantics/symbol.h

+5
Original file line numberDiff line numberDiff line change
@@ -435,12 +435,17 @@ class ProcEntityDetails : public EntityDetails, public WithPassArg {
435435
void set_init(std::nullptr_t) { init_ = nullptr; }
436436
bool isCUDAKernel() const { return isCUDAKernel_; }
437437
void set_isCUDAKernel(bool yes = true) { isCUDAKernel_ = yes; }
438+
std::optional<SourceName> usedAsProcedureHere() const {
439+
return usedAsProcedureHere_;
440+
}
441+
void set_usedAsProcedureHere(SourceName here) { usedAsProcedureHere_ = here; }
438442

439443
private:
440444
const Symbol *rawProcInterface_{nullptr};
441445
const Symbol *procInterface_{nullptr};
442446
std::optional<const Symbol *> init_;
443447
bool isCUDAKernel_{false};
448+
std::optional<SourceName> usedAsProcedureHere_;
444449
friend llvm::raw_ostream &operator<<(
445450
llvm::raw_ostream &, const ProcEntityDetails &);
446451
};

flang/lib/Semantics/resolve-names.cpp

+30-17
Original file line numberDiff line numberDiff line change
@@ -687,7 +687,7 @@ class ScopeHandler : public ImplicitRulesVisitor {
687687
Symbol &, bool respectImplicitNoneType = true);
688688
void CheckEntryDummyUse(SourceName, Symbol *);
689689
bool ConvertToObjectEntity(Symbol &);
690-
bool ConvertToProcEntity(Symbol &);
690+
bool ConvertToProcEntity(Symbol &, std::optional<SourceName> = std::nullopt);
691691

692692
const DeclTypeSpec &MakeNumericType(
693693
TypeCategory, const std::optional<parser::KindSelector> &);
@@ -2253,14 +2253,19 @@ void ScopeHandler::SayWithReason(const parser::Name &name, Symbol &symbol,
22532253

22542254
void ScopeHandler::SayWithDecl(
22552255
const parser::Name &name, Symbol &symbol, MessageFixedText &&msg) {
2256-
bool isFatal{msg.IsFatal()};
2257-
Say(name, std::move(msg), symbol.name())
2258-
.Attach(Message{symbol.name(),
2259-
symbol.test(Symbol::Flag::Implicit)
2260-
? "Implicit declaration of '%s'"_en_US
2261-
: "Declaration of '%s'"_en_US,
2262-
name.source});
2263-
context().SetError(symbol, isFatal);
2256+
auto &message{Say(name, std::move(msg), symbol.name())
2257+
.Attach(Message{symbol.name(),
2258+
symbol.test(Symbol::Flag::Implicit)
2259+
? "Implicit declaration of '%s'"_en_US
2260+
: "Declaration of '%s'"_en_US,
2261+
name.source})};
2262+
if (const auto *proc{symbol.detailsIf<ProcEntityDetails>()}) {
2263+
if (auto usedAsProc{proc->usedAsProcedureHere()}) {
2264+
if (usedAsProc->begin() != symbol.name().begin()) {
2265+
message.Attach(Message{*usedAsProc, "Referenced as a procedure"_en_US});
2266+
}
2267+
}
2268+
}
22642269
}
22652270

22662271
void ScopeHandler::SayLocalMustBeVariable(
@@ -2659,9 +2664,9 @@ bool ScopeHandler::ConvertToObjectEntity(Symbol &symbol) {
26592664
return true;
26602665
}
26612666
// Convert symbol to be a ProcEntity or return false if it can't be.
2662-
bool ScopeHandler::ConvertToProcEntity(Symbol &symbol) {
2667+
bool ScopeHandler::ConvertToProcEntity(
2668+
Symbol &symbol, std::optional<SourceName> usedHere) {
26632669
if (symbol.has<ProcEntityDetails>()) {
2664-
// nothing to do
26652670
} else if (symbol.has<UnknownDetails>()) {
26662671
symbol.set_details(ProcEntityDetails{});
26672672
} else if (auto *details{symbol.detailsIf<EntityDetails>()}) {
@@ -2684,6 +2689,10 @@ bool ScopeHandler::ConvertToProcEntity(Symbol &symbol) {
26842689
} else {
26852690
return false;
26862691
}
2692+
auto &proc{symbol.get<ProcEntityDetails>()};
2693+
if (usedHere && !proc.usedAsProcedureHere()) {
2694+
proc.set_usedAsProcedureHere(*usedHere);
2695+
}
26872696
return true;
26882697
}
26892698

@@ -4805,7 +4814,7 @@ bool DeclarationVisitor::Pre(const parser::ExternalStmt &x) {
48054814
HandleAttributeStmt(Attr::EXTERNAL, x.v);
48064815
for (const auto &name : x.v) {
48074816
auto *symbol{FindSymbol(name)};
4808-
if (!ConvertToProcEntity(DEREF(symbol))) {
4817+
if (!ConvertToProcEntity(DEREF(symbol), name.source)) {
48094818
// Check if previous symbol is an interface.
48104819
if (auto *details{symbol->detailsIf<SubprogramDetails>()}) {
48114820
if (details->isInterface()) {
@@ -4845,7 +4854,7 @@ void DeclarationVisitor::DeclareIntrinsic(const parser::Name &name) {
48454854
auto &symbol{DEREF(FindSymbol(name))};
48464855
if (symbol.has<GenericDetails>()) {
48474856
// Generic interface is extending intrinsic; ok
4848-
} else if (!ConvertToProcEntity(symbol)) {
4857+
} else if (!ConvertToProcEntity(symbol, name.source)) {
48494858
SayWithDecl(
48504859
name, symbol, "INTRINSIC attribute not allowed on '%s'"_err_en_US);
48514860
} else if (symbol.attrs().test(Attr::EXTERNAL)) { // C840
@@ -7705,6 +7714,7 @@ const parser::Name *DeclarationVisitor::ResolveDataRef(
77057714
} else if (!context().HasError(*name->symbol)) {
77067715
SayWithDecl(*name, *name->symbol,
77077716
"Cannot reference function '%s' as data"_err_en_US);
7717+
context().SetError(*name->symbol);
77087718
}
77097719
}
77107720
return name;
@@ -8119,7 +8129,7 @@ void ResolveNamesVisitor::HandleProcedureName(
81198129
symbol = &MakeSymbol(context().globalScope(), name.source, Attrs{});
81208130
}
81218131
Resolve(name, *symbol);
8122-
ConvertToProcEntity(*symbol);
8132+
ConvertToProcEntity(*symbol, name.source);
81238133
if (!symbol->attrs().test(Attr::INTRINSIC)) {
81248134
if (CheckImplicitNoneExternal(name.source, *symbol)) {
81258135
MakeExternal(*symbol);
@@ -8144,7 +8154,7 @@ void ResolveNamesVisitor::HandleProcedureName(
81448154
name.symbol = symbol;
81458155
}
81468156
CheckEntryDummyUse(name.source, symbol);
8147-
bool convertedToProcEntity{ConvertToProcEntity(*symbol)};
8157+
bool convertedToProcEntity{ConvertToProcEntity(*symbol, name.source)};
81488158
if (convertedToProcEntity && !symbol->attrs().test(Attr::EXTERNAL) &&
81498159
IsIntrinsic(symbol->name(), flag) && !IsDummy(*symbol)) {
81508160
AcquireIntrinsicProcedureFlags(*symbol);
@@ -8203,7 +8213,7 @@ void ResolveNamesVisitor::NoteExecutablePartCall(
82038213
? Symbol::Flag::Function
82048214
: Symbol::Flag::Subroutine};
82058215
if (!symbol->test(other)) {
8206-
ConvertToProcEntity(*symbol);
8216+
ConvertToProcEntity(*symbol, name);
82078217
if (auto *details{symbol->detailsIf<ProcEntityDetails>()}) {
82088218
symbol->set(flag);
82098219
if (IsDummy(*symbol)) {
@@ -8240,11 +8250,13 @@ bool ResolveNamesVisitor::SetProcFlag(
82408250
if (symbol.test(Symbol::Flag::Function) && flag == Symbol::Flag::Subroutine) {
82418251
SayWithDecl(
82428252
name, symbol, "Cannot call function '%s' like a subroutine"_err_en_US);
8253+
context().SetError(symbol);
82438254
return false;
82448255
} else if (symbol.test(Symbol::Flag::Subroutine) &&
82458256
flag == Symbol::Flag::Function) {
82468257
SayWithDecl(
82478258
name, symbol, "Cannot call subroutine '%s' like a function"_err_en_US);
8259+
context().SetError(symbol);
82488260
return false;
82498261
} else if (flag == Symbol::Flag::Function &&
82508262
IsLocallyImplicitGlobalSymbol(symbol, name) &&
@@ -8263,6 +8275,7 @@ bool ResolveNamesVisitor::SetProcFlag(
82638275
} else if (symbol.GetType() && flag == Symbol::Flag::Subroutine) {
82648276
SayWithDecl(
82658277
name, symbol, "Cannot call function '%s' like a subroutine"_err_en_US);
8278+
context().SetError(symbol);
82668279
} else if (symbol.attrs().test(Attr::INTRINSIC)) {
82678280
AcquireIntrinsicProcedureFlags(symbol);
82688281
}
@@ -8724,7 +8737,7 @@ bool ResolveNamesVisitor::Pre(const parser::PointerAssignmentStmt &x) {
87248737
context().globalScope(), name->source, Attrs{Attr::EXTERNAL})};
87258738
symbol.implicitAttrs().set(Attr::EXTERNAL);
87268739
Resolve(*name, symbol);
8727-
ConvertToProcEntity(symbol);
8740+
ConvertToProcEntity(symbol, name->source);
87288741
return false;
87298742
}
87308743
}

flang/test/Semantics/select-rank.f90

+1-2
Original file line numberDiff line numberDiff line change
@@ -219,11 +219,10 @@ subroutine CALL_ME10(x)
219219
SELECT RANK(ptr=>x)
220220
RANK (3)
221221
PRINT *, "PRINT RANK 3"
222-
!ERROR: 'ptr' is not an object that can appear in an expression
222+
!ERROR: 'kind=' argument must be a constant scalar integer whose value is a supported kind for the intrinsic result type
223223
j = INT(0, KIND=MERGE(KIND(0), -1, RANK(ptr) == 0))
224224
RANK (1)
225225
PRINT *, "PRINT RANK 1"
226-
!ERROR: 'ptr' is not an object that can appear in an expression
227226
j = INT(0, KIND=MERGE(KIND(0), -1, RANK(ptr) == 1))
228227
END SELECT
229228
end subroutine

0 commit comments

Comments
 (0)