forked from OSchip/llvm-project
[flang] Extract DeclarationVisitor from ResolveNamesVisitor
The is a refactoring to move all handling of declarations from ResolveNamesVisitor to a new class. No function change. Original-commit: flang-compiler/f18@2a5589ab96 Reviewed-on: https://github.com/flang-compiler/f18/pull/97 Tree-same-pre-rewrite: false
This commit is contained in:
parent
c263c68b2f
commit
06440bc34d
|
@ -428,10 +428,51 @@ private:
|
||||||
Symbol *GetSpecificFromGeneric(const parser::Name &);
|
Symbol *GetSpecificFromGeneric(const parser::Name &);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class DeclarationVisitor : public ArraySpecVisitor,
|
||||||
|
public virtual ScopeHandler {
|
||||||
|
public:
|
||||||
|
using ArraySpecVisitor::Post;
|
||||||
|
using ArraySpecVisitor::Pre;
|
||||||
|
|
||||||
|
void Post(const parser::EntityDecl &);
|
||||||
|
void Post(const parser::ObjectDecl &);
|
||||||
|
bool Pre(const parser::AsynchronousStmt &);
|
||||||
|
bool Pre(const parser::ContiguousStmt &);
|
||||||
|
bool Pre(const parser::ExternalStmt &);
|
||||||
|
bool Pre(const parser::IntrinsicStmt &);
|
||||||
|
bool Pre(const parser::OptionalStmt &);
|
||||||
|
bool Pre(const parser::ProtectedStmt &);
|
||||||
|
bool Pre(const parser::ValueStmt &);
|
||||||
|
bool Pre(const parser::VolatileStmt &);
|
||||||
|
bool Pre(const parser::AllocatableStmt &) {
|
||||||
|
objectDeclAttr_ = Attr::ALLOCATABLE;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void Post(const parser::AllocatableStmt &) { objectDeclAttr_ = std::nullopt; }
|
||||||
|
bool Pre(const parser::TargetStmt &x) {
|
||||||
|
objectDeclAttr_ = Attr::TARGET;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void Post(const parser::TargetStmt &) { objectDeclAttr_ = std::nullopt; }
|
||||||
|
void Post(const parser::DimensionStmt::Declaration &);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool BeginDecl();
|
||||||
|
void EndDecl();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// The attribute corresponding to the statement containing an ObjectDecl
|
||||||
|
std::optional<Attr> objectDeclAttr_;
|
||||||
|
|
||||||
|
// Handle a statement that sets an attribute on a list of names.
|
||||||
|
bool HandleAttributeStmt(Attr, const std::list<parser::Name> &);
|
||||||
|
void DeclareEntity(const parser::Name &, Attrs);
|
||||||
|
};
|
||||||
|
|
||||||
// Walk the parse tree and resolve names to symbols.
|
// Walk the parse tree and resolve names to symbols.
|
||||||
class ResolveNamesVisitor : public ArraySpecVisitor,
|
class ResolveNamesVisitor : public ModuleVisitor,
|
||||||
public ModuleVisitor,
|
public SubprogramVisitor,
|
||||||
public SubprogramVisitor {
|
public DeclarationVisitor {
|
||||||
public:
|
public:
|
||||||
using ArraySpecVisitor::Post;
|
using ArraySpecVisitor::Post;
|
||||||
using ArraySpecVisitor::Pre;
|
using ArraySpecVisitor::Pre;
|
||||||
|
@ -443,6 +484,8 @@ public:
|
||||||
using ModuleVisitor::Pre;
|
using ModuleVisitor::Pre;
|
||||||
using SubprogramVisitor::Post;
|
using SubprogramVisitor::Post;
|
||||||
using SubprogramVisitor::Pre;
|
using SubprogramVisitor::Pre;
|
||||||
|
using DeclarationVisitor::Post;
|
||||||
|
using DeclarationVisitor::Pre;
|
||||||
|
|
||||||
// Default action for a parse tree node is to visit children.
|
// Default action for a parse tree node is to visit children.
|
||||||
template<typename T> bool Pre(const T &) { return true; }
|
template<typename T> bool Pre(const T &) { return true; }
|
||||||
|
@ -456,35 +499,13 @@ public:
|
||||||
void Post(const parser::DataComponentDefStmt &) { EndDecl(); }
|
void Post(const parser::DataComponentDefStmt &) { EndDecl(); }
|
||||||
bool Pre(const parser::TypeDeclarationStmt &) { return BeginDecl(); }
|
bool Pre(const parser::TypeDeclarationStmt &) { return BeginDecl(); }
|
||||||
void Post(const parser::TypeDeclarationStmt &) { EndDecl(); }
|
void Post(const parser::TypeDeclarationStmt &) { EndDecl(); }
|
||||||
void Post(const parser::EntityDecl &);
|
|
||||||
void Post(const parser::ObjectDecl &);
|
|
||||||
void Post(const parser::ComponentDecl &);
|
void Post(const parser::ComponentDecl &);
|
||||||
bool Pre(const parser::PrefixSpec &);
|
bool Pre(const parser::PrefixSpec &);
|
||||||
bool Pre(const parser::AsynchronousStmt &);
|
|
||||||
bool Pre(const parser::ContiguousStmt &);
|
|
||||||
bool Pre(const parser::ExternalStmt &);
|
|
||||||
bool Pre(const parser::IntrinsicStmt &);
|
|
||||||
bool Pre(const parser::OptionalStmt &);
|
|
||||||
bool Pre(const parser::ProtectedStmt &);
|
|
||||||
bool Pre(const parser::ValueStmt &);
|
|
||||||
bool Pre(const parser::VolatileStmt &);
|
|
||||||
void Post(const parser::SpecificationPart &);
|
void Post(const parser::SpecificationPart &);
|
||||||
bool Pre(const parser::MainProgram &);
|
bool Pre(const parser::MainProgram &);
|
||||||
void Post(const parser::EndProgramStmt &);
|
void Post(const parser::EndProgramStmt &);
|
||||||
void Post(const parser::Program &);
|
void Post(const parser::Program &);
|
||||||
|
|
||||||
bool Pre(const parser::AllocatableStmt &) {
|
|
||||||
objectDeclAttr_ = Attr::ALLOCATABLE;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
void Post(const parser::AllocatableStmt &) { objectDeclAttr_ = std::nullopt; }
|
|
||||||
bool Pre(const parser::TargetStmt &x) {
|
|
||||||
objectDeclAttr_ = Attr::TARGET;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
void Post(const parser::TargetStmt &) { objectDeclAttr_ = std::nullopt; }
|
|
||||||
void Post(const parser::DimensionStmt::Declaration &);
|
|
||||||
|
|
||||||
void Post(const parser::Expr &x) { CheckImplicitSymbol(GetVariableName(x)); }
|
void Post(const parser::Expr &x) { CheckImplicitSymbol(GetVariableName(x)); }
|
||||||
void Post(const parser::Variable &x) {
|
void Post(const parser::Variable &x) {
|
||||||
CheckImplicitSymbol(GetVariableName(x));
|
CheckImplicitSymbol(GetVariableName(x));
|
||||||
|
@ -493,14 +514,6 @@ public:
|
||||||
void Post(const parser::ProcedureDesignator &);
|
void Post(const parser::ProcedureDesignator &);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// The attribute corresponding to the statement containing an ObjectDecl
|
|
||||||
std::optional<Attr> objectDeclAttr_;
|
|
||||||
|
|
||||||
bool BeginDecl();
|
|
||||||
void EndDecl();
|
|
||||||
// Handle a statement that sets an attribute on a list of names.
|
|
||||||
bool HandleAttributeStmt(Attr, const std::list<parser::Name> &);
|
|
||||||
void DeclareEntity(const parser::Name &, Attrs);
|
|
||||||
const parser::Name *GetVariableName(const parser::DataRef &);
|
const parser::Name *GetVariableName(const parser::DataRef &);
|
||||||
const parser::Name *GetVariableName(const parser::Designator &);
|
const parser::Name *GetVariableName(const parser::Designator &);
|
||||||
const parser::Name *GetVariableName(const parser::Expr &);
|
const parser::Name *GetVariableName(const parser::Expr &);
|
||||||
|
@ -1539,26 +1552,126 @@ Symbol *SubprogramVisitor::GetSpecificFromGeneric(const parser::Name &name) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResolveNamesVisitor implementation
|
// DeclarationVisitor implementation
|
||||||
|
|
||||||
void ResolveNamesVisitor::Post(const parser::EntityDecl &x) {
|
bool DeclarationVisitor::BeginDecl() {
|
||||||
|
BeginDeclTypeSpec();
|
||||||
|
BeginAttrs();
|
||||||
|
BeginArraySpec();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void DeclarationVisitor::EndDecl() {
|
||||||
|
EndDeclTypeSpec();
|
||||||
|
EndAttrs();
|
||||||
|
EndArraySpec();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeclarationVisitor::Post(const parser::DimensionStmt::Declaration &x) {
|
||||||
|
const auto &name = std::get<parser::Name>(x.t);
|
||||||
|
DeclareEntity(name, Attrs{});
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeclarationVisitor::Post(const parser::EntityDecl &x) {
|
||||||
// TODO: may be under StructureStmt
|
// TODO: may be under StructureStmt
|
||||||
const auto &name{std::get<parser::ObjectName>(x.t)};
|
const auto &name{std::get<parser::ObjectName>(x.t)};
|
||||||
// TODO: CoarraySpec, CharLength, Initialization
|
// TODO: CoarraySpec, CharLength, Initialization
|
||||||
DeclareEntity(name, attrs_ ? *attrs_ : Attrs());
|
DeclareEntity(name, attrs_ ? *attrs_ : Attrs());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ResolveNamesVisitor::BeginDecl() {
|
bool DeclarationVisitor::Pre(const parser::AsynchronousStmt &x) {
|
||||||
BeginDeclTypeSpec();
|
return HandleAttributeStmt(Attr::ASYNCHRONOUS, x.v);
|
||||||
BeginAttrs();
|
|
||||||
BeginArraySpec();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
void ResolveNamesVisitor::EndDecl() {
|
bool DeclarationVisitor::Pre(const parser::ContiguousStmt &x) {
|
||||||
EndDeclTypeSpec();
|
return HandleAttributeStmt(Attr::CONTIGUOUS, x.v);
|
||||||
EndAttrs();
|
|
||||||
EndArraySpec();
|
|
||||||
}
|
}
|
||||||
|
bool DeclarationVisitor::Pre(const parser::ExternalStmt &x) {
|
||||||
|
return HandleAttributeStmt(Attr::EXTERNAL, x.v);
|
||||||
|
}
|
||||||
|
bool DeclarationVisitor::Pre(const parser::IntrinsicStmt &x) {
|
||||||
|
return HandleAttributeStmt(Attr::INTRINSIC, x.v);
|
||||||
|
}
|
||||||
|
bool DeclarationVisitor::Pre(const parser::OptionalStmt &x) {
|
||||||
|
return HandleAttributeStmt(Attr::OPTIONAL, x.v);
|
||||||
|
}
|
||||||
|
bool DeclarationVisitor::Pre(const parser::ProtectedStmt &x) {
|
||||||
|
return HandleAttributeStmt(Attr::PROTECTED, x.v);
|
||||||
|
}
|
||||||
|
bool DeclarationVisitor::Pre(const parser::ValueStmt &x) {
|
||||||
|
return HandleAttributeStmt(Attr::VALUE, x.v);
|
||||||
|
}
|
||||||
|
bool DeclarationVisitor::Pre(const parser::VolatileStmt &x) {
|
||||||
|
return HandleAttributeStmt(Attr::VOLATILE, x.v);
|
||||||
|
}
|
||||||
|
bool DeclarationVisitor::HandleAttributeStmt(
|
||||||
|
Attr attr, const std::list<parser::Name> &names) {
|
||||||
|
for (const auto &name : names) {
|
||||||
|
const auto pair = CurrScope().try_emplace(name.source, Attrs{attr});
|
||||||
|
if (!pair.second) {
|
||||||
|
// symbol was already there: set attribute on it
|
||||||
|
Symbol &symbol{pair.first->second};
|
||||||
|
if (attr != Attr::ASYNCHRONOUS && attr != Attr::VOLATILE &&
|
||||||
|
symbol.has<UseDetails>()) {
|
||||||
|
Say(*currStmtSource(),
|
||||||
|
"Cannot change %s attribute on use-associated '%s'"_err_en_US,
|
||||||
|
EnumToString(attr), name.source);
|
||||||
|
}
|
||||||
|
symbol.attrs().set(attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeclarationVisitor::Post(const parser::ObjectDecl &x) {
|
||||||
|
CHECK(objectDeclAttr_.has_value());
|
||||||
|
const auto &name = std::get<parser::ObjectName>(x.t);
|
||||||
|
DeclareEntity(name, Attrs{*objectDeclAttr_});
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeclarationVisitor::DeclareEntity(const parser::Name &name, Attrs attrs) {
|
||||||
|
Symbol &symbol{MakeSymbol(name.source, attrs)};
|
||||||
|
// TODO: check attribute consistency
|
||||||
|
if (symbol.has<UnknownDetails>()) {
|
||||||
|
symbol.set_details(EntityDetails());
|
||||||
|
}
|
||||||
|
if (EntityDetails *details = symbol.detailsIf<EntityDetails>()) {
|
||||||
|
if (declTypeSpec_) {
|
||||||
|
if (details->type().has_value()) {
|
||||||
|
Say(name, "The type of '%s' has already been declared"_err_en_US);
|
||||||
|
} else {
|
||||||
|
details->set_type(*declTypeSpec_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!arraySpec().empty()) {
|
||||||
|
if (!details->shape().empty()) {
|
||||||
|
Say(name,
|
||||||
|
"The dimensions of '%s' have already been declared"_err_en_US);
|
||||||
|
} else {
|
||||||
|
details->set_shape(arraySpec());
|
||||||
|
}
|
||||||
|
ClearArraySpec();
|
||||||
|
}
|
||||||
|
} else if (UseDetails *details = symbol.detailsIf<UseDetails>()) {
|
||||||
|
Say(name.source,
|
||||||
|
"'%s' is use-associated from module '%s' and cannot be re-declared"_err_en_US,
|
||||||
|
name.source, details->module().name());
|
||||||
|
} else if (auto *details = symbol.detailsIf<SubprogramNameDetails>()) {
|
||||||
|
if (details->kind() == SubprogramKind::Module) {
|
||||||
|
Say(name,
|
||||||
|
"Declaration of '%s' conflicts with its use as module procedure"_err_en_US)
|
||||||
|
.Attach(symbol.name(), "Module procedure definition"_en_US);
|
||||||
|
} else if (details->kind() == SubprogramKind::Internal) {
|
||||||
|
Say(name,
|
||||||
|
"Declaration of '%s' conflicts with its use as internal procedure"_err_en_US)
|
||||||
|
.Attach(symbol.name(), "Internal procedure definition"_en_US);
|
||||||
|
} else {
|
||||||
|
CHECK(!"unexpected kind");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SayAlreadyDeclared(name.source, symbol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolveNamesVisitor implementation
|
||||||
|
|
||||||
bool ResolveNamesVisitor::Pre(const parser::TypeParamDefStmt &x) {
|
bool ResolveNamesVisitor::Pre(const parser::TypeParamDefStmt &x) {
|
||||||
BeginDeclTypeSpec();
|
BeginDeclTypeSpec();
|
||||||
|
@ -1629,104 +1742,6 @@ void ResolveNamesVisitor::Post(const parser::ProcedureDesignator &x) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ResolveNamesVisitor::Pre(const parser::AsynchronousStmt &x) {
|
|
||||||
return HandleAttributeStmt(Attr::ASYNCHRONOUS, x.v);
|
|
||||||
}
|
|
||||||
bool ResolveNamesVisitor::Pre(const parser::ContiguousStmt &x) {
|
|
||||||
return HandleAttributeStmt(Attr::CONTIGUOUS, x.v);
|
|
||||||
}
|
|
||||||
bool ResolveNamesVisitor::Pre(const parser::ExternalStmt &x) {
|
|
||||||
return HandleAttributeStmt(Attr::EXTERNAL, x.v);
|
|
||||||
}
|
|
||||||
bool ResolveNamesVisitor::Pre(const parser::IntrinsicStmt &x) {
|
|
||||||
return HandleAttributeStmt(Attr::INTRINSIC, x.v);
|
|
||||||
}
|
|
||||||
bool ResolveNamesVisitor::Pre(const parser::OptionalStmt &x) {
|
|
||||||
return HandleAttributeStmt(Attr::OPTIONAL, x.v);
|
|
||||||
}
|
|
||||||
bool ResolveNamesVisitor::Pre(const parser::ProtectedStmt &x) {
|
|
||||||
return HandleAttributeStmt(Attr::PROTECTED, x.v);
|
|
||||||
}
|
|
||||||
bool ResolveNamesVisitor::Pre(const parser::ValueStmt &x) {
|
|
||||||
return HandleAttributeStmt(Attr::VALUE, x.v);
|
|
||||||
}
|
|
||||||
bool ResolveNamesVisitor::Pre(const parser::VolatileStmt &x) {
|
|
||||||
return HandleAttributeStmt(Attr::VOLATILE, x.v);
|
|
||||||
}
|
|
||||||
bool ResolveNamesVisitor::HandleAttributeStmt(
|
|
||||||
Attr attr, const std::list<parser::Name> &names) {
|
|
||||||
for (const auto &name : names) {
|
|
||||||
const auto pair = CurrScope().try_emplace(name.source, Attrs{attr});
|
|
||||||
if (!pair.second) {
|
|
||||||
// symbol was already there: set attribute on it
|
|
||||||
Symbol &symbol{pair.first->second};
|
|
||||||
if (attr != Attr::ASYNCHRONOUS && attr != Attr::VOLATILE &&
|
|
||||||
symbol.has<UseDetails>()) {
|
|
||||||
Say(*currStmtSource(),
|
|
||||||
"Cannot change %s attribute on use-associated '%s'"_err_en_US,
|
|
||||||
EnumToString(attr), name.source);
|
|
||||||
}
|
|
||||||
symbol.attrs().set(attr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResolveNamesVisitor::Post(const parser::ObjectDecl &x) {
|
|
||||||
CHECK(objectDeclAttr_.has_value());
|
|
||||||
const auto &name = std::get<parser::ObjectName>(x.t);
|
|
||||||
DeclareEntity(name, Attrs{*objectDeclAttr_});
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResolveNamesVisitor::Post(const parser::DimensionStmt::Declaration &x) {
|
|
||||||
const auto &name = std::get<parser::Name>(x.t);
|
|
||||||
DeclareEntity(name, Attrs{});
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResolveNamesVisitor::DeclareEntity(const parser::Name &name, Attrs attrs) {
|
|
||||||
Symbol &symbol{MakeSymbol(name.source, attrs)};
|
|
||||||
// TODO: check attribute consistency
|
|
||||||
if (symbol.has<UnknownDetails>()) {
|
|
||||||
symbol.set_details(EntityDetails());
|
|
||||||
}
|
|
||||||
if (EntityDetails *details = symbol.detailsIf<EntityDetails>()) {
|
|
||||||
if (declTypeSpec_) {
|
|
||||||
if (details->type().has_value()) {
|
|
||||||
Say(name, "The type of '%s' has already been declared"_err_en_US);
|
|
||||||
} else {
|
|
||||||
details->set_type(*declTypeSpec_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!arraySpec().empty()) {
|
|
||||||
if (!details->shape().empty()) {
|
|
||||||
Say(name,
|
|
||||||
"The dimensions of '%s' have already been declared"_err_en_US);
|
|
||||||
} else {
|
|
||||||
details->set_shape(arraySpec());
|
|
||||||
}
|
|
||||||
ClearArraySpec();
|
|
||||||
}
|
|
||||||
} else if (UseDetails *details = symbol.detailsIf<UseDetails>()) {
|
|
||||||
Say(name.source,
|
|
||||||
"'%s' is use-associated from module '%s' and cannot be re-declared"_err_en_US,
|
|
||||||
name.source, details->module().name());
|
|
||||||
} else if (auto *details = symbol.detailsIf<SubprogramNameDetails>()) {
|
|
||||||
if (details->kind() == SubprogramKind::Module) {
|
|
||||||
Say(name,
|
|
||||||
"Declaration of '%s' conflicts with its use as module procedure"_err_en_US)
|
|
||||||
.Attach(symbol.name(), "Module procedure definition"_en_US);
|
|
||||||
} else if (details->kind() == SubprogramKind::Internal) {
|
|
||||||
Say(name,
|
|
||||||
"Declaration of '%s' conflicts with its use as internal procedure"_err_en_US)
|
|
||||||
.Attach(symbol.name(), "Internal procedure definition"_en_US);
|
|
||||||
} else {
|
|
||||||
CHECK(!"unexpected kind");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
SayAlreadyDeclared(name.source, symbol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ModuleVisitor::Pre(const parser::AccessStmt &x) {
|
bool ModuleVisitor::Pre(const parser::AccessStmt &x) {
|
||||||
Attr accessAttr = AccessSpecToAttr(std::get<parser::AccessSpec>(x.t));
|
Attr accessAttr = AccessSpecToAttr(std::get<parser::AccessSpec>(x.t));
|
||||||
if (CurrScope().kind() != Scope::Kind::Module) {
|
if (CurrScope().kind() != Scope::Kind::Module) {
|
||||||
|
|
Loading…
Reference in New Issue