Skip to content

[flang] Fix spurious error with separate module procedures #106768

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion flang/include/flang/Semantics/expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ class ExpressionAnalyzer {
parser::CharBlock, const ProcedureDesignator &, ActualArguments &);
using AdjustActuals =
std::optional<std::function<bool(const Symbol &, ActualArguments &)>>;
bool ResolveForward(const Symbol &);
const Symbol *ResolveForward(const Symbol &);
std::pair<const Symbol *, bool /* failure due ambiguity */> ResolveGeneric(
const Symbol &, const ActualArguments &, const AdjustActuals &,
bool isSubroutine, bool mightBeStructureConstructor = false);
Expand Down
2 changes: 2 additions & 0 deletions flang/include/flang/Semantics/semantics.h
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,8 @@ class SemanticsContext {
void NoteDefinedSymbol(const Symbol &);
bool IsSymbolDefined(const Symbol &) const;

void DumpSymbols(llvm::raw_ostream &);

private:
struct ScopeIndexComparator {
bool operator()(parser::CharBlock, parser::CharBlock) const;
Expand Down
41 changes: 26 additions & 15 deletions flang/lib/Semantics/expression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2650,9 +2650,9 @@ static int ComputeCudaMatchingDistance(
// Handles a forward reference to a module function from what must
// be a specification expression. Return false if the symbol is
// an invalid forward reference.
bool ExpressionAnalyzer::ResolveForward(const Symbol &symbol) {
const Symbol *ExpressionAnalyzer::ResolveForward(const Symbol &symbol) {
if (context_.HasError(symbol)) {
return false;
return nullptr;
}
if (const auto *details{
symbol.detailsIf<semantics::SubprogramNameDetails>()}) {
Expand All @@ -2661,28 +2661,33 @@ bool ExpressionAnalyzer::ResolveForward(const Symbol &symbol) {
// checking a specification expression in a sibling module
// procedure. Resolve its names now so that its interface
// is known.
const semantics::Scope &scope{symbol.owner()};
semantics::ResolveSpecificationParts(context_, symbol);
if (symbol.has<semantics::SubprogramNameDetails>()) {
const Symbol *resolved{nullptr};
if (auto iter{scope.find(symbol.name())}; iter != scope.cend()) {
resolved = &*iter->second;
}
if (!resolved || resolved->has<semantics::SubprogramNameDetails>()) {
// When the symbol hasn't had its details updated, we must have
// already been in the process of resolving the function's
// specification part; but recursive function calls are not
// allowed in specification parts (10.1.11 para 5).
Say("The module function '%s' may not be referenced recursively in a specification expression"_err_en_US,
symbol.name());
context_.SetError(symbol);
return false;
}
return resolved;
} else if (inStmtFunctionDefinition_) {
semantics::ResolveSpecificationParts(context_, symbol);
CHECK(symbol.has<semantics::SubprogramDetails>());
} else { // 10.1.11 para 4
Say("The internal function '%s' may not be referenced in a specification expression"_err_en_US,
symbol.name());
context_.SetError(symbol);
return false;
return nullptr;
}
}
return true;
return &symbol;
}

// Resolve a call to a generic procedure with given actual arguments.
Expand All @@ -2709,20 +2714,21 @@ std::pair<const Symbol *, bool> ExpressionAnalyzer::ResolveGeneric(
}
if (const auto *details{ultimate.detailsIf<semantics::GenericDetails>()}) {
for (const Symbol &specific0 : details->specificProcs()) {
const Symbol &specific{BypassGeneric(specific0)};
if (isSubroutine != !IsFunction(specific)) {
const Symbol &specific1{BypassGeneric(specific0)};
if (isSubroutine != !IsFunction(specific1)) {
continue;
}
if (!ResolveForward(specific)) {
const Symbol *specific{ResolveForward(specific1)};
if (!specific) {
continue;
}
if (std::optional<characteristics::Procedure> procedure{
characteristics::Procedure::Characterize(
ProcedureDesignator{specific}, context_.foldingContext(),
ProcedureDesignator{*specific}, context_.foldingContext(),
/*emitError=*/false)}) {
ActualArguments localActuals{actuals};
if (specific.has<semantics::ProcBindingDetails>()) {
if (!adjustActuals.value()(specific, localActuals)) {
if (specific->has<semantics::ProcBindingDetails>()) {
if (!adjustActuals.value()(*specific, localActuals)) {
continue;
}
}
Expand Down Expand Up @@ -2751,9 +2757,9 @@ std::pair<const Symbol *, bool> ExpressionAnalyzer::ResolveGeneric(
}
if (!procedure->IsElemental()) {
// takes priority over elemental match
nonElemental = &specific;
nonElemental = specific;
} else {
elemental = &specific;
elemental = specific;
}
crtMatchingDistance = ComputeCudaMatchingDistance(
context_.languageFeatures(), *procedure, localActuals);
Expand Down Expand Up @@ -2866,7 +2872,12 @@ auto ExpressionAnalyzer::GetCalleeAndArguments(const parser::Name &name,
if (context_.HasError(symbol)) {
return std::nullopt; // also handles null symbol
}
const Symbol &ultimate{DEREF(symbol).GetUltimate()};
symbol = ResolveForward(*symbol);
if (!symbol) {
return std::nullopt;
}
name.symbol = const_cast<Symbol *>(symbol);
const Symbol &ultimate{symbol->GetUltimate()};
CheckForBadRecursion(name.source, ultimate);
bool dueToAmbiguity{false};
bool isGenericInterface{ultimate.has<semantics::GenericDetails>()};
Expand Down
6 changes: 4 additions & 2 deletions flang/lib/Semantics/semantics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -655,10 +655,12 @@ void Semantics::EmitMessages(llvm::raw_ostream &os) {
context_.messages().Emit(os, context_.allCookedSources());
}

void Semantics::DumpSymbols(llvm::raw_ostream &os) {
DoDumpSymbols(os, context_.globalScope());
void SemanticsContext::DumpSymbols(llvm::raw_ostream &os) {
DoDumpSymbols(os, globalScope());
}

void Semantics::DumpSymbols(llvm::raw_ostream &os) { context_.DumpSymbols(os); }

void Semantics::DumpSymbolsSources(llvm::raw_ostream &os) const {
NameToSymbolMap symbols;
GetSymbolNames(context_.globalScope(), symbols);
Expand Down
20 changes: 20 additions & 0 deletions flang/test/Semantics/smp-proc-ref.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
!RUN: %flang_fc1 -fsyntax-only %s
module m
real :: qux(10)
interface
module subroutine bar(i)
end
module function baz()
end
end interface
end

submodule(m) sm
contains
module procedure bar
qux(i) = baz() ! ensure no bogus error here
end
module procedure baz
baz = 1.
end
end
Loading