summaryrefslogtreecommitdiff
path: root/flang/lib
diff options
context:
space:
mode:
authorPeter Klausler <pklausler@nvidia.com>2023-05-16 12:33:29 -0700
committerPeter Klausler <pklausler@nvidia.com>2023-05-16 14:32:48 -0700
commit7f7bbc73175d94f63cba905191a4ecc341b9fdba (patch)
treec5a1f8b0630f29acd28524a9c47297984f7e2d6b /flang/lib
parentfcaccf817d31d39096f7d0e7014cd6fe2fa3a683 (diff)
downloadllvm-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.cpp13
-rw-r--r--flang/lib/Lower/ConvertCall.cpp11
-rw-r--r--flang/lib/Semantics/expression.cpp52
-rw-r--r--flang/lib/Semantics/runtime-type-info.cpp25
-rw-r--r--flang/lib/Semantics/symbol.cpp4
-rw-r--r--flang/lib/Semantics/tools.cpp10
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;
+ }
+ }
}
}
}