https://github.com/kevinsala created 
https://github.com/llvm/llvm-project/pull/205700

PR #180608 added parsing for the `lower-bound` modifier in the `num_teams` 
clause. However, the lower bound expression is handled by adding it to the 
first position of the clause's varlist, which is the list that holds the number 
of teams for each dimension when `ompx_bare` is specified. Given that the 
interpretation of the varlist depends on its length, the following `ompx_bare` 
cases are broken:
- `#pragma omp target teams ompx_bare num_teams(11,10)` is interpreted as a 
lower-bound and upper-bound, triggering the error "_lower bound is greater than 
upper bound in 'num_teams' clause_".
- `#pragma omp target teams ompx_bare num_teams(1,2)` is interpreted as 
`num_teams(1:2)` when printing the AST.

This PR fixes the collision by storing the lower bound separated from the list 
of upper-bounds. This change is necessary for landing the upcoming support for 
multidimensional team spaces (OpenMP 6.1) through the `dims` modifier.

>From a1302994022eb26b1ce02e6c2e894179abac219c Mon Sep 17 00:00:00 2001
From: Kevin Sala <[email protected]>
Date: Wed, 24 Jun 2026 09:23:55 -0700
Subject: [PATCH] [OpenMP][Clang] Fix parsing of num_teams lower-bound modifier

---
 clang/include/clang/AST/OpenMPClause.h        | 43 +++++++++-
 clang/include/clang/AST/RecursiveASTVisitor.h |  2 +
 .../clang/Basic/DiagnosticSemaKinds.td        |  2 -
 clang/include/clang/Basic/OpenMPKinds.def     |  7 ++
 clang/include/clang/Basic/OpenMPKinds.h       |  6 ++
 clang/include/clang/Sema/SemaOpenMP.h         | 14 ++--
 clang/lib/AST/OpenMPClause.cpp                | 30 +++----
 clang/lib/AST/StmtProfile.cpp                 |  3 +
 clang/lib/Basic/OpenMPKinds.cpp               | 21 ++++-
 clang/lib/Parse/ParseOpenMP.cpp               | 56 +++----------
 clang/lib/Sema/SemaOpenMP.cpp                 | 81 +++++++++++--------
 clang/lib/Sema/TreeTransform.h                | 23 ++++--
 clang/lib/Serialization/ASTReader.cpp         |  3 +
 clang/lib/Serialization/ASTWriter.cpp         |  3 +
 clang/test/OpenMP/target_teams_ast_print.cpp  | 10 ++-
 ...et_teams_distribute_num_teams_messages.cpp |  4 +-
 ...ribute_parallel_for_num_teams_messages.cpp |  4 +-
 .../test/OpenMP/teams_num_teams_messages.cpp  | 28 ++++---
 18 files changed, 209 insertions(+), 131 deletions(-)

diff --git a/clang/include/clang/AST/OpenMPClause.h 
b/clang/include/clang/AST/OpenMPClause.h
index 8ceafc4669297..bae396d883dc8 100644
--- a/clang/include/clang/AST/OpenMPClause.h
+++ b/clang/include/clang/AST/OpenMPClause.h
@@ -6975,6 +6975,13 @@ class OMPMapClause final : public 
OMPMappableExprListClause<OMPMapClause>,
 /// In this example directive '#pragma omp teams' has clause 'num_teams'
 /// with single expression 'n'.
 ///
+/// \code
+/// #pragma omp teams num_teams(m:n)
+/// \endcode
+/// In this example directive '#pragma omp teams' has clause 'num_teams' with
+/// single expression 'n' as upper-bound and modifier expression 'm' as
+/// lower-bound.
+///
 /// When 'ompx_bare' clause exists on a 'target' directive, 'num_teams' clause
 /// can accept up to three expressions.
 ///
@@ -6991,6 +6998,12 @@ class OMPNumTeamsClause final
   /// Location of '('.
   SourceLocation LParenLoc;
 
+  /// Modifier that was specified.
+  OpenMPNumTeamsClauseModifier Modifier = OMPC_NUMTEAMS_unknown;
+
+  /// Location of the modifier.
+  SourceLocation ModifierLoc;
+
   OMPNumTeamsClause(const ASTContext &C, SourceLocation StartLoc,
                     SourceLocation LParenLoc, SourceLocation EndLoc, unsigned 
N)
       : OMPVarListClause(llvm::omp::OMPC_num_teams, StartLoc, LParenLoc, 
EndLoc,
@@ -7011,11 +7024,16 @@ class OMPNumTeamsClause final
   /// \param LParenLoc Location of '('.
   /// \param EndLoc Ending location of the clause.
   /// \param VL List of references to the variables.
+  /// \param Modifier The modifier specified in the clause.
+  /// \param ModifierExpr The expression of the modifier.
+  /// \param ModifierLoc Location of the modifier.
   /// \param PreInit
   static OMPNumTeamsClause *
   Create(const ASTContext &C, OpenMPDirectiveKind CaptureRegion,
          SourceLocation StartLoc, SourceLocation LParenLoc,
-         SourceLocation EndLoc, ArrayRef<Expr *> VL, Stmt *PreInit);
+         SourceLocation EndLoc, ArrayRef<Expr *> VL,
+         OpenMPNumTeamsClauseModifier Modifier, Expr *ModifierExpr,
+         SourceLocation ModifierLoc, Stmt *PreInit);
 
   /// Creates an empty clause with \a N variables.
   ///
