diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h --- a/flang/lib/Semantics/check-omp-structure.h +++ b/flang/lib/Semantics/check-omp-structure.h @@ -172,7 +172,8 @@ // specific clause related bool ScheduleModifierHasType(const parser::OmpScheduleClause &, const parser::OmpScheduleModifierType::ModType &); - + void CheckAllowedMapTypes(const parser::OmpMapType::Type &, + const std::list &); llvm::StringRef getClauseName(llvm::omp::Clause clause) override; llvm::StringRef getDirectiveName(llvm::omp::Directive directive) override; }; diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -9,7 +9,7 @@ #include "check-omp-structure.h" #include "flang/Parser/parse-tree.h" #include "flang/Semantics/tools.h" - +#include namespace Fortran::semantics { // Use when clause falls under 'struct OmpClause' in 'parse-tree.h'. @@ -160,8 +160,8 @@ switch (dir.v) { // 2.7.2 end-sections -> END SECTIONS [nowait-clause] case llvm::omp::Directive::OMPD_sections: - SetContextDirectiveEnum(llvm::omp::Directive::OMPD_end_sections); - SetContextAllowedOnce(OmpClauseSet{llvm::omp::Clause::OMPC_nowait}); + PushContextAndClauseSets( + dir.source, llvm::omp::Directive::OMPD_end_sections); break; default: // no clauses are allowed @@ -183,8 +183,7 @@ PushContext(dir.source, llvm::omp::Directive::OMPD_declare_target); const auto &spec{std::get(x.t)}; if (std::holds_alternative(spec.u)) { - SetContextAllowed( - OmpClauseSet{llvm::omp::Clause::OMPC_to, llvm::omp::Clause::OMPC_link}); + SetClauseSets(llvm::omp::Directive::OMPD_declare_target); } } @@ -248,17 +247,13 @@ switch (dir.v) { // 2.7.3 end-single-clause -> copyprivate-clause | // nowait-clause - case llvm::omp::Directive::OMPD_single: { - SetContextDirectiveEnum(llvm::omp::Directive::OMPD_end_single); - OmpClauseSet allowed{llvm::omp::Clause::OMPC_copyprivate}; - SetContextAllowed(allowed); - OmpClauseSet allowedOnce{llvm::omp::Clause::OMPC_nowait}; - SetContextAllowedOnce(allowedOnce); - } break; + case llvm::omp::Directive::OMPD_single: + PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_end_single); + break; // 2.7.4 end-workshare -> END WORKSHARE [nowait-clause] case llvm::omp::Directive::OMPD_workshare: - SetContextDirectiveEnum(llvm::omp::Directive::OMPD_end_workshare); - SetContextAllowed(OmpClauseSet{llvm::omp::Clause::OMPC_nowait}); + PushContextAndClauseSets( + dir.source, llvm::omp::Directive::OMPD_end_workshare); break; default: // no clauses are allowed @@ -300,11 +295,8 @@ std::get(clause->u)}; if (orderedClause.v) { - if (FindClause(llvm::omp::Clause::OMPC_linear)) { - context_.Say(clause->source, - "A loop directive may not have both a LINEAR clause and " - "an ORDERED clause with a parameter"_err_en_US); - } + CheckNotAllowedIfClause( + llvm::omp::Clause::OMPC_ordered, {llvm::omp::Clause::OMPC_linear}); if (auto *clause2{FindClause(llvm::omp::Clause::OMPC_collapse)}) { const auto &collapseClause{ @@ -347,19 +339,13 @@ } } } - // TODO: A list-item cannot appear in more than one aligned clause } // SIMD // 2.7.3 Single Construct Restriction if (GetContext().directive == llvm::omp::Directive::OMPD_end_single) { - if (auto *clause{FindClause(llvm::omp::Clause::OMPC_copyprivate)}) { - if (FindClause(llvm::omp::Clause::OMPC_nowait)) { - context_.Say(clause->source, - "The COPYPRIVATE clause must not be used with " - "the NOWAIT clause"_err_en_US); - } - } + CheckNotAllowedIfClause( + llvm::omp::Clause::OMPC_copyprivate, {llvm::omp::Clause::OMPC_nowait}); } GetContext().requiredClauses.IterateOverMembers( @@ -410,7 +396,6 @@ // the parameter of ordered clause is optional if (const auto &expr{x.v}) { RequiresConstantPositiveParameter(llvm::omp::Clause::OMPC_ordered, *expr); - // 2.8.3 Loop SIMD Construct Restriction if (llvm::omp::doSimdSet.test(GetContext().directive)) { context_.Say(GetContext().clauseSource, @@ -437,13 +422,7 @@ if (const auto &expr{ std::get>(x.t)}) { - if (const auto v{GetIntValue(*expr)}) { - if (*v <= 0) { - context_.Say(GetContext().clauseSource, - "The ALIGNMENT parameter of the ALIGNED clause must be " - "a constant positive integer expression"_err_en_US); - } - } + RequiresConstantPositiveParameter(llvm::omp::Clause::OMPC_aligned, *expr); } // 2.8.1 TODO: list-item attribute check } @@ -502,6 +481,32 @@ } } } + +void OmpStructureChecker::CheckAllowedMapTypes( + const parser::OmpMapType::Type &type, + const std::list &allowedMapTypeList) { + const auto mapEnumListToString = + [&](const std::list &allowedList) { + std::string commaSeperatedList; + llvm::interleave( + allowedList.begin(), allowedList.end(), + [&](const parser::OmpMapType::Type &mapType) { + commaSeperatedList.append(parser::ToUpperCaseLetters( + parser::OmpMapType::EnumToString(mapType))); + }, + [&] { commaSeperatedList.append(", "); }); + return commaSeperatedList; + }; + const auto found{std::find( + std::begin(allowedMapTypeList), std::end(allowedMapTypeList), type)}; + if (found == std::end(allowedMapTypeList)) { + context_.Say(GetContext().clauseSource, + "Only the %s map types are permitted " + "for MAP clauses on the %s directive"_err_en_US, + mapEnumListToString(allowedMapTypeList), ContextDirectiveAsFortran()); + } +} + void OmpStructureChecker::Enter(const parser::OmpMapClause &x) { CheckAllowed(llvm::omp::Clause::OMPC_map); if (const auto &maptype{std::get>(x.t)}) { @@ -514,31 +519,16 @@ case llvm::omp::Directive::OMPD_target_teams_distribute_simd: case llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do: case llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do_simd: - case llvm::omp::Directive::OMPD_target_data: { - if (type != Type::To && type != Type::From && type != Type::Tofrom && - type != Type::Alloc) { - context_.Say(GetContext().clauseSource, - "Only the TO, FROM, TOFROM, or ALLOC map types are permitted " - "for MAP clauses on the %s directive"_err_en_US, - ContextDirectiveAsFortran()); - } - } break; - case llvm::omp::Directive::OMPD_target_enter_data: { - if (type != Type::To && type != Type::Alloc) { - context_.Say(GetContext().clauseSource, - "Only the TO or ALLOC map types are permitted " - "for MAP clauses on the %s directive"_err_en_US, - ContextDirectiveAsFortran()); - } - } break; - case llvm::omp::Directive::OMPD_target_exit_data: { - if (type != Type::Delete && type != Type::Release && type != Type::From) { - context_.Say(GetContext().clauseSource, - "Only the FROM, RELEASE, or DELETE map types are permitted " - "for MAP clauses on the %s directive"_err_en_US, - ContextDirectiveAsFortran()); - } - } break; + case llvm::omp::Directive::OMPD_target_data: + CheckAllowedMapTypes( + type, {Type::To, Type::From, Type::Tofrom, Type::Alloc}); + break; + case llvm::omp::Directive::OMPD_target_enter_data: + CheckAllowedMapTypes(type, {Type::To, Type::Alloc}); + break; + case llvm::omp::Directive::OMPD_target_exit_data: + CheckAllowedMapTypes(type, {Type::From, Type::Release, Type::Delete}); + break; default: break; } diff --git a/flang/test/Semantics/omp-clause-validity01.f90 b/flang/test/Semantics/omp-clause-validity01.f90 --- a/flang/test/Semantics/omp-clause-validity01.f90 +++ b/flang/test/Semantics/omp-clause-validity01.f90 @@ -215,8 +215,9 @@ a = 3.14 enddo + !ERROR: Clause LINEAR is not allowed if clause ORDERED appears on the DO directive + !ERROR: Clause LINEAR is not allowed if clause ORDERED appears on the DO directive !ERROR: The parameter of the ORDERED clause must be a constant positive integer expression - !ERROR: A loop directive may not have both a LINEAR clause and an ORDERED clause with a parameter !ERROR: Internal: no symbol found for 'b' !ERROR: Internal: no symbol found for 'a' !$omp do ordered(1-1) private(b) linear(b) linear(a) @@ -322,7 +323,7 @@ !ERROR: LASTPRIVATE clause is not allowed on the SINGLE directive !$omp single private(a) lastprivate(c) a = 3.14 - !ERROR: The COPYPRIVATE clause must not be used with the NOWAIT clause + !ERROR: Clause NOWAIT is not allowed if clause COPYPRIVATE appears on the END SINGLE directive !ERROR: At most one NOWAIT clause can appear on the END SINGLE directive !$omp end single copyprivate(a) nowait nowait c = 2 @@ -368,7 +369,7 @@ a = 3.14 enddo - !ERROR: The ALIGNMENT parameter of the ALIGNED clause must be a constant positive integer expression + !ERROR: The parameter of the ALIGNED clause must be a constant positive integer expression !ERROR: Internal: no symbol found for 'b' !$omp simd aligned(b:-2) do i = 1, N @@ -557,7 +558,7 @@ enddo !ERROR: The parameter of the SIMDLEN clause must be a constant positive integer expression - !ERROR: The ALIGNMENT parameter of the ALIGNED clause must be a constant positive integer expression + !ERROR: The parameter of the ALIGNED clause must be a constant positive integer expression !ERROR: Internal: no symbol found for 'a' !$omp taskloop simd simdlen(-1) aligned(a:-2) do i = 1, N diff --git a/flang/test/Semantics/omp-combined-constructs.f90 b/flang/test/Semantics/omp-combined-constructs.f90 --- a/flang/test/Semantics/omp-combined-constructs.f90 +++ b/flang/test/Semantics/omp-combined-constructs.f90 @@ -205,7 +205,7 @@ enddo !$omp end target teams - !ERROR: Only the TO, FROM, TOFROM, or ALLOC map types are permitted for MAP clauses on the TARGET TEAMS directive + !ERROR: Only the TO, FROM, TOFROM, ALLOC map types are permitted for MAP clauses on the TARGET TEAMS directive !$omp target teams map(delete:a) do i = 1, N a(i) = 3.14 @@ -305,7 +305,7 @@ enddo !$omp end target teams distribute - !ERROR: Only the TO, FROM, TOFROM, or ALLOC map types are permitted for MAP clauses on the TARGET TEAMS DISTRIBUTE directive + !ERROR: Only the TO, FROM, TOFROM, ALLOC map types are permitted for MAP clauses on the TARGET TEAMS DISTRIBUTE directive !$omp target teams distribute map(delete:a) do i = 1, N a(i) = 3.14 @@ -398,7 +398,7 @@ enddo !$omp end target teams distribute parallel do - !ERROR: Only the TO, FROM, TOFROM, or ALLOC map types are permitted for MAP clauses on the TARGET TEAMS DISTRIBUTE PARALLEL DO directive + !ERROR: Only the TO, FROM, TOFROM, ALLOC map types are permitted for MAP clauses on the TARGET TEAMS DISTRIBUTE PARALLEL DO directive !$omp target teams distribute parallel do map(delete:a) do i = 1, N a(i) = 3.14 @@ -498,7 +498,7 @@ enddo !$omp end target teams distribute parallel do simd - !ERROR: Only the TO, FROM, TOFROM, or ALLOC map types are permitted for MAP clauses on the TARGET TEAMS DISTRIBUTE PARALLEL DO SIMD directive + !ERROR: Only the TO, FROM, TOFROM, ALLOC map types are permitted for MAP clauses on the TARGET TEAMS DISTRIBUTE PARALLEL DO SIMD directive !$omp target teams distribute parallel do simd map(delete:a) do i = 1, N a(i) = 3.14 diff --git a/flang/test/Semantics/omp-device-constructs.f90 b/flang/test/Semantics/omp-device-constructs.f90 --- a/flang/test/Semantics/omp-device-constructs.f90 +++ b/flang/test/Semantics/omp-device-constructs.f90 @@ -109,7 +109,7 @@ enddo !$omp end target - !ERROR: Only the TO, FROM, TOFROM, or ALLOC map types are permitted for MAP clauses on the TARGET directive + !ERROR: Only the TO, FROM, TOFROM, ALLOC map types are permitted for MAP clauses on the TARGET directive !$omp target map(delete:a) do i = 1, N a = 3.14 @@ -132,7 +132,7 @@ !ERROR: At most one IF clause can appear on the TARGET ENTER DATA directive !$omp target enter data map(to:a) if(.true.) if(.false.) - !ERROR: Only the TO or ALLOC map types are permitted for MAP clauses on the TARGET ENTER DATA directive + !ERROR: Only the TO, ALLOC map types are permitted for MAP clauses on the TARGET ENTER DATA directive !$omp target enter data map(from:a) !$omp target exit data map(delete:a) @@ -140,7 +140,7 @@ !ERROR: At most one DEVICE clause can appear on the TARGET EXIT DATA directive !$omp target exit data map(from:a) device(0) device(1) - !ERROR: Only the FROM, RELEASE, or DELETE map types are permitted for MAP clauses on the TARGET EXIT DATA directive + !ERROR: Only the FROM, RELEASE, DELETE map types are permitted for MAP clauses on the TARGET EXIT DATA directive !$omp target exit data map(to:a) !$omp target diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td --- a/llvm/include/llvm/Frontend/OpenMP/OMP.td +++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td @@ -870,7 +870,12 @@ VersionedClause ]; } -def OMP_DeclareTarget : Directive<"declare target"> {} +def OMP_DeclareTarget : Directive<"declare target"> { + let allowedClauses = [ + VersionedClause, + VersionedClause + ]; +} def OMP_EndDeclareTarget : Directive<"end declare target"> {} def OMP_DistributeParallelFor : Directive<"distribute parallel for"> { let allowedClauses = [ @@ -1581,9 +1586,24 @@ def OMP_Workshare : Directive<"workshare"> {} def OMP_EndDo : Directive<"end do"> {} def OMP_EndDoSimd : Directive<"end do simd"> {} -def OMP_EndSections : Directive<"end sections"> {} -def OMP_EndSingle : Directive<"end single"> {} -def OMP_EndWorkshare : Directive<"end workshare"> {} +def OMP_EndSections : Directive<"end sections"> { + let allowedOnceClauses = [ + VersionedClause + ]; +} +def OMP_EndSingle : Directive<"end single"> { + let allowedClauses = [ + VersionedClause + ]; + let allowedOnceClauses = [ + VersionedClause + ]; +} +def OMP_EndWorkshare : Directive<"end workshare"> { + let allowedClauses = [ + VersionedClause + ]; +} def OMP_Unknown : Directive<"unknown"> { let isDefault = 1; }