Skip to content

Commit

Permalink
[flang] Combine GenericDetails and GenericBindingDetails
Browse files Browse the repository at this point in the history
`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@f65a9ed
Reviewed-on: flang-compiler/f18#841
Tree-same-pre-rewrite: false
  • Loading branch information
tskeith committed Nov 26, 2019
1 parent 701a9bd commit e2b939e
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 77 deletions.
26 changes: 14 additions & 12 deletions flang/lib/semantics/mod-file.cc
Expand Up @@ -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); },
Expand All @@ -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{'/'};
Expand Down
2 changes: 0 additions & 2 deletions flang/lib/semantics/resolve-names-utils.cc
Expand Up @@ -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);
Expand Down
28 changes: 9 additions & 19 deletions flang/lib/semantics/resolve-names.cc
Expand Up @@ -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);
}
Expand Down Expand Up @@ -2557,24 +2557,14 @@ 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) {
auto count{specifics.size()};
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};
Expand Down Expand Up @@ -2829,7 +2819,7 @@ Symbol &SubprogramVisitor::PushSubprogramScope(
MakeExternal(*symbol);
}
if (isGeneric()) {
GetGenericDetails().add_specificProc(*symbol);
GetGenericDetails().AddSpecificProc(*symbol, name.source);
}
implicitRules().set_inheritFromParent(false);
}
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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 {
Expand All @@ -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;
}
Expand Down Expand Up @@ -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());
}
}
Expand Down
10 changes: 5 additions & 5 deletions flang/lib/semantics/symbol.cc
Expand Up @@ -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_);
Expand Down Expand Up @@ -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"; },
Expand Down Expand Up @@ -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());
Expand Down
68 changes: 29 additions & 39 deletions flang/lib/semantics/symbol.h
Expand Up @@ -270,42 +270,6 @@ class ProcBindingDetails : public WithPassArg {
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_; }
Expand Down Expand Up @@ -400,6 +364,30 @@ class HostAssocDetails {
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() {}
Expand All @@ -409,7 +397,8 @@ class GenericDetails {
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.
Expand All @@ -435,6 +424,7 @@ class GenericDetails {
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
Expand All @@ -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 &);

Expand Down

0 comments on commit e2b939e

Please sign in to comment.