Index: flang/lib/Semantics/check-omp-structure.h =================================================================== --- flang/lib/Semantics/check-omp-structure.h +++ flang/lib/Semantics/check-omp-structure.h @@ -194,6 +194,7 @@ void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct &x); void CheckDoWhile(const parser::OpenMPLoopConstruct &x); void CheckCycleConstraints(const parser::OpenMPLoopConstruct &x); + void CheckDistLinear(const parser::OpenMPLoopConstruct &x); std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x); void CheckIfDoOrderedClause(const parser::OmpBlockDirective &blkDirectiv); bool CheckReductionOperators(const parser::OmpClause::Reduction &); Index: flang/lib/Semantics/check-omp-structure.cpp =================================================================== --- flang/lib/Semantics/check-omp-structure.cpp +++ flang/lib/Semantics/check-omp-structure.cpp @@ -233,6 +233,7 @@ CheckDoWhile(x); CheckLoopItrVariableIsInt(x); CheckCycleConstraints(x); + CheckDistLinear(x); } const parser::Name OmpStructureChecker::GetLoopIndex( const parser::DoConstruct *x) { @@ -329,6 +330,76 @@ parser::Walk(x, ompCycleChecker); } +void OmpStructureChecker::CheckDistLinear( + const parser::OpenMPLoopConstruct &x) { + OmpDirectiveSet distributeSet{llvm::omp::Directive::OMPD_distribute, + llvm::omp::Directive::OMPD_distribute_parallel_do, + llvm::omp::Directive::OMPD_distribute_parallel_do_simd, + llvm::omp::Directive::OMPD_distribute_parallel_for, + llvm::omp::Directive::OMPD_distribute_parallel_for_simd, + llvm::omp::Directive::OMPD_distribute_simd}; + const auto &beginLoopDir{std::get(x.t)}; + const auto &beginDir{std::get(beginLoopDir.t)}; + + if (distributeSet.test(beginDir.v)) { + // Extract iteration variables of all the loops in a map + semantics::UnorderedSymbolSet indexVars; + + if (const auto &loopConstruct{ + std::get>(x.t)}) { + + for (const parser::DoConstruct *loop{&*loopConstruct}; loop;) { + if (loop->IsDoNormal()) { + const parser::Name &itrVal{GetLoopIndex(loop)}; + + if (itrVal.symbol) { + indexVars.insert(*(itrVal.symbol)); + } + } + // Get the next DoConstruct if block is not empty. + const auto &block{std::get(loop->t)}; + const auto it{block.begin()}; + loop = it != block.end() ? parser::Unwrap(*it) + : nullptr; + } + } + + // A variable may not appear in a linear clause, unless it is the loop + // iteration variable. + const auto &beginLoopDir{std::get(x.t)}; + const auto &clauses{std::get(beginLoopDir.t)}; + + for (const auto &clause : clauses.v) { + if (const auto *linearClause{ + std::get_if(&clause.u)}) { + + std::list values; + // Get the variant type + if (std::holds_alternative( + linearClause->v.u)) { + const auto &withM{std::get( + linearClause->v.u)}; + values = withM.names; + } else { + const auto &withOutM{ + std::get( + linearClause->v.u)}; + values = withOutM.names; + } + for (auto const &v : values) { + // Check if the variable is not inside the collected index variables + // of the loop + if (indexVars.count(*(v.symbol)) < 1) { + context_.Say(v.source, + "Variable '%s' not allowed at `LINEAR` clause, only loop iterator can be specified in `LINEAR` clause of a construct combined with `DISTRIBUTE`"_err_en_US, + v.ToString()); + } + } + } + } + } +} + void OmpStructureChecker::Leave(const parser::OpenMPLoopConstruct &) { dirContext_.pop_back(); } Index: flang/test/Semantics/omp-linear-iter.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/omp-linear-iter.f90 @@ -0,0 +1,56 @@ +! RUN: %S/test_errors.sh %s %t %flang -fopenmp +! OpenMP Version 4.5 +! Various checks with the ordered construct + +SUBROUTINE LINEAR_GOOD(N) + INTEGER N, i, j, a, b(10) + !$omp target + !$omp teams + !$omp distribute parallel do simd linear(i) + do i = 1, N + a = 3.14 + enddo + !$omp end distribute parallel do simd + !$omp end teams + !$omp end target +END SUBROUTINE LINEAR_GOOD + +SUBROUTINE LINEAR_BAD(N) + INTEGER N, i, j, a, b(10) + + !$omp target + !$omp teams + !ERROR: Variable 'j' not allowed at `LINEAR` clause, only loop iterator can be specified in `LINEAR` clause of a construct combined with `DISTRIBUTE` + !$omp distribute parallel do simd linear(j) + do i = 1, N + a = 3.14 + enddo + !$omp end distribute parallel do simd + !$omp end teams + !$omp end target + + !$omp target + !$omp teams + !ERROR: Variable 'j' not allowed at `LINEAR` clause, only loop iterator can be specified in `LINEAR` clause of a construct combined with `DISTRIBUTE` + !ERROR: Variable 'b' not allowed at `LINEAR` clause, only loop iterator can be specified in `LINEAR` clause of a construct combined with `DISTRIBUTE` + !$omp distribute parallel do simd linear(j) linear(b) + do i = 1, N + a = 3.14 + enddo + !$omp end distribute parallel do simd + !$omp end teams + !$omp end target + + !$omp target + !$omp teams + !ERROR: Variable 'j' not allowed at `LINEAR` clause, only loop iterator can be specified in `LINEAR` clause of a construct combined with `DISTRIBUTE` + !ERROR: Variable 'b' not allowed at `LINEAR` clause, only loop iterator can be specified in `LINEAR` clause of a construct combined with `DISTRIBUTE` + !$omp distribute parallel do simd linear(j, b) + do i = 1, N + a = 3.14 + enddo + !$omp end distribute parallel do simd + !$omp end teams + !$omp end target + +END SUBROUTINE LINEAR_BAD