================
@@ -2712,6 +2714,153 @@ 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 = llvm::any_of(VMIs, [](const VariantMatchInfo &VMI) 
{
+      return VMI.HasNonConstantUserCondition;
+    });
+
+    // 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<OpenMPClauseKind, 4> ClauseKinds;
+      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));
+        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();
+        }
+
+        OpenMPDirectiveKind DKind = OMPD_unknown;
+        SmallVector<OMPClause *, 5> Clauses;
+
+        if (!Tok.is(tok::r_paren)) {
+          // Parse directive kind (e.g., 'parallel', 'single').
+          DKind = parseOpenMPDirectiveKind(*this);
+
+          if (Tok.isNot(tok::annot_pragma_openmp_end) &&
+              Tok.isNot(tok::r_paren))
+            ConsumeAnyToken();
+
+          // Open temporary DSA block so clauses have an active directive 
frame.
+          if (DKind != OMPD_unknown)
+            Actions.OpenMP().StartOpenMPDSABlock(DKind, DeclarationNameInfo(),
+                                                 getCurScope(), ClauseLoc);
+
+          // Parse clauses for this directive variant.
+          while (Tok.isNot(tok::r_paren) &&
+                 Tok.isNot(tok::annot_pragma_openmp_end)) {
+            // Skip optional commas between clauses.
+            if (Tok.is(tok::comma))
+              ConsumeAnyToken();
+
+            OpenMPClauseKind ClauseKind =
+                Tok.isAnnotation() ? OMPC_unknown
+                                   : getOpenMPClauseKind(PP.getSpelling(Tok));
+
+            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);
+          }
+
+          // Close the temporary DSA block for header parsing.
+          if (DKind != OMPD_unknown)
+            Actions.OpenMP().EndOpenMPDSABlock(nullptr);
+        }
+
+        // Parse ')' or recover to pragma end on syntax error.
+        if (T.consumeClose())
+          T.skipToEnd();
+
+        ClauseKinds.push_back(CKind);
+        DirectiveKinds.push_back(DKind);
+        DirectiveClauses.push_back(Clauses);
+      }
+
+      SourceLocation EndLoc = Tok.getLocation();
+      ConsumeAnnotationToken();
+
+      // Parse the body separately for each variant to establish proper DSA.
+      SmallVector<Stmt *, 4> VariantBodies;
+
+      for (unsigned I : llvm::seq<unsigned>(DirectiveKinds.size())) {
+        std::optional<TentativeParsingAction> TPA;
+        if (I < DirectiveKinds.size() - 1)
+          TPA.emplace(*this);
+
+        const bool HasDirective = (DirectiveKinds[I] != OMPD_unknown);
+
+        if (HasDirective) {
+          Actions.OpenMP().StartOpenMPDSABlock(
+              DirectiveKinds[I], DeclarationNameInfo(), getCurScope(), Loc);
+          Actions.OpenMP().ActOnOpenMPRegionStart(DirectiveKinds[I],
+                                                  getCurScope());
+        }
+
+        StmtResult Body;
+        ParsingOpenMPDirectiveRAII NormalScope(*this, /*Value=*/false);
+        {
+          Sema::CompoundScopeRAII Scope(Actions);
+          Body = ParseStatement();
+        }
+        if (Body.isInvalid()) {
+          if (HasDirective)
+            Actions.OpenMP().EndOpenMPDSABlock(nullptr);
+          if (TPA)
+            TPA->Revert();
+          return StmtError();
+        }
+        if (HasDirective) {
+          Body =
+              Actions.OpenMP().ActOnOpenMPRegionEnd(Body, DirectiveClauses[I]);
+          if (Body.isInvalid()) {
+            Actions.OpenMP().EndOpenMPDSABlock(nullptr);
+            if (TPA)
+              TPA->Revert();
+            return StmtError();
+          }
+
+          Actions.OpenMP().EndOpenMPDSABlock(Body.get());
+        }
+        VariantBodies.push_back(Body.get());
+        if (TPA)
+          TPA->Revert();
+      }
+
+      // Convert DirectiveClauses to ArrayRef<ArrayRef<OMPClause *>>.
+      SmallVector<ArrayRef<OMPClause *>, 4> ClausesArrayRefs;
+      for (const auto &Clauses : DirectiveClauses)
+        ClausesArrayRefs.push_back(Clauses);
+      return Actions.OpenMP().ActOnOpenMPMetaDirective(
+          Loc, EndLoc, TraitInfos, ClauseKinds, DirectiveKinds,
+          ClausesArrayRefs, VariantBodies);
----------------
alexey-bataev wrote:

```suggestion
      // Reuse the normal metadirective variant parse per clause so every
      // variant is a complete directive node with its own body.
      SmallVector<Stmt *, 4> Variants;
      while (Tok.isNot(tok::annot_pragma_openmp_end)) {
        TentativeParsingAction TPA2(*this);
        // parse this clause's selectors, then the variant directive via
        // ParseOpenMPDeclarativeOrExecutableDirective(..., true) — or a plain
        // ParseStatement() when the clause has no directive ('otherwise()').
        ...
        Variants.push_back(Variant.get());
        TPA2.Revert();
        // skip this clause (paren-skip, as at 2723-2736) to advance
      }
      // parse the last variant once more without reverting
      return Actions.OpenMP().ActOnOpenMPMetaDirective(Loc, EndLoc, TraitInfos,
                                                       Variants);
```

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

Reply via email to