Index: flang/include/flang/Semantics/symbol.h =================================================================== --- flang/include/flang/Semantics/symbol.h +++ flang/include/flang/Semantics/symbol.h @@ -337,6 +337,7 @@ public: explicit ProcBindingDetails(const Symbol &symbol) : symbol_{symbol} {} const Symbol &symbol() const { return symbol_; } + void ReplaceSymbol(const Symbol &symbol) { symbol_ = symbol; } private: SymbolRef symbol_; // procedure bound to; may be forward Index: flang/include/flang/Semantics/tools.h =================================================================== --- flang/include/flang/Semantics/tools.h +++ flang/include/flang/Semantics/tools.h @@ -108,7 +108,7 @@ // Returns a pointer to the function's symbol when true, else null const Symbol *IsFunctionResultWithSameNameAsFunction(const Symbol &); bool IsOrContainsEventOrLockComponent(const Symbol &); -bool CanBeTypeBoundProc(const Symbol *); +bool CanBeTypeBoundProc(const Symbol &); // Does a non-PARAMETER symbol have explicit initialization with =value or // =>target in its declaration (but not in a DATA statement)? (Being // ALLOCATABLE or having a derived type with default component initialization @@ -252,7 +252,7 @@ expr.u); } -// Apply GetUltimate(), then if the symbol is a generic procedure shadowing a +// Applies GetUltimate(), then if the symbol is a generic procedure shadowing a // specific procedure of the same name, return it instead. const Symbol &BypassGeneric(const Symbol &); Index: flang/lib/Semantics/resolve-names.cpp =================================================================== --- flang/lib/Semantics/resolve-names.cpp +++ flang/lib/Semantics/resolve-names.cpp @@ -3998,9 +3998,8 @@ } if (isGeneric()) { Symbol &genericSymbol{GetGenericSymbol()}; - if (genericSymbol.has()) { - genericSymbol.get().AddSpecificProc( - *symbol, name.source); + if (auto *details{genericSymbol.detailsIf()}) { + details->AddSpecificProc(*symbol, name.source); } else { CHECK(context().HasError(genericSymbol)); } @@ -5145,8 +5144,8 @@ procedure = NoteInterfaceName(procedureName); } if (procedure) { - if (auto *s{ - MakeTypeSymbol(bindingName, ProcBindingDetails{*procedure})}) { + const Symbol &bindTo{BypassGeneric(*procedure)}; + if (auto *s{MakeTypeSymbol(bindingName, ProcBindingDetails{bindTo})}) { SetPassNameOn(*s); if (GetAttrs().test(Attr::DEFERRED)) { context().SetError(*s); @@ -5163,7 +5162,11 @@ auto &bindingName{std::get(declaration.t)}; if (Symbol * binding{FindInScope(bindingName)}) { if (auto *details{binding->detailsIf()}) { - const Symbol *procedure{FindSubprogram(details->symbol())}; + const Symbol &ultimate{details->symbol().GetUltimate()}; + const Symbol &procedure{BypassGeneric(ultimate)}; + if (&procedure != &ultimate) { + details->ReplaceSymbol(procedure); + } if (!CanBeTypeBoundProc(procedure)) { if (details->symbol().name() != binding->name()) { Say(binding->name(), Index: flang/lib/Semantics/tools.cpp =================================================================== --- flang/lib/Semantics/tools.cpp +++ flang/lib/Semantics/tools.cpp @@ -611,16 +611,19 @@ } // Check this symbol suitable as a type-bound procedure - C769 -bool CanBeTypeBoundProc(const Symbol *symbol) { - if (!symbol || IsDummy(*symbol) || IsProcedurePointer(*symbol)) { +bool CanBeTypeBoundProc(const Symbol &symbol) { + if (IsDummy(symbol) || IsProcedurePointer(symbol)) { return false; - } else if (symbol->has()) { - return symbol->owner().kind() == Scope::Kind::Module; - } else if (auto *details{symbol->detailsIf()}) { - return symbol->owner().kind() == Scope::Kind::Module || - details->isInterface(); - } else if (const auto *proc{symbol->detailsIf()}) { - return !symbol->attrs().test(Attr::INTRINSIC) && + } else if (symbol.has()) { + return symbol.owner().kind() == Scope::Kind::Module; + } else if (auto *details{symbol.detailsIf()}) { + if (details->isInterface()) { + return !symbol.attrs().test(Attr::ABSTRACT); + } else { + return symbol.owner().kind() == Scope::Kind::Module; + } + } else if (const auto *proc{symbol.detailsIf()}) { + return !symbol.attrs().test(Attr::INTRINSIC) && proc->HasExplicitInterface(); } else { return false; Index: flang/test/Semantics/resolve32.f90 =================================================================== --- flang/test/Semantics/resolve32.f90 +++ flang/test/Semantics/resolve32.f90 @@ -18,6 +18,10 @@ subroutine foo end subroutine end interface + abstract interface + subroutine absfoo + end subroutine + end interface integer :: i type t1 integer :: c @@ -34,6 +38,8 @@ !ERROR: 's3' must be either an accessible module procedure or an external procedure with an explicit interface procedure, nopass :: s3 procedure, nopass :: foo + !ERROR: 'absfoo' must be either an accessible module procedure or an external procedure with an explicit interface + procedure, nopass :: absfoo !ERROR: 'bar' must be either an accessible module procedure or an external procedure with an explicit interface procedure, nopass :: bar !ERROR: 'i' must be either an accessible module procedure or an external procedure with an explicit interface