@@ -435,6 +435,22 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
435435 return true ;
436436 }
437437
438+ bool Pre (const parser::UseStmt &x) {
439+ if (x.moduleName .symbol ) {
440+ Scope &thisScope{context_.FindScope (x.moduleName .source )};
441+ common::visit (
442+ [&](auto &&details) {
443+ if constexpr (std::is_convertible_v<decltype (details),
444+ const WithOmpDeclarative &>) {
445+ AddOmpRequiresToScope (thisScope, details.ompRequires (),
446+ details.ompAtomicDefaultMemOrder ());
447+ }
448+ },
449+ x.moduleName .symbol ->details ());
450+ }
451+ return true ;
452+ }
453+
438454 bool Pre (const parser::OmpMetadirectiveDirective &x) {
439455 PushContext (x.v .source , llvm::omp::Directive::OMPD_metadirective);
440456 return true ;
@@ -538,38 +554,37 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
538554 void Post (const parser::OpenMPFlushConstruct &) { PopContext (); }
539555
540556 bool Pre (const parser::OpenMPRequiresConstruct &x) {
541- using Flags = WithOmpDeclarative::RequiresFlags;
542- using Requires = WithOmpDeclarative::RequiresFlag;
557+ using RequiresClauses = WithOmpDeclarative::RequiresClauses;
543558 PushContext (x.source , llvm::omp::Directive::OMPD_requires);
544559
545560 // Gather information from the clauses.
546- Flags flags ;
547- std::optional< common::OmpMemoryOrderType> memOrder;
561+ RequiresClauses reqs ;
562+ const common::OmpMemoryOrderType * memOrder{ nullptr } ;
548563 for (const parser::OmpClause &clause : x.v .Clauses ().v ) {
549- flags |= common::visit (
564+ using OmpClause = parser::OmpClause;
565+ reqs |= common::visit (
550566 common::visitors{
551- [&memOrder](
552- const parser::OmpClause::AtomicDefaultMemOrder &atomic) {
553- memOrder = atomic.v .v ;
554- return Flags{};
555- },
556- [](const parser::OmpClause::ReverseOffload &) {
557- return Flags{Requires::ReverseOffload};
558- },
559- [](const parser::OmpClause::UnifiedAddress &) {
560- return Flags{Requires::UnifiedAddress};
567+ [&](const OmpClause::AtomicDefaultMemOrder &atomic) {
568+ memOrder = &atomic.v .v ;
569+ return RequiresClauses{};
561570 },
562- [](const parser::OmpClause::UnifiedSharedMemory &) {
563- return Flags{Requires::UnifiedSharedMemory};
564- },
565- [](const parser::OmpClause::DynamicAllocators &) {
566- return Flags{Requires::DynamicAllocators};
571+ [&](auto &&s) {
572+ using TypeS = llvm::remove_cvref_t <decltype (s)>;
573+ if constexpr ( //
574+ std::is_same_v<TypeS, OmpClause::DynamicAllocators> ||
575+ std::is_same_v<TypeS, OmpClause::ReverseOffload> ||
576+ std::is_same_v<TypeS, OmpClause::UnifiedAddress> ||
577+ std::is_same_v<TypeS, OmpClause::UnifiedSharedMemory>) {
578+ return RequiresClauses{clause.Id ()};
579+ } else {
580+ return RequiresClauses{};
581+ }
567582 },
568- []( const auto &) { return Flags{}; } },
583+ },
569584 clause.u );
570585 }
571586 // Merge clauses into parents' symbols details.
572- AddOmpRequiresToScope (currScope (), flags , memOrder);
587+ AddOmpRequiresToScope (currScope (), &reqs , memOrder);
573588 return true ;
574589 }
575590 void Post (const parser::OpenMPRequiresConstruct &) { PopContext (); }
@@ -1001,8 +1016,9 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
10011016
10021017 std::int64_t ordCollapseLevel{0 };
10031018
1004- void AddOmpRequiresToScope (Scope &, WithOmpDeclarative::RequiresFlags,
1005- std::optional<common::OmpMemoryOrderType>);
1019+ void AddOmpRequiresToScope (Scope &,
1020+ const WithOmpDeclarative::RequiresClauses *,
1021+ const common::OmpMemoryOrderType *);
10061022 void IssueNonConformanceWarning (llvm::omp::Directive D,
10071023 parser::CharBlock source, unsigned EmitFromVersion);
10081024
@@ -3309,86 +3325,6 @@ void ResolveOmpParts(
33093325 }
33103326}
33113327
3312- void ResolveOmpTopLevelParts (
3313- SemanticsContext &context, const parser::Program &program) {
3314- if (!context.IsEnabled (common::LanguageFeature::OpenMP)) {
3315- return ;
3316- }
3317-
3318- // Gather REQUIRES clauses from all non-module top-level program unit symbols,
3319- // combine them together ensuring compatibility and apply them to all these
3320- // program units. Modules are skipped because their REQUIRES clauses should be
3321- // propagated via USE statements instead.
3322- WithOmpDeclarative::RequiresFlags combinedFlags;
3323- std::optional<common::OmpMemoryOrderType> combinedMemOrder;
3324-
3325- // Function to go through non-module top level program units and extract
3326- // REQUIRES information to be processed by a function-like argument.
3327- auto processProgramUnits{[&](auto processFn) {
3328- for (const parser::ProgramUnit &unit : program.v ) {
3329- if (!std::holds_alternative<common::Indirection<parser::Module>>(
3330- unit.u ) &&
3331- !std::holds_alternative<common::Indirection<parser::Submodule>>(
3332- unit.u ) &&
3333- !std::holds_alternative<
3334- common::Indirection<parser::CompilerDirective>>(unit.u )) {
3335- Symbol *symbol{common::visit (
3336- [&context](auto &x) {
3337- Scope *scope = GetScope (context, x.value ());
3338- return scope ? scope->symbol () : nullptr ;
3339- },
3340- unit.u )};
3341- // FIXME There is no symbol defined for MainProgram units in certain
3342- // circumstances, so REQUIRES information has no place to be stored in
3343- // these cases.
3344- if (!symbol) {
3345- continue ;
3346- }
3347- common::visit (
3348- [&](auto &details) {
3349- if constexpr (std::is_convertible_v<decltype (&details),
3350- WithOmpDeclarative *>) {
3351- processFn (*symbol, details);
3352- }
3353- },
3354- symbol->details ());
3355- }
3356- }
3357- }};
3358-
3359- // Combine global REQUIRES information from all program units except modules
3360- // and submodules.
3361- processProgramUnits ([&](Symbol &symbol, WithOmpDeclarative &details) {
3362- if (const WithOmpDeclarative::RequiresFlags *
3363- flags{details.ompRequires ()}) {
3364- combinedFlags |= *flags;
3365- }
3366- if (const common::OmpMemoryOrderType *
3367- memOrder{details.ompAtomicDefaultMemOrder ()}) {
3368- if (combinedMemOrder && *combinedMemOrder != *memOrder) {
3369- context.Say (symbol.scope ()->sourceRange (),
3370- " Conflicting '%s' REQUIRES clauses found in compilation "
3371- " unit" _err_en_US,
3372- parser::ToUpperCaseLetters (llvm::omp::getOpenMPClauseName (
3373- llvm::omp::Clause::OMPC_atomic_default_mem_order)
3374- .str ()));
3375- }
3376- combinedMemOrder = *memOrder;
3377- }
3378- });
3379-
3380- // Update all program units except modules and submodules with the combined
3381- // global REQUIRES information.
3382- processProgramUnits ([&](Symbol &, WithOmpDeclarative &details) {
3383- if (combinedFlags.any ()) {
3384- details.set_ompRequires (combinedFlags);
3385- }
3386- if (combinedMemOrder) {
3387- details.set_ompAtomicDefaultMemOrder (*combinedMemOrder);
3388- }
3389- });
3390- }
3391-
33923328static bool IsSymbolThreadprivate (const Symbol &symbol) {
33933329 if (const auto *details{symbol.detailsIf <HostAssocDetails>()}) {
33943330 return details->symbol ().test (Symbol::Flag::OmpThreadprivate);
@@ -3547,23 +3483,22 @@ void OmpAttributeVisitor::CheckLabelContext(const parser::CharBlock source,
35473483}
35483484
35493485void OmpAttributeVisitor::AddOmpRequiresToScope (Scope &scope,
3550- WithOmpDeclarative::RequiresFlags flags ,
3551- std::optional< common::OmpMemoryOrderType> memOrder) {
3486+ const WithOmpDeclarative::RequiresClauses *reqs ,
3487+ const common::OmpMemoryOrderType * memOrder) {
35523488 const Scope &programUnit{omp::GetProgramUnit (scope)};
3489+ using RequiresClauses = WithOmpDeclarative::RequiresClauses;
3490+ RequiresClauses combinedReqs{reqs ? *reqs : RequiresClauses{}};
35533491
35543492 if (auto *symbol{const_cast <Symbol *>(programUnit.symbol ())}) {
35553493 common::visit (
35563494 [&](auto &details) {
3557- // Store clauses information into the symbol for the parent and
3558- // enclosing modules, programs, functions and subroutines.
35593495 if constexpr (std::is_convertible_v<decltype (&details),
35603496 WithOmpDeclarative *>) {
3561- if (flags.any ()) {
3562- if (const WithOmpDeclarative::RequiresFlags *otherFlags{
3563- details.ompRequires ()}) {
3564- flags |= *otherFlags;
3497+ if (combinedReqs.any ()) {
3498+ if (const RequiresClauses *otherReqs{details.ompRequires ()}) {
3499+ combinedReqs |= *otherReqs;
35653500 }
3566- details.set_ompRequires (flags );
3501+ details.set_ompRequires (combinedReqs );
35673502 }
35683503 if (memOrder) {
35693504 if (details.has_ompAtomicDefaultMemOrder () &&
0 commit comments