https://github.com/zahiraam updated 
https://github.com/llvm/llvm-project/pull/192455

>From 95d0b4b3826a65b11b7f05d48a39b23bd5b5b0a5 Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <[email protected]>
Date: Mon, 17 Aug 2026 14:21:21 -0700
Subject: [PATCH 1/3] Implement phase 1 of plan

---
 clang/include/clang/AST/OpenMPClause.h        |  13 ++
 clang/include/clang/Sema/SemaOpenMP.h         |   8 ++
 clang/lib/AST/OpenMPClause.cpp                |   4 +-
 clang/lib/Parse/ParseOpenMP.cpp               |  91 +++++++++++-
 clang/lib/Sema/SemaOpenMP.cpp                 |   9 ++
 .../metadirective_user_condition_parse.cpp    | 134 ++++++++++++++++++
 .../include/llvm/Frontend/OpenMP/OMPContext.h |   4 +
 7 files changed, 260 insertions(+), 3 deletions(-)
 create mode 100644 clang/test/OpenMP/metadirective_user_condition_parse.cpp

diff --git a/clang/include/clang/AST/OpenMPClause.h 
b/clang/include/clang/AST/OpenMPClause.h
index 9e9295e1a0c54..c1e69b6ef3468 100644
--- a/clang/include/clang/AST/OpenMPClause.h
+++ b/clang/include/clang/AST/OpenMPClause.h
@@ -10019,6 +10019,19 @@ class OMPTraitInfo {
     return false;
   }
 
+  /// Check if this trait info contains any user conditions.
+  bool hasUserCondition() const {
+    for (const OMPTraitSet &Set : Sets) {
+      if (Set.Kind != llvm::omp::TraitSet::user)
+        continue;
+      for (const OMPTraitSelector &Selector : Set.Selectors) {
+        if (Selector.Kind == llvm::omp::TraitSelector::user_condition)
+          return true;
+      }
+    }
+    return false;
+  }
+
   /// Print a human readable representation into \p OS.
   void print(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const;
 };
diff --git a/clang/include/clang/Sema/SemaOpenMP.h 
b/clang/include/clang/Sema/SemaOpenMP.h
index 361473140e236..e6cd31b9c456f 100644
--- a/clang/include/clang/Sema/SemaOpenMP.h
+++ b/clang/include/clang/Sema/SemaOpenMP.h
@@ -217,6 +217,14 @@ class SemaOpenMP : public SemaBase {
                                       Stmt *AStmt, SourceLocation StartLoc,
                                       SourceLocation EndLoc);
 
+  /// Called for metadirectives with user conditions that may require runtime
+  /// selection.
+  StmtResult ActOnOpenMPMetaDirective(
+      SourceLocation StartLoc, SourceLocation EndLoc,
+      ArrayRef<OMPTraitInfo *> TraitInfos,
+      ArrayRef<OpenMPClauseKind> ClauseKinds,
+      ArrayRef<OpenMPDirectiveKind> DirectiveKinds, Stmt *AssociatedStmt);
+
   // OpenMP directives and clauses.
   /// Called on correct id-expression from the '#pragma omp
   /// threadprivate'.
diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp
index cac701994def8..ce1d624249de8 100644
--- a/clang/lib/AST/OpenMPClause.cpp
+++ b/clang/lib/AST/OpenMPClause.cpp
@@ -3086,8 +3086,10 @@ void OMPTraitInfo::getAsVariantMatchInfo(ASTContext 
&ASTCtx,
           VMI.addTrait(CondVal->isZero() ? TraitProperty::user_condition_false
                                          : TraitProperty::user_condition_true,
                        "<condition>");
-        else
+        else {
           VMI.addTrait(TraitProperty::user_condition_false, "<condition>");
+          VMI.HasNonConstantUserCondition = true;
+        }
         continue;
       }
 
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index 30b6c64e69f4c..96a877a444351 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -108,6 +108,22 @@ static OpenMPDirectiveKind parseOpenMPDirectiveKind(Parser 
&P) {
   return checkOpenMPDirectiveName(P, Loc, S->Value, Concat);
 }
 
