@@ -576,11 +576,11 @@ static std::optional<DummyArgument> CharacterizeDummyArgument(
576576 semantics::UnorderedSymbolSet seenProcs);
577577static std::optional<FunctionResult> CharacterizeFunctionResult (
578578 const semantics::Symbol &symbol, FoldingContext &context,
579- semantics::UnorderedSymbolSet seenProcs);
579+ semantics::UnorderedSymbolSet seenProcs, bool emitError );
580580
581581static std::optional<Procedure> CharacterizeProcedure (
582582 const semantics::Symbol &original, FoldingContext &context,
583- semantics::UnorderedSymbolSet seenProcs) {
583+ semantics::UnorderedSymbolSet seenProcs, bool emitError ) {
584584 const auto &symbol{ResolveAssociations (original)};
585585 if (seenProcs.find (symbol) != seenProcs.end ()) {
586586 std::string procsList{GetSeenProcs (seenProcs)};
@@ -591,14 +591,21 @@ static std::optional<Procedure> CharacterizeProcedure(
591591 return std::nullopt ;
592592 }
593593 seenProcs.insert (symbol);
594+ auto CheckForNested{[&](const Symbol &symbol) {
595+ if (emitError) {
596+ context.messages ().Say (
597+ " Procedure '%s' is referenced before being sufficiently defined in a context where it must be so" _err_en_US,
598+ symbol.name ());
599+ }
600+ }};
594601 auto result{common::visit (
595602 common::visitors{
596603 [&](const semantics::SubprogramDetails &subp)
597604 -> std::optional<Procedure> {
598605 Procedure result;
599606 if (subp.isFunction ()) {
600607 if (auto fr{CharacterizeFunctionResult (
601- subp.result (), context, seenProcs)}) {
608+ subp.result (), context, seenProcs, emitError )}) {
602609 result.functionResult = std::move (fr);
603610 } else {
604611 return std::nullopt ;
@@ -641,8 +648,8 @@ static std::optional<Procedure> CharacterizeProcedure(
641648 }
642649 if (const semantics::Symbol *
643650 interfaceSymbol{proc.procInterface ()}) {
644- auto result{
645- CharacterizeProcedure ( *interfaceSymbol, context, seenProcs)};
651+ auto result{CharacterizeProcedure (
652+ *interfaceSymbol, context, seenProcs, /* emitError= */ false )};
646653 if (result && (IsDummy (symbol) || IsPointer (symbol))) {
647654 // Dummy procedures and procedure pointers may not be
648655 // ELEMENTAL, but we do accept the use of elemental intrinsic
@@ -675,8 +682,8 @@ static std::optional<Procedure> CharacterizeProcedure(
675682 }
676683 },
677684 [&](const semantics::ProcBindingDetails &binding) {
678- if (auto result{CharacterizeProcedure (
679- binding. symbol (), context, seenProcs )}) {
685+ if (auto result{CharacterizeProcedure (binding. symbol (), context,
686+ seenProcs, /* emitError= */ false )}) {
680687 if (binding.symbol ().attrs ().test (semantics::Attr::INTRINSIC)) {
681688 result->attrs .reset (Procedure::Attr::Elemental);
682689 }
@@ -695,33 +702,32 @@ static std::optional<Procedure> CharacterizeProcedure(
695702 }
696703 },
697704 [&](const semantics::UseDetails &use) {
698- return CharacterizeProcedure (use.symbol (), context, seenProcs);
705+ return CharacterizeProcedure (
706+ use.symbol (), context, seenProcs, /* emitError=*/ false );
699707 },
700708 [](const semantics::UseErrorDetails &) {
701709 // Ambiguous use-association will be handled later during symbol
702710 // checks, ignore UseErrorDetails here without actual symbol usage.
703711 return std::optional<Procedure>{};
704712 },
705713 [&](const semantics::HostAssocDetails &assoc) {
706- return CharacterizeProcedure (assoc.symbol (), context, seenProcs);
714+ return CharacterizeProcedure (
715+ assoc.symbol (), context, seenProcs, /* emitError=*/ false );
707716 },
708717 [&](const semantics::GenericDetails &generic) {
709718 if (const semantics::Symbol * specific{generic.specific ()}) {
710- return CharacterizeProcedure (*specific, context, seenProcs);
719+ return CharacterizeProcedure (
720+ *specific, context, seenProcs, emitError);
711721 } else {
712722 return std::optional<Procedure>{};
713723 }
714724 },
715725 [&](const semantics::EntityDetails &) {
716- context.messages ().Say (
717- " Procedure '%s' is referenced before being sufficiently defined in a context where it must be so" _err_en_US,
718- symbol.name ());
726+ CheckForNested (symbol);
719727 return std::optional<Procedure>{};
720728 },
721729 [&](const semantics::SubprogramNameDetails &) {
722- context.messages ().Say (
723- " Procedure '%s' is referenced before being sufficiently defined in a context where it must be so" _err_en_US,
724- symbol.name ());
730+ CheckForNested (symbol);
725731 return std::optional<Procedure>{};
726732 },
727733 [&](const auto &) {
@@ -752,7 +758,8 @@ static std::optional<Procedure> CharacterizeProcedure(
752758static std::optional<DummyProcedure> CharacterizeDummyProcedure (
753759 const semantics::Symbol &symbol, FoldingContext &context,
754760 semantics::UnorderedSymbolSet seenProcs) {
755- if (auto procedure{CharacterizeProcedure (symbol, context, seenProcs)}) {
761+ if (auto procedure{CharacterizeProcedure (
762+ symbol, context, seenProcs, /* emitError=*/ true )}) {
756763 // Dummy procedures may not be elemental. Elemental dummy procedure
757764 // interfaces are errors when the interface is not intrinsic, and that
758765 // error is caught elsewhere. Elemental intrinsic interfaces are
@@ -854,7 +861,8 @@ std::optional<DummyArgument> DummyArgument::FromActual(std::string &&name,
854861 std::move (name), std::move (obj));
855862 },
856863 [&](const ProcedureDesignator &designator) {
857- if (auto proc{Procedure::Characterize (designator, context)}) {
864+ if (auto proc{Procedure::Characterize (
865+ designator, context, /* emitError=*/ true )}) {
858866 return std::make_optional<DummyArgument>(
859867 std::move (name), DummyProcedure{std::move (*proc)});
860868 } else {
@@ -988,7 +996,7 @@ bool FunctionResult::operator==(const FunctionResult &that) const {
988996
989997static std::optional<FunctionResult> CharacterizeFunctionResult (
990998 const semantics::Symbol &symbol, FoldingContext &context,
991- semantics::UnorderedSymbolSet seenProcs) {
999+ semantics::UnorderedSymbolSet seenProcs, bool emitError ) {
9921000 if (const auto *object{symbol.detailsIf <semantics::ObjectEntityDetails>()}) {
9931001 if (auto type{TypeAndShape::Characterize (
9941002 symbol, context, /* invariantOnly=*/ false )}) {
@@ -1002,8 +1010,8 @@ static std::optional<FunctionResult> CharacterizeFunctionResult(
10021010 result.cudaDataAttr = object->cudaDataAttr ();
10031011 return result;
10041012 }
1005- } else if (auto maybeProc{
1006- CharacterizeProcedure ( symbol, context, seenProcs)}) {
1013+ } else if (auto maybeProc{CharacterizeProcedure (
1014+ symbol, context, seenProcs, emitError )}) {
10071015 FunctionResult result{std::move (*maybeProc)};
10081016 result.attrs .set (FunctionResult::Attr::Pointer);
10091017 return result;
@@ -1014,7 +1022,8 @@ static std::optional<FunctionResult> CharacterizeFunctionResult(
10141022std::optional<FunctionResult> FunctionResult::Characterize (
10151023 const Symbol &symbol, FoldingContext &context) {
10161024 semantics::UnorderedSymbolSet seenProcs;
1017- return CharacterizeFunctionResult (symbol, context, seenProcs);
1025+ return CharacterizeFunctionResult (
1026+ symbol, context, seenProcs, /* emitError=*/ false );
10181027}
10191028
10201029bool FunctionResult::IsAssumedLengthCharacter () const {
@@ -1360,27 +1369,26 @@ bool Procedure::CanOverride(
13601369}
13611370
13621371std::optional<Procedure> Procedure::Characterize (
1363- const semantics::Symbol &original , FoldingContext &context) {
1372+ const semantics::Symbol &symbol , FoldingContext &context) {
13641373 semantics::UnorderedSymbolSet seenProcs;
1365- return CharacterizeProcedure (original , context, seenProcs);
1374+ return CharacterizeProcedure (symbol , context, seenProcs, /* emitError= */ true );
13661375}
13671376
13681377std::optional<Procedure> Procedure::Characterize (
1369- const ProcedureDesignator &proc, FoldingContext &context) {
1378+ const ProcedureDesignator &proc, FoldingContext &context, bool emitError ) {
13701379 if (const auto *symbol{proc.GetSymbol ()}) {
1371- if (auto result{
1372- characteristics::Procedure::Characterize (*symbol, context)}) {
1373- return result;
1374- }
1380+ semantics::UnorderedSymbolSet seenProcs;
1381+ return CharacterizeProcedure (*symbol, context, seenProcs, emitError);
13751382 } else if (const auto *intrinsic{proc.GetSpecificIntrinsic ()}) {
13761383 return intrinsic->characteristics .value ();
1384+ } else {
1385+ return std::nullopt ;
13771386 }
1378- return std::nullopt ;
13791387}
13801388
13811389std::optional<Procedure> Procedure::Characterize (
13821390 const ProcedureRef &ref, FoldingContext &context) {
1383- if (auto callee{Characterize (ref.proc (), context)}) {
1391+ if (auto callee{Characterize (ref.proc (), context, /* emitError= */ true )}) {
13841392 if (callee->functionResult ) {
13851393 if (const Procedure *
13861394 proc{callee->functionResult ->IsProcedurePointer ()}) {
@@ -1397,7 +1405,7 @@ std::optional<Procedure> Procedure::Characterize(
13971405 return Characterize (*procRef, context);
13981406 } else if (const auto *procDesignator{
13991407 std::get_if<ProcedureDesignator>(&expr.u )}) {
1400- return Characterize (*procDesignator, context);
1408+ return Characterize (*procDesignator, context, /* emitError= */ true );
14011409 } else if (const Symbol * symbol{UnwrapWholeSymbolOrComponentDataRef (expr)}) {
14021410 return Characterize (*symbol, context);
14031411 } else {
@@ -1409,7 +1417,7 @@ std::optional<Procedure> Procedure::Characterize(
14091417
14101418std::optional<Procedure> Procedure::FromActuals (const ProcedureDesignator &proc,
14111419 const ActualArguments &args, FoldingContext &context) {
1412- auto callee{Characterize (proc, context)};
1420+ auto callee{Characterize (proc, context, /* emitError= */ true )};
14131421 if (callee) {
14141422 if (callee->dummyArguments .empty () &&
14151423 callee->attrs .test (Procedure::Attr::ImplicitInterface)) {
0 commit comments