@@ -1593,13 +1593,25 @@ class OmpVisitor : public virtual DeclarationVisitor {
15931593 }
15941594 bool Pre (const parser::OmpCriticalDirective &x) {
15951595 AddOmpSourceRange (x.source );
1596+ // Manually resolve names in CRITICAL directives. This is because these
1597+ // names do not denote Fortran objects, and the CRITICAL directive causes
1598+ // them to be "auto-declared", i.e. inserted into the global scope.
1599+ // More specifically, they are not expected to have explicit declarations,
1600+ // and if they do the behavior is unspeficied.
1601+ if (auto &maybeName{std::get<std::optional<parser::Name>>(x.t )}) {
1602+ ResolveCriticalName (*maybeName);
1603+ }
15961604 return true ;
15971605 }
15981606 void Post (const parser::OmpCriticalDirective &) {
15991607 messageHandler ().set_currStmtSource (std::nullopt );
16001608 }
16011609 bool Pre (const parser::OmpEndCriticalDirective &x) {
16021610 AddOmpSourceRange (x.source );
1611+ // Manually resolve names in CRITICAL directives.
1612+ if (auto &maybeName{std::get<std::optional<parser::Name>>(x.t )}) {
1613+ ResolveCriticalName (*maybeName);
1614+ }
16031615 return true ;
16041616 }
16051617 void Post (const parser::OmpEndCriticalDirective &) {
@@ -1720,6 +1732,8 @@ class OmpVisitor : public virtual DeclarationVisitor {
17201732 const std::optional<parser::OmpClauseList> &clauses,
17211733 const T &wholeConstruct);
17221734
1735+ void ResolveCriticalName (const parser::Name &name);
1736+
17231737 int metaLevel_{0 };
17241738 const parser::OmpMetadirectiveDirective *metaDirective_{nullptr };
17251739};
@@ -1947,6 +1961,28 @@ void OmpVisitor::ProcessReductionSpecifier(
19471961 }
19481962}
19491963
1964+ void OmpVisitor::ResolveCriticalName (const parser::Name &name) {
1965+ auto &globalScope{[&]() -> Scope & {
1966+ for (Scope *s{&currScope ()};; s = &s->parent ()) {
1967+ if (s->IsTopLevel ()) {
1968+ return *s;
1969+ }
1970+ }
1971+ llvm_unreachable (" Cannot find global scope" );
1972+ }()};
1973+
1974+ if (auto *symbol{FindInScope (globalScope, name)}) {
1975+ if (!symbol->test (Symbol::Flag::OmpCriticalLock)) {
1976+ SayWithDecl (name, *symbol,
1977+ " CRITICAL construct name '%s' conflicts with a previous declaration" _warn_en_US,
1978+ name.ToString ());
1979+ }
1980+ } else {
1981+ name.symbol = &MakeSymbol (globalScope, name.source , Attrs{});
1982+ name.symbol ->set (Symbol::Flag::OmpCriticalLock);
1983+ }
1984+ }
1985+
19501986bool OmpVisitor::Pre (const parser::OmpDirectiveSpecification &x) {
19511987 AddOmpSourceRange (x.source );
19521988 if (metaLevel_ == 0 ) {
0 commit comments