+/// Skip tokens until reaching the matching closing parenthesis.
+/// Handles nested parentheses correctly.
+static void skipToMatchingParen(Parser &P) {
+  int ParenDepth = 0;
+  while ((P.getCurToken().isNot(tok::r_paren) || ParenDepth != 0) &&
+         P.getCurToken().isNot(tok::annot_pragma_openmp_end) &&
+         P.getCurToken().isNot(tok::eof)) {
+    if (P.getCurToken().is(tok::l_paren))
+      ParenDepth++;
+    if (P.getCurToken().is(tok::r_paren) && ParenDepth > 0)
+      ParenDepth--;
+    if (ParenDepth > 0 || P.getCurToken().isNot(tok::r_paren))
+      P.ConsumeAnyToken();
+  }
+}
+
 static DeclarationName parseOpenMPReductionId(Parser &P) {
   Token Tok = P.getCurToken();
   Sema &Actions = P.getActions();
@@ -2602,10 +2618,11 @@ StmtResult 
Parser::ParseOpenMPDeclarativeOrExecutableDirective(
   case OMPD_metadirective: {
     ConsumeToken();
     SmallVector<VariantMatchInfo, 4> VMIs;
+    SmallVector<OMPTraitInfo *, 4> TraitInfos;
 
     // First iteration of parsing all clauses of metadirective.
-    // This iteration only parses and collects all context selector ignoring 
the
-    // associated directives.
+    // This iteration only parses and collects all context selectors ignoring
+    // the associated directives.
     TentativeParsingAction TPA(*this);
     ASTContext &ASTContext = Actions.getASTContext();
 
@@ -2681,6 +2698,7 @@ StmtResult 
Parser::ParseOpenMPDeclarativeOrExecutableDirective(
       TI.getAsVariantMatchInfo(ASTContext, VMI);
 
       VMIs.push_back(VMI);
+      TraitInfos.push_back(&TI);
     }
 
     TPA.Revert();
@@ -2700,6 +2718,75 @@ StmtResult 
Parser::ParseOpenMPDeclarativeOrExecutableDirective(
     // A single match is returned for OpenMP 5.0
     int BestIdx = getBestVariantMatchForContext(VMIs, OMPCtx);
 
+    // Check if we have user conditions with non-constant expressions that
+    // require runtime selection.
+    bool HasUserCondition = false;
+    for (const VariantMatchInfo &VMI : VMIs) {
+      if (VMI.HasNonConstantUserCondition) {
+        HasUserCondition = true;
+        break;
+      }
+    }
+
+    // If we have user conditions that couldn't be resolved at compile time,
+    // parse all variants and the body.
+    if (HasUserCondition) {
+      SmallVector<OpenMPDirectiveKind, 4> DirectiveKinds;
+      SmallVector<OpenMPClauseKind, 4> ClauseKinds;
+
+      // TODO: Phase 2 - Parse directive clauses and store them.
+      // For now in Phase 1, we only extract directive kinds.
+      // Sema will extract conditions from TraitInfos.
+
+      BalancedDelimiterTracker T(*this, tok::l_paren,
+                                 tok::annot_pragma_openmp_end);
+      while (Tok.isNot(tok::annot_pragma_openmp_end)) {
+        OpenMPClauseKind CKind =
+            Tok.isAnnotation() ? OMPC_unknown
+                               : getOpenMPClauseKind(PP.getSpelling(Tok));
+        SourceLocation ClauseLoc = ConsumeToken();
+
+        // Parse '('.
+        T.consumeOpen();
+
+        if (CKind == OMPC_when) {
+          OMPTraitInfo &TI = Actions.getASTContext().getNewOMPTraitInfo();
+          parseOMPContextSelectors(ClauseLoc, TI);
+
+          // Parse ':'.
+          if (Tok.is(tok::colon))
+            ConsumeAnyToken();
+        }
+
+        // Parse directive kind only for now.
+        OpenMPDirectiveKind DKind = OMPD_unknown;
+        if (!Tok.is(tok::r_paren)) {
+          DKind = parseOpenMPDirectiveKind(*this);
+          skipToMatchingParen(*this);
+        }
+
+        // Parse ')'.
+        if (Tok.is(tok::r_paren))
+          T.consumeClose();
+
+        DirectiveKinds.push_back(DKind);
+        ClauseKinds.push_back(CKind);
+      }
+
+      SourceLocation EndLoc = Tok.getLocation();
+      ConsumeAnnotationToken();
+
+      // Parse the body statement.
+      StmtResult AssociatedStmt = ParseStatement();
+      if (AssociatedStmt.isInvalid())
+        return StmtError();
+
+      // Pass to Sema for Phase 2 processing.
+      return Actions.OpenMP().ActOnOpenMPMetaDirective(
+          Loc, EndLoc, TraitInfos, ClauseKinds, DirectiveKinds,
+          AssociatedStmt.get());
+    }
+
     int Idx = 0;
     // In OpenMP 5.0 metadirective is either replaced by another directive or
     // ignored.
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index b39dd853ab378..5bf6ea4128b71 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -3768,6 +3768,15 @@ StmtResult 
SemaOpenMP::ActOnOpenMPAssumeDirective(ArrayRef<OMPClause *> Clauses,
                                     AStmt);
 }
 
+StmtResult SemaOpenMP::ActOnOpenMPMetaDirective(
+    SourceLocation StartLoc, SourceLocation EndLoc,
+    ArrayRef<OMPTraitInfo *> TraitInfos, ArrayRef<OpenMPClauseKind> 
ClauseKinds,
+    ArrayRef<OpenMPDirectiveKind> DirectiveKinds, Stmt *AssociatedStmt) {
+  // Stub for Phase 1 (Parser) testing.
+  // Sema will extract conditions from TraitInfos in Phase 2.
+  return AssociatedStmt;
+}
+
 OMPRequiresDecl *
 SemaOpenMP::CheckOMPRequiresDecl(SourceLocation Loc,
                                  ArrayRef<OMPClause *> ClauseList) {
diff --git a/clang/test/OpenMP/metadirective_user_condition_parse.cpp 
b/clang/test/OpenMP/metadirective_user_condition_parse.cpp
new file mode 100644
index 0000000000000..7306a5ab107fa
--- /dev/null
+++ b/clang/test/OpenMP/metadirective_user_condition_parse.cpp
@@ -0,0 +1,134 @@
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=52 -std=c++11 \
+// RUN:   -fsyntax-only %s
+
+// expected-no-diagnostics
+
+void test_runtime_condition(int flag) {
+#pragma omp metadirective                      \
+  when(user={condition(flag)}: parallel)       \
+  otherwise(single)
+  {
+    int x = 0;
+  }
+}
+
+void test_two_conditions(int flag1, int flag2) {
+#pragma omp metadirective                      \
+  when(user={condition(flag1)}: parallel)      \
+  when(user={condition(flag2)}: single)                \
+  otherwise()
+  {
+    int y = 1;
+  }
+}
+
+void test_complex_condition(int a, int b) {
+#pragma omp metadirective                      \
+  when(user={condition(a > b)}: parallel)      \
+  otherwise(single)
+  {
+    int z = 2;
+  }
+}
+
+void test_logical_condition(bool flag1, bool flag2) {
+#pragma omp metadirective                              \
+  when(user={condition(flag1 && flag2)}: parallel)     \
+  otherwise()
+  {
+    int w = 3;
+  }
+}
+
+void test_multiple_variants(int flag1, int flag2, int flag3) {
+#pragma omp metadirective                      \
+  when(user={condition(flag1)}: parallel)      \
+  when(user={condition(flag2)}: single)                \
+  when(user={condition(flag3)}: teams)         \
+  otherwise()
+  {
+    int v = 4;
+  }
+}
+
+void test_otherwise_only() {
+#pragma omp metadirective otherwise(parallel)
+  {
+    int u = 5;
+  }
+}
+
+void test_different_directives(int flag) {
+#pragma omp metadirective              \
+  when(user={condition(flag)}: teams)  \
+  otherwise(task)
+  {
+    int t = 6;
+  }
+}
+
+void test_nested_statement(int flag) {
+#pragma omp metadirective                      \
+  when(user={condition(flag)}: parallel)       \
+  otherwise()
+  {
+    for (int i = 0; i < 10; ++i) {
+      int s = i;
+    }
+  }
+}
+
+template <int N>
+void test_nontype_template(int flag) {
+#pragma omp metadirective                      \
+  when(user={condition(N > 0)}: parallel)      \
+  otherwise(single)
+  {
+    int x = N;
+  }
+}
+
+template <int Threshold>
+void test_threshold_condition(int value) {
+#pragma omp metadirective                              \
+  when(user={condition(value > Threshold)}: parallel)  \
+  otherwise()
+  {
+    int y = value;
+  }
+}
+
+template <bool UseParallel>
+void test_bool_template() {
+#pragma omp metadirective                      \
+  when(user={condition(UseParallel)}: parallel)        \
+  otherwise(single)
+  {
+    int z = 0;
+  }
+}
+
+template <typename T>
+void test_sizeof_condition(T* ptr) {
+#pragma omp metadirective                              \
+  when(user={condition(sizeof(T) > 4)}: parallel)      \
+  otherwise(single)
+  {
+    T val = *ptr;
+  }
+}
+
+void instantiate_templates() {
+  int flag = 1;
+  int value = 10;
+  int iptr;
+  double dptr;
+
+  test_nontype_template<5>(flag);
+  test_nontype_template<-3>(flag);
+  test_threshold_condition<100>(value);
+  test_bool_template<true>();
+  test_bool_template<false>();
+  test_sizeof_condition<int>(&iptr);
+  test_sizeof_condition<double>(&dptr);
+}
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPContext.h 
b/llvm/include/llvm/Frontend/OpenMP/OMPContext.h
index 7849d32665994..7c069721ba677 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMPContext.h
+++ b/llvm/include/llvm/Frontend/OpenMP/OMPContext.h
@@ -156,6 +156,10 @@ struct VariantMatchInfo {
   SmallVector<StringRef, 8> ISATraits;
   SmallVector<TraitProperty, 8> ConstructTraits;
   SmallDenseMap<TraitProperty, APInt> ScoreMap;
+
+  /// True if this variant has a user condition that could not be evaluated at
+  /// compile time (non-constant expression).
+  bool HasNonConstantUserCondition = false;
 };
 
 /// The context for a source location is made up of active property traits,

>From cc17edd7f94a68a79b1869cc05408f8e10b2168b Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <[email protected]>
Date: Tue, 18 Aug 2026 06:08:45 -0700
Subject: [PATCH 2/3] Fix format

---
 clang/include/clang/Sema/SemaOpenMP.h | 11 ++++++-----
 clang/lib/Parse/ParseOpenMP.cpp       |  6 +++---
 2 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/clang/include/clang/Sema/SemaOpenMP.h 
b/clang/include/clang/Sema/SemaOpenMP.h
index e6cd31b9c456f..4298ec7d86db7 100644
--- a/clang/include/clang/Sema/SemaOpenMP.h
+++ b/clang/include/clang/Sema/SemaOpenMP.h
@@ -219,11 +219,12 @@ class SemaOpenMP : public SemaBase {
 
   /// Called for metadirectives with user conditions that may require runtime
   /// selection.
-  StmtResult ActOnOpenMPMetaDirective(
-      SourceLocation StartLoc, SourceLocation EndLoc,
-      ArrayRef<OMPTraitInfo *> TraitInfos,
-      ArrayRef<OpenMPClauseKind> ClauseKinds,
-      ArrayRef<OpenMPDirectiveKind> DirectiveKinds, Stmt *AssociatedStmt);
+  StmtResult
+  ActOnOpenMPMetaDirective(SourceLocation StartLoc, SourceLocation EndLoc,
+                           ArrayRef<OMPTraitInfo *> TraitInfos,
+                           ArrayRef<OpenMPClauseKind> ClauseKinds,
+                           ArrayRef<OpenMPDirectiveKind> DirectiveKinds,
+                           Stmt *AssociatedStmt);
 
   // OpenMP directives and clauses.
   /// Called on correct id-expression from the '#pragma omp
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index 96a877a444351..7dde8b01ecce8 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -2741,9 +2741,9 @@ StmtResult 
Parser::ParseOpenMPDeclarativeOrExecutableDirective(
       BalancedDelimiterTracker T(*this, tok::l_paren,
                                  tok::annot_pragma_openmp_end);
       while (Tok.isNot(tok::annot_pragma_openmp_end)) {
-        OpenMPClauseKind CKind =
-            Tok.isAnnotation() ? OMPC_unknown
-                               : getOpenMPClauseKind(PP.getSpelling(Tok));
+        OpenMPClauseKind CKind = Tok.isAnnotation()
+                                     ? OMPC_unknown
+                                     : 
getOpenMPClauseKind(PP.getSpelling(Tok));
         SourceLocation ClauseLoc = ConsumeToken();
 
         // Parse '('.

>From 336326383a47de1ac5541d1850ff780d3367e7da Mon Sep 17 00:00:00 2001
From: Zahira Ammarguellat <[email protected]>
Date: Fri, 21 Aug 2026 14:04:49 -0700
Subject: [PATCH 3/3]  Phase 2 of metadirective runtime selection

---
 clang/include/clang/Lex/Preprocessor.h        |   5 +
 clang/include/clang/Sema/SemaOpenMP.h         |  13 +-
 clang/lib/Lex/PPCaching.cpp                   |  18 ++
 clang/lib/Parse/ParseOpenMP.cpp               | 187 ++++++++++++++----
 clang/lib/Sema/SemaOpenMP.cpp                 |  28 ++-
 .../metadirective_user_condition_parse.cpp    |  54 -----
 6 files changed, 207 insertions(+), 98 deletions(-)

diff --git a/clang/include/clang/Lex/Preprocessor.h 
b/clang/include/clang/Lex/Preprocessor.h
index e752010dd2062..5344ae61211ad 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -1776,6 +1776,11 @@ class Preprocessor {
   /// Disable the last EnableBacktrackAtThisPos call.
   void CommitBacktrackedTokens();
 
+  /// Get the tokens cached since EnableBacktrackAtThisPos() and commit
+  /// the backtrack. The main token stream remains at the current position
+  /// (advanced past the cached tokens).
+  ArrayRef<Token> GetAndCommitBacktrackedTokens();
+
   /// Make Preprocessor re-lex the tokens that were lexed since
   /// EnableBacktrackAtThisPos() was previously called.
   void Backtrack();
diff --git a/clang/include/clang/Sema/SemaOpenMP.h 
b/clang/include/clang/Sema/SemaOpenMP.h
index 4298ec7d86db7..0409ab032fd5a 100644
--- a/clang/include/clang/Sema/SemaOpenMP.h
+++ b/clang/include/clang/Sema/SemaOpenMP.h
@@ -219,12 +219,13 @@ class SemaOpenMP : public SemaBase {
 
   /// Called for metadirectives with user conditions that may require runtime
   /// selection.
-  StmtResult
-  ActOnOpenMPMetaDirective(SourceLocation StartLoc, SourceLocation EndLoc,
-                           ArrayRef<OMPTraitInfo *> TraitInfos,
-                           ArrayRef<OpenMPClauseKind> ClauseKinds,
-                           ArrayRef<OpenMPDirectiveKind> DirectiveKinds,
-                           Stmt *AssociatedStmt);
+  StmtResult ActOnOpenMPMetaDirective(
+      SourceLocation StartLoc, SourceLocation EndLoc,
+      ArrayRef<OMPTraitInfo *> TraitInfos,
+      ArrayRef<OpenMPClauseKind> ClauseKinds,
+      ArrayRef<OpenMPDirectiveKind> DirectiveKinds,
+      ArrayRef<ArrayRef<OMPClause *>> DirectiveClauses,
+      ArrayRef<Stmt *> VariantBodies);
 
   // OpenMP directives and clauses.
   /// Called on correct id-expression from the '#pragma omp
diff --git a/clang/lib/Lex/PPCaching.cpp b/clang/lib/Lex/PPCaching.cpp
index 3f0ebd8455685..b21d97dd77fa0 100644
--- a/clang/lib/Lex/PPCaching.cpp
+++ b/clang/lib/Lex/PPCaching.cpp
@@ -61,6 +61,24 @@ void Preprocessor::CommitBacktrackedTokens() {
     PopUnannotatedBacktrackTokens();
 }
 
+// Get the tokens cached since EnableBacktrackAtThisPos() and commit
+// the backtrack.
+ArrayRef<Token> Preprocessor::GetAndCommitBacktrackedTokens() {
+  assert(isBacktrackEnabled() &&
+         "Should only be called when backtracking is enabled");
+
+  auto [LastPos, Unannotated] = LastBacktrackPos();
+
+  // Get range of tokens cached since EnableBacktrackAtThisPos.
+  ArrayRef<Token> CachedRange(CachedTokens.begin() + LastPos,
+                               CachedTokens.begin() + CachedLexPos);
+
+  // Commit backtrack to keep stream advanced.
+  CommitBacktrackedTokens();
+
+  return CachedRange;
+}
+
 // Make Preprocessor re-lex the tokens that were lexed since
 // EnableBacktrackAtThisPos() was previously called.
 void Preprocessor::Backtrack() {
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index 7dde8b01ecce8..14e2d712bc70c 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -108,22 +108,6 @@ static OpenMPDirectiveKind parseOpenMPDirectiveKind(Parser 
&P) {
   return checkOpenMPDirectiveName(P, Loc, S->Value, Concat);
 }
 
-/// Skip tokens until reaching the matching closing parenthesis.
-/// Handles nested parentheses correctly.
-static void skipToMatchingParen(Parser &P) {
-  int ParenDepth = 0;
-  while ((P.getCurToken().isNot(tok::r_paren) || ParenDepth != 0) &&
-         P.getCurToken().isNot(tok::annot_pragma_openmp_end) &&
-         P.getCurToken().isNot(tok::eof)) {
-    if (P.getCurToken().is(tok::l_paren))
-      ParenDepth++;
-    if (P.getCurToken().is(tok::r_paren) && ParenDepth > 0)
-      ParenDepth--;
-    if (ParenDepth > 0 || P.getCurToken().isNot(tok::r_paren))
-      P.ConsumeAnyToken();
-  }
-}
-
 static DeclarationName parseOpenMPReductionId(Parser &P) {
   Token Tok = P.getCurToken();
   Sema &Actions = P.getActions();
@@ -2728,22 +2712,20 @@ StmtResult 
Parser::ParseOpenMPDeclarativeOrExecutableDirective(
       }
     }
 
-    // If we have user conditions that couldn't be resolved at compile time,
-    // parse all variants and the body.
+    // Different directives have different data-sharing attributes, so each
+    // variant needs its own CapturedStmt with proper DSA context.
+    // We manually cache body tokens and inject them for each variant parse.
     if (HasUserCondition) {
-      SmallVector<OpenMPDirectiveKind, 4> DirectiveKinds;
       SmallVector<OpenMPClauseKind, 4> ClauseKinds;
-
-      // TODO: Phase 2 - Parse directive clauses and store them.
-      // For now in Phase 1, we only extract directive kinds.
-      // Sema will extract conditions from TraitInfos.
+      SmallVector<OpenMPDirectiveKind, 4> DirectiveKinds;
+      SmallVector<SmallVector<OMPClause *, 5>, 4> DirectiveClauses;
 
       BalancedDelimiterTracker T(*this, tok::l_paren,
                                  tok::annot_pragma_openmp_end);
       while (Tok.isNot(tok::annot_pragma_openmp_end)) {
-        OpenMPClauseKind CKind = Tok.isAnnotation()
-                                     ? OMPC_unknown
-                                     : 
getOpenMPClauseKind(PP.getSpelling(Tok));
+        OpenMPClauseKind CKind =
+            Tok.isAnnotation() ? OMPC_unknown
+                               : getOpenMPClauseKind(PP.getSpelling(Tok));
         SourceLocation ClauseLoc = ConsumeToken();
 
         // Parse '('.
@@ -2758,33 +2740,170 @@ StmtResult 
Parser::ParseOpenMPDeclarativeOrExecutableDirective(
             ConsumeAnyToken();
         }
 
-        // Parse directive kind only for now.
+        // Parse the directive kind and clauses manually.
         OpenMPDirectiveKind DKind = OMPD_unknown;
+        SmallVector<OMPClause *, 5> Clauses;
+
         if (!Tok.is(tok::r_paren)) {
+          // Parse directive kind (handles combined directives like
+          // 'parallel for simd').
           DKind = parseOpenMPDirectiveKind(*this);
-          skipToMatchingParen(*this);
+
+          // Consume the last token of the directive name.
+          if (Tok.isNot(tok::annot_pragma_openmp_end) &&
+              Tok.isNot(tok::r_paren))
+            ConsumeAnyToken();
+
+          // Parse clauses for this directive if any exist.
+          // We stop at ')' which ends the metadirective variant.
+          while (Tok.isNot(tok::r_paren) &&
+                 Tok.isNot(tok::annot_pragma_openmp_end)) {
+            // Check if current token is a clause keyword.
+            OpenMPClauseKind ClauseKind =
+                Tok.isAnnotation()
+                    ? OMPC_unknown
+                    : getOpenMPClauseKind(PP.getSpelling(Tok));
+
+            // If not a clause keyword, we've parsed all clauses.
+            if (ClauseKind == OMPC_unknown)
+              break;
+
+            Actions.OpenMP().StartOpenMPClause(ClauseKind);
+            OMPClause *Clause =
+                ParseOpenMPClause(DKind, ClauseKind,
+                                  /* FirstClause */ Clauses.empty());
+            Actions.OpenMP().EndOpenMPClause();
+
+            if (Clause)
+              Clauses.push_back(Clause);
+
+            // Check for comma separator between clauses.
+            if (Tok.is(tok::comma))
+              ConsumeAnyToken();
+            else if (Tok.isNot(tok::r_paren) &&
+                     Tok.isNot(tok::annot_pragma_openmp_end)) {
+              // Unexpected token - not comma, not closing paren.
+              break;
+            }
+          }
         }
 
         // Parse ')'.
         if (Tok.is(tok::r_paren))
           T.consumeClose();
 
-        DirectiveKinds.push_back(DKind);
         ClauseKinds.push_back(CKind);
+        DirectiveKinds.push_back(DKind);
+        DirectiveClauses.push_back(Clauses);
       }
 
       SourceLocation EndLoc = Tok.getLocation();
       ConsumeAnnotationToken();
 
-      // Parse the body statement.
-      StmtResult AssociatedStmt = ParseStatement();
-      if (AssociatedStmt.isInvalid())
+      // Manually cache all body tokens for unlimited replay.
+      SmallVector<Token, 64> BodyTokens;
+
+      // Cache the current token before enabling backtracking.
+      BodyTokens.push_back(Tok);
+
+      // Parse the statement once and cache remaining tokens.
+      PP.EnableBacktrackAtThisPos();
+      {
+        ParsingOpenMPDirectiveRAII NormalScope(*this, /*Value=*/false);
+        StmtResult BodyStmt = ParseStatement();
+        if (BodyStmt.isInvalid()) {
+          PP.Backtrack();
+          return StmtError();
+        }
+      }
+
+      // Get cached tokens and commit (keeps stream advanced).
+      ArrayRef<Token> CachedRange = PP.GetAndCommitBacktrackedTokens();
+      BodyTokens.append(CachedRange.begin(), CachedRange.end());
+
+      if (BodyTokens.empty()) {
+        Diag(Tok, diag::err_expected_statement);
         return StmtError();
+      }
+
+      // Add an EOF token with marker to end the injected stream.
+      Token EofToken;
+      EofToken.startToken();
+      EofToken.setKind(tok::eof);
+      EofToken.setLocation(Tok.getLocation());
+      EofToken.setEofData(this);
+      BodyTokens.push_back(EofToken);
+
+      // Parse the body separately for each variant to get correct DSA.
+      SmallVector<Stmt *, 4> VariantBodies;
+      for (unsigned i = 0; i < DirectiveKinds.size(); ++i) {
+        if (DirectiveKinds[i] == OMPD_unknown) {
+          VariantBodies.push_back(nullptr);
+          continue;
+        }
+
+        auto TokensCopy = std::make_unique<Token[]>(BodyTokens.size());
+        std::copy(BodyTokens.begin(), BodyTokens.end(), TokensCopy.get());
+        PP.EnterTokenStream(std::move(TokensCopy), BodyTokens.size(),
+                      /*DisableMacroExpansion=*/false,
+                      /*IsReinject=*/false);
+        // Consume first token from the injected stream to update Tok.
+        ConsumeAnyToken();
+
+        // Start DSA block for this directive.
+        Actions.OpenMP().StartOpenMPDSABlock(DirectiveKinds[i],
+                                             DeclarationNameInfo(),
+                                             getCurScope(), Loc);
+
+        // Start captured region for this directive.
+        Actions.OpenMP().ActOnOpenMPRegionStart(DirectiveKinds[i],
+                                                getCurScope());
+
+        // Parse the body.
+        StmtResult Body;
+        ParsingOpenMPDirectiveRAII NormalScope(*this, /*Value=*/false);
+        {
+          Sema::CompoundScopeRAII Scope(Actions);
+          Body = ParseStatement();
+        }
+
+        if (Body.isInvalid())
+          return StmtError();
+
+        // End captured region - wraps body in CapturedStmt.
+        Body = Actions.OpenMP().ActOnOpenMPRegionEnd(Body,
+                                                     DirectiveClauses[i]);
+        if (Body.isInvalid())
+          return StmtError();
+
+        // End DSA block for this variant.
+        Actions.OpenMP().EndOpenMPDSABlock(Body.get());
+
+        VariantBodies.push_back(Body.get());
+
+        // Clean up this variant's injected token stream.
+        // Skip cleanup for the last variant to avoid stream corruption.
+        if (i < DirectiveKinds.size() - 1) {
+          while (Tok.isNot(tok::eof))
+            ConsumeAnyToken();
+
+          // Consume the marked EOF to pop the injected stream.
+          if (Tok.is(tok::eof) && Tok.getEofData() == this)
+            ConsumeAnyToken();
+        }
+      }
+
+      // The last variant's token stream remains active. The variants'
+      // CapturedStmts already include the body.
+
+      // Convert DirectiveClauses to ArrayRef<ArrayRef<OMPClause *>>.
+      SmallVector<ArrayRef<OMPClause *>, 4> ClausesArrayRefs;
+      for (const auto &Clauses : DirectiveClauses)
+        ClausesArrayRefs.push_back(Clauses);
 
-      // Pass to Sema for Phase 2 processing.
       return Actions.OpenMP().ActOnOpenMPMetaDirective(
           Loc, EndLoc, TraitInfos, ClauseKinds, DirectiveKinds,
-          AssociatedStmt.get());
+          ClausesArrayRefs, VariantBodies);
     }
 
     int Idx = 0;
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 5bf6ea4128b71..a36cb4a564182 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -3771,10 +3771,30 @@ StmtResult 
SemaOpenMP::ActOnOpenMPAssumeDirective(ArrayRef<OMPClause *> Clauses,
 StmtResult SemaOpenMP::ActOnOpenMPMetaDirective(
     SourceLocation StartLoc, SourceLocation EndLoc,
     ArrayRef<OMPTraitInfo *> TraitInfos, ArrayRef<OpenMPClauseKind> 
ClauseKinds,
-    ArrayRef<OpenMPDirectiveKind> DirectiveKinds, Stmt *AssociatedStmt) {
-  // Stub for Phase 1 (Parser) testing.
-  // Sema will extract conditions from TraitInfos in Phase 2.
-  return AssociatedStmt;
+    ArrayRef<OpenMPDirectiveKind> DirectiveKinds,
+    ArrayRef<ArrayRef<OMPClause *>> DirectiveClauses,
+    ArrayRef<Stmt *> VariantBodies) {
+
+  assert((ClauseKinds.size() == DirectiveKinds.size() &&
+          DirectiveKinds.size() == DirectiveClauses.size() &&
+          DirectiveClauses.size() == VariantBodies.size()) &&
+         "Mismatched variant arrays");
+
+  // VariantBodies are complete CapturedStmt nodes with DSA from Parser.
+  // TODO Phase 3: Build OMPMetaDirective AST node holding all variants.
+  // TODO Phase 3: Extract conditions from TraitInfos.
+  // TODO Phase 4: Codegen - generate runtime if-else chain.
+
+  // Temporary stub: return first variant until OMPMetaDirective exists.
+  // Early return if no variants were successfully parsed.
+  if (VariantBodies.empty())
+    return StmtError();
+
+  // Return first variant if it's valid.
+  if (VariantBodies[0])
+    return VariantBodies[0];
+
+  return StmtError();
 }
 
 OMPRequiresDecl *
diff --git a/clang/test/OpenMP/metadirective_user_condition_parse.cpp 
b/clang/test/OpenMP/metadirective_user_condition_parse.cpp
index 7306a5ab107fa..6d121c42302e4 100644
--- a/clang/test/OpenMP/metadirective_user_condition_parse.cpp
+++ b/clang/test/OpenMP/metadirective_user_condition_parse.cpp
@@ -78,57 +78,3 @@ void test_nested_statement(int flag) {
   }
 }
 
-template <int N>
-void test_nontype_template(int flag) {
-#pragma omp metadirective                      \
-  when(user={condition(N > 0)}: parallel)      \
-  otherwise(single)
-  {
-    int x = N;
-  }
-}
-
-template <int Threshold>
-void test_threshold_condition(int value) {
-#pragma omp metadirective                              \
-  when(user={condition(value > Threshold)}: parallel)  \
-  otherwise()
-  {
-    int y = value;
-  }
-}
-
-template <bool UseParallel>
-void test_bool_template() {
-#pragma omp metadirective                      \
-  when(user={condition(UseParallel)}: parallel)        \
-  otherwise(single)
-  {
-    int z = 0;
-  }
-}
-
-template <typename T>
-void test_sizeof_condition(T* ptr) {
-#pragma omp metadirective                              \
-  when(user={condition(sizeof(T) > 4)}: parallel)      \
-  otherwise(single)
-  {
-    T val = *ptr;
-  }
-}
-
-void instantiate_templates() {
-  int flag = 1;
-  int value = 10;
-  int iptr;
-  double dptr;
-
-  test_nontype_template<5>(flag);
-  test_nontype_template<-3>(flag);
-  test_threshold_condition<100>(value);
-  test_bool_template<true>();
-  test_bool_template<false>();
-  test_sizeof_condition<int>(&iptr);
-  test_sizeof_condition<double>(&dptr);
-}

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

Reply via email to