@@ -974,6 +974,42 @@ void OmpStructureChecker::CheckDistLinear(
974974}
975975
976976void OmpStructureChecker::Leave (const parser::OpenMPLoopConstruct &x) {
977+ const auto &beginLoopDir = std::get<parser::OmpBeginLoopDirective>(x.t );
978+ const auto &clauseList{std::get<parser::OmpClauseList>(beginLoopDir.t )};
979+ for (const auto &clause : clauseList.v ) {
980+ if (const auto *reductionClause{
981+ std::get_if<parser::OmpClause::Reduction>(&clause.u )}) {
982+ using ReductionModifier = parser::OmpReductionClause::ReductionModifier;
983+ const auto &maybeModifier{
984+ std::get<std::optional<ReductionModifier>>(reductionClause->v .t )};
985+ if (maybeModifier && *maybeModifier == ReductionModifier::Inscan) {
986+
987+ const auto &objectList{
988+ std::get<parser::OmpObjectList>(reductionClause->v .t )};
989+ for (const auto &ompObj : objectList.v ) {
990+ common::visit (
991+ common::visitors{
992+ [&](const parser::Designator &designator) {
993+ if (const auto *name{semantics::getDesignatorNameIfDataRef (
994+ designator)}) {
995+ std::string nameStr = name->symbol ->name ().ToString ();
996+ if (GetContext ().usedInScanDirective .find (nameStr) ==
997+ GetContext ().usedInScanDirective .end ()) {
998+ context_.Say (name->source ,
999+ " List item %s must appear in 'inclusive' or "
1000+ " 'exclusive' clause of an "
1001+ " enclosed scan directive" _err_en_US,
1002+ nameStr);
1003+ }
1004+ }
1005+ },
1006+ [&](const auto &name) {},
1007+ },
1008+ ompObj.u );
1009+ }
1010+ }
1011+ }
1012+ }
9771013 if (llvm::omp::allSimdSet.test (GetContext ().directive )) {
9781014 ExitDirectiveNest (SIMDNest);
9791015 }
@@ -1646,19 +1682,32 @@ void OmpStructureChecker::Leave(const parser::OpenMPAllocatorsConstruct &x) {
16461682 dirContext_.pop_back ();
16471683}
16481684
1685+ void OmpStructureChecker::CheckScan (
1686+ const parser::OpenMPSimpleStandaloneConstruct &x) {
1687+ if (std::get<parser::OmpClauseList>(x.t ).v .size () != 1 ) {
1688+ context_.Say (x.source ,
1689+ " Exactly one of `exclusive` or `inclusive` clause is expected" _err_en_US);
1690+ }
1691+ if (!CurrentDirectiveIsNested () ||
1692+ !llvm::omp::scanParentAllowedSet.test (GetContextParent ().directive )) {
1693+ context_.Say (x.source ,
1694+ " Orphaned `omp scan` directives are prohibited; perhaps you forgot "
1695+ " to enclose the directive in to a worksharing loop, a worksharing "
1696+ " loop simd or a simd directive." _err_en_US);
1697+ }
1698+ }
1699+
16491700void OmpStructureChecker::CheckBarrierNesting (
16501701 const parser::OpenMPSimpleStandaloneConstruct &x) {
16511702 // A barrier region may not be `closely nested` inside a worksharing, loop,
16521703 // task, taskloop, critical, ordered, atomic, or master region.
16531704 // TODO: Expand the check to include `LOOP` construct as well when it is
16541705 // supported.
1655- if (GetContext ().directive == llvm::omp::Directive::OMPD_barrier) {
1656- if (IsCloselyNestedRegion (llvm::omp::nestedBarrierErrSet)) {
1657- context_.Say (parser::FindSourceLocation (x),
1658- " `BARRIER` region may not be closely nested inside of `WORKSHARING`, "
1659- " `LOOP`, `TASK`, `TASKLOOP`,"
1660- " `CRITICAL`, `ORDERED`, `ATOMIC` or `MASTER` region." _err_en_US);
1661- }
1706+ if (IsCloselyNestedRegion (llvm::omp::nestedBarrierErrSet)) {
1707+ context_.Say (parser::FindSourceLocation (x),
1708+ " `BARRIER` region may not be closely nested inside of `WORKSHARING`, "
1709+ " `LOOP`, `TASK`, `TASKLOOP`,"
1710+ " `CRITICAL`, `ORDERED`, `ATOMIC` or `MASTER` region." _err_en_US);
16621711 }
16631712}
16641713
@@ -1842,7 +1891,16 @@ void OmpStructureChecker::Enter(
18421891 const parser::OpenMPSimpleStandaloneConstruct &x) {
18431892 const auto &dir{std::get<parser::OmpSimpleStandaloneDirective>(x.t )};
18441893 PushContextAndClauseSets (dir.source , dir.v );
1845- CheckBarrierNesting (x);
1894+ switch (dir.v ) {
1895+ case llvm::omp::Directive::OMPD_barrier:
1896+ CheckBarrierNesting (x);
1897+ break ;
1898+ case llvm::omp::Directive::OMPD_scan:
1899+ CheckScan (x);
1900+ break ;
1901+ default :
1902+ break ;
1903+ }
18461904}
18471905
18481906void OmpStructureChecker::Leave (
@@ -2674,15 +2732,13 @@ CHECK_SIMPLE_CLAUSE(Depobj, OMPC_depobj)
26742732CHECK_SIMPLE_CLAUSE (Detach, OMPC_detach)
26752733CHECK_SIMPLE_CLAUSE (DeviceType, OMPC_device_type)
26762734CHECK_SIMPLE_CLAUSE (DistSchedule, OMPC_dist_schedule)
2677- CHECK_SIMPLE_CLAUSE (Exclusive, OMPC_exclusive)
26782735CHECK_SIMPLE_CLAUSE (Final, OMPC_final)
26792736CHECK_SIMPLE_CLAUSE (Flush, OMPC_flush)
26802737CHECK_SIMPLE_CLAUSE (Full, OMPC_full)
26812738CHECK_SIMPLE_CLAUSE (Grainsize, OMPC_grainsize)
26822739CHECK_SIMPLE_CLAUSE (Hint, OMPC_hint)
26832740CHECK_SIMPLE_CLAUSE (Holds, OMPC_holds)
26842741CHECK_SIMPLE_CLAUSE (InReduction, OMPC_in_reduction)
2685- CHECK_SIMPLE_CLAUSE (Inclusive, OMPC_inclusive)
26862742CHECK_SIMPLE_CLAUSE (Match, OMPC_match)
26872743CHECK_SIMPLE_CLAUSE (Nontemporal, OMPC_nontemporal)
26882744CHECK_SIMPLE_CLAUSE (NumTasks, OMPC_num_tasks)
@@ -2775,7 +2831,24 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Reduction &x) {
27752831 if (CheckReductionOperators (x)) {
27762832 CheckReductionTypeList (x);
27772833 }
2778- CheckReductionModifier (x);
2834+ using ReductionModifier = parser::OmpReductionClause::ReductionModifier;
2835+ if (const auto &maybeModifier{
2836+ std::get<std::optional<ReductionModifier>>(x.v .t )}) {
2837+ ReductionModifier modifier{*maybeModifier};
2838+ const auto &ompObjectList{std::get<parser::OmpObjectList>(x.v .t )};
2839+ addModifiertoMap (ompObjectList, modifier);
2840+ CheckReductionModifier (modifier);
2841+ }
2842+ }
2843+
2844+ void OmpStructureChecker::Enter (const parser::OmpClause::Inclusive &x) {
2845+ CheckAllowed (llvm::omp::Clause::OMPC_inclusive);
2846+ checkAndAddSymbolsToUsedInScanList (x.v );
2847+ }
2848+
2849+ void OmpStructureChecker::Enter (const parser::OmpClause::Exclusive &x) {
2850+ CheckAllowed (llvm::omp::Clause::OMPC_exclusive);
2851+ checkAndAddSymbolsToUsedInScanList (x.v );
27792852}
27802853
27812854bool OmpStructureChecker::CheckReductionOperators (
@@ -2818,6 +2891,49 @@ bool OmpStructureChecker::CheckReductionOperators(
28182891
28192892 return ok;
28202893}
2894+
2895+ void OmpStructureChecker::addModifiertoMap (const parser::OmpObjectList &x,
2896+ parser::OmpReductionClause::ReductionModifier &modifier) {
2897+ for (const auto &ompObject : x.v ) {
2898+ if (const auto *name{parser::Unwrap<parser::Name>(ompObject)}) {
2899+ if (const auto *symbol{name->symbol }) {
2900+ GetContext ().reductionMod [symbol->name ().ToString ()] = modifier;
2901+ }
2902+ }
2903+ }
2904+ }
2905+
2906+ void OmpStructureChecker::checkAndAddSymbolsToUsedInScanList (
2907+ const parser::OmpObjectList &x) {
2908+ for (const auto &ompObj : x.v ) {
2909+ common::visit (
2910+ common::visitors{
2911+ [&](const parser::Designator &designator) {
2912+ if (const auto *name{
2913+ semantics::getDesignatorNameIfDataRef (designator)}) {
2914+ if (name->symbol ) {
2915+ if (CurrentDirectiveIsNested ()) {
2916+ std::string nameStr = name->symbol ->name ().ToString ();
2917+ if (GetContextParent ().reductionMod .find (nameStr) ==
2918+ GetContextParent ().reductionMod .end ()) {
2919+
2920+ context_.Say (name->source ,
2921+ " List item %s must appear in 'reduction' clause "
2922+ " with the 'inscan' modifier of the parent "
2923+ " directive" _err_en_US,
2924+ nameStr);
2925+ }
2926+ GetContextParent ().usedInScanDirective .insert (nameStr);
2927+ }
2928+ }
2929+ }
2930+ },
2931+ [&](const auto &name) {},
2932+ },
2933+ ompObj.u );
2934+ }
2935+ }
2936+
28212937bool OmpStructureChecker::CheckIntrinsicOperator (
28222938 const parser::DefinedOperator::IntrinsicOperator &op) {
28232939
@@ -2952,14 +3068,12 @@ void OmpStructureChecker::CheckReductionTypeList(
29523068}
29533069
29543070void OmpStructureChecker::CheckReductionModifier (
2955- const parser::OmpClause::Reduction &x ) {
3071+ const parser::OmpReductionClause::ReductionModifier &modifier ) {
29563072 using ReductionModifier = parser::OmpReductionClause::ReductionModifier;
2957- const auto &maybeModifier{std::get<std::optional<ReductionModifier>>(x.v .t )};
2958- if (!maybeModifier || *maybeModifier == ReductionModifier::Default) {
2959- // No modifier, or the default one is always ok.
3073+ if (modifier == ReductionModifier::Default) {
3074+ // the default one is always ok.
29603075 return ;
29613076 }
2962- ReductionModifier modifier{*maybeModifier};
29633077 const DirectiveContext &dirCtx{GetContext ()};
29643078 if (dirCtx.directive == llvm::omp::Directive::OMPD_loop) {
29653079 // [5.2:257:33-34]
0 commit comments