template <typename T> void Post(const T &) {}
bool Pre(const parser::SpecificationPart &);
+ bool Pre(const parser::Program &);
void Post(const parser::Program &);
bool Pre(const parser::ImplicitStmt &);
void Post(const parser::PointerObject &);
return false;
}
+template <typename A> std::set<SourceName> GetUses(const A &x) {
+ std::set<SourceName> uses;
+ if constexpr (!std::is_same_v<A, parser::CompilerDirective>) {
+ const auto &spec{std::get<parser::SpecificationPart>(x.t)};
+ const auto &unitUses{std::get<
+ std::list<parser::Statement<common::Indirection<parser::UseStmt>>>>(
+ spec.t)};
+ for (const auto &u : unitUses) {
+ uses.insert(u.statement.value().moduleName.source);
+ }
+ }
+ return uses;
+}
+
+bool ResolveNamesVisitor::Pre(const parser::Program &x) {
+ std::map<SourceName, const parser::ProgramUnit *> modules;
+ std::set<SourceName> uses;
+ bool disordered{false};
+ for (const auto &progUnit : x.v) {
+ if (const auto *indMod{
+ std::get_if<common::Indirection<parser::Module>>(&progUnit.u)}) {
+ const parser::Module &mod{indMod->value()};
+ const auto &moduleStmt{
+ std::get<parser::Statement<parser::ModuleStmt>>(mod.t)};
+ const SourceName &name{moduleStmt.statement.v.source};
+ if (auto iter{modules.find(name)}; iter != modules.end()) {
+ Say(name,
+ "Module '%s' appears multiple times in a compilation unit"_err_en_US)
+ .Attach(iter->first, "First definition of module"_en_US);
+ return true;
+ }
+ modules.emplace(name, &progUnit);
+ if (auto iter{uses.find(name)}; iter != uses.end()) {
+ Say(name,
+ "A USE statement referencing module '%s' appears earlier in this compilation unit"_port_en_US)
+ .Attach(*iter, "First USE of module"_en_US);
+ disordered = true;
+ }
+ }
+ for (SourceName used : common::visit(
+ [](const auto &indUnit) { return GetUses(indUnit.value()); },
+ progUnit.u)) {
+ uses.insert(used);
+ }
+ }
+ if (!disordered) {
+ return true;
+ }
+ // Process modules in topological order
+ std::vector<const parser::ProgramUnit *> moduleOrder;
+ while (!modules.empty()) {
+ bool ok;
+ for (const auto &pair : modules) {
+ const SourceName &name{pair.first};
+ const parser::ProgramUnit &progUnit{*pair.second};
+ const parser::Module &m{
+ std::get<common::Indirection<parser::Module>>(progUnit.u).value()};
+ ok = true;
+ for (const SourceName &use : GetUses(m)) {
+ if (modules.find(use) != modules.end()) {
+ ok = false;
+ break;
+ }
+ }
+ if (ok) {
+ moduleOrder.push_back(&progUnit);
+ modules.erase(name);
+ break;
+ }
+ }
+ if (!ok) {
+ parser::Message *msg{nullptr};
+ for (const auto &pair : modules) {
+ if (msg) {
+ msg->Attach(pair.first, "Module in a cycle"_en_US);
+ } else {
+ msg = &Say(pair.first,
+ "Some modules in this compilation unit form one or more cycles of dependence"_err_en_US);
+ }
+ }
+ return false;
+ }
+ }
+ // Modules can be ordered. Process them first, and then all of the other
+ // program units.
+ for (const parser::ProgramUnit *progUnit : moduleOrder) {
+ Walk(*progUnit);
+ }
+ for (const auto &progUnit : x.v) {
+ if (!std::get_if<common::Indirection<parser::Module>>(&progUnit.u)) {
+ Walk(progUnit);
+ }
+ }
+ return false;
+}
+
// References to 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 {