[flang-commits] [flang] 7082de5 - [flang] Handle multiple names for same operator
Tim Keith via flang-commits
flang-commits at lists.llvm.org
Wed Dec 16 07:07:17 PST 2020
Author: Tim Keith
Date: 2020-12-16T07:06:55-08:00
New Revision: 7082de56b7ad4b4eeb75e59e0d4c28bed44b5d23
URL: https://github.com/llvm/llvm-project/commit/7082de56b7ad4b4eeb75e59e0d4c28bed44b5d23
DIFF: https://github.com/llvm/llvm-project/commit/7082de56b7ad4b4eeb75e59e0d4c28bed44b5d23.diff
LOG: [flang] Handle multiple names for same operator
Some operators have more than one name, e.g. operator(==), operator(.eq).
That was working correctly in generic definitions but they can also
appear in other contexts: USE statements and access statements, for
example.
This changes FindInScope to always look for each of the names for
a symbol. So an operator may be use-associated under one name but
declared private under another name and it will be the same symbol.
This replaces GenericSpecInfo::FindInScope which was only usable in
some cases.
Add a version of FindInScope() that looks in the current scope to
simplify many of the calls.
Differential Revision: https://reviews.llvm.org/D93344
Added:
Modified:
flang/lib/Semantics/resolve-names-utils.cpp
flang/lib/Semantics/resolve-names-utils.h
flang/lib/Semantics/resolve-names.cpp
flang/test/Semantics/modfile07.f90
Removed:
################################################################################
diff --git a/flang/lib/Semantics/resolve-names-utils.cpp b/flang/lib/Semantics/resolve-names-utils.cpp
index 8dbd25e163ac..83bff78f426a 100644
--- a/flang/lib/Semantics/resolve-names-utils.cpp
+++ b/flang/lib/Semantics/resolve-names-utils.cpp
@@ -29,6 +29,8 @@ using common::NumericOperator;
using common::RelationalOperator;
using IntrinsicOperator = parser::DefinedOperator::IntrinsicOperator;
+static constexpr const char *operatorPrefix{"operator("};
+
static GenericKind MapIntrinsicOperator(IntrinsicOperator);
Symbol *Resolve(const parser::Name &name, Symbol *symbol) {
@@ -65,6 +67,37 @@ bool IsIntrinsicOperator(
return false;
}
+template <typename E>
+std::forward_list<std::string> GetOperatorNames(
+ const SemanticsContext &context, E opr) {
+ std::forward_list<std::string> result;
+ for (const char *name : context.languageFeatures().GetNames(opr)) {
+ result.emplace_front(std::string{operatorPrefix} + name + ')');
+ }
+ return result;
+}
+
+std::forward_list<std::string> GetAllNames(
+ const SemanticsContext &context, const SourceName &name) {
+ std::string str{name.ToString()};
+ if (!name.empty() && name.end()[-1] == ')' &&
+ name.ToString().rfind(std::string{operatorPrefix}, 0) == 0) {
+ for (int i{0}; i != common::LogicalOperator_enumSize; ++i) {
+ auto names{GetOperatorNames(context, LogicalOperator{i})};
+ if (std::find(names.begin(), names.end(), str) != names.end()) {
+ return names;
+ }
+ }
+ for (int i{0}; i != common::RelationalOperator_enumSize; ++i) {
+ auto names{GetOperatorNames(context, RelationalOperator{i})};
+ if (std::find(names.begin(), names.end(), str) != names.end()) {
+ return names;
+ }
+ }
+ }
+ return {str};
+}
+
bool IsLogicalConstant(
const SemanticsContext &context, const SourceName &name) {
std::string str{name.ToString()};
@@ -73,37 +106,6 @@ bool IsLogicalConstant(
(str == ".t" || str == ".f."));
}
-// The operators <, <=, >, >=, ==, and /= always have the same interpretations
-// as the operators .LT., .LE., .GT., .GE., .EQ., and .NE., respectively.
-std::forward_list<std::string> GenericSpecInfo::GetAllNames(
- SemanticsContext &context) const {
- auto getNames{[&](auto opr) {
- std::forward_list<std::string> result;
- for (const char *name : context.languageFeatures().GetNames(opr)) {
- result.emplace_front("operator("s + name + ')');
- }
- return result;
- }};
- return std::visit(
- common::visitors{[&](const LogicalOperator &x) { return getNames(x); },
- [&](const RelationalOperator &x) { return getNames(x); },
- [&](const auto &) -> std::forward_list<std::string> {
- return {symbolName_.value().ToString()};
- }},
- kind_.u);
-}
-
-Symbol *GenericSpecInfo::FindInScope(
- SemanticsContext &context, const Scope &scope) const {
- for (const auto &name : GetAllNames(context)) {
- auto iter{scope.find(SourceName{name})};
- if (iter != scope.end()) {
- return &*iter->second;
- }
- }
- return nullptr;
-}
-
void GenericSpecInfo::Resolve(Symbol *symbol) const {
if (symbol) {
if (auto *details{symbol->detailsIf<GenericDetails>()}) {
@@ -162,6 +164,16 @@ void GenericSpecInfo::Analyze(const parser::GenericSpec &x) {
x.u);
}
+llvm::raw_ostream &operator<<(
+ llvm::raw_ostream &os, const GenericSpecInfo &info) {
+ os << "GenericSpecInfo: kind=" << info.kind_.ToString();
+ os << " parseName="
+ << (info.parseName_ ? info.parseName_->ToString() : "null");
+ os << " symbolName="
+ << (info.symbolName_ ? info.symbolName_->ToString() : "null");
+ return os;
+}
+
// parser::DefinedOperator::IntrinsicOperator -> GenericKind
static GenericKind MapIntrinsicOperator(IntrinsicOperator op) {
switch (op) {
diff --git a/flang/lib/Semantics/resolve-names-utils.h b/flang/lib/Semantics/resolve-names-utils.h
index 17462d111d97..89011ff3b956 100644
--- a/flang/lib/Semantics/resolve-names-utils.h
+++ b/flang/lib/Semantics/resolve-names-utils.h
@@ -19,6 +19,7 @@
#include "flang/Semantics/semantics.h"
#include "flang/Semantics/symbol.h"
#include "flang/Semantics/type.h"
+#include "llvm/Support/raw_ostream.h"
#include <forward_list>
namespace Fortran::parser {
@@ -50,6 +51,11 @@ parser::MessageFixedText WithIsFatal(
bool IsIntrinsicOperator(const SemanticsContext &, const SourceName &);
bool IsLogicalConstant(const SemanticsContext &, const SourceName &);
+// Some intrinsic operators have more than one name (e.g. `operator(.eq.)` and
+// `operator(==)`). GetAllNames() returns them all, including symbolName.
+std::forward_list<std::string> GetAllNames(
+ const SemanticsContext &, const SourceName &);
+
template <typename T>
MaybeIntExpr EvaluateIntExpr(SemanticsContext &context, const T &expr) {
if (MaybeExpr maybeExpr{
@@ -75,13 +81,11 @@ class GenericSpecInfo {
GenericKind kind() const { return kind_; }
const SourceName &symbolName() const { return symbolName_.value(); }
- // Some intrinsic operators have more than one name (e.g. `operator(.eq.)` and
- // `operator(==)`). GetAllNames() returns them all, including symbolName.
- std::forward_list<std::string> GetAllNames(SemanticsContext &) const;
// Set the GenericKind in this symbol and resolve the corresponding
// name if there is one
void Resolve(Symbol *) const;
- Symbol *FindInScope(SemanticsContext &, const Scope &) const;
+ friend llvm::raw_ostream &operator<<(
+ llvm::raw_ostream &, const GenericSpecInfo &);
private:
GenericKind kind_;
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 5ac787b61d68..1288b11a7727 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -502,6 +502,9 @@ class ScopeHandler : public ImplicitRulesVisitor {
// Search for name only in scope, not in enclosing scopes.
Symbol *FindInScope(const Scope &, const parser::Name &);
Symbol *FindInScope(const Scope &, const SourceName &);
+ template <typename T> Symbol *FindInScope(const T &name) {
+ return FindInScope(currScope(), name);
+ }
// Search for name in a derived type scope and its parents.
Symbol *FindInTypeOrParents(const Scope &, const parser::Name &);
Symbol *FindInTypeOrParents(const parser::Name &);
@@ -533,7 +536,7 @@ class ScopeHandler : public ImplicitRulesVisitor {
const SourceName &name, const Attrs &attrs, D &&details) {
// Note: don't use FindSymbol here. If this is a derived type scope,
// we want to detect whether the name is already declared as a component.
- auto *symbol{FindInScope(currScope(), name)};
+ auto *symbol{FindInScope(name)};
if (!symbol) {
symbol = &MakeSymbol(name, attrs);
symbol->set_details(std::move(details));
@@ -2048,7 +2051,7 @@ Symbol &ScopeHandler::MakeHostAssocSymbol(
return symbol;
}
Symbol &ScopeHandler::CopySymbol(const SourceName &name, const Symbol &symbol) {
- CHECK(!FindInScope(currScope(), name));
+ CHECK(!FindInScope(name));
return MakeSymbol(currScope(), name, symbol.attrs());
}
@@ -2058,11 +2061,14 @@ Symbol *ScopeHandler::FindInScope(
return Resolve(name, FindInScope(scope, name.source));
}
Symbol *ScopeHandler::FindInScope(const Scope &scope, const SourceName &name) {
- if (auto it{scope.find(name)}; it != scope.end()) {
- return &*it->second;
- } else {
- return nullptr;
+ // all variants of names, e.g. "operator(.ne.)" for "operator(/=)"
+ for (const std::string &n : GetAllNames(context(), name)) {
+ auto it{scope.find(SourceName{n})};
+ if (it != scope.end()) {
+ return &*it->second;
+ }
}
+ return nullptr;
}
// Find a component or type parameter by name in a derived type or its parents.
@@ -2318,7 +2324,7 @@ void ModuleVisitor::Post(const parser::UseStmt &x) {
!symbol->attrs().test(Attr::INTRINSIC) &&
!symbol->has<MiscDetails>() && useNames.count(name) == 0) {
SourceName location{x.moduleName.source};
- if (auto *localSymbol{FindInScope(currScope(), name)}) {
+ if (auto *localSymbol{FindInScope(name)}) {
DoAddUse(location, localSymbol->name(), *localSymbol, *symbol);
} else {
DoAddUse(location, location, CopySymbol(name, *symbol), *symbol);
@@ -2397,8 +2403,7 @@ void ModuleVisitor::DoAddUse(const SourceName &location,
generic1.CopyFrom(generic2);
}
EraseSymbol(localSymbol);
- MakeSymbol(
- localSymbol.name(), localUltimate.attrs(), std::move(generic1));
+ MakeSymbol(localSymbol.name(), localSymbol.attrs(), std::move(generic1));
} else {
ConvertToUseError(localSymbol, location, *useModuleScope_);
}
@@ -2435,8 +2440,7 @@ void ModuleVisitor::DoAddUse(const SourceName &location,
void ModuleVisitor::AddUse(const GenericSpecInfo &info) {
if (useModuleScope_) {
const auto &name{info.symbolName()};
- auto rename{
- AddUse(name, name, info.FindInScope(context(), *useModuleScope_))};
+ auto rename{AddUse(name, name, FindInScope(*useModuleScope_, name))};
info.Resolve(rename.use);
}
}
@@ -2523,7 +2527,7 @@ void InterfaceVisitor::Post(const parser::EndInterfaceStmt &) {
// Create a symbol in genericSymbol_ for this GenericSpec.
bool InterfaceVisitor::Pre(const parser::GenericSpec &x) {
- if (auto *symbol{GenericSpecInfo{x}.FindInScope(context(), currScope())}) {
+ if (auto *symbol{FindInScope(GenericSpecInfo{x}.symbolName())}) {
SetGenericSymbol(*symbol);
}
return false;
@@ -3402,7 +3406,7 @@ Symbol &DeclarationVisitor::HandleAttributeStmt(
if (attr == Attr::INTRINSIC && !IsIntrinsic(name.source, std::nullopt)) {
Say(name.source, "'%s' is not a known intrinsic procedure"_err_en_US);
}
- auto *symbol{FindInScope(currScope(), name)};
+ auto *symbol{FindInScope(name)};
if (attr == Attr::ASYNCHRONOUS || attr == Attr::VOLATILE) {
// these can be set on a symbol that is host-assoc or use-assoc
if (!symbol &&
@@ -4065,7 +4069,7 @@ void DeclarationVisitor::CheckBindings(
CHECK(currScope().IsDerivedType());
for (auto &declaration : tbps.declarations) {
auto &bindingName{std::get<parser::Name>(declaration.t)};
- if (Symbol * binding{FindInScope(currScope(), bindingName)}) {
+ if (Symbol * binding{FindInScope(bindingName)}) {
if (auto *details{binding->detailsIf<ProcBindingDetails>()}) {
const Symbol *procedure{FindSubprogram(details->symbol())};
if (!CanBeTypeBoundProc(procedure)) {
@@ -4134,7 +4138,7 @@ bool DeclarationVisitor::Pre(const parser::TypeBoundGenericStmt &x) {
SourceName symbolName{info.symbolName()};
bool isPrivate{accessSpec ? accessSpec->v == parser::AccessSpec::Kind::Private
: derivedTypeInfo_.privateBindings};
- auto *genericSymbol{info.FindInScope(context(), currScope())};
+ auto *genericSymbol{FindInScope(symbolName)};
if (genericSymbol) {
if (!genericSymbol->has<GenericDetails>()) {
genericSymbol = nullptr; // MakeTypeSymbol will report the error below
@@ -4142,7 +4146,7 @@ bool DeclarationVisitor::Pre(const parser::TypeBoundGenericStmt &x) {
} else {
// look in parent types:
Symbol *inheritedSymbol{nullptr};
- for (const auto &name : info.GetAllNames(context())) {
+ for (const auto &name : GetAllNames(context(), symbolName)) {
inheritedSymbol = currScope().FindComponent(SourceName{name});
if (inheritedSymbol) {
break;
@@ -4298,7 +4302,7 @@ bool DeclarationVisitor::Pre(const parser::NamelistStmt::Group &x) {
}
const auto &groupName{std::get<parser::Name>(x.t)};
- auto *groupSymbol{FindInScope(currScope(), groupName)};
+ auto *groupSymbol{FindInScope(groupName)};
if (!groupSymbol || !groupSymbol->has<NamelistDetails>()) {
groupSymbol = &MakeSymbol(groupName, std::move(details));
groupSymbol->ReplaceName(groupName.source);
@@ -4397,7 +4401,7 @@ bool DeclarationVisitor::Pre(const parser::SaveStmt &x) {
void DeclarationVisitor::CheckSaveStmts() {
for (const SourceName &name : saveInfo_.entities) {
- auto *symbol{FindInScope(currScope(), name)};
+ auto *symbol{FindInScope(name)};
if (!symbol) {
// error was reported
} else if (saveInfo_.saveAll) {
@@ -5159,7 +5163,7 @@ bool ConstructVisitor::Pre(const parser::ChangeTeamStmt &x) {
void ConstructVisitor::Post(const parser::CoarrayAssociation &x) {
const auto &decl{std::get<parser::CodimensionDecl>(x.t)};
const auto &name{std::get<parser::Name>(decl.t)};
- if (auto *symbol{FindInScope(currScope(), name)}) {
+ if (auto *symbol{FindInScope(name)}) {
const auto &selector{std::get<parser::Selector>(x.t)};
if (auto sel{ResolveSelector(selector)}) {
const Symbol *whole{UnwrapWholeSymbolDataRef(sel.expr)};
@@ -5962,7 +5966,7 @@ bool ModuleVisitor::Pre(const parser::AccessStmt &x) {
[=](const Indirection<parser::GenericSpec> &y) {
auto info{GenericSpecInfo{y.value()}};
const auto &symbolName{info.symbolName()};
- if (auto *symbol{info.FindInScope(context(), currScope())}) {
+ if (auto *symbol{FindInScope(symbolName)}) {
info.Resolve(&SetAccess(symbolName, accessAttr, symbol));
} else if (info.kind().IsName()) {
info.Resolve(&SetAccess(symbolName, accessAttr));
@@ -6084,7 +6088,7 @@ void ResolveNamesVisitor::CreateGeneric(const parser::GenericSpec &x) {
return;
}
GenericDetails genericDetails;
- if (Symbol * existing{info.FindInScope(context(), currScope())}) {
+ if (Symbol * existing{FindInScope(symbolName)}) {
if (existing->has<GenericDetails>()) {
info.Resolve(existing);
return; // already have generic, add to it
@@ -6204,7 +6208,7 @@ void ResolveNamesVisitor::CheckImports() {
void ResolveNamesVisitor::CheckImport(
const SourceName &location, const SourceName &name) {
- if (auto *symbol{FindInScope(currScope(), name)}) {
+ if (auto *symbol{FindInScope(name)}) {
Say(location, "'%s' from host is not accessible"_err_en_US, name)
.Attach(symbol->name(), "'%s' is hidden by this entity"_en_US,
symbol->name());
diff --git a/flang/test/Semantics/modfile07.f90 b/flang/test/Semantics/modfile07.f90
index 0809da471a60..f3e98bf195f9 100644
--- a/flang/test/Semantics/modfile07.f90
+++ b/flang/test/Semantics/modfile07.f90
@@ -549,3 +549,52 @@ subroutine test()
! end
!end
+! Verify that equivalent names are used when generic operators are merged
+
+module m10a
+ interface operator(.ne.)
+ end interface
+end
+!Expect: m10a.mod
+!module m10a
+! interface operator(.ne.)
+! end interface
+!end
+
+module m10b
+ interface operator(<>)
+ end interface
+end
+!Expect: m10b.mod
+!module m10b
+! interface operator(<>)
+! end interface
+!end
+
+module m10c
+ use m10a
+ use m10b
+ interface operator(/=)
+ end interface
+end
+!Expect: m10c.mod
+!module m10c
+! use m10b,only:operator(.ne.)
+! use m10a,only:operator(.ne.)
+! interface operator(.ne.)
+! end interface
+!end
+
+module m10d
+ use m10a
+ use m10c
+ private :: operator(<>)
+end
+!Expect: m10d.mod
+!module m10d
+! use m10c,only:operator(.ne.)
+! use m10a,only:operator(.ne.)
+! interface operator(.ne.)
+! end interface
+! private::operator(.ne.)
+!end
More information about the flang-commits
mailing list