================
@@ -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