diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp --- a/flang/lib/Semantics/expression.cpp +++ b/flang/lib/Semantics/expression.cpp @@ -909,7 +909,10 @@ return std::nullopt; } else if (baseExpr->Rank() == 0) { if (const Symbol * symbol{GetLastSymbol(*baseExpr)}) { - Say("'%s' is not an array"_err_en_US, symbol->name()); + if (!context_.HasError(symbol)) { + Say("'%s' is not an array"_err_en_US, symbol->name()); + context_.SetError(const_cast(*symbol)); + } } } else if (std::optional dataRef{ ExtractDataRef(std::move(*baseExpr))}) { diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp --- a/flang/lib/Semantics/resolve-names.cpp +++ b/flang/lib/Semantics/resolve-names.cpp @@ -1426,6 +1426,7 @@ } void NoteExecutablePartCall(Symbol::Flag, const parser::Call &); + void NoteExecutablePartArrayElement(const parser::Name &); friend void ResolveSpecificationParts(SemanticsContext &, const Symbol &); @@ -5879,7 +5880,11 @@ // Subtlety: The symbol pointers in the parse tree are not set, because // they might end up resolving elsewhere (e.g., construct entities in // SELECT TYPE). - if (Symbol * symbol{currScope().FindSymbol(name->source)}) { + Symbol *symbol{name->symbol}; + if (!symbol) { + symbol = currScope().FindSymbol(name->source); + } + if (symbol) { Symbol::Flag other{flag == Symbol::Flag::Subroutine ? Symbol::Flag::Function : Symbol::Flag::Subroutine}; @@ -5897,6 +5902,25 @@ } } +void ResolveNamesVisitor::NoteExecutablePartArrayElement( + const parser::Name &name) { + // See the "subtlety" comment above for why we're getting the symbol this way + Symbol *symbol{name.symbol}; + if (!symbol) { + symbol = currScope().FindSymbol(name.source); + } + if (symbol) { + if (symbol->detailsIf()) { + if (!context().HasError(*symbol)) { + SayWithDecl( + name, *symbol, "Cannot reference function '%s' as data"_err_en_US); + } + } else { + ConvertToObjectEntity(*symbol); + } + } +} + // Check and set the Function or Subroutine flag on symbol; false on error. bool ResolveNamesVisitor::SetProcFlag( const parser::Name &name, Symbol &symbol, Symbol::Flag flag) { @@ -6263,6 +6287,13 @@ template bool Pre(const A &) { return true; } template void Post(const A &) {} + void Post(const parser::ArrayElement &elem) { + // To avoid converting the name of the array to a function call, note that + // the name we're referencing is an object entity + if (const parser::Name * name{std::get_if(&elem.base.u)}) { + resolver_.NoteExecutablePartArrayElement(*name); + } + } void Post(const parser::FunctionReference &fr) { resolver_.NoteExecutablePartCall(Symbol::Flag::Function, fr.v); } @@ -6994,6 +7025,9 @@ for (const auto &child : node.children()) { ResolveExecutionParts(child); } + // Skim again to catch errors on names declared in blocks that previously did + // not have symbols + ExecutionPartSkimmer{*this}.Walk(node.exec()); } void ResolveNamesVisitor::ResolveOmpParts(const parser::ProgramUnit &node) { diff --git a/flang/test/Semantics/resolve93.f90 b/flang/test/Semantics/resolve93.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/resolve93.f90 @@ -0,0 +1,41 @@ +! RUN: %S/test_errors.sh %s %t %f18 +subroutine s1() + character(10) str + character(10) str1 + !ERROR: 'str' is not an array + print *, str(1:9), str(7) + block + character(10) str2 + !ERROR: Cannot reference function 'str2' as data + print *, str2(1:9), str2(7) + !ERROR: 'str1' is not an array + print *, str1(1:9), str1(7) + end block +end subroutine s1 + +subroutine s2() + character(10) func + !ERROR: Cannot reference function 'func' as data + print *, func(7), func(1:9) +end subroutine s2 + +subroutine s3() + real(8) :: func + !ERROR: Cannot reference function 'func' as data + print *, func(7), func(1:6) +end subroutine s3 + +subroutine s4() + real(8) :: local + real(8) :: local1 + !ERROR: 'local' is not an array + print *, local(1:6), local(7) + !ERROR: Cannot reference function 'local1' as data + print *, local1(7), local1(1:6) +end subroutine s4 + +subroutine s5(arg) + integer :: iVar + external :: arg + iVar = loc(arg) +end subroutine s5