return true;
}
void ScopeHandler::ApplyImplicitRules(Symbol &symbol) {
- ConvertToObjectEntity(symbol);
if (NeedsType(symbol)) {
if (isImplicitNoneType()) {
Say(symbol.name(), "No explicit type declared for '%s'"_err_en_US);
// Declare the name as an object in the enclosing scope so that
// the name can't be repurposed there later as something else.
prev = &MakeSymbol(InclusiveScope(), name.source, Attrs{});
+ ConvertToObjectEntity(*prev);
ApplyImplicitRules(*prev);
implicit = true;
}
return nullptr; // reported an error
}
if (symbol->IsDummy()) {
+ ConvertToObjectEntity(*symbol);
ApplyImplicitRules(*symbol);
}
return &name;
"'%s' from host scoping unit is not accessible due to IMPORT"_err_en_US);
return nullptr;
}
+ ConvertToObjectEntity(*symbol);
ApplyImplicitRules(*symbol);
return &name;
}
return false;
}
+// Calls to dummy procedures need to record that their symbols are known
+// to be procedures, so that they don't get converted to objects by default.
+class ExecutionPartSkimmer {
+public:
+ ExecutionPartSkimmer(SemanticsContext &c, Scope &s)
+ : context_{c}, scope_{s} {}
+
+ void Walk(const parser::ExecutionPart *exec) {
+ if (exec != nullptr) {
+ parser::Walk(*exec, *this);
+ }
+ }
+
+ template<typename A> bool Pre(const A &) { return true; }
+ template<typename A> void Post(const A &) {}
+ void Post(const parser::FunctionReference &fr) {
+ NoteCall(Symbol::Flag::Function, fr.v);
+ }
+ void Post(const parser::CallStmt &cs) {
+ NoteCall(Symbol::Flag::Subroutine, cs.v);
+ }
+
+private:
+ void NoteCall(Symbol::Flag, const parser::Call &);
+
+ SemanticsContext &context_;
+ Scope &scope_;
+};
+
+void ExecutionPartSkimmer::NoteCall(
+ Symbol::Flag flag, const parser::Call &call) {
+ auto &designator{std::get<parser::ProcedureDesignator>(call.t)};
+ if (const auto *name{std::get_if<parser::Name>(&designator.u)}) {
+ if (Symbol * symbol{scope_.FindSymbol(name->source)}) {
+ if (auto *details{symbol->detailsIf<EntityDetails>()}) {
+ if (details->isDummy()) {
+ symbol->set_details(ProcEntityDetails{std::move(*details)});
+ symbol->set(flag);
+ symbol->attrs().set(Attr::EXTERNAL);
+ }
+ }
+ }
+ }
+}
+
// Build the scope tree and resolve names in the specification parts of this
// node and its children
void ResolveNamesVisitor::ResolveSpecificationParts(ProgramTree &node) {
if (node.IsModule()) {
ApplyDefaultAccess();
}
- for (auto &child : node.children()) {
- ResolveSpecificationParts(child);
- }
- // Subtlety: PopScope() is not called here because we want to defer
- // conversions of uncategorized entities into objects until after
- // we have traversed the executable part of the subprogram.
- // Function results, however, are converted now so that they can
- // be used in executable parts.
if (Symbol * symbol{currScope().symbol()}) {
if (auto *details{symbol->detailsIf<SubprogramDetails>()}) {
if (details->isFunction()) {
}
}
}
+ ExecutionPartSkimmer{context(), scope}.Walk(node.exec());
+ for (auto &child : node.children()) {
+ ResolveSpecificationParts(child);
+ }
+ // Subtlety: PopScope() is not called here because we want to defer
+ // conversions of uncategorized entities into objects until after
+ // we have traversed the executable part of the subprogram.
SetScope(currScope().parent());
}