@@ -2310,6 +2310,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Reduction &x) {
2310
2310
if (CheckReductionOperators (x)) {
2311
2311
CheckReductionTypeList (x);
2312
2312
}
2313
+ CheckReductionModifier (x);
2313
2314
}
2314
2315
2315
2316
bool OmpStructureChecker::CheckReductionOperators (
@@ -2394,6 +2395,64 @@ void OmpStructureChecker::CheckReductionTypeList(
2394
2395
}
2395
2396
}
2396
2397
2398
+ void OmpStructureChecker::CheckReductionModifier (
2399
+ const parser::OmpClause::Reduction &x) {
2400
+ using ReductionModifier = parser::OmpReductionClause::ReductionModifier;
2401
+ const auto &maybeModifier{std::get<std::optional<ReductionModifier>>(x.v .t )};
2402
+ if (!maybeModifier || *maybeModifier == ReductionModifier::Default) {
2403
+ // No modifier, or the default one is always ok.
2404
+ return ;
2405
+ }
2406
+ ReductionModifier modifier{*maybeModifier};
2407
+ const DirectiveContext &dirCtx{GetContext ()};
2408
+ if (dirCtx.directive == llvm::omp::Directive::OMPD_loop) {
2409
+ // [5.2:257:33-34]
2410
+ // If a reduction-modifier is specified in a reduction clause that
2411
+ // appears on the directive, then the reduction modifier must be
2412
+ // default.
2413
+ context_.Say (GetContext ().clauseSource ,
2414
+ " REDUCTION modifier on LOOP directive must be DEFAULT" _err_en_US);
2415
+ }
2416
+ if (modifier == ReductionModifier::Task) {
2417
+ // "Task" is only allowed on worksharing or "parallel" directive.
2418
+ static llvm::omp::Directive worksharing[]{
2419
+ llvm::omp::Directive::OMPD_do, llvm::omp::Directive::OMPD_scope,
2420
+ llvm::omp::Directive::OMPD_sections,
2421
+ // There are more worksharing directives, but they do not apply:
2422
+ // "for" is C++ only,
2423
+ // "single" and "workshare" don't allow reduction clause,
2424
+ // "loop" has different restrictions (checked above).
2425
+ };
2426
+ if (dirCtx.directive != llvm::omp::Directive::OMPD_parallel &&
2427
+ !llvm::is_contained (worksharing, dirCtx.directive )) {
2428
+ context_.Say (GetContext ().clauseSource ,
2429
+ " Modifier 'TASK' on REDUCTION clause is only allowed with "
2430
+ " PARALLEL or worksharing directive" _err_en_US);
2431
+ }
2432
+ } else if (modifier == ReductionModifier::Inscan) {
2433
+ // "Inscan" is only allowed on worksharing-loop, worksharing-loop simd,
2434
+ // or "simd" directive.
2435
+ // The worksharing-loop directives are OMPD_do and OMPD_for. Only the
2436
+ // former is allowed in Fortran.
2437
+ switch (dirCtx.directive ) {
2438
+ case llvm::omp::Directive::OMPD_do: // worksharing-loop
2439
+ case llvm::omp::Directive::OMPD_do_simd: // worksharing-loop simd
2440
+ case llvm::omp::Directive::OMPD_simd: // "simd"
2441
+ break ;
2442
+ default :
2443
+ context_.Say (GetContext ().clauseSource ,
2444
+ " Modifier 'INSCAN' on REDUCTION clause is only allowed with "
2445
+ " worksharing-loop, worksharing-loop simd, "
2446
+ " or SIMD directive" _err_en_US);
2447
+ }
2448
+ } else {
2449
+ // Catch-all for potential future modifiers to make sure that this
2450
+ // function is up-to-date.
2451
+ context_.Say (GetContext ().clauseSource ,
2452
+ " Unexpected modifier on REDUCTION clause" _err_en_US);
2453
+ }
2454
+ }
2455
+
2397
2456
void OmpStructureChecker::CheckIntentInPointerAndDefinable (
2398
2457
const parser::OmpObjectList &objectList, const llvm::omp::Clause clause) {
2399
2458
for (const auto &ompObject : objectList.v ) {
0 commit comments