forked from OSchip/llvm-project
[flang] Combine GenericDetails and GenericBindingDetails
`GenericDetails` and `GenericBindingDetails` were almost identical: the former has optional data members to handle the case when a specific procedure or derived type has the same name as the generic symbol. Most places they are handled the same way so it simplifies things to have only one type. In the case where we want to know if it is a generic binding (e.g. in `mod-file.cc`) we can check the kind of scope that owns the symbol. Save name from the generic binding for better location of error messages. Original-commit: flang-compiler/f18@f65a9edca2 Reviewed-on: https://github.com/flang-compiler/f18/pull/841 Tree-same-pre-rewrite: false
This commit is contained in:
parent
701a9bd0e5
commit
e2b939e5f3
|
@ -200,12 +200,20 @@ void ModFileWriter::PutSymbol(
|
|||
[&](const DerivedTypeDetails &) { PutDerivedType(symbol); },
|
||||
[&](const SubprogramDetails &) { PutSubprogram(symbol); },
|
||||
[&](const GenericDetails &x) {
|
||||
PutGeneric(symbol);
|
||||
if (x.specific()) {
|
||||
PutSymbol(typeBindings, *x.specific());
|
||||
}
|
||||
if (x.derivedType()) {
|
||||
PutSymbol(typeBindings, *x.derivedType());
|
||||
if (symbol.owner().IsDerivedType()) {
|
||||
// generic binding
|
||||
for (const Symbol &proc : x.specificProcs()) {
|
||||
typeBindings << "generic::" << symbol.name() << "=>"
|
||||
<< proc.name() << '\n';
|
||||
}
|
||||
} else {
|
||||
PutGeneric(symbol);
|
||||
if (x.specific()) {
|
||||
PutSymbol(typeBindings, *x.specific());
|
||||
}
|
||||
if (x.derivedType()) {
|
||||
PutSymbol(typeBindings, *x.derivedType());
|
||||
}
|
||||
}
|
||||
},
|
||||
[&](const UseDetails &) { PutUse(symbol); },
|
||||
|
@ -228,12 +236,6 @@ void ModFileWriter::PutSymbol(
|
|||
}
|
||||
typeBindings << '\n';
|
||||
},
|
||||
[&](const GenericBindingDetails &x) {
|
||||
for (const Symbol &proc : x.specificProcs()) {
|
||||
typeBindings << "generic::" << symbol.name() << "=>"
|
||||
<< proc.name() << '\n';
|
||||
}
|
||||
},
|
||||
[&](const NamelistDetails &x) {
|
||||
decls_ << "namelist/" << symbol.name();
|
||||
char sep{'/'};
|
||||
|
|
|
@ -120,8 +120,6 @@ void GenericSpecInfo::Resolve(Symbol *symbol) const {
|
|||
if (symbol) {
|
||||
if (auto *details{symbol->detailsIf<GenericDetails>()}) {
|
||||
details->set_kind(kind_);
|
||||
} else if (auto *details{symbol->detailsIf<GenericBindingDetails>()}) {
|
||||
details->set_kind(kind_);
|
||||
}
|
||||
if (parseName_) {
|
||||
semantics::Resolve(*parseName_, symbol);
|
||||
|
|
|
@ -2488,7 +2488,7 @@ void InterfaceVisitor::ResolveSpecificsInGeneric(Symbol &generic) {
|
|||
name->source, generic.name());
|
||||
continue;
|
||||
}
|
||||
details.add_specificProc(*symbol);
|
||||
details.AddSpecificProc(*symbol, name->source);
|
||||
}
|
||||
specificProcs_.erase(range.first, range.second);
|
||||
}
|
||||
|
@ -2557,16 +2557,6 @@ void InterfaceVisitor::SayNotDistinguishable(
|
|||
}
|
||||
}
|
||||
|
||||
static GenericKind GetGenericKind(const Symbol &generic) {
|
||||
return std::visit(
|
||||
common::visitors{
|
||||
[&](const GenericDetails &x) { return x.kind(); },
|
||||
[&](const GenericBindingDetails &x) { return x.kind(); },
|
||||
[](auto &) -> GenericKind { DIE("not a generic"); },
|
||||
},
|
||||
generic.details());
|
||||
}
|
||||
|
||||
// Check that the specifics of this generic are distinguishable from each other
|
||||
void InterfaceVisitor::CheckSpecificsAreDistinguishable(
|
||||
Symbol &generic, const SymbolVector &specifics) {
|
||||
|
@ -2574,7 +2564,7 @@ void InterfaceVisitor::CheckSpecificsAreDistinguishable(
|
|||
if (specifics.size() < 2) {
|
||||
return;
|
||||
}
|
||||
auto kind{GetGenericKind(generic)};
|
||||
auto kind{generic.get<GenericDetails>().kind()};
|
||||
auto distinguishable{kind.IsAssignment() || kind.IsOperator()
|
||||
? evaluate::characteristics::DistinguishableOpOrAssign
|
||||
: evaluate::characteristics::Distinguishable};
|
||||
|
@ -2829,7 +2819,7 @@ Symbol &SubprogramVisitor::PushSubprogramScope(
|
|||
MakeExternal(*symbol);
|
||||
}
|
||||
if (isGeneric()) {
|
||||
GetGenericDetails().add_specificProc(*symbol);
|
||||
GetGenericDetails().AddSpecificProc(*symbol, name.source);
|
||||
}
|
||||
implicitRules().set_inheritFromParent(false);
|
||||
}
|
||||
|
@ -3767,8 +3757,8 @@ void DeclarationVisitor::Post(const parser::TypeBoundProcedurePart &) {
|
|||
SayWithDecl(*bindingName, *symbol, // C772
|
||||
"'%s' is not the name of a specific binding of this type"_err_en_US);
|
||||
} else {
|
||||
auto &details{generic->get<GenericBindingDetails>()};
|
||||
details.add_specificProc(*symbol);
|
||||
generic->get<GenericDetails>().AddSpecificProc(
|
||||
*symbol, bindingName->source);
|
||||
}
|
||||
}
|
||||
genericBindings_.clear();
|
||||
|
@ -3864,7 +3854,7 @@ bool DeclarationVisitor::Pre(const parser::TypeBoundGenericStmt &x) {
|
|||
: derivedTypeInfo_.privateBindings};
|
||||
auto *genericSymbol{info.FindInScope(context(), currScope())};
|
||||
if (genericSymbol) {
|
||||
if (!genericSymbol->has<GenericBindingDetails>()) {
|
||||
if (!genericSymbol->has<GenericDetails>()) {
|
||||
genericSymbol = nullptr; // MakeTypeSymbol will report the error below
|
||||
}
|
||||
} else {
|
||||
|
@ -3876,14 +3866,14 @@ bool DeclarationVisitor::Pre(const parser::TypeBoundGenericStmt &x) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (inheritedSymbol && inheritedSymbol->has<GenericBindingDetails>()) {
|
||||
if (inheritedSymbol && inheritedSymbol->has<GenericDetails>()) {
|
||||
CheckAccessibility(symbolName, isPrivate, *inheritedSymbol); // C771
|
||||
}
|
||||
}
|
||||
if (genericSymbol) {
|
||||
CheckAccessibility(symbolName, isPrivate, *genericSymbol); // C771
|
||||
} else {
|
||||
genericSymbol = MakeTypeSymbol(symbolName, GenericBindingDetails{});
|
||||
genericSymbol = MakeTypeSymbol(symbolName, GenericDetails{});
|
||||
if (!genericSymbol) {
|
||||
return false;
|
||||
}
|
||||
|
@ -6118,7 +6108,7 @@ void ResolveNamesVisitor::FinishDerivedTypeDefinition(Scope &scope) {
|
|||
}
|
||||
for (auto &pair : scope) {
|
||||
Symbol &comp{*pair.second};
|
||||
if (const auto *details{comp.detailsIf<GenericBindingDetails>()}) {
|
||||
if (const auto *details{comp.detailsIf<GenericDetails>()}) {
|
||||
CheckSpecificsAreDistinguishable(comp, details->specificProcs());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -150,6 +150,11 @@ UseErrorDetails &UseErrorDetails::add_occurrence(
|
|||
GenericDetails::GenericDetails(const SymbolVector &specificProcs)
|
||||
: specificProcs_{specificProcs} {}
|
||||
|
||||
void GenericDetails::AddSpecificProc(
|
||||
const Symbol &proc, SourceName bindingName) {
|
||||
specificProcs_.push_back(proc);
|
||||
bindingNames_.push_back(bindingName);
|
||||
}
|
||||
void GenericDetails::set_specific(Symbol &specific) {
|
||||
CHECK(!specific_);
|
||||
CHECK(!derivedType_);
|
||||
|
@ -214,7 +219,6 @@ std::string DetailsToString(const Details &details) {
|
|||
[](const HostAssocDetails &) { return "HostAssoc"; },
|
||||
[](const GenericDetails &) { return "Generic"; },
|
||||
[](const ProcBindingDetails &) { return "ProcBinding"; },
|
||||
[](const GenericBindingDetails &) { return "GenericBinding"; },
|
||||
[](const NamelistDetails &) { return "Namelist"; },
|
||||
[](const CommonBlockDetails &) { return "CommonBlockDetails"; },
|
||||
[](const FinalProcDetails &) { return "FinalProc"; },
|
||||
|
@ -437,10 +441,6 @@ std::ostream &operator<<(std::ostream &os, const Details &details) {
|
|||
os << " => " << x.symbol().name();
|
||||
DumpOptional(os, "passName", x.passName());
|
||||
},
|
||||
[&](const GenericBindingDetails &x) {
|
||||
os << " =>";
|
||||
DumpSymbolVector(os, x.specificProcs());
|
||||
},
|
||||
[&](const NamelistDetails &x) {
|
||||
os << ':';
|
||||
DumpSymbolVector(os, x.objects());
|
||||
|
|
|
@ -270,42 +270,6 @@ private:
|
|||
SymbolRef symbol_; // procedure bound to; may be forward
|
||||
};
|
||||
|
||||
// A GenericKind is one of: generic name, defined operator,
|
||||
// defined assignment, intrinsic operator, or defined I/O.
|
||||
struct GenericKind {
|
||||
ENUM_CLASS(OtherKind, Name, DefinedOp, Assignment, Concat)
|
||||
ENUM_CLASS(DefinedIo, // defined io
|
||||
ReadFormatted, ReadUnformatted, WriteFormatted, WriteUnformatted)
|
||||
GenericKind() : u{OtherKind::Name} {}
|
||||
template<typename T> GenericKind(const T &x) { u = x; }
|
||||
bool IsName() const { return Is(OtherKind::Name); }
|
||||
bool IsAssignment() const { return Is(OtherKind::Assignment); }
|
||||
bool IsDefinedOperator() const { return Is(OtherKind::DefinedOp); }
|
||||
bool IsIntrinsicOperator() const;
|
||||
bool IsOperator() const;
|
||||
std::string ToString() const;
|
||||
std::variant<OtherKind, common::NumericOperator, common::LogicalOperator,
|
||||
common::RelationalOperator, DefinedIo>
|
||||
u;
|
||||
|
||||
private:
|
||||
template<typename T> bool Has() const { return std::holds_alternative<T>(u); }
|
||||
bool Is(OtherKind) const;
|
||||
};
|
||||
|
||||
class GenericBindingDetails {
|
||||
public:
|
||||
GenericBindingDetails() {}
|
||||
GenericKind kind() const { return kind_; }
|
||||
void set_kind(GenericKind kind) { kind_ = kind; }
|
||||
const SymbolVector &specificProcs() const { return specificProcs_; }
|
||||
void add_specificProc(const Symbol &proc) { specificProcs_.push_back(proc); }
|
||||
|
||||
private:
|
||||
GenericKind kind_;
|
||||
SymbolVector specificProcs_;
|
||||
};
|
||||
|
||||
class NamelistDetails {
|
||||
public:
|
||||
const SymbolVector &objects() const { return objects_; }
|
||||
|
@ -400,6 +364,30 @@ private:
|
|||
SymbolRef symbol_;
|
||||
};
|
||||
|
||||
// A GenericKind is one of: generic name, defined operator,
|
||||
// defined assignment, intrinsic operator, or defined I/O.
|
||||
struct GenericKind {
|
||||
ENUM_CLASS(OtherKind, Name, DefinedOp, Assignment, Concat)
|
||||
ENUM_CLASS(DefinedIo, // defined io
|
||||
ReadFormatted, ReadUnformatted, WriteFormatted, WriteUnformatted)
|
||||
GenericKind() : u{OtherKind::Name} {}
|
||||
template<typename T> GenericKind(const T &x) { u = x; }
|
||||
bool IsName() const { return Is(OtherKind::Name); }
|
||||
bool IsAssignment() const { return Is(OtherKind::Assignment); }
|
||||
bool IsDefinedOperator() const { return Is(OtherKind::DefinedOp); }
|
||||
bool IsIntrinsicOperator() const;
|
||||
bool IsOperator() const;
|
||||
std::string ToString() const;
|
||||
std::variant<OtherKind, common::NumericOperator, common::LogicalOperator,
|
||||
common::RelationalOperator, DefinedIo>
|
||||
u;
|
||||
|
||||
private:
|
||||
template<typename T> bool Has() const { return std::holds_alternative<T>(u); }
|
||||
bool Is(OtherKind) const;
|
||||
};
|
||||
|
||||
// A generic interface or type-bound generic.
|
||||
class GenericDetails {
|
||||
public:
|
||||
GenericDetails() {}
|
||||
|
@ -409,7 +397,8 @@ public:
|
|||
void set_kind(GenericKind kind) { kind_ = kind; }
|
||||
|
||||
const SymbolVector &specificProcs() const { return specificProcs_; }
|
||||
void add_specificProc(const Symbol &proc) { specificProcs_.push_back(proc); }
|
||||
const std::vector<SourceName> &bindingNames() const { return bindingNames_; }
|
||||
void AddSpecificProc(const Symbol &, SourceName bindingName);
|
||||
|
||||
// specific and derivedType indicate a specific procedure or derived type
|
||||
// with the same name as this generic. Only one of them may be set.
|
||||
|
@ -435,6 +424,7 @@ private:
|
|||
GenericKind kind_;
|
||||
// all of the specific procedures for this generic
|
||||
SymbolVector specificProcs_;
|
||||
std::vector<SourceName> bindingNames_;
|
||||
// a specific procedure with the same name as this generic, if any
|
||||
Symbol *specific_{nullptr};
|
||||
// a derived type with the same name as this generic, if any
|
||||
|
@ -450,8 +440,8 @@ using Details = std::variant<UnknownDetails, MainProgramDetails, ModuleDetails,
|
|||
SubprogramDetails, SubprogramNameDetails, EntityDetails,
|
||||
ObjectEntityDetails, ProcEntityDetails, AssocEntityDetails,
|
||||
DerivedTypeDetails, UseDetails, UseErrorDetails, HostAssocDetails,
|
||||
GenericDetails, ProcBindingDetails, GenericBindingDetails, NamelistDetails,
|
||||
CommonBlockDetails, FinalProcDetails, TypeParamDetails, MiscDetails>;
|
||||
GenericDetails, ProcBindingDetails, NamelistDetails, CommonBlockDetails,
|
||||
FinalProcDetails, TypeParamDetails, MiscDetails>;
|
||||
std::ostream &operator<<(std::ostream &, const Details &);
|
||||
std::string DetailsToString(const Details &);
|
||||
|
||||
|
|
Loading…
Reference in New Issue