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.
-class ResolveNamesVisitor : public ArraySpecVisitor,
- public ModuleVisitor,
- public SubprogramVisitor {
+class ResolveNamesVisitor : public ModuleVisitor,
+ public SubprogramVisitor,
+ public DeclarationVisitor {
public:
using ArraySpecVisitor::Post;
using ArraySpecVisitor::Pre;
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<typename T> bool Pre(const T &) { return true; }
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));
void Post(const parser::ProcedureDesignator &);
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::Designator &);
const parser::Name *GetVariableName(const parser::Expr &);
return nullptr;
}
-// ResolveNamesVisitor implementation
-
-void ResolveNamesVisitor::Post(const parser::EntityDecl &x) {
- // TODO: may be under StructureStmt
- const auto &name{std::get<parser::ObjectName>(x.t)};
- // TODO: CoarraySpec, CharLength, Initialization
- DeclareEntity(name, attrs_ ? *attrs_ : Attrs());
-}
+// DeclarationVisitor implementation
-bool ResolveNamesVisitor::BeginDecl() {
+bool DeclarationVisitor::BeginDecl() {
BeginDeclTypeSpec();
BeginAttrs();
BeginArraySpec();
return true;
}
-void ResolveNamesVisitor::EndDecl() {
+void DeclarationVisitor::EndDecl() {
EndDeclTypeSpec();
EndAttrs();
EndArraySpec();
}
-bool ResolveNamesVisitor::Pre(const parser::TypeParamDefStmt &x) {
- BeginDeclTypeSpec();
- return true;
-}
-void ResolveNamesVisitor::Post(const parser::TypeParamDefStmt &x) {
- EndDeclTypeSpec();
- // TODO: TypeParamDefStmt
-}
-
-bool ResolveNamesVisitor::Pre(const parser::CommonBlockObject &x) {
- BeginArraySpec();
- return true;
-}
-void ResolveNamesVisitor::Post(const parser::CommonBlockObject &x) {
- ClearArraySpec();
- // TODO: CommonBlockObject
-}
-
-void ResolveNamesVisitor::Post(const parser::ComponentDecl &) {
- ClearArraySpec();
-}
-
-bool ResolveNamesVisitor::Pre(const parser::PrefixSpec &x) {
- return true; // TODO
-}
-
-bool ResolveNamesVisitor::CheckUseError(
- const SourceName &name, const Symbol &symbol) {
- const auto *details = symbol.detailsIf<UseErrorDetails>();
- if (!details) {
- return false;
- }
- Message &msg{Say(name, "Reference to '%s' is ambiguous"_err_en_US)};
- for (const auto &pair : details->occurrences()) {
- const SourceName &location{*pair.first};
- const SourceName &moduleName{pair.second->name()};
- msg.Attach(location,
- MessageFormattedText{"'%s' was use-associated from module '%s'"_en_US,
- name.ToString().data(), moduleName.ToString().data()});
- }
- return true;
+void DeclarationVisitor::Post(const parser::DimensionStmt::Declaration &x) {
+ const auto &name = std::get<parser::Name>(x.t);
+ DeclareEntity(name, Attrs{});
}
-void ResolveNamesVisitor::Post(const parser::ProcedureDesignator &x) {
- if (const auto *name = std::get_if<parser::Name>(&x.u)) {
- Symbol &symbol{MakeSymbol(name->source)};
- if (symbol.has<UnknownDetails>()) {
- if (isImplicitNoneExternal() && !symbol.attrs().test(Attr::EXTERNAL)) {
- Say(*name,
- "'%s' is an external procedure without the EXTERNAL"
- " attribute in a scope with IMPLICIT NONE(EXTERNAL)"_err_en_US);
- }
- symbol.attrs().set(Attr::EXTERNAL);
- symbol.set_details(SubprogramDetails{});
- } else if (CheckUseError(name->source, symbol)) {
- // error was reported
- } else if (!symbol.isSubprogram()) {
- auto *details = symbol.detailsIf<EntityDetails>();
- if (!details || !details->isArray()) {
- Say(*name,
- "Use of '%s' as a procedure conflicts with its declaration"_err_en_US)
- .Attach(symbol.name(),
- MessageFormattedText{"Declaration of '%s'"_en_US,
- symbol.name().ToString().data()});
- }
- }
- }
+void DeclarationVisitor::Post(const parser::EntityDecl &x) {
+ // TODO: may be under StructureStmt
+ const auto &name{std::get<parser::ObjectName>(x.t)};
+ // TODO: CoarraySpec, CharLength, Initialization
+ DeclareEntity(name, attrs_ ? *attrs_ : Attrs());
}
-bool ResolveNamesVisitor::Pre(const parser::AsynchronousStmt &x) {
+bool DeclarationVisitor::Pre(const parser::AsynchronousStmt &x) {
return HandleAttributeStmt(Attr::ASYNCHRONOUS, x.v);
}
-bool ResolveNamesVisitor::Pre(const parser::ContiguousStmt &x) {
+bool DeclarationVisitor::Pre(const parser::ContiguousStmt &x) {
return HandleAttributeStmt(Attr::CONTIGUOUS, x.v);
}
-bool ResolveNamesVisitor::Pre(const parser::ExternalStmt &x) {
+bool DeclarationVisitor::Pre(const parser::ExternalStmt &x) {
return HandleAttributeStmt(Attr::EXTERNAL, x.v);
}
-bool ResolveNamesVisitor::Pre(const parser::IntrinsicStmt &x) {
+bool DeclarationVisitor::Pre(const parser::IntrinsicStmt &x) {
return HandleAttributeStmt(Attr::INTRINSIC, x.v);
}
-bool ResolveNamesVisitor::Pre(const parser::OptionalStmt &x) {
+bool DeclarationVisitor::Pre(const parser::OptionalStmt &x) {
return HandleAttributeStmt(Attr::OPTIONAL, x.v);
}
-bool ResolveNamesVisitor::Pre(const parser::ProtectedStmt &x) {
+bool DeclarationVisitor::Pre(const parser::ProtectedStmt &x) {
return HandleAttributeStmt(Attr::PROTECTED, x.v);
}
-bool ResolveNamesVisitor::Pre(const parser::ValueStmt &x) {
+bool DeclarationVisitor::Pre(const parser::ValueStmt &x) {
return HandleAttributeStmt(Attr::VALUE, x.v);
}
-bool ResolveNamesVisitor::Pre(const parser::VolatileStmt &x) {
+bool DeclarationVisitor::Pre(const parser::VolatileStmt &x) {
return HandleAttributeStmt(Attr::VOLATILE, x.v);
}
-bool ResolveNamesVisitor::HandleAttributeStmt(
+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});
return false;
}
-void ResolveNamesVisitor::Post(const parser::ObjectDecl &x) {
+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 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) {
+void DeclarationVisitor::DeclareEntity(const parser::Name &name, Attrs attrs) {
Symbol &symbol{MakeSymbol(name.source, attrs)};
// TODO: check attribute consistency
if (symbol.has<UnknownDetails>()) {
}
}
+// ResolveNamesVisitor implementation
+
+bool ResolveNamesVisitor::Pre(const parser::TypeParamDefStmt &x) {
+ BeginDeclTypeSpec();
+ return true;
+}
+void ResolveNamesVisitor::Post(const parser::TypeParamDefStmt &x) {
+ EndDeclTypeSpec();
+ // TODO: TypeParamDefStmt
+}
+
+bool ResolveNamesVisitor::Pre(const parser::CommonBlockObject &x) {
+ BeginArraySpec();
+ return true;
+}
+void ResolveNamesVisitor::Post(const parser::CommonBlockObject &x) {
+ ClearArraySpec();
+ // TODO: CommonBlockObject
+}
+
+void ResolveNamesVisitor::Post(const parser::ComponentDecl &) {
+ ClearArraySpec();
+}
+
+bool ResolveNamesVisitor::Pre(const parser::PrefixSpec &x) {
+ return true; // TODO
+}
+
+bool ResolveNamesVisitor::CheckUseError(
+ const SourceName &name, const Symbol &symbol) {
+ const auto *details = symbol.detailsIf<UseErrorDetails>();
+ if (!details) {
+ return false;
+ }
+ Message &msg{Say(name, "Reference to '%s' is ambiguous"_err_en_US)};
+ for (const auto &pair : details->occurrences()) {
+ const SourceName &location{*pair.first};
+ const SourceName &moduleName{pair.second->name()};
+ msg.Attach(location,
+ MessageFormattedText{"'%s' was use-associated from module '%s'"_en_US,
+ name.ToString().data(), moduleName.ToString().data()});
+ }
+ return true;
+}
+
+void ResolveNamesVisitor::Post(const parser::ProcedureDesignator &x) {
+ if (const auto *name = std::get_if<parser::Name>(&x.u)) {
+ Symbol &symbol{MakeSymbol(name->source)};
+ if (symbol.has<UnknownDetails>()) {
+ if (isImplicitNoneExternal() && !symbol.attrs().test(Attr::EXTERNAL)) {
+ Say(*name,
+ "'%s' is an external procedure without the EXTERNAL"
+ " attribute in a scope with IMPLICIT NONE(EXTERNAL)"_err_en_US);
+ }
+ symbol.attrs().set(Attr::EXTERNAL);
+ symbol.set_details(SubprogramDetails{});
+ } else if (CheckUseError(name->source, symbol)) {
+ // error was reported
+ } else if (!symbol.isSubprogram()) {
+ auto *details = symbol.detailsIf<EntityDetails>();
+ if (!details || !details->isArray()) {
+ Say(*name,
+ "Use of '%s' as a procedure conflicts with its declaration"_err_en_US)
+ .Attach(symbol.name(),
+ MessageFormattedText{"Declaration of '%s'"_en_US,
+ symbol.name().ToString().data()});
+ }
+ }
+ }
+}
+
bool ModuleVisitor::Pre(const parser::AccessStmt &x) {
Attr accessAttr = AccessSpecToAttr(std::get<parser::AccessSpec>(x.t));
if (CurrScope().kind() != Scope::Kind::Module) {