@@ -7037,9 +7055,30 @@ class OMPNumTeamsClause final
     return const_cast<OMPNumTeamsClause *>(this)->getNumTeams();
   }
 
+  /// Get the modifier.
+  OpenMPNumTeamsClauseModifier getModifier() const { return Modifier; }
+
+  /// Set the modifier.
+  void setModifier(OpenMPNumTeamsClauseModifier M) { Modifier = M; }
+
+  /// Get the expression of the modifier.
+  const Expr *getModifierExpr() const { return *varlist_end(); }
+
+  /// Get the expression of the modifier.
+  Expr *getModifierExpr() { return *varlist_end(); }
+
+  /// Set the expression of the modifier.
+  void setModifierExpr(Expr *E) { *varlist_end() = E; }
+
+  /// Get the location of the modifier.
+  SourceLocation getModifierLoc() const { return ModifierLoc; }
+
+  /// Set the location of the modifier.
+  void setModifierLoc(SourceLocation Loc) { ModifierLoc = Loc; }
+
   child_range children() {
     return child_range(reinterpret_cast<Stmt **>(varlist_begin()),
-                       reinterpret_cast<Stmt **>(varlist_end()));
+                       reinterpret_cast<Stmt **>(varlist_end()) + 1);
   }
 
   const_child_range children() const {
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h 
b/clang/include/clang/AST/RecursiveASTVisitor.h
index 529d657fc01f5..e930ebe85ac90 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -4077,6 +4077,8 @@ bool 
RecursiveASTVisitor<Derived>::VisitOMPMapClause(OMPMapClause *C) {
 template <typename Derived>
 bool RecursiveASTVisitor<Derived>::VisitOMPNumTeamsClause(
     OMPNumTeamsClause *C) {
+  if (auto *E = C->getModifierExpr())
+    TRY_TO(VisitStmt(E));
   TRY_TO(VisitOMPClauseList(C));
   TRY_TO(VisitOMPClauseWithPreInit(C));
   return true;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index f7fba8df1e4d7..e3f07750b7bc6 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12774,8 +12774,6 @@ 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 expressions 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
diff --git a/clang/include/clang/Basic/OpenMPKinds.def 
b/clang/include/clang/Basic/OpenMPKinds.def
index 3b79b940a1253..079ff4a583f9f 100644
--- a/clang/include/clang/Basic/OpenMPKinds.def
+++ b/clang/include/clang/Basic/OpenMPKinds.def
@@ -95,6 +95,9 @@
 #ifndef OPENMP_NUMTASKS_MODIFIER
 #define OPENMP_NUMTASKS_MODIFIER(Name)
 #endif
+#ifndef OPENMP_NUMTEAMS_MODIFIER
+#define OPENMP_NUMTEAMS_MODIFIER(Name)
+#endif
 #ifndef OPENMP_NUMTHREADS_MODIFIER
 #define OPENMP_NUMTHREADS_MODIFIER(Name)
 #endif
@@ -268,6 +271,9 @@ OPENMP_DYN_GROUPPRIVATE_FALLBACK_MODIFIER(default_mem)
 // Modifiers for the 'num_tasks' clause.
 OPENMP_NUMTASKS_MODIFIER(strict)
 
+// Modifiers for the 'num_teams' clause.
+OPENMP_NUMTEAMS_MODIFIER(lower_bound)
+
 // Modifiers for the 'num_tasks' clause.
 OPENMP_NUMTHREADS_MODIFIER(strict)
 
@@ -293,6 +299,7 @@ OPENMP_USE_DEVICE_PTR_FALLBACK_MODIFIER(fb_nullify)
 OPENMP_USE_DEVICE_PTR_FALLBACK_MODIFIER(fb_preserve)
 
 #undef OPENMP_NUMTASKS_MODIFIER
+#undef OPENMP_NUMTEAMS_MODIFIER
 #undef OPENMP_NUMTHREADS_MODIFIER
 #undef OPENMP_DYN_GROUPPRIVATE_MODIFIER
 #undef OPENMP_DYN_GROUPPRIVATE_FALLBACK_MODIFIER
diff --git a/clang/include/clang/Basic/OpenMPKinds.h 
b/clang/include/clang/Basic/OpenMPKinds.h
index 40f80802167fa..3ee6cb83a431e 100644
--- a/clang/include/clang/Basic/OpenMPKinds.h
+++ b/clang/include/clang/Basic/OpenMPKinds.h
@@ -262,6 +262,12 @@ enum OpenMPNumTasksClauseModifier {
   OMPC_NUMTASKS_unknown
 };
 
+enum OpenMPNumTeamsClauseModifier {
+#define OPENMP_NUMTEAMS_MODIFIER(Name) OMPC_NUMTEAMS_##Name,
+#include "clang/Basic/OpenMPKinds.def"
+  OMPC_NUMTEAMS_unknown
+};
+
 enum OpenMPNumThreadsClauseModifier {
 #define OPENMP_NUMTHREADS_MODIFIER(Name) OMPC_NUMTHREADS_##Name,
 #include "clang/Basic/OpenMPKinds.def"
diff --git a/clang/include/clang/Sema/SemaOpenMP.h 
b/clang/include/clang/Sema/SemaOpenMP.h
index 3621ce96b8724..f689e227866a7 100644
--- a/clang/include/clang/Sema/SemaOpenMP.h
+++ b/clang/include/clang/Sema/SemaOpenMP.h
@@ -1188,8 +1188,10 @@ class SemaOpenMP : public SemaBase {
     SourceLocation RLoc;
     CXXScopeSpec ReductionOrMapperIdScopeSpec;
     DeclarationNameInfo ReductionOrMapperId;
-    int ExtraModifier = -1; ///< Additional modifier for linear, map, depend,
-                            ///< lastprivate, or use_device_ptr clause.
+    int ExtraModifier =
+        -1; ///< Additional modifier for linear, map, depend,
+            ///< lastprivate, use_device_ptr, or num_teams clause.
+    Expr *ExtraModifierExpr = nullptr;
     int OriginalSharingModifier = 0; // Default is shared
     int NeedDevicePtrModifier = 0;
     SourceLocation NeedDevicePtrModifierLoc;
@@ -1341,10 +1343,10 @@ class SemaOpenMP : public SemaBase {
       const OMPVarListLocTy &Locs, bool NoDiagnose = false,
       ArrayRef<Expr *> UnresolvedMappers = {});
   /// Called on well-formed 'num_teams' clause.
-  OMPClause *ActOnOpenMPNumTeamsClause(ArrayRef<Expr *> VarList,
-                                       SourceLocation StartLoc,
-                                       SourceLocation LParenLoc,
-                                       SourceLocation EndLoc);
+  OMPClause *ActOnOpenMPNumTeamsClause(
+      ArrayRef<Expr *> VarList, OpenMPNumTeamsClauseModifier Modifier,
+      Expr *ModifierExpr, SourceLocation ModifierLoc, SourceLocation StartLoc,
+      SourceLocation LParenLoc, SourceLocation EndLoc);
   /// Called on well-formed 'thread_limit' clause.
   OMPClause *ActOnOpenMPThreadLimitClause(ArrayRef<Expr *> VarList,
                                           SourceLocation StartLoc,
diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp
index ed00e80144c25..f3e548e898b39 100644
--- a/clang/lib/AST/OpenMPClause.cpp
+++ b/clang/lib/AST/OpenMPClause.cpp
@@ -1954,18 +1954,24 @@ OMPContainsClause *OMPContainsClause::CreateEmpty(const 
ASTContext &C,
 OMPNumTeamsClause *OMPNumTeamsClause::Create(
     const ASTContext &C, OpenMPDirectiveKind CaptureRegion,
     SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc,
-    ArrayRef<Expr *> VL, Stmt *PreInit) {
-  void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(VL.size()));
+    ArrayRef<Expr *> VL, OpenMPNumTeamsClauseModifier Modifier,
+    Expr *ModifierExpr, SourceLocation ModifierLoc, Stmt *PreInit) {
+  // Reserve space for an extra modifier expression.
+  void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(VL.size() + 1));
   OMPNumTeamsClause *Clause =
       new (Mem) OMPNumTeamsClause(C, StartLoc, LParenLoc, EndLoc, VL.size());
   Clause->setVarRefs(VL);
+  Clause->setModifier(Modifier);
+  Clause->setModifierExpr(ModifierExpr);
+  Clause->setModifierLoc(ModifierLoc);
   Clause->setPreInitStmt(PreInit, CaptureRegion);
   return Clause;
 }
 
 OMPNumTeamsClause *OMPNumTeamsClause::CreateEmpty(const ASTContext &C,
                                                   unsigned N) {
-  void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(N));
+  // Reserve space for an extra modifier expression.
+  void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(N + 1));
   return new (Mem) OMPNumTeamsClause(N);
 }
 
@@ -2366,19 +2372,13 @@ void 
OMPClausePrinter::VisitOMPDeviceClause(OMPDeviceClause *Node) {
 
 void OMPClausePrinter::VisitOMPNumTeamsClause(OMPNumTeamsClause *Node) {
   if (!Node->varlist_empty()) {
-    OS << "num_teams(";
-    // Handle lower-bound:upper-bound syntax when there are exactly 2
-    // expressions
-    if (Node->varlist_size() == 2) {
-      llvm::interleave(
-          Node->varlist(), OS,
-          [&](const auto *Expr) { Expr->printPretty(OS, nullptr, Policy, 0); },
-          ":");
+    OS << "num_teams";
+    if (const Expr *LowerBound = Node->getModifierExpr()) {
+      OS << "(";
+      LowerBound->printPretty(OS, nullptr, Policy, 0);
+      VisitOMPClauseList(Node, ':');
     } else {
-      // For single expression or other cases, use comma-separated list
-      llvm::interleaveComma(Node->varlist(), OS, [&](const auto *Expr) {
-        Expr->printPretty(OS, nullptr, Policy, 0);
-      });
+      VisitOMPClauseList(Node, '(');
     }
     OS << ")";
   }
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 90eab530e0c2e..a7e7006c98a1b 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -912,6 +912,9 @@ void OMPClauseProfiler::VisitOMPAllocateClause(const 
OMPAllocateClause *C) {
   VisitOMPClauseList(C);
 }
 void OMPClauseProfiler::VisitOMPNumTeamsClause(const OMPNumTeamsClause *C) {
+  Profiler->VisitInteger(C->getModifier());
+  if (const Expr *Modifier = C->getModifierExpr())
+    Profiler->VisitStmt(Modifier);
   VisitOMPClauseList(C);
   VisitOMPClauseWithPreInit(C);
 }
diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp
index 675d86349c933..c590113578081 100644
--- a/clang/lib/Basic/OpenMPKinds.cpp
+++ b/clang/lib/Basic/OpenMPKinds.cpp
@@ -215,6 +215,15 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind 
Kind, StringRef Str,
       return OMPC_NUMTASKS_unknown;
     return Type;
   }
+  case OMPC_num_teams: {
+    unsigned Type = llvm::StringSwitch<unsigned>(Str)
+#define OPENMP_NUMTEAMS_MODIFIER(Name) .Case(#Name, OMPC_NUMTEAMS_##Name)
+#include "clang/Basic/OpenMPKinds.def"
+                        .Default(OMPC_NUMTEAMS_unknown);
+    if (LangOpts.OpenMP < 51)
+      return OMPC_NUMTEAMS_unknown;
+    return Type;
+  }
   case OMPC_allocate:
     return llvm::StringSwitch<OpenMPAllocateClauseModifier>(Str)
 #define OPENMP_ALLOCATE_MODIFIER(Name) .Case(#Name, OMPC_ALLOCATE_##Name)
@@ -285,7 +294,6 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind 
Kind, StringRef Str,
   case OMPC_relaxed:
   case OMPC_threads:
   case OMPC_simd:
-  case OMPC_num_teams:
   case OMPC_thread_limit:
   case OMPC_priority:
   case OMPC_nogroup:
@@ -588,6 +596,16 @@ const char 
*clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
 #include "clang/Basic/OpenMPKinds.def"
     }
     llvm_unreachable("Invalid OpenMP 'num_tasks' clause modifier");
+  case OMPC_num_teams:
+    switch (Type) {
+    case OMPC_NUMTEAMS_unknown:
+      return "unknown";
+#define OPENMP_NUMTEAMS_MODIFIER(Name)                                         
\
+  case OMPC_NUMTEAMS_##Name:                                                   
\
+    return #Name;
+#include "clang/Basic/OpenMPKinds.def"
+    }
+    llvm_unreachable("Invalid OpenMP 'num_teams' clause modifier");
   case OMPC_allocate:
     switch (Type) {
     case OMPC_ALLOCATE_unknown:
@@ -665,7 +683,6 @@ const char 
*clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
   case OMPC_relaxed:
   case OMPC_threads:
   case OMPC_simd:
-  case OMPC_num_teams:
   case OMPC_thread_limit:
   case OMPC_priority:
   case OMPC_nogroup:
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index af52295df2d8b..62715da7966d0 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -5289,62 +5289,30 @@ 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)) {
+  } else if (Kind == OMPC_num_teams) {
+    // Handle optional lower-bound modifier for num_teams clause.
+    Data.ExtraModifier = OMPC_NUMTEAMS_unknown;
+    TentativeParsingAction TPA(*this);
+    SourceLocation TLoc = Tok.getLocation();
     ExprResult FirstExpr = ParseAssignmentExpression();
     if (FirstExpr.isInvalid()) {
       SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch);
       Data.RLoc = Tok.getLocation();
       if (!T.consumeClose())
         Data.RLoc = T.getCloseLocation();
+      TPA.Commit();
       return true;
     }
 
     if (Tok.is(tok::colon)) {
-      // Lower-bound:upper-bound syntax
       ConsumeToken();
-      ExprResult UpperBound = ParseAssignmentExpression();
-      if (UpperBound.isInvalid()) {
-        SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch);
-        Data.RLoc = Tok.getLocation();
-        if (!T.consumeClose())
-          Data.RLoc = T.getCloseLocation();
-        return true;
-      }
-      Vars.push_back(FirstExpr.get());  // lower-bound
-      Vars.push_back(UpperBound.get()); // upper-bound
-      Data.RLoc = Tok.getLocation();
-      if (!T.consumeClose())
-        Data.RLoc = T.getCloseLocation();
-      return false; // Success
-    }
-    if (Tok.is(tok::comma)) {
-      Vars.push_back(FirstExpr.get());
-      while (Tok.is(tok::comma)) {
-        ConsumeToken();
-        ExprResult NextExpr = ParseAssignmentExpression();
-        if (NextExpr.isUsable()) {
-          Vars.push_back(NextExpr.get());
-        } else {
-          SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
-                    StopBeforeMatch);
-          break;
-        }
-      }
-      Data.RLoc = Tok.getLocation();
-      bool HadError = T.consumeClose();
-      if (!HadError)
-        Data.RLoc = T.getCloseLocation();
-      return HadError;
+      Data.ExtraModifier = OMPC_NUMTEAMS_lower_bound;
+      Data.ExtraModifierExpr = FirstExpr.get();
+      Data.ExtraModifierLoc = TLoc;
+      TPA.Commit();
+    } else {
+      TPA.Revert();
     }
-
-    // Single value - parse closing paren
-    Vars.push_back(FirstExpr.get());
-    Data.RLoc = Tok.getLocation();
-    if (!T.consumeClose())
-      Data.RLoc = T.getCloseLocation();
-    return false; // Success
   }
 
   bool IsComma =
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 247a4a6ad9271..f50ac924e927c 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -13648,8 +13648,7 @@ 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=*/1, diag::err_omp_multi_expr_not_allowed) 
||
       !checkNumExprsInClause<OMPThreadLimitClause>(
           *this, Clauses, /*MaxNum=*/1, diag::err_omp_multi_expr_not_allowed))
     return StmtError();
