diff --git a/flang/lib/Semantics/check-acc-structure.cpp b/flang/lib/Semantics/check-acc-structure.cpp index abda9409efd33..932d5776a0468 100644 --- a/flang/lib/Semantics/check-acc-structure.cpp +++ b/flang/lib/Semantics/check-acc-structure.cpp @@ -561,6 +561,8 @@ void AccStructureChecker::Enter(const parser::AccClause::NumGangs &n) { /*warnInsteadOfError=*/GetContext().directive == llvm::acc::Directive::ACCD_serial || GetContext().directive == llvm::acc::Directive::ACCD_serial_loop); + CheckAllowedOncePerGroup( + llvm::acc::Clause::ACCC_num_gangs, llvm::acc::Clause::ACCC_device_type); if (n.v.size() > 3) context_.Say(GetContext().clauseSource, @@ -572,6 +574,8 @@ void AccStructureChecker::Enter(const parser::AccClause::NumWorkers &n) { /*warnInsteadOfError=*/GetContext().directive == llvm::acc::Directive::ACCD_serial || GetContext().directive == llvm::acc::Directive::ACCD_serial_loop); + CheckAllowedOncePerGroup( + llvm::acc::Clause::ACCC_num_workers, llvm::acc::Clause::ACCC_device_type); } void AccStructureChecker::Enter(const parser::AccClause::VectorLength &n) { @@ -579,6 +583,8 @@ void AccStructureChecker::Enter(const parser::AccClause::VectorLength &n) { /*warnInsteadOfError=*/GetContext().directive == llvm::acc::Directive::ACCD_serial || GetContext().directive == llvm::acc::Directive::ACCD_serial_loop); + CheckAllowedOncePerGroup(llvm::acc::Clause::ACCC_vector_length, + llvm::acc::Clause::ACCC_device_type); } void AccStructureChecker::Enter(const parser::AccClause::Reduction &reduction) { diff --git a/flang/lib/Semantics/check-directive-structure.h b/flang/lib/Semantics/check-directive-structure.h index 84240b87f47ec..f7a6233a32edd 100644 --- a/flang/lib/Semantics/check-directive-structure.h +++ b/flang/lib/Semantics/check-directive-structure.h @@ -349,6 +349,10 @@ class DirectiveStructureChecker : public virtual BaseChecker { void CheckAllowed(C clause, bool warnInsteadOfError = false); + // Check that the clause appears only once. The counter is reset when the + // separator clause appears. + void CheckAllowedOncePerGroup(C clause, C separator); + void CheckAtLeastOneClause(); void CheckNotAllowedIfClause( @@ -545,6 +549,27 @@ void DirectiveStructureChecker +void DirectiveStructureChecker::CheckAllowedOncePerGroup(C clause, C separator) { + bool clauseIsPresent = false; + for (auto cl : GetContext().actualClauses) { + if (cl == clause) { + if (clauseIsPresent) { + context_.Say(GetContext().clauseSource, + "At most one %s clause can appear on the %s directive or in group separated by the %s clause"_err_en_US, + parser::ToUpperCaseLetters(getClauseName(clause).str()), + parser::ToUpperCaseLetters(GetContext().directiveSource.ToString()), + parser::ToUpperCaseLetters(getClauseName(separator).str())); + } else { + clauseIsPresent = true; + } + } + if (cl == separator) + clauseIsPresent = false; + } +} + // Check the value of the clause is a constant positive integer. template void DirectiveStructureChecker { def ACC_Parallel : Directive<"parallel"> { let allowedClauses = [ VersionedClause, + VersionedClause, VersionedClause, VersionedClause, VersionedClause, @@ -342,20 +343,19 @@ def ACC_Parallel : Directive<"parallel"> { VersionedClause, VersionedClause, VersionedClause, + VersionedClause, + VersionedClause, VersionedClause, VersionedClause, VersionedClause, VersionedClause, - VersionedClause + VersionedClause, + VersionedClause ]; let allowedOnceClauses = [ - VersionedClause, VersionedClause, VersionedClause, - VersionedClause, - VersionedClause, - VersionedClause, - VersionedClause + VersionedClause ]; }