diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -1779,7 +1779,7 @@ struct Variable { UNION_CLASS_BOILERPLATE(Variable); mutable TypedExpr typedExpr; - parser::CharBlock GetSource() const; + CharBlock GetSource() const; std::variant, common::Indirection> u; diff --git a/flang/include/flang/Semantics/tools.h b/flang/include/flang/Semantics/tools.h --- a/flang/include/flang/Semantics/tools.h +++ b/flang/include/flang/Semantics/tools.h @@ -252,6 +252,10 @@ expr.u); } +// Apply 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 &); + using SomeExpr = evaluate::Expr; bool ExprHasTypeCategory( diff --git a/flang/lib/Evaluate/fold-reduction.h b/flang/lib/Evaluate/fold-reduction.h --- a/flang/lib/Evaluate/fold-reduction.h +++ b/flang/lib/Evaluate/fold-reduction.h @@ -139,7 +139,7 @@ static_assert(T::category == TypeCategory::Integer || T::category == TypeCategory::Real || T::category == TypeCategory::Character); - using Element = Scalar; // pmk: was typename Constant::Element; + using Element = Scalar; std::optional dim; if (std::optional> array{ ProcessReductionArgs(context, ref.arguments(), dim, identity, 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 @@ -175,14 +175,18 @@ // or procedure pointer reference in a ProcedureDesignator. MaybeExpr ExpressionAnalyzer::Designate(DataRef &&ref) { const Symbol &last{ref.GetLastSymbol()}; - const Symbol &symbol{last.GetUltimate()}; + const Symbol &symbol{BypassGeneric(last).GetUltimate()}; if (semantics::IsProcedure(symbol)) { if (auto *component{std::get_if(&ref.u)}) { return Expr{ProcedureDesignator{std::move(*component)}}; } else if (!std::holds_alternative(ref.u)) { DIE("unexpected alternative in DataRef"); } else if (!symbol.attrs().test(semantics::Attr::INTRINSIC)) { - return Expr{ProcedureDesignator{symbol}}; + if (symbol.has()) { + Say("'%s' is not a specific procedure"_err_en_US, symbol.name()); + } else { + return Expr{ProcedureDesignator{symbol}}; + } } else if (auto interface{context_.intrinsics().IsSpecificIntrinsicFunction( symbol.name().ToString())}) { SpecificIntrinsic intrinsic{ @@ -3117,8 +3121,6 @@ std::optional actual; std::visit(common::visitors{ [&](const common::Indirection &x) { - // TODO: Distinguish & handle procedure name and - // proc-component-ref actual = AnalyzeExpr(x.value()); }, [&](const parser::AltReturnSpec &label) { 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 @@ -2751,7 +2751,7 @@ auto &details{generic.get()}; UnorderedSymbolSet symbolsSeen; for (const Symbol &symbol : details.specificProcs()) { - symbolsSeen.insert(symbol); + symbolsSeen.insert(symbol.GetUltimate()); } auto range{specificProcs_.equal_range(&generic)}; for (auto it{range.first}; it != range.second; ++it) { @@ -2762,12 +2762,8 @@ Say(*name, "Procedure '%s' not found"_err_en_US); continue; } - if (symbol == &generic) { - if (auto *specific{generic.get().specific()}) { - symbol = specific; - } - } - const Symbol &ultimate{symbol->GetUltimate()}; + const Symbol &specific{BypassGeneric(*symbol)}; + const Symbol &ultimate{specific.GetUltimate()}; if (!ultimate.has() && !ultimate.has()) { Say(*name, "'%s' is not a subprogram"_err_en_US); @@ -2788,20 +2784,21 @@ } } } - if (!symbolsSeen.insert(ultimate).second) { - if (symbol == &ultimate) { - Say(name->source, - "Procedure '%s' is already specified in generic '%s'"_err_en_US, - name->source, MakeOpName(generic.name())); - } else { - Say(name->source, - "Procedure '%s' from module '%s' is already specified in generic '%s'"_err_en_US, - ultimate.name(), ultimate.owner().GetName().value(), - MakeOpName(generic.name())); - } - continue; + if (symbolsSeen.insert(ultimate).second /*true if added*/) { + // When a specific procedure is a USE association, that association + // is saved in the generic's specifics, not its ultimate symbol, + // so that module file output of interfaces can distinguish them. + details.AddSpecificProc(specific, name->source); + } else if (&specific == &ultimate) { + Say(name->source, + "Procedure '%s' is already specified in generic '%s'"_err_en_US, + name->source, MakeOpName(generic.name())); + } else { + Say(name->source, + "Procedure '%s' from module '%s' is already specified in generic '%s'"_err_en_US, + ultimate.name(), ultimate.owner().GetName().value(), + MakeOpName(generic.name())); } - details.AddSpecificProc(*symbol, name->source); } specificProcs_.erase(range.first, range.second); } diff --git a/flang/lib/Semantics/tools.cpp b/flang/lib/Semantics/tools.cpp --- a/flang/lib/Semantics/tools.cpp +++ b/flang/lib/Semantics/tools.cpp @@ -359,6 +359,16 @@ return nullptr; } +const Symbol &BypassGeneric(const Symbol &symbol) { + const Symbol &ultimate{symbol.GetUltimate()}; + if (const auto *generic{ultimate.detailsIf()}) { + if (const Symbol * specific{generic->specific()}) { + return *specific; + } + } + return symbol; +} + bool ExprHasTypeCategory( const SomeExpr &expr, const common::TypeCategory &type) { auto dynamicType{expr.GetType()}; diff --git a/flang/runtime/type-info.h b/flang/runtime/type-info.h --- a/flang/runtime/type-info.h +++ b/flang/runtime/type-info.h @@ -82,8 +82,7 @@ lenParameterKind_; // pointer to rank-1 array of INTEGER(1) // This array of local data components includes the parent component. - // Components are in alphabetic order. - // TODO pmk: fix to be "component order" + // Components are in component order, not collation order of their names. // It does not include procedure pointer components. StaticDescriptor<1, true> component_; // TYPE(COMPONENT), POINTER, DIMENSION(:), CONTIGUOUS