[flang-commits] [flang] [llvm] [flang][OpenMP] Check conflicts between predetermined/explicit DSA (PR #194961)
Krzysztof Parzyszek via flang-commits
flang-commits at lists.llvm.org
Thu Apr 30 04:13:36 PDT 2026
https://github.com/kparzysz updated https://github.com/llvm/llvm-project/pull/194961
>From 865fd2a6509dca71178cce61d431a2d5230dd09c Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Tue, 28 Apr 2026 07:29:16 -0500
Subject: [PATCH 1/2] [flang][OpenMP] Check conflicts between
predetermined/explicit DSA
Improve checks for loop iteration variables with predetermined DSA
appearing in DSA clauses. Show both the location of the variable
in the offending clause, and in the loop.
Make the checks a bit more accurate as well: only allow LINEAR clause
on SIMD construct with a single affected loop.
---
flang/include/flang/Semantics/openmp-utils.h | 4 +-
flang/lib/Semantics/check-omp-loop.cpp | 102 ++++++++++++++----
flang/lib/Semantics/check-omp-structure.cpp | 15 ---
flang/lib/Semantics/check-omp-structure.h | 5 +-
flang/lib/Semantics/openmp-utils.cpp | 20 ++--
flang/lib/Semantics/resolve-directives.cpp | 12 ---
flang/test/Parser/OpenMP/linear-clause.f90 | 25 ++---
flang/test/Semantics/OpenMP/do01.f90 | 3 +-
flang/test/Semantics/OpenMP/do04.f90 | 14 +--
flang/test/Semantics/OpenMP/do10.f90 | 3 -
.../test/Semantics/OpenMP/linear-clause03.f90 | 2 +
flang/test/Semantics/OpenMP/linear-iter.f90 | 4 +
llvm/include/llvm/Frontend/OpenMP/OMP.h | 27 +++++
13 files changed, 151 insertions(+), 85 deletions(-)
diff --git a/flang/include/flang/Semantics/openmp-utils.h b/flang/include/flang/Semantics/openmp-utils.h
index 3124005a4bbff..aab63df2e6e14 100644
--- a/flang/include/flang/Semantics/openmp-utils.h
+++ b/flang/include/flang/Semantics/openmp-utils.h
@@ -99,6 +99,8 @@ bool IsVarOrFunctionRef(const MaybeExpr &expr);
bool IsWholeAssumedSizeArray(const parser::OmpObject &object);
+const Symbol *GetHostSymbol(const Symbol &sym);
+
bool IsMapEnteringType(parser::OmpMapType::Value type);
bool IsMapExitingType(parser::OmpMapType::Value type);
@@ -150,7 +152,7 @@ struct LoopControl {
LoopControl(const parser::LoopControl::Bounds &x);
LoopControl(const parser::ConcurrentControl &x);
- const Symbol *iv{nullptr};
+ parser::Name iv;
WithSource<MaybeExpr> lbound, ubound, step;
private:
diff --git a/flang/lib/Semantics/check-omp-loop.cpp b/flang/lib/Semantics/check-omp-loop.cpp
index b246d027e4807..42626efe8b4fd 100644
--- a/flang/lib/Semantics/check-omp-loop.cpp
+++ b/flang/lib/Semantics/check-omp-loop.cpp
@@ -414,7 +414,6 @@ void OmpStructureChecker::Enter(const parser::OpenMPLoopConstruct &x) {
// nesting check
HasInvalidWorksharingNesting(beginName, llvm::omp::nestedWorkshareErrSet);
}
- SetLoopInfo(x);
for (auto &construct : std::get<parser::Block>(x.t)) {
if (const auto *doConstruct{parser::omp::GetDoConstruct(construct)}) {
@@ -422,7 +421,7 @@ void OmpStructureChecker::Enter(const parser::OpenMPLoopConstruct &x) {
CheckNoBranching(doBlock, beginName.v, beginName.source);
}
}
- CheckIterationVariableType(x);
+ CheckIterationVariables(x);
CheckNestedConstruct(x);
CheckAssociatedLoopConstraints(x);
HasInvalidDistributeNesting(x);
@@ -443,30 +442,89 @@ const parser::Name OmpStructureChecker::GetLoopIndex(
return std::get<Bounds>(x->GetLoopControl()->u).Name().thing;
}
-void OmpStructureChecker::SetLoopInfo(const parser::OpenMPLoopConstruct &x) {
- if (const auto *loop{x.GetNestedLoop()}) {
- if (loop->IsDoNormal()) {
- const parser::Name &itrVal{GetLoopIndex(loop)};
- SetLoopIv(itrVal.symbol);
+void OmpStructureChecker::CheckIterationVariables(
+ const parser::OpenMPLoopConstruct &x) {
+ unsigned version{context_.langOptions().OpenMPVersion};
+ auto doLoops{CollectAffectedDoLoops(x, version, &context_)};
+ if (!doLoops) {
+ return;
+ }
+ const parser::OmpDirectiveSpecification &spec{x.BeginDir()};
+ llvm::omp::Directive dirId{spec.DirId()};
+
+ // Collect symbols from DSA clauses on the construct. These symbols
+ // are the "host" versions of symbols inside the construct. The flags
+ // of interest are on the associated symbols.
+ std::map<const Symbol *, std::pair<parser::CharBlock, llvm::omp::Clause>> dsa;
+ for (auto &clause : spec.Clauses().v) {
+ llvm::omp::Clause clauseId{clause.Id()};
+ if (llvm::omp::isDataSharingAttributeClause(clauseId, version)) {
+ for (auto &object : parser::omp::GetOmpObjectList(clause)->v) {
+ if (auto *symbol{GetObjectSymbol(object)}) {
+ auto maybeSource{parser::omp::GetObjectSource(object)};
+ assert(maybeSource && "Expecting object source");
+ dsa.insert(
+ std::make_pair(symbol, std::make_pair(*maybeSource, clauseId)));
+ }
+ }
}
}
-}
-void OmpStructureChecker::CheckIterationVariableType(
- const parser::OpenMPLoopConstruct &x) {
- auto &body{std::get<parser::Block>(x.t)};
- for (auto &construct : LoopRange(body, LoopRange::Step::Into)) {
- // 'construct' can also be OpenMPLoopConstruct
- if (auto *loop{parser::Unwrap<parser::DoConstruct>(construct)}) {
- if (loop->IsDoNormal()) {
- if (const parser::Name &iv{GetLoopIndex(loop)}; iv.symbol) {
- const auto *type{iv.symbol->GetType()};
- if (!type->IsNumeric(TypeCategory::Integer)) {
- context_.Say(iv.source,
- "The DO loop iteration variable must be of integer type"_err_en_US,
- iv.ToString());
- }
+ auto [depth, _]{GetAffectedNestDepthWithReason(spec, version)};
+ bool isLinearAllowed{false};
+ if (!depth || depth.value == 1) {
+ auto leafs{llvm::omp::getLeafConstructsOrSelf(dirId)};
+ isLinearAllowed = leafs.back() == llvm::omp::Directive::OMPD_simd;
+ }
+
+ std::vector<parser::Name> ivs;
+ for (const parser::DoConstruct *loop : *doLoops) {
+ for (auto &control : GetLoopControls(*loop)) {
+ if (control.iv.symbol) {
+ ivs.push_back(control.iv);
+ }
+ }
+ }
+
+ for (const parser::Name &iv : ivs) {
+ const auto *type{iv.symbol->GetType()};
+ if (!type->IsNumeric(TypeCategory::Integer)) {
+ context_.Say(iv.source,
+ "The DO loop iteration variable must be of integer type"_err_en_US,
+ iv.ToString());
+ }
+ const Symbol *host{GetHostSymbol(*iv.symbol)};
+ if (!host) {
+ continue;
+ }
+ if (host->test(Symbol::Flag::OmpThreadprivate)) {
+ context_.Say(iv.source,
+ "Loop iteration variable of an affected loop cannot be THREADPRIVATE"_err_en_US,
+ iv.ToString());
+ }
+ // Check conflict between a predetermined DSA and explicit DSA.
+ assert(iv.symbol->test(Symbol::Flag::OmpPreDetermined) &&
+ "Expecting affected iteration variable to have predetermined DSA");
+ if (iv.symbol->test(Symbol::Flag::OmpExplicit)) {
+ if (auto f{dsa.find(host)}; f != dsa.end()) {
+ llvm::omp::Clause id{f->second.second};
+ if (!llvm::omp::isAllowedClauseForDirective(dirId, id, version)) {
+ continue;
+ }
+ if (id == llvm::omp::Clause::OMPC_private ||
+ id == llvm::omp::Clause::OMPC_lastprivate) {
+ continue;
}
+ if (id == llvm::omp::Clause::OMPC_linear && isLinearAllowed) {
+ continue;
+ }
+ context_
+ .Say(f->second.first,
+ "Loop iteration variable with a predetermined data sharing attribute cannot appear in a %s clause"_err_en_US,
+ parser::omp::GetUpperName(id, version))
+ .Attach(iv.source,
+ "'%s' is an iteration variable of an affected loop"_because_en_US,
+ iv.ToString());
}
}
}
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 7bff7de2f8fbf..790c8c325c60f 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -4285,7 +4285,6 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Firstprivate &x) {
CheckVarIsNotPartOfAnotherVar(GetContext().clauseSource, x.v, "FIRSTPRIVATE");
CheckCrayPointee(x.v, "FIRSTPRIVATE");
- CheckIsLoopIvPartOfClause(llvm::omp::Clause::OMPC_firstprivate, x.v);
SymbolSourceMap currSymbols;
GetSymbolsInObjectList(x.v, currSymbols);
@@ -4323,20 +4322,6 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Firstprivate &x) {
currSymbols, dirClauseTriple, llvm::omp::Clause::OMPC_firstprivate);
}
-void OmpStructureChecker::CheckIsLoopIvPartOfClause(
- llvm::omp::Clause clause, const parser::OmpObjectList &ompObjectList) {
- unsigned version{context_.langOptions().OpenMPVersion};
- for (const auto &ompObject : ompObjectList.v) {
- if (const parser::Name *name{parser::Unwrap<parser::Name>(ompObject)}) {
- if (name->symbol == GetContext().loopIV) {
- context_.Say(name->source,
- "DO iteration variable %s is not allowed in %s clause."_err_en_US,
- name->ToString(), parser::omp::GetUpperName(clause, version));
- }
- }
- }
-}
-
void OmpStructureChecker::Enter(const parser::OmpClause::Align &x) {
CheckAllowedClause(llvm::omp::Clause::OMPC_align);
if (const auto &v{GetIntValue(x.v.v)}) {
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index e75bb5da847a9..6634582708173 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -250,8 +250,7 @@ class OmpStructureChecker : public OmpStructureCheckerBase {
const omp::LoopSequence &nest);
void CheckNestedConstruct(const parser::OpenMPLoopConstruct &x);
const parser::Name GetLoopIndex(const parser::DoConstruct *x);
- void SetLoopInfo(const parser::OpenMPLoopConstruct &x);
- void CheckIterationVariableType(const parser::OpenMPLoopConstruct &x);
+ void CheckIterationVariables(const parser::OpenMPLoopConstruct &x);
std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x);
void CheckAssociatedLoopConstraints(const parser::OpenMPLoopConstruct &x);
void CheckScanModifier(const parser::OmpClause::Reduction &x);
@@ -351,8 +350,6 @@ class OmpStructureChecker : public OmpStructureCheckerBase {
SymbolSourceMap &, const llvm::omp::Clause);
void CheckPrivateSymbolsInOuterCxt(
SymbolSourceMap &, DirectivesClauseTriple &, const llvm::omp::Clause);
- void CheckIsLoopIvPartOfClause(
- llvm::omp::Clause clause, const parser::OmpObjectList &ompObjectList);
bool CheckTargetBlockOnlyTeams(const parser::Block &);
void CheckWorkshareBlockStmts(const parser::Block &, parser::CharBlock);
void CheckWorkdistributeBlockStmts(const parser::Block &, parser::CharBlock);
diff --git a/flang/lib/Semantics/openmp-utils.cpp b/flang/lib/Semantics/openmp-utils.cpp
index 9c5f77ef03a27..e837f8dca19f6 100644
--- a/flang/lib/Semantics/openmp-utils.cpp
+++ b/flang/lib/Semantics/openmp-utils.cpp
@@ -207,6 +207,13 @@ bool IsWholeAssumedSizeArray(const parser::OmpObject &object) {
return false;
}
+const Symbol *GetHostSymbol(const Symbol &sym) {
+ if (auto *details{sym.detailsIf<HostAssocDetails>()}) {
+ return &details->symbol();
+ }
+ return nullptr;
+}
+
bool IsMapEnteringType(parser::OmpMapType::Value type) {
switch (type) {
case parser::OmpMapType::Value::Alloc:
@@ -576,7 +583,7 @@ static bool IsTransformableLoop(const parser::ExecutionPartConstruct &epc) {
}
LoopControl::LoopControl(const parser::LoopControl::Bounds &x) {
- iv = x.Name().thing.symbol;
+ iv = x.Name().thing;
lbound = fromParserExpr(parser::UnwrapRef<parser::Expr>(x.Lower()));
ubound = fromParserExpr(parser::UnwrapRef<parser::Expr>(x.Upper()));
if (auto &inc{x.Step()}) {
@@ -586,7 +593,7 @@ LoopControl::LoopControl(const parser::LoopControl::Bounds &x) {
LoopControl::LoopControl(const parser::ConcurrentControl &x) {
auto &[name, lower, upper, inc]{x.t};
- iv = name.symbol;
+ iv = name;
lbound = fromParserExpr(parser::UnwrapRef<parser::Expr>(lower));
ubound = fromParserExpr(parser::UnwrapRef<parser::Expr>(upper));
if (inc) {
@@ -605,7 +612,8 @@ std::vector<LoopControl> GetLoopControls(const parser::DoConstruct &x) {
controls.emplace_back(std::get<parser::LoopControl::Bounds>(control.u));
} else if (x.IsDoConcurrent()) {
const parser::LoopControl &control{*x.GetLoopControl()};
- auto &header{parser::UnwrapRef<parser::ConcurrentHeader>(control)};
+ auto &concurrent{std::get<parser::LoopControl::Concurrent>(control.u)};
+ auto &header{std::get<parser::ConcurrentHeader>(concurrent.t)};
for (auto &cc : std::get<std::list<parser::ConcurrentControl>>(header.t)) {
controls.emplace_back(cc);
}
@@ -1776,8 +1784,8 @@ WithReason<bool> LoopSequence::isRectangular(
SymbolVector outerIVs;
for (auto *sequence : llvm::reverse(outer)) {
for (auto &control : sequence->getLoopControls()) {
- if (control.iv) {
- outerIVs.emplace_back(*control.iv);
+ if (control.iv.symbol) {
+ outerIVs.emplace_back(*control.iv.symbol);
}
}
}
@@ -1785,7 +1793,7 @@ WithReason<bool> LoopSequence::isRectangular(
WithReason<bool> result(true);
for (auto &control : getLoopControls()) {
- if (!control.iv || !control.lbound.value || !control.ubound.value) {
+ if (!control.iv.symbol || !control.lbound.value || !control.ubound.value) {
continue;
}
CheckSymbolExprOverlap(result, outerIVs, *control.lbound.value,
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 22c2ca082ff22..d056917d849fd 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -2114,16 +2114,6 @@ void OmpAttributeVisitor::PrivatizeAssociatedLoopIndex(
ivDSA = Symbol::Flag::OmpLastPrivate;
}
- auto checkThreadprivate{[&](const parser::Name &iv) {
- if (const auto *details{iv.symbol->detailsIf<HostAssocDetails>()}) {
- if (details->symbol().test(Symbol::Flag::OmpThreadprivate)) {
- context_.Say(iv.source,
- "Loop iteration variable %s is not allowed in THREADPRIVATE."_err_en_US,
- iv.ToString());
- }
- }
- }};
-
Scope &scope{currScope()};
if (auto doLoops{omp::CollectAffectedDoLoops(x, version, &context_)}) {
@@ -2132,9 +2122,7 @@ void OmpAttributeVisitor::PrivatizeAssociatedLoopIndex(
if (!iv || (iv->symbol && IsLocalInsideScope(*iv->symbol, scope))) {
continue;
}
-
if (auto *symbol{ResolveOmp(*iv, ivDSA, scope)}) {
- checkThreadprivate(*iv);
SetSymbolDSA(*symbol, {Symbol::Flag::OmpPreDetermined, ivDSA});
iv->symbol = symbol; // adjust the symbol within region
AddToContextObjectWithDSA(*symbol, ivDSA);
diff --git a/flang/test/Parser/OpenMP/linear-clause.f90 b/flang/test/Parser/OpenMP/linear-clause.f90
index 5df37e0b3b028..45d288ce2077d 100644
--- a/flang/test/Parser/OpenMP/linear-clause.f90
+++ b/flang/test/Parser/OpenMP/linear-clause.f90
@@ -1,5 +1,5 @@
-!RUN: %flang_fc1 -fdebug-unparse -fopenmp -fopenmp-version=52 %s | FileCheck --ignore-case --check-prefix="UNPARSE" %s
-!RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp -fopenmp-version=52 %s | FileCheck --check-prefix="PARSE-TREE" %s
+!RUN: %flang_fc1 -fdebug-unparse-no-sema -fopenmp -fopenmp-version=52 %s | FileCheck --ignore-case --check-prefix="UNPARSE" %s
+!RUN: %flang_fc1 -fdebug-dump-parse-tree-no-sema -fopenmp -fopenmp-version=52 %s | FileCheck --check-prefix="PARSE-TREE" %s
subroutine f00(x)
integer :: x
@@ -12,7 +12,7 @@ subroutine f00(x)
!UNPARSE: SUBROUTINE f00 (x)
!UNPARSE: INTEGER x
!UNPARSE: !$OMP DO LINEAR(x)
-!UNPARSE: DO x=1_4,10_4
+!UNPARSE: DO x=1,10
!UNPARSE: END DO
!UNPARSE: !$OMP END DO
!UNPARSE: END SUBROUTINE
@@ -35,8 +35,8 @@ subroutine f01(x)
!UNPARSE: SUBROUTINE f01 (x)
!UNPARSE: INTEGER x
-!UNPARSE: !$OMP DO LINEAR(x: 2_4)
-!UNPARSE: DO x=1_4,10_4
+!UNPARSE: !$OMP DO LINEAR(x: 2)
+!UNPARSE: DO x=1,10
!UNPARSE: END DO
!UNPARSE: !$OMP END DO
!UNPARSE: END SUBROUTINE
@@ -45,8 +45,7 @@ subroutine f01(x)
!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = do
!PARSE-TREE: | OmpClauseList -> OmpClause -> Linear -> OmpLinearClause
!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
-!PARSE-TREE: | | Modifier -> OmpStepSimpleModifier -> Scalar -> Integer -> Expr = '2_4'
-!PARSE-TREE: | | | LiteralConstant -> IntLiteralConstant = '2'
+!PARSE-TREE: | | Modifier -> OmpStepSimpleModifier -> Scalar -> Integer -> Expr -> LiteralConstant -> IntLiteralConstant = '2'
!PARSE-TREE: | | bool = 'true'
!PARSE-TREE: | Flags = {}
!PARSE-TREE: DoConstruct
@@ -61,8 +60,8 @@ subroutine f02(x)
!UNPARSE: SUBROUTINE f02 (x)
!UNPARSE: INTEGER x
-!UNPARSE: !$OMP DO LINEAR(x: STEP(3_4))
-!UNPARSE: DO x=1_4,10_4
+!UNPARSE: !$OMP DO LINEAR(x: STEP(3))
+!UNPARSE: DO x=1,10
!UNPARSE: END DO
!UNPARSE: !$OMP END DO
!UNPARSE: END SUBROUTINE
@@ -71,8 +70,7 @@ subroutine f02(x)
!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = do
!PARSE-TREE: | OmpClauseList -> OmpClause -> Linear -> OmpLinearClause
!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
-!PARSE-TREE: | | Modifier -> OmpStepComplexModifier -> Scalar -> Integer -> Expr = '3_4'
-!PARSE-TREE: | | | LiteralConstant -> IntLiteralConstant = '3'
+!PARSE-TREE: | | Modifier -> OmpStepComplexModifier -> Scalar -> Integer -> Expr -> LiteralConstant -> IntLiteralConstant = '3'
!PARSE-TREE: | | bool = 'true'
!PARSE-TREE: | Flags = {}
!PARSE-TREE: DoConstruct
@@ -102,7 +100,7 @@ subroutine f04(x)
!UNPARSE: SUBROUTINE f04 (x)
!UNPARSE: INTEGER x
-!UNPARSE: !$OMP DECLARE SIMD LINEAR(x: UVAL, STEP(3_4))
+!UNPARSE: !$OMP DECLARE SIMD LINEAR(x: UVAL, STEP(3))
!UNPARSE: END SUBROUTINE
!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareSimdDirective -> OmpDirectiveSpecification
@@ -110,7 +108,6 @@ subroutine f04(x)
!PARSE-TREE: | OmpClauseList -> OmpClause -> Linear -> OmpLinearClause
!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
!PARSE-TREE: | | Modifier -> OmpLinearModifier -> Value = Uval
-!PARSE-TREE: | | Modifier -> OmpStepComplexModifier -> Scalar -> Integer -> Expr = '3_4'
-!PARSE-TREE: | | | LiteralConstant -> IntLiteralConstant = '3'
+!PARSE-TREE: | | Modifier -> OmpStepComplexModifier -> Scalar -> Integer -> Expr -> LiteralConstant -> IntLiteralConstant = '3'
!PARSE-TREE: | | bool = 'true'
!PARSE-TREE: | Flags = {}
diff --git a/flang/test/Semantics/OpenMP/do01.f90 b/flang/test/Semantics/OpenMP/do01.f90
index 78c3ba38bc873..a06df1339774e 100644
--- a/flang/test/Semantics/OpenMP/do01.f90
+++ b/flang/test/Semantics/OpenMP/do01.f90
@@ -6,8 +6,9 @@
program omp_do
integer i, j, k
- !ERROR: DO iteration variable i is not allowed in FIRSTPRIVATE clause.
+ !ERROR: Loop iteration variable with a predetermined data sharing attribute cannot appear in a FIRSTPRIVATE clause
!$omp do firstprivate(k,i)
+ !BECAUSE: 'i' is an iteration variable of an affected loop
do i = 1, 10
do j = 1, 10
print *, "Hello"
diff --git a/flang/test/Semantics/OpenMP/do04.f90 b/flang/test/Semantics/OpenMP/do04.f90
index 6690f4927f6a9..7c24ccac229c0 100644
--- a/flang/test/Semantics/OpenMP/do04.f90
+++ b/flang/test/Semantics/OpenMP/do04.f90
@@ -8,9 +8,9 @@ subroutine omp_do
integer, save:: i, j, k,n
!$omp threadprivate(k,j,i)
!$omp do collapse(2)
- !ERROR: Loop iteration variable i is not allowed in THREADPRIVATE.
+ !ERROR: Loop iteration variable of an affected loop cannot be THREADPRIVATE
do i = 1, 10
- !ERROR: Loop iteration variable j is not allowed in THREADPRIVATE.
+ !ERROR: Loop iteration variable of an affected loop cannot be THREADPRIVATE
do j = 1, 10
print *, "Hello"
end do
@@ -22,7 +22,7 @@ subroutine omp_do1
integer, save :: i, j, k
!$omp threadprivate(k,j,i)
!$omp do
- !ERROR: Loop iteration variable i is not allowed in THREADPRIVATE.
+ !ERROR: Loop iteration variable of an affected loop cannot be THREADPRIVATE
do i = 1, 10
do j = 1, 10
print *, "Hello"
@@ -40,7 +40,7 @@ subroutine omp_do2
contains
subroutine compute()
!$omp do ordered(1) collapse(1)
- !ERROR: Loop iteration variable k is not allowed in THREADPRIVATE.
+ !ERROR: Loop iteration variable of an affected loop cannot be THREADPRIVATE
foo: do k = 1, 10
do i = 1, 10
print *, "Hello"
@@ -58,7 +58,7 @@ subroutine omp_do3
print *, "parallel"
!$omp end parallel
!$omp do
- !ERROR: Loop iteration variable i is not allowed in THREADPRIVATE.
+ !ERROR: Loop iteration variable of an affected loop cannot be THREADPRIVATE
do i = 1, 10
do j = 1, 10
print *, "Hello"
@@ -82,7 +82,7 @@ end module usetp
subroutine main
use usetp
!$omp do
- !ERROR: Loop iteration variable i is not allowed in THREADPRIVATE.
+ !ERROR: Loop iteration variable of an affected loop cannot be THREADPRIVATE
do i = 1, 10
do j = 1, 10
print *, "Hello"
@@ -94,7 +94,7 @@ subroutine main
subroutine main1
use tp
!$omp do
- !ERROR: Loop iteration variable j is not allowed in THREADPRIVATE.
+ !ERROR: Loop iteration variable of an affected loop cannot be THREADPRIVATE
do j = 1, 10
do i = 1, 10
print *, "Hello"
diff --git a/flang/test/Semantics/OpenMP/do10.f90 b/flang/test/Semantics/OpenMP/do10.f90
index b609567c4d93d..1878864a4a5db 100644
--- a/flang/test/Semantics/OpenMP/do10.f90
+++ b/flang/test/Semantics/OpenMP/do10.f90
@@ -8,7 +8,6 @@ program omp_do
!$omp do
!ERROR: The DO loop iteration variable must be of integer type
do i = 1, 10
- !ERROR: The DO loop iteration variable must be of integer type
do j = 1, 10
print *, "it", i, j
end do
@@ -18,9 +17,7 @@ program omp_do
!ERROR: This construct requires a perfect nest of depth 3, but the associated nest is a perfect nest of depth 2
!BECAUSE: COLLAPSE clause was specified with argument 3
!$omp do collapse(3)
- !ERROR: The DO loop iteration variable must be of integer type
do i = 1, 10
- !ERROR: The DO loop iteration variable must be of integer type
do j = 1, 10
print *, "it", i, j
end do
diff --git a/flang/test/Semantics/OpenMP/linear-clause03.f90 b/flang/test/Semantics/OpenMP/linear-clause03.f90
index 124eb65701e26..7143db5927d46 100644
--- a/flang/test/Semantics/OpenMP/linear-clause03.f90
+++ b/flang/test/Semantics/OpenMP/linear-clause03.f90
@@ -15,7 +15,9 @@ subroutine f(x, y)
subroutine g
integer :: i
!ERROR: Clause LINEAR is not allowed if clause ORDERED appears on the DO directive
+ !ERROR: Loop iteration variable with a predetermined data sharing attribute cannot appear in a LINEAR clause
!$omp do ordered(1) linear(i)
+ !BECAUSE: 'i' is an iteration variable of an affected loop
do i = 1, 10
end do
end
diff --git a/flang/test/Semantics/OpenMP/linear-iter.f90 b/flang/test/Semantics/OpenMP/linear-iter.f90
index a46a3411fab34..d810bc26c3606 100644
--- a/flang/test/Semantics/OpenMP/linear-iter.f90
+++ b/flang/test/Semantics/OpenMP/linear-iter.f90
@@ -76,8 +76,12 @@ SUBROUTINE LINEAR_BAD(N)
!$omp end distribute simd
!WARNING: `DISTRIBUTE` must be dynamically enclosed in a `TEAMS` region.
+ !ERROR: Loop iteration variable with a predetermined data sharing attribute cannot appear in a LINEAR clause
+ !ERROR: Loop iteration variable with a predetermined data sharing attribute cannot appear in a LINEAR clause
!$omp distribute simd linear(i,j) collapse(2)
+ !BECAUSE: 'i' is an iteration variable of an affected loop
do i = 1, N
+ !BECAUSE: 'j' is an iteration variable of an affected loop
do j = 1, N
a = 3.14
enddo
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.h b/llvm/include/llvm/Frontend/OpenMP/OMP.h
index c7ad54ef3ed1b..c153707961d64 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMP.h
+++ b/llvm/include/llvm/Frontend/OpenMP/OMP.h
@@ -69,6 +69,33 @@ static constexpr inline bool isPrivatizingClause(Clause C, unsigned Version) {
}
}
+static constexpr inline bool isDataSharingAttributeClause(Clause C,
+ unsigned Version) {
+ // The "Version" parameter is in case the result is version-depenent
+ // in the future.
+ (void)Version;
+ switch (C) {
+ case OMPC_detach:
+ case OMPC_firstprivate:
+ case OMPC_has_device_addr:
+ case OMPC_induction:
+ case OMPC_in_reduction:
+ case OMPC_is_device_ptr:
+ case OMPC_lastprivate:
+ case OMPC_linear:
+ case OMPC_private:
+ case OMPC_reduction:
+ case OMPC_shared:
+ case OMPC_task_reduction:
+ case OMPC_use_device_addr:
+ case OMPC_use_device_ptr:
+ case OMPC_uses_allocators:
+ return true;
+ default:
+ return false;
+ }
+}
+
static constexpr unsigned FallbackVersion = 52;
LLVM_ABI ArrayRef<unsigned> getOpenMPVersions();
>From 2f964578b2aff825e3eb2e42843461e15be1e0e5 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Thu, 30 Apr 2026 06:13:06 -0500
Subject: [PATCH 2/2] Remove loopIV from DirectiveContext
---
flang/lib/Semantics/check-directive-structure.h | 4 ----
1 file changed, 4 deletions(-)
diff --git a/flang/lib/Semantics/check-directive-structure.h b/flang/lib/Semantics/check-directive-structure.h
index 46fbc5191b38a..8b4c3be76098e 100644
--- a/flang/lib/Semantics/check-directive-structure.h
+++ b/flang/lib/Semantics/check-directive-structure.h
@@ -231,11 +231,8 @@ class DirectiveStructureChecker : public virtual BaseChecker {
std::list<C> actualClauses;
std::list<C> endDirectiveClauses;
std::list<C> crtGroup;
- Symbol *loopIV{nullptr};
};
- void SetLoopIv(Symbol *symbol) { GetContext().loopIV = symbol; }
-
// back() is the top of the stack
DirectiveContext &GetContext() {
CHECK(!dirContext_.empty());
@@ -260,7 +257,6 @@ class DirectiveStructureChecker : public virtual BaseChecker {
GetContext().allowedExclusiveClauses = {};
GetContext().requiredClauses = {};
GetContext().clauseInfo = {};
- GetContext().loopIV = {nullptr};
}
void SetContextDirectiveSource(const parser::CharBlock &directive) {
More information about the flang-commits
mailing list