diff options
author | Peter Klausler <pklausler@nvidia.com> | 2023-05-16 12:33:29 -0700 |
---|---|---|
committer | Peter Klausler <pklausler@nvidia.com> | 2023-05-16 14:32:48 -0700 |
commit | 7f7bbc73175d94f63cba905191a4ecc341b9fdba (patch) | |
tree | c5a1f8b0630f29acd28524a9c47297984f7e2d6b /flang/lib | |
parent | fcaccf817d31d39096f7d0e7014cd6fe2fa3a683 (diff) | |
download | llvm-7f7bbc73175d94f63cba905191a4ecc341b9fdba.tar.gz |
[flang] Correct overriding (or not) of inaccessible bindings
Fortran doesn't allow inaccessible procedure bindings to be
overridden, and this needs to apply to generic resolution.
When resolving a type-bound generic procedure from another
module, ensure only that the most extended override from its
module is used if it is PRIVATE, not a later apparent override
from another module.
Differential Revision: https://reviews.llvm.org/D150721
Diffstat (limited to 'flang/lib')
-rw-r--r-- | flang/lib/Lower/Bridge.cpp | 13 | ||||
-rw-r--r-- | flang/lib/Lower/ConvertCall.cpp | 11 | ||||
-rw-r--r-- | flang/lib/Semantics/expression.cpp | 52 | ||||
-rw-r--r-- | flang/lib/Semantics/runtime-type-info.cpp | 25 | ||||
-rw-r--r-- | flang/lib/Semantics/symbol.cpp | 4 | ||||
-rw-r--r-- | flang/lib/Semantics/tools.cpp | 10 |
6 files changed, 83 insertions, 32 deletions
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp index c1dbac108b88..875f8624e448 100644 --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -227,13 +227,14 @@ public: builder.createBlock(&dt.getRegion()); for (const Fortran::semantics::SymbolRef &binding : bindings) { - const auto *details = - binding.get().detailsIf<Fortran::semantics::ProcBindingDetails>(); - std::string bindingName = converter.mangleName(details->symbol()); + const auto &details = + binding.get().get<Fortran::semantics::ProcBindingDetails>(); + std::string tbpName = binding.get().name().ToString(); + if (details.numPrivatesNotOverridden() > 0) + tbpName += "."s + std::to_string(details.numPrivatesNotOverridden()); + std::string bindingName = converter.mangleName(details.symbol()); builder.create<fir::DTEntryOp>( - info.loc, - mlir::StringAttr::get(builder.getContext(), - binding.get().name().ToString()), + info.loc, mlir::StringAttr::get(builder.getContext(), tbpName), mlir::SymbolRefAttr::get(builder.getContext(), bindingName)); } if (!bindings.empty()) diff --git a/flang/lib/Lower/ConvertCall.cpp b/flang/lib/Lower/ConvertCall.cpp index 674e2c8c3ae9..d2d91735e21a 100644 --- a/flang/lib/Lower/ConvertCall.cpp +++ b/flang/lib/Lower/ConvertCall.cpp @@ -376,11 +376,16 @@ fir::ExtendedValue Fortran::lower::genCallOpAndResult( // fir.dispatch. // Get the raw procedure name. The procedure name is not mangled in the - // binding table. + // binding table, but there can be a suffix to distinguish bindings of + // the same name (which happens only when PRIVATE bindings exist in + // ancestor types in other modules). const auto &ultimateSymbol = caller.getCallDescription().proc().GetSymbol()->GetUltimate(); - auto procName = toStringRef(ultimateSymbol.name()); - + std::string procName = ultimateSymbol.name().ToString(); + if (const auto &binding{ + ultimateSymbol.get<Fortran::semantics::ProcBindingDetails>()}; + binding.numPrivatesNotOverridden() > 0) + procName += "."s + std::to_string(binding.numPrivatesNotOverridden()); fir::DispatchOp dispatch; if (std::optional<unsigned> passArg = caller.getPassArgIndex()) { // PASS, PASS(arg-name) diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp index b946409d4783..afd92674ed29 100644 --- a/flang/lib/Semantics/expression.cpp +++ b/flang/lib/Semantics/expression.cpp @@ -2199,6 +2199,7 @@ auto ExpressionAnalyzer::AnalyzeProcedureComponentRef( } if (auto *dtExpr{UnwrapExpr<Expr<SomeDerived>>(*base)}) { if (sym->has<semantics::GenericDetails>()) { + const Symbol &generic{*sym}; auto dyType{dtExpr->GetType()}; AdjustActuals adjustment{ [&](const Symbol &proc, ActualArguments &actuals) { @@ -2207,25 +2208,46 @@ auto ExpressionAnalyzer::AnalyzeProcedureComponentRef( } return true; }}; - auto pair{ResolveGeneric(*sym, arguments, adjustment, isSubroutine)}; + auto pair{ + ResolveGeneric(generic, arguments, adjustment, isSubroutine)}; sym = pair.first; - if (sym) { - // re-resolve the name to the specific binding - CHECK(sym->has<semantics::ProcBindingDetails>()); - // Use the most recent override of the binding, if any - CHECK(dyType && dyType->category() == TypeCategory::Derived && - !dyType->IsUnlimitedPolymorphic()); - if (const Symbol *latest{ - DEREF(dyType->GetDerivedTypeSpec().typeSymbol().scope()) - .FindComponent(sym->name())}) { + if (!sym) { + EmitGenericResolutionError(generic, pair.second, isSubroutine); + return std::nullopt; + } + // re-resolve the name to the specific binding + CHECK(sym->has<semantics::ProcBindingDetails>()); + // Use the most recent override of a binding, respecting + // the rule that inaccessible bindings may not be overridden + // outside their module. Fortran doesn't allow a PUBLIC + // binding to be overridden by a PRIVATE one. + CHECK(dyType && dyType->category() == TypeCategory::Derived && + !dyType->IsUnlimitedPolymorphic()); + if (const Symbol * + latest{DEREF(dyType->GetDerivedTypeSpec().typeSymbol().scope()) + .FindComponent(sym->name())}) { + if (sym->attrs().test(semantics::Attr::PRIVATE)) { + const auto *bindingModule{FindModuleContaining(generic.owner())}; + const Symbol *s{latest}; + while (s && FindModuleContaining(s->owner()) != bindingModule) { + if (const auto *parent{s->owner().GetDerivedTypeParent()}) { + s = parent->FindComponent(sym->name()); + } else { + s = nullptr; + } + } + if (s && !s->attrs().test(semantics::Attr::PRIVATE)) { + // The latest override in the same module as the binding + // is public, so it can be overridden. + } else { + latest = s; + } + } + if (latest) { sym = latest; } - sc.component.symbol = const_cast<Symbol *>(sym); - } else { - EmitGenericResolutionError( - *sc.component.symbol, pair.second, isSubroutine); - return std::nullopt; } + sc.component.symbol = const_cast<Symbol *>(sym); } std::optional<DataRef> dataRef{ExtractDataRef(std::move(*dtExpr))}; if (dataRef && !CheckDataRef(*dataRef)) { diff --git a/flang/lib/Semantics/runtime-type-info.cpp b/flang/lib/Semantics/runtime-type-info.cpp index acd3c49b3909..5f62a0870745 100644 --- a/flang/lib/Semantics/runtime-type-info.cpp +++ b/flang/lib/Semantics/runtime-type-info.cpp @@ -964,12 +964,13 @@ SomeExpr RuntimeTableBuilder::PackageIntValueExpr( SymbolVector CollectBindings(const Scope &dtScope) { SymbolVector result; - std::map<SourceName, const Symbol *> localBindings; + std::map<SourceName, Symbol *> localBindings; // Collect local bindings for (auto pair : dtScope) { - const Symbol &symbol{*pair.second}; - if (symbol.has<ProcBindingDetails>()) { + Symbol &symbol{const_cast<Symbol &>(*pair.second)}; + if (auto *binding{symbol.detailsIf<ProcBindingDetails>()}) { localBindings.emplace(symbol.name(), &symbol); + binding->set_numPrivatesNotOverridden(0); } } if (const Scope * parentScope{dtScope.GetDerivedTypeParent()}) { @@ -977,10 +978,20 @@ SymbolVector CollectBindings(const Scope &dtScope) { // Apply overrides from the local bindings of the extended type for (auto iter{result.begin()}; iter != result.end(); ++iter) { const Symbol &symbol{**iter}; - auto overridden{localBindings.find(symbol.name())}; - if (overridden != localBindings.end()) { - *iter = *overridden->second; - localBindings.erase(overridden); + auto overriderIter{localBindings.find(symbol.name())}; + if (overriderIter != localBindings.end()) { + Symbol &overrider{*overriderIter->second}; + if (symbol.attrs().test(Attr::PRIVATE) && + FindModuleContaining(symbol.owner()) != + FindModuleContaining(dtScope)) { + // Don't override inaccessible PRIVATE bindings + auto &binding{overrider.get<ProcBindingDetails>()}; + binding.set_numPrivatesNotOverridden( + binding.numPrivatesNotOverridden() + 1); + } else { + *iter = overrider; + localBindings.erase(overriderIter); + } } } } diff --git a/flang/lib/Semantics/symbol.cpp b/flang/lib/Semantics/symbol.cpp index d35938971d75..83d73f2d0a7a 100644 --- a/flang/lib/Semantics/symbol.cpp +++ b/flang/lib/Semantics/symbol.cpp @@ -518,6 +518,10 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Details &details) { [&](const ProcBindingDetails &x) { os << " => " << x.symbol().name(); DumpOptional(os, "passName", x.passName()); + if (x.numPrivatesNotOverridden() > 0) { + os << " numPrivatesNotOverridden: " + << x.numPrivatesNotOverridden(); + } }, [&](const NamelistDetails &x) { os << ':'; diff --git a/flang/lib/Semantics/tools.cpp b/flang/lib/Semantics/tools.cpp index 711537ec4947..d7ef29951e8c 100644 --- a/flang/lib/Semantics/tools.cpp +++ b/flang/lib/Semantics/tools.cpp @@ -515,7 +515,15 @@ const Symbol *FindOverriddenBinding(const Symbol &symbol) { if (const DeclTypeSpec * parentType{FindParentTypeSpec(symbol.owner())}) { if (const DerivedTypeSpec * parentDerived{parentType->AsDerived()}) { if (const Scope * parentScope{parentDerived->typeSymbol().scope()}) { - return parentScope->FindComponent(symbol.name()); + if (const Symbol * + overridden{parentScope->FindComponent(symbol.name())}) { + // 7.5.7.3 p1: only accessible bindings are overridden + if (!overridden->attrs().test(Attr::PRIVATE) || + (FindModuleContaining(overridden->owner()) == + FindModuleContaining(symbol.owner()))) { + return overridden; + } + } } } } |