From 06440bc34de41532e11a9161c333cb898d860bf0 Mon Sep 17 00:00:00 2001 From: Tim Keith Date: Wed, 30 May 2018 14:11:45 -0700 Subject: [PATCH] [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@2a5589ab969421b1723c63105fe6922941ec1096 Reviewed-on: https://github.com/flang-compiler/f18/pull/97 Tree-same-pre-rewrite: false --- flang/lib/semantics/resolve-names.cc | 299 ++++++++++++++------------- 1 file changed, 157 insertions(+), 142 deletions(-) diff --git a/flang/lib/semantics/resolve-names.cc b/flang/lib/semantics/resolve-names.cc index 4370c4a7599b..f01af9a649ca 100644 --- a/flang/lib/semantics/resolve-names.cc +++ b/flang/lib/semantics/resolve-names.cc @@ -428,10 +428,51 @@ private: 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 objectDeclAttr_; + + // Handle a statement that sets an attribute on a list of names. + bool HandleAttributeStmt(Attr, const std::list &); + void DeclareEntity(const parser::Name &, Attrs); +}; + // Walk the parse tree and resolve names to symbols. -class ResolveNamesVisitor : public ArraySpecVisitor, - public ModuleVisitor, - public SubprogramVisitor { +class ResolveNamesVisitor : public ModuleVisitor, + public SubprogramVisitor, + public DeclarationVisitor { public: using ArraySpecVisitor::Post; using ArraySpecVisitor::Pre; @@ -443,6 +484,8 @@ public: using ModuleVisitor::Pre; using SubprogramVisitor::Post; using SubprogramVisitor::Pre; + using DeclarationVisitor::Post; + using DeclarationVisitor::Pre; // Default action for a parse tree node is to visit children. template bool Pre(const T &) { return true; } @@ -456,35 +499,13 @@ public: void Post(const parser::DataComponentDefStmt &) { EndDecl(); } bool Pre(const parser::TypeDeclarationStmt &) { return BeginDecl(); } void Post(const parser::TypeDeclarationStmt &) { EndDecl(); } - void Post(const parser::EntityDecl &); - void Post(const parser::ObjectDecl &); void Post(const parser::ComponentDecl &); 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 &); bool Pre(const parser::MainProgram &); void Post(const parser::EndProgramStmt &); 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::Variable &x) { CheckImplicitSymbol(GetVariableName(x)); @@ -493,14 +514,6 @@ public: void Post(const parser::ProcedureDesignator &); private: - // The attribute corresponding to the statement containing an ObjectDecl - std::optional objectDeclAttr_; - - bool BeginDecl(); - void EndDecl(); - // Handle a statement that sets an attribute on a list of names. - bool HandleAttributeStmt(Attr, const std::list &); - void DeclareEntity(const parser::Name &, Attrs); const parser::Name *GetVariableName(const parser::DataRef &); const parser::Name *GetVariableName(const parser::Designator &); const parser::Name *GetVariableName(const parser::Expr &); @@ -1539,26 +1552,126 @@ Symbol *SubprogramVisitor::GetSpecificFromGeneric(const parser::Name &name) { 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(x.t); + DeclareEntity(name, Attrs{}); +} + +void DeclarationVisitor::Post(const parser::EntityDecl &x) { // TODO: may be under StructureStmt const auto &name{std::get(x.t)}; // TODO: CoarraySpec, CharLength, Initialization DeclareEntity(name, attrs_ ? *attrs_ : Attrs()); } -bool ResolveNamesVisitor::BeginDecl() { - BeginDeclTypeSpec(); - BeginAttrs(); - BeginArraySpec(); - return true; +bool DeclarationVisitor::Pre(const parser::AsynchronousStmt &x) { + return HandleAttributeStmt(Attr::ASYNCHRONOUS, x.v); } -void ResolveNamesVisitor::EndDecl() { - EndDeclTypeSpec(); - EndAttrs(); - EndArraySpec(); +bool DeclarationVisitor::Pre(const parser::ContiguousStmt &x) { + return HandleAttributeStmt(Attr::CONTIGUOUS, x.v); } +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 &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()) { + 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(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()) { + symbol.set_details(EntityDetails()); + } + if (EntityDetails *details = symbol.detailsIf()) { + 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()) { + 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()) { + 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) { 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 &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()) { - 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(x.t); - DeclareEntity(name, Attrs{*objectDeclAttr_}); -} - -void ResolveNamesVisitor::Post(const parser::DimensionStmt::Declaration &x) { - const auto &name = std::get(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()) { - symbol.set_details(EntityDetails()); - } - if (EntityDetails *details = symbol.detailsIf()) { - 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()) { - 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()) { - 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) { Attr accessAttr = AccessSpecToAttr(std::get(x.t)); if (CurrScope().kind() != Scope::Kind::Module) {