@@ -1203,6 +1203,64 @@ void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) {
12031203 deviceConstructFound_ = true ;
12041204 }
12051205
1206+ if (GetContext ().directive == llvm::omp::Directive::OMPD_single) {
1207+ std::set<Symbol *> singleCopyprivateSyms;
1208+ std::set<Symbol *> endSingleCopyprivateSyms;
1209+ bool foundNowait{false };
1210+ parser::CharBlock NowaitSource;
1211+
1212+ auto catchCopyPrivateNowaitClauses = [&](const auto &dir, bool endDir) {
1213+ for (auto &clause : std::get<parser::OmpClauseList>(dir.t ).v ) {
1214+ if (clause.Id () == llvm::omp::Clause::OMPC_copyprivate) {
1215+ for (const auto &ompObject : GetOmpObjectList (clause)->v ) {
1216+ const auto *name{parser::Unwrap<parser::Name>(ompObject)};
1217+ if (Symbol * symbol{name->symbol }) {
1218+ if (singleCopyprivateSyms.count (symbol)) {
1219+ if (endDir) {
1220+ context_.Warn (common::UsageWarning::OpenMPUsage, name->source ,
1221+ " The COPYPRIVATE clause with '%s' is already used on the SINGLE directive" _warn_en_US,
1222+ name->ToString ());
1223+ } else {
1224+ context_.Say (name->source ,
1225+ " '%s' appears in more than one COPYPRIVATE clause on the SINGLE directive" _err_en_US,
1226+ name->ToString ());
1227+ }
1228+ } else if (endSingleCopyprivateSyms.count (symbol)) {
1229+ context_.Say (name->source ,
1230+ " '%s' appears in more than one COPYPRIVATE clause on the END SINGLE directive" _err_en_US,
1231+ name->ToString ());
1232+ } else {
1233+ if (endDir) {
1234+ endSingleCopyprivateSyms.insert (symbol);
1235+ } else {
1236+ singleCopyprivateSyms.insert (symbol);
1237+ }
1238+ }
1239+ }
1240+ }
1241+ } else if (clause.Id () == llvm::omp::Clause::OMPC_nowait) {
1242+ if (foundNowait) {
1243+ context_.Say (clause.source ,
1244+ " At most one NOWAIT clause can appear on the SINGLE directive" _err_en_US);
1245+ } else {
1246+ foundNowait = !endDir;
1247+ }
1248+ if (!NowaitSource.ToString ().size ()) {
1249+ NowaitSource = clause.source ;
1250+ }
1251+ }
1252+ }
1253+ };
1254+ catchCopyPrivateNowaitClauses (beginBlockDir, false );
1255+ catchCopyPrivateNowaitClauses (endBlockDir, true );
1256+ unsigned version{context_.langOptions ().OpenMPVersion };
1257+ if (version <= 52 && NowaitSource.ToString ().size () &&
1258+ (singleCopyprivateSyms.size () || endSingleCopyprivateSyms.size ())) {
1259+ context_.Say (NowaitSource,
1260+ " NOWAIT clause must not be used with COPYPRIVATE clause on the SINGLE directive" _err_en_US);
1261+ }
1262+ }
1263+
12061264 switch (beginDir.v ) {
12071265 case llvm::omp::Directive::OMPD_target:
12081266 if (CheckTargetBlockOnlyTeams (block)) {
@@ -2903,12 +2961,6 @@ void OmpStructureChecker::Leave(const parser::OmpClauseList &) {
29032961 // clause
29042962 CheckMultListItems ();
29052963
2906- // 2.7.3 Single Construct Restriction
2907- if (GetContext ().directive == llvm::omp::Directive::OMPD_end_single) {
2908- CheckNotAllowedIfClause (
2909- llvm::omp::Clause::OMPC_copyprivate, {llvm::omp::Clause::OMPC_nowait});
2910- }
2911-
29122964 auto testThreadprivateVarErr = [&](Symbol sym, parser::Name name,
29132965 llvmOmpClause clauseTy) {
29142966 if (sym.test (Symbol::Flag::OmpThreadprivate))
@@ -3549,15 +3601,6 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Private &x) {
35493601
35503602void OmpStructureChecker::Enter (const parser::OmpClause::Nowait &x) {
35513603 CheckAllowedClause (llvm::omp::Clause::OMPC_nowait);
3552- if (llvm::omp::noWaitClauseNotAllowedSet.test (GetContext ().directive )) {
3553- context_.Say (GetContext ().clauseSource ,
3554- " %s clause is not allowed on the OMP %s directive,"
3555- " use it on OMP END %s directive " _err_en_US,
3556- parser::ToUpperCaseLetters (
3557- getClauseName (llvm::omp::Clause::OMPC_nowait).str ()),
3558- parser::ToUpperCaseLetters (GetContext ().directiveSource .ToString ()),
3559- parser::ToUpperCaseLetters (GetContext ().directiveSource .ToString ()));
3560- }
35613604}
35623605
35633606bool OmpStructureChecker::IsDataRefTypeParamInquiry (
@@ -4288,15 +4331,6 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Copyprivate &x) {
42884331 CheckIntentInPointer (symbols, llvm::omp::Clause::OMPC_copyprivate);
42894332 CheckCopyingPolymorphicAllocatable (
42904333 symbols, llvm::omp::Clause::OMPC_copyprivate);
4291- if (GetContext ().directive == llvm::omp::Directive::OMPD_single) {
4292- context_.Say (GetContext ().clauseSource ,
4293- " %s clause is not allowed on the OMP %s directive,"
4294- " use it on OMP END %s directive " _err_en_US,
4295- parser::ToUpperCaseLetters (
4296- getClauseName (llvm::omp::Clause::OMPC_copyprivate).str ()),
4297- parser::ToUpperCaseLetters (GetContext ().directiveSource .ToString ()),
4298- parser::ToUpperCaseLetters (GetContext ().directiveSource .ToString ()));
4299- }
43004334}
43014335
43024336void OmpStructureChecker::Enter (const parser::OmpClause::Lastprivate &x) {
0 commit comments