[clang] [OpenMP][Clang] Parsing support for num_teams lower bound (PR #180608)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Feb 9 13:47:37 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: ykhatav (ykhatav)
<details>
<summary>Changes</summary>
According to OpenMP 5.2 the num_teams clause should support a lower-bound as modifier for its argument. This PR adds Parsing support for the lower bound in num_teams clause.
---
Full diff: https://github.com/llvm/llvm-project/pull/180608.diff
8 Files Affected:
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+4)
- (modified) clang/lib/Parse/ParseOpenMP.cpp (+48)
- (modified) clang/lib/Sema/SemaOpenMP.cpp (+47-14)
- (added) clang/test/OpenMP/num_teams_lower_bound_error_test.cpp (+49)
- (added) clang/test/OpenMP/num_teams_lower_bound_support.cpp (+12)
- (modified) clang/test/OpenMP/target_teams_distribute_num_teams_messages.cpp (+2-2)
- (modified) clang/test/OpenMP/target_teams_distribute_parallel_for_num_teams_messages.cpp (+2-2)
- (modified) clang/test/OpenMP/teams_num_teams_messages.cpp (+2-2)
``````````diff
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index f12677ac11600..59ff6e563d779 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12543,6 +12543,10 @@ def err_omp_transparent_invalid_value : Error<"invalid value for transparent cla
" expected one of: omp_not_impex, omp_import, omp_export, omp_impex">;
def err_omp_transparent_invalid_type : Error<
"transparent clause cannot be applied to type: %0">;
+def err_omp_num_teams_multi_expr_not_allowed
+ : Error<"only two expression allowed in 'num_teams' clause">;
+def err_omp_num_teams_lower_bound_larger
+ : Error<"lower bound is greater than upper bound in 'num_teams' clause">;
} // end of OpenMP category
let CategoryName = "Related Result Type Issue" in {
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index b41803d23cb25..5bdaeb182bb9e 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -5080,6 +5080,54 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
Diag(Tok, diag::err_modifier_expected_colon) << "fallback";
}
}
+ } // Handle num_teams clause with optional lower-bound:upper-bound syntax
+ if (Kind == OMPC_num_teams && !Tok.is(tok::r_paren) &&
+ !Tok.is(tok::annot_pragma_openmp_end)) {
+ // Look ahead to detect top-level colon
+ TentativeParsingAction TPA(*this);
+ bool HasColon = false;
+ int Depth = 0;
+
+ while (!Tok.is(tok::r_paren) && !Tok.is(tok::annot_pragma_openmp_end)) {
+ if (Tok.isOneOf(tok::l_paren, tok::l_square))
+ Depth++;
+ else if (Tok.isOneOf(tok::r_paren, tok::r_square)) {
+ if (Depth == 0)
+ break;
+ Depth--;
+ } else if (Tok.is(tok::comma) && Depth == 0)
+ break; // comma-separated syntax
+ else if (Tok.is(tok::colon) && Depth == 0) {
+ HasColon = true;
+ break;
+ }
+ ConsumeAnyToken();
+ }
+ TPA.Revert();
+
+ // Only handle colon syntax, let normal parsing handle everything else
+ if (HasColon) {
+ ExprResult LowerBound = ParseAssignmentExpression();
+ if (!LowerBound.isInvalid()) {
+ Vars.push_back(LowerBound.get());
+ if (Tok.is(tok::colon)) {
+ ConsumeToken();
+ ExprResult UpperBound = ParseAssignmentExpression();
+ if (!UpperBound.isInvalid())
+ Vars.push_back(UpperBound.get());
+ else
+ SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end,
+ StopBeforeMatch);
+ }
+ } else {
+ SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch);
+ }
+
+ Data.RLoc = Tok.getLocation();
+ if (!T.consumeClose())
+ Data.RLoc = T.getCloseLocation();
+ return false;
+ }
}
bool IsComma =
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index e90884a89bf6e..f2dc68481b451 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -13508,7 +13508,8 @@ StmtResult SemaOpenMP::ActOnOpenMPTeamsDirective(ArrayRef<OMPClause *> Clauses,
return StmtError();
if (!checkNumExprsInClause<OMPNumTeamsClause>(
- *this, Clauses, /*MaxNum=*/1, diag::err_omp_multi_expr_not_allowed) ||
+ *this, Clauses, /*MaxNum=*/2,
+ diag::err_omp_num_teams_multi_expr_not_allowed) ||
!checkNumExprsInClause<OMPThreadLimitClause>(
*this, Clauses, /*MaxNum=*/1, diag::err_omp_multi_expr_not_allowed))
return StmtError();
@@ -14287,16 +14288,20 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetTeamsDirective(
return StmtError();
}
- unsigned ClauseMaxNumExprs = HasBareClause ? 3 : 1;
- unsigned DiagNo = HasBareClause
- ? diag::err_ompx_more_than_three_expr_not_allowed
- : diag::err_omp_multi_expr_not_allowed;
- if (!checkNumExprsInClause<OMPNumTeamsClause>(*this, Clauses,
- ClauseMaxNumExprs, DiagNo) ||
- !checkNumExprsInClause<OMPThreadLimitClause>(*this, Clauses,
- ClauseMaxNumExprs, DiagNo))
- return StmtError();
+ unsigned ClauseMaxNumExprs = HasBareClause ? 3 : 2;
+ unsigned NumTeamsDiag = HasBareClause
+ ? diag::err_ompx_more_than_three_expr_not_allowed
+ : diag::err_omp_num_teams_multi_expr_not_allowed;
+ unsigned ThreadLimitDiag =
+ HasBareClause ? diag::err_ompx_more_than_three_expr_not_allowed
+ : diag::err_omp_multi_expr_not_allowed;
+ if (!checkNumExprsInClause<OMPNumTeamsClause>(
+ *this, Clauses, ClauseMaxNumExprs, NumTeamsDiag) ||
+ !checkNumExprsInClause<OMPThreadLimitClause>(
+ *this, Clauses, ClauseMaxNumExprs, ThreadLimitDiag)) {
+ return StmtError();
+ }
return OMPTargetTeamsDirective::Create(getASTContext(), StartLoc, EndLoc,
Clauses, AStmt);
}
@@ -14308,7 +14313,8 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetTeamsDistributeDirective(
return StmtError();
if (!checkNumExprsInClause<OMPNumTeamsClause>(
- *this, Clauses, /*MaxNum=*/1, diag::err_omp_multi_expr_not_allowed) ||
+ *this, Clauses, /*MaxNum=*/2,
+ diag::err_omp_num_teams_multi_expr_not_allowed) ||
!checkNumExprsInClause<OMPThreadLimitClause>(
*this, Clauses, /*MaxNum=*/1, diag::err_omp_multi_expr_not_allowed))
return StmtError();
@@ -14340,7 +14346,8 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetTeamsDistributeParallelForDirective(
return StmtError();
if (!checkNumExprsInClause<OMPNumTeamsClause>(
- *this, Clauses, /*MaxNum=*/1, diag::err_omp_multi_expr_not_allowed) ||
+ *this, Clauses, /*MaxNum=*/2,
+ diag::err_omp_num_teams_multi_expr_not_allowed) ||
!checkNumExprsInClause<OMPThreadLimitClause>(
*this, Clauses, /*MaxNum=*/1, diag::err_omp_multi_expr_not_allowed))
return StmtError();
@@ -14373,7 +14380,8 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetTeamsDistributeParallelForSimdDirective(
return StmtError();
if (!checkNumExprsInClause<OMPNumTeamsClause>(
- *this, Clauses, /*MaxNum=*/1, diag::err_omp_multi_expr_not_allowed) ||
+ *this, Clauses, /*MaxNum=*/2,
+ diag::err_omp_num_teams_multi_expr_not_allowed) ||
!checkNumExprsInClause<OMPThreadLimitClause>(
*this, Clauses, /*MaxNum=*/1, diag::err_omp_multi_expr_not_allowed))
return StmtError();
@@ -14409,7 +14417,8 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetTeamsDistributeSimdDirective(
return StmtError();
if (!checkNumExprsInClause<OMPNumTeamsClause>(
- *this, Clauses, /*MaxNum=*/1, diag::err_omp_multi_expr_not_allowed) ||
+ *this, Clauses, /*MaxNum=*/2,
+ diag::err_omp_num_teams_multi_expr_not_allowed) ||
!checkNumExprsInClause<OMPThreadLimitClause>(
*this, Clauses, /*MaxNum=*/1, diag::err_omp_multi_expr_not_allowed))
return StmtError();
@@ -23880,6 +23889,30 @@ OMPClause *SemaOpenMP::ActOnOpenMPNumTeamsClause(ArrayRef<Expr *> VarList,
return nullptr;
}
+ // OpenMP 5.2: Validate lower-bound ≤ upper-bound constraint
+ if (VarList.size() == 2) {
+ Expr *LowerBound = VarList[0];
+ Expr *UpperBound = VarList[1];
+
+ // Check if both are compile-time constants for validation
+ if (LowerBound->isIntegerConstantExpr(getASTContext()) &&
+ UpperBound->isIntegerConstantExpr(getASTContext())) {
+
+ // Get the actual constant values
+ llvm::APSInt LowerVal =
+ LowerBound->EvaluateKnownConstInt(getASTContext());
+ llvm::APSInt UpperVal =
+ UpperBound->EvaluateKnownConstInt(getASTContext());
+
+ if (LowerVal > UpperVal) {
+ Diag(LowerBound->getExprLoc(),
+ diag::err_omp_num_teams_lower_bound_larger)
+ << LowerBound->getSourceRange() << UpperBound->getSourceRange();
+ return nullptr;
+ }
+ }
+ }
+
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
OpenMPDirectiveKind CaptureRegion = getOpenMPCaptureRegionForClause(
DKind, OMPC_num_teams, getLangOpts().OpenMP);
diff --git a/clang/test/OpenMP/num_teams_lower_bound_error_test.cpp b/clang/test/OpenMP/num_teams_lower_bound_error_test.cpp
new file mode 100644
index 0000000000000..9c6817999f17c
--- /dev/null
+++ b/clang/test/OpenMP/num_teams_lower_bound_error_test.cpp
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 -verify -fopenmp -std=c++11 %s -Wuninitialized
+
+// Test invalid syntax cases for num_teams lower-bound:upper-bound
+void test_invalid_syntax() {
+ int a = 1, b = 2, c = 3;
+
+ // expected-error at +1 {{only two expression allowed in 'num_teams' clause}}
+ #pragma omp teams num_teams(a, b, c)
+ { }
+ // expected-error at +1 {{lower bound is greater than upper bound in 'num_teams' clause}}
+ #pragma omp teams num_teams(10:5)
+ { }
+
+ // expected-error at +1 {{only two expression allowed in 'num_teams' clause}}
+ #pragma omp target teams num_teams(a, b, c)
+ { }
+ // expected-error at +1 {{lower bound is greater than upper bound in 'num_teams' clause}}
+ #pragma omp target teams num_teams(8:3)
+ { }
+
+ // expected-error at +1 {{only two expression allowed in 'num_teams' clause}}
+ #pragma omp target teams distribute num_teams(a, b, c)
+ for (int i = 0; i < 100; ++i) { }
+ // expected-error at +1 {{lower bound is greater than upper bound in 'num_teams' clause}}
+ #pragma omp target teams distribute num_teams(15:7)
+ for (int i = 0; i < 100; ++i) { }
+
+ // expected-error at +1 {{only two expression allowed in 'num_teams' clause}}
+ #pragma omp target teams distribute parallel for num_teams(a, b, c)
+ for (int i = 0; i < 100; ++i) { }
+ // expected-error at +1 {{lower bound is greater than upper bound in 'num_teams' clause}}
+ #pragma omp target teams distribute parallel for num_teams(12:4)
+ for (int i = 0; i < 100; ++i) { }
+
+ // Test target teams distribute parallel for simd directive
+ // expected-error at +1 {{only two expression allowed in 'num_teams' clause}}
+ #pragma omp target teams distribute parallel for simd num_teams(a, b, c)
+ for (int i = 0; i < 100; ++i) { }
+ // expected-error at +1 {{lower bound is greater than upper bound in 'num_teams' clause}}
+ #pragma omp target teams distribute parallel for simd num_teams(20:6)
+ for (int i = 0; i < 100; ++i) { }
+
+ // expected-error at +1 {{only two expression allowed in 'num_teams' clause}}
+ #pragma omp target teams distribute simd num_teams(a, b, c)
+ for (int i = 0; i < 100; ++i) { }
+ // expected-error at +1 {{lower bound is greater than upper bound in 'num_teams' clause}}
+ #pragma omp target teams distribute simd num_teams(9:2)
+ for (int i = 0; i < 100; ++i) { }
+}
diff --git a/clang/test/OpenMP/num_teams_lower_bound_support.cpp b/clang/test/OpenMP/num_teams_lower_bound_support.cpp
new file mode 100644
index 0000000000000..13aa1dacd9a8e
--- /dev/null
+++ b/clang/test/OpenMP/num_teams_lower_bound_support.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple x86_64-unknown-linux-gnu -emit-llvm %s -o -
+// expected-no-diagnostics
+//
+
+int main() {
+ #pragma omp teams num_teams(1:1)
+ {
+ // Teams region
+ }
+
+ return 0;
+}
diff --git a/clang/test/OpenMP/target_teams_distribute_num_teams_messages.cpp b/clang/test/OpenMP/target_teams_distribute_num_teams_messages.cpp
index 8bf388f0b5da9..478c2d5202419 100644
--- a/clang/test/OpenMP/target_teams_distribute_num_teams_messages.cpp
+++ b/clang/test/OpenMP/target_teams_distribute_num_teams_messages.cpp
@@ -44,7 +44,7 @@ T tmain(T argc) {
#pragma omp target teams distribute num_teams(3.14) // expected-error 2 {{expression must have integral or unscoped enumeration type, not 'double'}}
for (int i=0; i<100; i++) foo();
-#pragma omp target teams distribute num_teams(1, 2, 3) // expected-error {{only one expression allowed in 'num_teams' clause}}
+#pragma omp target teams distribute num_teams(1, 2, 3) // expected-error {{only two expression allowed in 'num_teams' clause}}
for (int i=0; i<100; i++) foo();
#pragma omp target teams distribute thread_limit(1, 2, 3) // expected-error {{only one expression allowed in 'thread_limit' clause}}
@@ -97,7 +97,7 @@ int main(int argc, char **argv) {
#pragma omp target teams distribute num_teams (3.14) // expected-error {{expression must have integral or unscoped enumeration type, not 'double'}}
for (int i=0; i<100; i++) foo();
-#pragma omp target teams distribute num_teams(1, 2, 3) // expected-error {{only one expression allowed in 'num_teams' clause}}
+#pragma omp target teams distribute num_teams(1, 2, 3) // expected-error {{only two expression allowed in 'num_teams' clause}}
for (int i=0; i<100; i++) foo();
#pragma omp target teams distribute thread_limit(1, 2, 3) // expected-error {{only one expression allowed in 'thread_limit' clause}}
diff --git a/clang/test/OpenMP/target_teams_distribute_parallel_for_num_teams_messages.cpp b/clang/test/OpenMP/target_teams_distribute_parallel_for_num_teams_messages.cpp
index 092e0137d250d..c9b3d3f562ed7 100644
--- a/clang/test/OpenMP/target_teams_distribute_parallel_for_num_teams_messages.cpp
+++ b/clang/test/OpenMP/target_teams_distribute_parallel_for_num_teams_messages.cpp
@@ -43,7 +43,7 @@ T tmain(T argc) {
for (int i=0; i<100; i++) foo();
#pragma omp target teams distribute parallel for num_teams(3.14) // expected-error 2 {{expression must have integral or unscoped enumeration type, not 'double'}}
for (int i=0; i<100; i++) foo();
-#pragma omp target teams distribute parallel for num_teams(1, 2, 3) // expected-error {{only one expression allowed in 'num_teams' clause}}
+#pragma omp target teams distribute parallel for num_teams(1, 2, 3) // expected-error {{only two expression allowed in 'num_teams' clause}}
for (int i=0; i<100; i++) foo();
#pragma omp target teams distribute parallel for thread_limit(1, 2, 3) // expected-error {{only one expression allowed in 'thread_limit' clause}}
for (int i=0; i<100; i++) foo();
@@ -89,7 +89,7 @@ int main(int argc, char **argv) {
#pragma omp target teams distribute parallel for num_teams (3.14) // expected-error {{expression must have integral or unscoped enumeration type, not 'double'}}
for (int i=0; i<100; i++) foo();
-#pragma omp target teams distribute parallel for num_teams(1, 2, 3) // expected-error {{only one expression allowed in 'num_teams' clause}}
+#pragma omp target teams distribute parallel for num_teams(1, 2, 3) // expected-error {{only two expression allowed in 'num_teams' clause}}
for (int i=0; i<100; i++) foo();
#pragma omp target teams distribute parallel for thread_limit(1, 2, 3) // expected-error {{only one expression allowed in 'thread_limit' clause}}
diff --git a/clang/test/OpenMP/teams_num_teams_messages.cpp b/clang/test/OpenMP/teams_num_teams_messages.cpp
index 615bf0be0d814..458e4e9d640b3 100644
--- a/clang/test/OpenMP/teams_num_teams_messages.cpp
+++ b/clang/test/OpenMP/teams_num_teams_messages.cpp
@@ -58,7 +58,7 @@ T tmain(T argc) {
#pragma omp teams num_teams(3.14) // expected-error 2 {{expression must have integral or unscoped enumeration type, not 'double'}}
foo();
#pragma omp target
-#pragma omp teams num_teams (1, 2, 3) // expected-error {{only one expression allowed in 'num_teams' clause}}
+#pragma omp teams num_teams (1, 2, 3) // expected-error {{only two expression allowed in 'num_teams' clause}}
foo();
#pragma omp target
#pragma omp teams thread_limit(1, 2, 3) // expected-error {{only one expression allowed in 'thread_limit' clause}}
@@ -118,7 +118,7 @@ int main(int argc, char **argv) {
foo();
#pragma omp target
-#pragma omp teams num_teams (1, 2, 3) // expected-error {{only one expression allowed in 'num_teams' clause}}
+#pragma omp teams num_teams (1, 2, 3) // expected-error {{only two expression allowed in 'num_teams' clause}}
foo();
#pragma omp target
``````````
</details>
https://github.com/llvm/llvm-project/pull/180608
More information about the cfe-commits
mailing list