@@ -14428,18 +14427,15 @@ StmtResult 
SemaOpenMP::ActOnOpenMPTargetTeamsDirective(
     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;
+  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, NumTeamsDiag) ||
-      !checkNumExprsInClause<OMPThreadLimitClause>(
-          *this, Clauses, ClauseMaxNumExprs, ThreadLimitDiag)) {
+  if (!checkNumExprsInClause<OMPNumTeamsClause>(*this, Clauses,
+                                                ClauseMaxNumExprs, DiagNo) ||
+      !checkNumExprsInClause<OMPThreadLimitClause>(*this, Clauses,
+                                                   ClauseMaxNumExprs, DiagNo)) 
{
     return StmtError();
   }
   return OMPTargetTeamsDirective::Create(getASTContext(), StartLoc, EndLoc,
@@ -14453,8 +14449,7 @@ StmtResult 
SemaOpenMP::ActOnOpenMPTargetTeamsDistributeDirective(
     return StmtError();
 
   if (!checkNumExprsInClause<OMPNumTeamsClause>(
-          *this, Clauses, /*MaxNum=*/2,
-          diag::err_omp_num_teams_multi_expr_not_allowed) ||
+          *this, Clauses, /*MaxNum=*/1, diag::err_omp_multi_expr_not_allowed) 
||
       !checkNumExprsInClause<OMPThreadLimitClause>(
           *this, Clauses, /*MaxNum=*/1, diag::err_omp_multi_expr_not_allowed))
     return StmtError();
@@ -14486,8 +14481,7 @@ StmtResult 
SemaOpenMP::ActOnOpenMPTargetTeamsDistributeParallelForDirective(
     return StmtError();
 
   if (!checkNumExprsInClause<OMPNumTeamsClause>(
-          *this, Clauses, /*MaxNum=*/2,
-          diag::err_omp_num_teams_multi_expr_not_allowed) ||
+          *this, Clauses, /*MaxNum=*/1, diag::err_omp_multi_expr_not_allowed) 
||
       !checkNumExprsInClause<OMPThreadLimitClause>(
           *this, Clauses, /*MaxNum=*/1, diag::err_omp_multi_expr_not_allowed))
     return StmtError();
@@ -14520,8 +14514,7 @@ StmtResult 
SemaOpenMP::ActOnOpenMPTargetTeamsDistributeParallelForSimdDirective(
     return StmtError();
 
   if (!checkNumExprsInClause<OMPNumTeamsClause>(
-          *this, Clauses, /*MaxNum=*/2,
-          diag::err_omp_num_teams_multi_expr_not_allowed) ||
+          *this, Clauses, /*MaxNum=*/1, diag::err_omp_multi_expr_not_allowed) 
||
       !checkNumExprsInClause<OMPThreadLimitClause>(
           *this, Clauses, /*MaxNum=*/1, diag::err_omp_multi_expr_not_allowed))
     return StmtError();
@@ -14557,8 +14550,7 @@ StmtResult 
SemaOpenMP::ActOnOpenMPTargetTeamsDistributeSimdDirective(
     return StmtError();
 
   if (!checkNumExprsInClause<OMPNumTeamsClause>(
-          *this, Clauses, /*MaxNum=*/2,
-          diag::err_omp_num_teams_multi_expr_not_allowed) ||
+          *this, Clauses, /*MaxNum=*/1, diag::err_omp_multi_expr_not_allowed) 
||
       !checkNumExprsInClause<OMPThreadLimitClause>(
           *this, Clauses, /*MaxNum=*/1, diag::err_omp_multi_expr_not_allowed))
     return StmtError();
@@ -19190,6 +19182,7 @@ OMPClause 
*SemaOpenMP::ActOnOpenMPVarListClause(OpenMPClauseKind Kind,
   OMPClause *Res = nullptr;
   int ExtraModifier = Data.ExtraModifier;
   int OriginalSharingModifier = Data.OriginalSharingModifier;
+  Expr *ExtraModifierExpr = Data.ExtraModifierExpr;
   SourceLocation ExtraModifierLoc = Data.ExtraModifierLoc;
   SourceLocation ColonLoc = Data.ColonLoc;
   switch (Kind) {
@@ -19336,7 +19329,11 @@ OMPClause 
*SemaOpenMP::ActOnOpenMPVarListClause(OpenMPClauseKind Kind,
         ExtraModifierLoc, ColonLoc, VarList, StartLoc, LParenLoc, EndLoc);
     break;
   case OMPC_num_teams:
-    Res = ActOnOpenMPNumTeamsClause(VarList, StartLoc, LParenLoc, EndLoc);
+    assert(0 <= ExtraModifier && ExtraModifier <= OMPC_NUMTEAMS_unknown &&
+           "Unexpected num_teams modifier.");
+    Res = ActOnOpenMPNumTeamsClause(
+        VarList, static_cast<OpenMPNumTeamsClauseModifier>(ExtraModifier),
+        ExtraModifierExpr, ExtraModifierLoc, StartLoc, LParenLoc, EndLoc);
     break;
   case OMPC_thread_limit:
     Res = ActOnOpenMPThreadLimitClause(VarList, StartLoc, LParenLoc, EndLoc);
@@ -24404,32 +24401,39 @@ const ValueDecl 
*SemaOpenMP::getOpenMPDeclareMapperVarName() const {
   return cast<DeclRefExpr>(DSAStack->getDeclareMapperVarRef())->getDecl();
 }
 
-OMPClause *SemaOpenMP::ActOnOpenMPNumTeamsClause(ArrayRef<Expr *> VarList,
-                                                 SourceLocation StartLoc,
-                                                 SourceLocation LParenLoc,
-                                                 SourceLocation EndLoc) {
+OMPClause *SemaOpenMP::ActOnOpenMPNumTeamsClause(
+    ArrayRef<Expr *> VarList, OpenMPNumTeamsClauseModifier Modifier,
+    Expr *ModifierExpr, SourceLocation ModifierLoc, SourceLocation StartLoc,
+    SourceLocation LParenLoc, SourceLocation EndLoc) {
   if (VarList.empty())
     return nullptr;
 
   for (Expr *ValExpr : VarList) {
-    // OpenMP [teams Constrcut, Restrictions]
+    // OpenMP [teams Construct, Restrictions]
     // The num_teams expression must evaluate to a positive integer value.
     if (!isNonNegativeIntegerValue(ValExpr, SemaRef, OMPC_num_teams,
                                    /*StrictlyPositive=*/true))
       return nullptr;
   }
 
-  // OpenMP 5.2: Validate lower-bound ≤ upper-bound constraint
-  if (VarList.size() == 2) {
-    Expr *LowerBound = VarList[0];
-    Expr *UpperBound = VarList[1];
+  // OpenMP [teams Construct, Restrictions]
+  // The lower-bound expression in num_teams must evaluate to a positive 
integer
+  // value.
+  if (ModifierExpr) {
+    if (!isNonNegativeIntegerValue(ModifierExpr, SemaRef, OMPC_num_teams,
+                                   /*StrictlyPositive=*/true))
+      return nullptr;
+
+    // OpenMP 5.2: Validate lower-bound is less than or equal to upper-bound.
+    Expr *LowerBound = ModifierExpr;
+    Expr *UpperBound = VarList[0];
 
-    // Check if both are compile-time constants for validation
+    // Check if both are compile-time constants for validation.
     if (!LowerBound->isValueDependent() && !UpperBound->isValueDependent() &&
         LowerBound->isIntegerConstantExpr(getASTContext()) &&
         UpperBound->isIntegerConstantExpr(getASTContext())) {
 
-      // Get the actual constant values
+      // Get the actual constant values.
       llvm::APSInt LowerVal =
           LowerBound->EvaluateKnownConstInt(getASTContext());
       llvm::APSInt UpperVal =
@@ -24449,7 +24453,8 @@ OMPClause 
*SemaOpenMP::ActOnOpenMPNumTeamsClause(ArrayRef<Expr *> VarList,
       DKind, OMPC_num_teams, getLangOpts().OpenMP);
   if (CaptureRegion == OMPD_unknown || 
SemaRef.CurContext->isDependentContext())
     return OMPNumTeamsClause::Create(getASTContext(), CaptureRegion, StartLoc,
-                                     LParenLoc, EndLoc, VarList,
+                                     LParenLoc, EndLoc, VarList, Modifier,
+                                     ModifierExpr, ModifierLoc,
                                      /*PreInit=*/nullptr);
 
   llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
@@ -24460,9 +24465,15 @@ OMPClause 
*SemaOpenMP::ActOnOpenMPNumTeamsClause(ArrayRef<Expr *> VarList,
     Vars.push_back(ValExpr);
   }
 
+  if (ModifierExpr) {
+    ModifierExpr = SemaRef.MakeFullExpr(ModifierExpr).get();
+    ModifierExpr = tryBuildCapture(SemaRef, ModifierExpr, Captures).get();
+  }
+
   Stmt *PreInit = buildPreInits(getASTContext(), Captures);
   return OMPNumTeamsClause::Create(getASTContext(), CaptureRegion, StartLoc,
-                                   LParenLoc, EndLoc, Vars, PreInit);
+                                   LParenLoc, EndLoc, Vars, Modifier,
+                                   ModifierExpr, ModifierLoc, PreInit);
 }
 
 OMPClause *SemaOpenMP::ActOnOpenMPThreadLimitClause(ArrayRef<Expr *> VarList,
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 53107c827006d..e3e76847ebb88 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -2144,12 +2144,13 @@ class TreeTransform {
   ///
   /// By default, performs semantic analysis to build the new statement.
   /// Subclasses may override this routine to provide different behavior.
-  OMPClause *RebuildOMPNumTeamsClause(ArrayRef<Expr *> VarList,
-                                      SourceLocation StartLoc,
-                                      SourceLocation LParenLoc,
-                                      SourceLocation EndLoc) {
-    return getSema().OpenMP().ActOnOpenMPNumTeamsClause(VarList, StartLoc,
-                                                        LParenLoc, EndLoc);
+  OMPClause *RebuildOMPNumTeamsClause(
+      ArrayRef<Expr *> VarList, OpenMPNumTeamsClauseModifier Modifier,
+      Expr *ModifierExpr, SourceLocation ModifierLoc, SourceLocation StartLoc,
+      SourceLocation LParenLoc, SourceLocation EndLoc) {
+    return getSema().OpenMP().ActOnOpenMPNumTeamsClause(
+        VarList, Modifier, ModifierExpr, ModifierLoc, StartLoc, LParenLoc,
+        EndLoc);
   }
 
   /// Build a new OpenMP 'thread_limit' clause.
@@ -11603,8 +11604,16 @@ 
TreeTransform<Derived>::TransformOMPNumTeamsClause(OMPNumTeamsClause *C) {
       return nullptr;
     Vars.push_back(EVar.get());
   }
+  Expr *ModifierExpr = C->getModifierExpr();
+  if (ModifierExpr) {
+    ExprResult EVar = getDerived().TransformExpr(cast<Expr>(ModifierExpr));
+    if (EVar.isInvalid())
+      return nullptr;
+    ModifierExpr = EVar.get();
+  }
   return getDerived().RebuildOMPNumTeamsClause(
-      Vars, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
+      Vars, C->getModifier(), ModifierExpr, C->getModifierLoc(),
+      C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
 }
 
 template <typename Derived>
diff --git a/clang/lib/Serialization/ASTReader.cpp 
b/clang/lib/Serialization/ASTReader.cpp
index f8a6a38bb9b5c..b01b18fe3e0ec 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -12594,6 +12594,9 @@ void 
OMPClauseReader::VisitOMPAllocateClause(OMPAllocateClause *C) {
 }
 
 void OMPClauseReader::VisitOMPNumTeamsClause(OMPNumTeamsClause *C) {
+  C->setModifier(Record.readEnum<OpenMPNumTeamsClauseModifier>());
+  C->setModifierLoc(Record.readSourceLocation());
+  C->setModifierExpr(Record.readSubExpr());
   VisitOMPClauseWithPreInit(C);
   C->setLParenLoc(Record.readSourceLocation());
   unsigned NumVars = C->varlist_size();
diff --git a/clang/lib/Serialization/ASTWriter.cpp 
b/clang/lib/Serialization/ASTWriter.cpp
index 21dda6f3733e4..360b63bbbee7b 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -8588,6 +8588,9 @@ void 
OMPClauseWriter::VisitOMPAllocateClause(OMPAllocateClause *C) {
 
 void OMPClauseWriter::VisitOMPNumTeamsClause(OMPNumTeamsClause *C) {
   Record.push_back(C->varlist_size());
+  Record.writeEnum(C->getModifier());
+  Record.AddSourceLocation(C->getModifierLoc());
+  Record.AddStmt(C->getModifierExpr());
   VisitOMPClauseWithPreInit(C);
   Record.AddSourceLocation(C->getLParenLoc());
   for (auto *VE : C->varlist())
diff --git a/clang/test/OpenMP/target_teams_ast_print.cpp 
b/clang/test/OpenMP/target_teams_ast_print.cpp
index 5a577bd2d1b1e..eda4db8c7b8b1 100644
--- a/clang/test/OpenMP/target_teams_ast_print.cpp
+++ b/clang/test/OpenMP/target_teams_ast_print.cpp
@@ -95,7 +95,7 @@ T tmain(T argc, T *argv) {
 // CHECK-NEXT: foo()
 // CHECK-NEXT: #pragma omp target teams allocate(my_allocator: f) reduction(^: 
e,f) reduction(&&: g) uses_allocators(my_allocator(traits))
 // CHECK-NEXT: foo()
-// CHECK-NEXT: #pragma omp target teams ompx_bare num_teams(1, 1, 1) 
thread_limit(d * 1,d * 1,d * 1)
+// CHECK-NEXT: #pragma omp target teams ompx_bare num_teams(1,1,1) 
thread_limit(d * 1,d * 1,d * 1)
 // CHECK-NEXT: foo();
 
 enum Enum { };
@@ -115,10 +115,14 @@ int main (int argc, char **argv) {
 // CHECK-NEXT: #pragma omp target teams ompx_bare num_teams(1) thread_limit(32)
   a=3;
 // CHECK-NEXT: a = 3;
-#pragma omp target teams ompx_bare num_teams(1, 2, 3) thread_limit(2, 4, 6)
-// CHECK-NEXT: #pragma omp target teams ompx_bare num_teams(1, 2, 3) 
thread_limit(2,4,6)
+#pragma omp target teams ompx_bare num_teams(2, 1) thread_limit(4, 2)
+// CHECK-NEXT: #pragma omp target teams ompx_bare num_teams(2,1) 
thread_limit(4,2)
   a=4;
 // CHECK-NEXT: a = 4;
+#pragma omp target teams ompx_bare num_teams(1, 2, 3) thread_limit(2, 4, 6)
+// CHECK-NEXT: #pragma omp target teams ompx_bare num_teams(1,2,3) 
thread_limit(2,4,6)
+  a=5;
+// CHECK-NEXT: a = 5;
 #pragma omp target teams default(none), private(argc,b) num_teams(f) 
firstprivate(argv) reduction(| : c, d) reduction(* : e) thread_limit(f+g)
 // CHECK-NEXT: #pragma omp target teams default(none) private(argc,b) 
num_teams(f) firstprivate(argv) reduction(|: c,d) reduction(*: e) 
thread_limit(f + g)
   foo();
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 51948adba354f..8bf388f0b5da9 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 two expressions allowed in 'num_teams' clause}}
+#pragma omp target teams distribute num_teams(1, 2, 3) // expected-error 
{{only one 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 two expressions allowed in 'num_teams' clause}}
+#pragma omp target teams distribute num_teams(1, 2, 3) // expected-error 
{{only one 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 02393f5094e09..092e0137d250d 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 two expressions allowed in 'num_teams' clause}}
+#pragma omp target teams distribute parallel for num_teams(1, 2, 3) // 
expected-error {{only one 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 two expressions allowed in 'num_teams' clause}}
+#pragma omp target teams distribute parallel for num_teams(1, 2, 3) // 
expected-error {{only one 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 166e77142e27c..61f5d17b1cfb7 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 two expressions 
allowed in 'num_teams' clause}}
+#pragma omp teams num_teams (1, 2, 3) // expected-error {{only one 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 two expressions 
allowed in 'num_teams' clause}}
+#pragma omp teams num_teams (1, 2, 3) // expected-error {{only one expression 
allowed in 'num_teams' clause}}
   foo();
 
 #pragma omp target
@@ -132,28 +132,28 @@ int main(int argc, char **argv) {
 void test_invalid_syntax() {
   int a = 1, b = 2, c = 3;
 
-  // expected-error@+1 {{only two expressions allowed in 'num_teams' clause}}
+  // expected-error@+1 {{only one 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 expressions allowed in 'num_teams' clause}}
+  // expected-error@+1 {{only one 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 expressions allowed in 'num_teams' clause}}
+  // expected-error@+1 {{only one 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 expressions allowed in 'num_teams' clause}}
+  // expected-error@+1 {{only one 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}}
@@ -161,14 +161,14 @@ void test_invalid_syntax() {
   for (int i = 0; i < 100; ++i) { }
 
   // Test target teams distribute parallel for simd directive
-  // expected-error@+1 {{only two expressions allowed in 'num_teams' clause}}
+  // expected-error@+1 {{only one 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 expressions allowed in 'num_teams' clause}}
+  // expected-error@+1 {{only one 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}}
@@ -181,8 +181,10 @@ void test_non_matching_delimiters() {
   int arr[10];
   int x = 5;
 
+  // expected-error@+6 {{expected ')'}}
+  // expected-error@+5 {{expected ')'}}
   // expected-error@+4 {{expected ')'}}
-  // expected-error@+3 {{expected ')'}}
+  // expected-note@+3 {{to match this '('}}
   // expected-note@+2 {{to match this '('}}
   // expected-note@+1 {{to match this '('}}
   #pragma omp teams num_teams((x + 1:10)
@@ -204,16 +206,20 @@ void test_multi_level_non_matching_delimiters() {
   int arr[10][10];
   int x = 5, y = 10;
 
+  // expected-error@+6 {{expected ')'}}
+  // expected-error@+5 {{expected ')'}}
   // expected-error@+4 {{expected ')'}}
   // expected-note@+3 {{to match this '('}}
-  // expected-error@+2 {{expected ')'}}
+  // expected-note@+2 {{to match this '('}}
   // expected-note@+1 {{to match this '('}}
   #pragma omp teams num_teams(((x + 1) * 2:10)
   { }
 
+  // expected-error@+6 {{expected ')'}}
+  // expected-error@+5 {{expected ')'}}
   // expected-error@+4 {{expected ')'}}
   // expected-note@+3 {{to match this '('}}
-  // expected-error@+2 {{expected ')'}}
+  // expected-note@+2 {{to match this '('}}
   // expected-note@+1 {{to match this '('}}
   #pragma omp teams num_teams((x + (y - 1):10)
   { }

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to