https://github.com/ykhatav updated https://github.com/llvm/llvm-project/pull/180608
>From 911e236f65cc14874bdc77d17ea5c0da9d326041 Mon Sep 17 00:00:00 2001 From: "Khatavkar, Yashasvi" <[email protected]> Date: Mon, 9 Feb 2026 12:39:08 -0800 Subject: [PATCH 1/2] Add parsing support for num_teams lower bound --- .../clang/Basic/DiagnosticSemaKinds.td | 4 ++ clang/lib/Parse/ParseOpenMP.cpp | 48 ++++++++++++++++ clang/lib/Sema/SemaOpenMP.cpp | 56 ++++++++++++++----- .../num_teams_lower_bound_error_test.cpp | 49 ++++++++++++++++ .../OpenMP/num_teams_lower_bound_support.cpp | 12 ++++ ...et_teams_distribute_num_teams_messages.cpp | 4 +- ...ribute_parallel_for_num_teams_messages.cpp | 4 +- .../test/OpenMP/teams_num_teams_messages.cpp | 4 +- 8 files changed, 161 insertions(+), 20 deletions(-) create mode 100644 clang/test/OpenMP/num_teams_lower_bound_error_test.cpp create mode 100644 clang/test/OpenMP/num_teams_lower_bound_support.cpp 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..0caef8dbf0c5f 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -13508,7 +13508,7 @@ 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 +14287,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 +14312,7 @@ 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 +14344,7 @@ 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 +14377,7 @@ 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 +14413,7 @@ 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 +23884,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@+1 {{only two expression allowed in 'num_teams' clause}} + #pragma omp teams num_teams(a, b, c) + { } + // expected-error@+1 {{lower bound is greater than upper bound in 'num_teams' clause}} + #pragma omp teams num_teams(10:5) + { } + + // expected-error@+1 {{only two expression allowed in 'num_teams' clause}} + #pragma omp target teams num_teams(a, b, c) + { } + // expected-error@+1 {{lower bound is greater than upper bound in 'num_teams' clause}} + #pragma omp target teams num_teams(8:3) + { } + + // expected-error@+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@+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@+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@+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@+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@+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@+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@+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 >From 81efa66b63185b9af9dd37a6282fe1608f2ee79d Mon Sep 17 00:00:00 2001 From: "Khatavkar, Yashasvi" <[email protected]> Date: Mon, 9 Feb 2026 12:46:31 -0800 Subject: [PATCH 2/2] Apply clang-format --- clang/lib/Sema/SemaOpenMP.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 0caef8dbf0c5f..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=*/2, diag::err_omp_num_teams_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(); @@ -14312,7 +14313,8 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetTeamsDistributeDirective( return StmtError(); if (!checkNumExprsInClause<OMPNumTeamsClause>( - *this, Clauses, /*MaxNum=*/2, diag::err_omp_num_teams_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(); @@ -14344,7 +14346,8 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetTeamsDistributeParallelForDirective( return StmtError(); if (!checkNumExprsInClause<OMPNumTeamsClause>( - *this, Clauses, /*MaxNum=*/2, diag::err_omp_num_teams_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(); @@ -14377,7 +14380,8 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetTeamsDistributeParallelForSimdDirective( return StmtError(); if (!checkNumExprsInClause<OMPNumTeamsClause>( - *this, Clauses, /*MaxNum=*/2, diag::err_omp_num_teams_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(); @@ -14413,7 +14417,8 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetTeamsDistributeSimdDirective( return StmtError(); if (!checkNumExprsInClause<OMPNumTeamsClause>( - *this, Clauses, /*MaxNum=*/2, diag::err_omp_num_teams_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(); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
