llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: ykhatav (ykhatav)

<details>
<summary>Changes</summary>

This PR adds parsing support for the OpenMP 6.0 brace-grouped prefer_type 
modifier on the init clause of #pragma omp interop, while preserving the OpenMP 
5.1 flat form. Each preference-specification can now carry an optional
  fr(&lt;foreign-runtime-id&gt;) and zero or more 
attr(&lt;string-literal&gt;...) selectors, eg:

  #pragma omp interop init(prefer_type({fr("sycl"), attr("ompx_propX")}, \
                                       {fr("level_zero")}, \
                                       {attr("ompx_propY")}), targetsync: obj)


---

Patch is 29.68 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/198868.diff


12 Files Affected:

- (modified) clang/include/clang/AST/OpenMPClause.h (+75-7) 
- (modified) clang/include/clang/Basic/DiagnosticParseKinds.td (+2) 
- (modified) clang/include/clang/Basic/OpenMPKinds.h (+9-1) 
- (modified) clang/include/clang/Parse/Parser.h (+6) 
- (modified) clang/lib/AST/OpenMPClause.cpp (+78-20) 
- (modified) clang/lib/Parse/ParseOpenMP.cpp (+113-13) 
- (modified) clang/lib/Sema/SemaOpenMP.cpp (+8-3) 
- (modified) clang/lib/Sema/TreeTransform.h (+21-6) 
- (modified) clang/lib/Serialization/ASTReader.cpp (+20-2) 
- (modified) clang/lib/Serialization/ASTWriter.cpp (+12) 
- (added) clang/test/OpenMP/interop_prefer_type_brace_ast_print.cpp (+71) 
- (added) clang/test/OpenMP/interop_prefer_type_brace_messages.cpp (+42) 


``````````diff
diff --git a/clang/include/clang/AST/OpenMPClause.h 
b/clang/include/clang/AST/OpenMPClause.h
index ccf2c40bc5efa..629d03f9e74a6 100644
--- a/clang/include/clang/AST/OpenMPClause.h
+++ b/clang/include/clang/AST/OpenMPClause.h
@@ -8851,7 +8851,7 @@ class OMPOrderClause final : public OMPClause {
 /// \endcode
 class OMPInitClause final
     : public OMPVarListClause<OMPInitClause>,
-      private llvm::TrailingObjects<OMPInitClause, Expr *> {
+      private llvm::TrailingObjects<OMPInitClause, Expr *, unsigned> {
   friend class OMPClauseReader;
   friend OMPVarListClause;
   friend TrailingObjects;
@@ -8861,6 +8861,30 @@ class OMPInitClause final
 
   bool IsTarget = false;
   bool IsTargetSync = false;
+  bool HasPreferAttrs = false;
+
+  /// Total number of attr() exprs across all pref-specs (sum of the
+  /// per-pref-spec counts in the trailing unsigned[]).
+  unsigned NumAttrs = 0;
+
+  /// Trailing-objects layout (single contiguous Expr* array):
+  ///   Expr*[ varlist_size() + NumAttrs ]:
+  ///     [0]                    = InteropVar
+  ///     [1 .. NumPrefs]        = Fr expr per pref-spec (null if attr-only)
+  ///     [varlist_size() ..]    = flat list of attr exprs, concatenated in
+  ///                              pref-spec order
+  ///   unsigned[ NumPrefs ]:
+  ///     [i]                    = number of attr() exprs in pref-spec i
+  ///
+  /// varlist_size() = 1 + NumPrefs, so OMPVarListClause iteration covers
+  /// InteropVar + the Fr block.
+
+  size_t numTrailingObjects(OverloadToken<Expr *>) const {
+    return varlist_size() + NumAttrs;
+  }
+  size_t numTrailingObjects(OverloadToken<unsigned>) const {
+    return getNumPrefs();
+  }
 
   void setInteropVar(Expr *E) { varlist_begin()[0] = E; }
 
@@ -8868,6 +8892,10 @@ class OMPInitClause final
 
   void setIsTargetSync(bool V) { IsTargetSync = V; }
 
+  void setHasPreferAttrs(bool V) { HasPreferAttrs = V; }
+
+  void setAttrs(ArrayRef<unsigned> Counts, ArrayRef<Expr *> Attrs);
+
   /// Sets the location of the interop variable.
   void setVarLoc(SourceLocation Loc) { VarLoc = Loc; }
 
@@ -8879,7 +8907,7 @@ class OMPInitClause final
   /// \param LParenLoc Location of '('.
   /// \param VarLoc Location of the interop variable.
   /// \param EndLoc Ending location of the clause.
-  /// \param N Number of expressions.
+  /// \param N Number of varlist entries (1 + NumPrefs).
   OMPInitClause(bool IsTarget, bool IsTargetSync, SourceLocation StartLoc,
                 SourceLocation LParenLoc, SourceLocation VarLoc,
                 SourceLocation EndLoc, unsigned N)
@@ -8894,6 +8922,14 @@ class OMPInitClause final
   }
 
 public:
+  struct PrefView {
+    /// Foreign-runtime-id expression. Null for attr-only specs.
+    Expr *Fr;
+    /// attr() string-literal expressions. Empty for fr-only or OMP 5.1
+    /// flat specs.
+    ArrayRef<Expr *> Attrs;
+  };
+
   /// Creates a fully specified clause.
   ///
   /// \param C AST context.
@@ -8909,11 +8945,14 @@ class OMPInitClause final
                                SourceLocation LParenLoc, SourceLocation VarLoc,
                                SourceLocation EndLoc);
 
-  /// Creates an empty clause with \a N expressions.
+  /// Creates an empty clause sized for \a NumPrefs pref-specs and \a NumAttrs
+  /// total attr() exprs across them.
   ///
   /// \param C AST context.
-  /// \param N Number of expression items.
-  static OMPInitClause *CreateEmpty(const ASTContext &C, unsigned N);
+  /// \param NumPrefs Number of pref-specs (length of the Fr block).
+  /// \param NumAttrs Total attr() exprs across all pref-specs.
+  static OMPInitClause *CreateEmpty(const ASTContext &C, unsigned NumPrefs,
+                                    unsigned NumAttrs);
 
   /// Returns the location of the interop variable.
   SourceLocation getVarLoc() const { return VarLoc; }
@@ -8928,9 +8967,38 @@ class OMPInitClause final
   /// Returns true is interop-type 'targetsync' is used.
   bool getIsTargetSync() const { return IsTargetSync; }
 
+  /// Returns true if OMP 6.0 {fr/attr} syntax is used.
+  bool getHasPreferAttrs() const { return HasPreferAttrs; }
+
+  /// Number of pref-specs in prefer_type(...).
+  unsigned getNumPrefs() const { return varlist_size() - 1; }
+
+  /// Total attrs across all pref-specs.
+  unsigned getNumAttrs() const { return NumAttrs; }
+
+  /// Per-pref-spec attr counts (one entry per pref-spec).
+  ArrayRef<unsigned> getAttrCounts() const {
+    return getTrailingObjects<unsigned>(getNumPrefs());
+  }
+
+  PrefView getPref(unsigned I) {
+    assert(I < getNumPrefs() && "pref-spec index out of range");
+    Expr **E = getTrailingObjects<Expr *>();
+    ArrayRef<unsigned> Counts = getAttrCounts();
+    unsigned AttrStart = 0;
+    for (unsigned K = 0; K < I; ++K)
+      AttrStart += Counts[K];
+    return PrefView{
+        E[1 + I], ArrayRef<Expr *>(E + varlist_size() + AttrStart, Counts[I])};
+  }
+  PrefView getPref(unsigned I) const {
+    return const_cast<OMPInitClause *>(this)->getPref(I);
+  }
+
   child_range children() {
-    return child_range(reinterpret_cast<Stmt **>(varlist_begin()),
-                       reinterpret_cast<Stmt **>(varlist_end()));
+    return child_range(
+        reinterpret_cast<Stmt **>(varlist_begin()),
+        reinterpret_cast<Stmt **>(varlist_begin() + varlist_size() + 
NumAttrs));
   }
 
   const_child_range children() const {
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td 
b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 7bcd1870a2600..6abda0671add2 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1691,6 +1691,8 @@ def err_omp_expected_interop_type : Error<
 def warn_omp_more_one_interop_type
   : Warning<"interop type '%0' cannot be specified more than once">,
     InGroup<OpenMPClauses>;
+def err_omp_interop_multiple_fr : Error<
+  "only one 'fr' selector allowed per preference-specification">;
 def err_expected_sequence_or_directive : Error<
   "expected an OpenMP 'directive' or 'sequence' attribute argument">;
 def ext_omp_attributes : ExtWarn<
diff --git a/clang/include/clang/Basic/OpenMPKinds.h 
b/clang/include/clang/Basic/OpenMPKinds.h
index 4e83bfcd0128b..72b25e0908a34 100644
--- a/clang/include/clang/Basic/OpenMPKinds.h
+++ b/clang/include/clang/Basic/OpenMPKinds.h
@@ -292,12 +292,20 @@ static constexpr unsigned 
NumberOfOMPAllocateClauseModifiers =
 
 /// Contains 'interop' data for 'append_args' and 'init' clauses.
 class Expr;
+/// One entry of a prefer_type list. Each pref-spec carries an optional fr()
+/// foreign-runtime-id expression and zero or more attr() ext-string-literal
+/// expressions. Fr is nullptr for attr-only specs.
+struct OMPInteropPref final {
+  Expr *Fr = nullptr;
+  llvm::SmallVector<Expr *, 2> Attrs;
+};
 struct OMPInteropInfo final {
   OMPInteropInfo(bool IsTarget = false, bool IsTargetSync = false)
       : IsTarget(IsTarget), IsTargetSync(IsTargetSync) {}
   bool IsTarget;
   bool IsTargetSync;
-  llvm::SmallVector<Expr *, 4> PreferTypes;
+  bool HasPreferAttrs = false;
+  llvm::SmallVector<OMPInteropPref, 4> Prefs;
 };
 
 OpenMPDefaultClauseVariableCategory
diff --git a/clang/include/clang/Parse/Parser.h 
b/clang/include/clang/Parse/Parser.h
index dc3dc8a4ae0e9..ada8ca7e7e52c 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -7001,6 +7001,12 @@ class Parser : public CodeCompletionHandler {
   /// Parses the 'interop' parts of the 'append_args' and 'init' clauses.
   bool ParseOMPInteropInfo(OMPInteropInfo &InteropInfo, OpenMPClauseKind Kind);
 
+  /// Parses 'fr(<foreign-runtime-id>)'.
+  ExprResult ParseOMPInteropFrSelector();
+
+  /// Parses 'attr(<string-literal>[, ...])', appending to \p Attrs.
+  bool ParseOMPInteropAttrSelector(SmallVectorImpl<Expr *> &Attrs);
+
   /// Parses clause with an interop variable of kind \a Kind.
   ///
   /// \verbatim
diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp
index 3a35e17aff40b..9fce666ce00d8 100644
--- a/clang/lib/AST/OpenMPClause.cpp
+++ b/clang/lib/AST/OpenMPClause.cpp
@@ -1805,19 +1805,52 @@ OMPInitClause *OMPInitClause::Create(const ASTContext 
&C, Expr *InteropVar,
                                      SourceLocation VarLoc,
                                      SourceLocation EndLoc) {
 
-  void *Mem =
-      C.Allocate(totalSizeToAlloc<Expr *>(InteropInfo.PreferTypes.size() + 1));
-  auto *Clause = new (Mem) OMPInitClause(
-      InteropInfo.IsTarget, InteropInfo.IsTargetSync, StartLoc, LParenLoc,
-      VarLoc, EndLoc, InteropInfo.PreferTypes.size() + 1);
-  Clause->setInteropVar(InteropVar);
-  llvm::copy(InteropInfo.PreferTypes, Clause->getTrailingObjects() + 1);
+  unsigned NumPrefs = InteropInfo.Prefs.size();
+  unsigned NumAttrs = 0;
+  for (const OMPInteropPref &P : InteropInfo.Prefs)
+    NumAttrs += P.Attrs.size();
+
+  // Trailing layout: Expr*[1 + NumPrefs + NumAttrs], unsigned[NumPrefs].
+  void *Mem = C.Allocate(
+      totalSizeToAlloc<Expr *, unsigned>(1 + NumPrefs + NumAttrs, NumPrefs));
+  auto *Clause = new (Mem)
+      OMPInitClause(InteropInfo.IsTarget, InteropInfo.IsTargetSync, StartLoc,
+                    LParenLoc, VarLoc, EndLoc, /*VarListN=*/1 + NumPrefs);
+  Clause->NumAttrs = NumAttrs;
+  Clause->HasPreferAttrs = InteropInfo.HasPreferAttrs;
+
+  Expr **E = Clause->getTrailingObjects<Expr *>();
+  E[0] = InteropVar;
+  for (unsigned I = 0; I < NumPrefs; ++I)
+    E[1 + I] = InteropInfo.Prefs[I].Fr;
+  unsigned *Counts = Clause->getTrailingObjects<unsigned>();
+  unsigned AttrPos = 1 + NumPrefs;
+  for (unsigned I = 0; I < NumPrefs; ++I) {
+    Counts[I] = InteropInfo.Prefs[I].Attrs.size();
+    for (Expr *A : InteropInfo.Prefs[I].Attrs)
+      E[AttrPos++] = A;
+  }
   return Clause;
 }
 
-OMPInitClause *OMPInitClause::CreateEmpty(const ASTContext &C, unsigned N) {
-  void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(N));
-  return new (Mem) OMPInitClause(N);
+OMPInitClause *OMPInitClause::CreateEmpty(const ASTContext &C,
+                                          unsigned NumPrefs,
+                                          unsigned NumAttrs) {
+  void *Mem = C.Allocate(
+      totalSizeToAlloc<Expr *, unsigned>(1 + NumPrefs + NumAttrs, NumPrefs));
+  auto *Clause = new (Mem) OMPInitClause(/*VarListN=*/1 + NumPrefs);
+  Clause->NumAttrs = NumAttrs;
+  return Clause;
+}
+
+void OMPInitClause::setAttrs(ArrayRef<unsigned> Counts,
+                             ArrayRef<Expr *> Attrs) {
+  assert(Counts.size() == getNumPrefs() &&
+         "attr-count vector size must match number of pref-specs");
+  assert(Attrs.size() == NumAttrs &&
+         "attr-expr count must match preallocated NumAttrs");
+  llvm::copy(Counts, getTrailingObjects<unsigned>());
+  llvm::copy(Attrs, getTrailingObjects<Expr *>() + varlist_size());
 }
 
 OMPBindClause *
@@ -2388,17 +2421,42 @@ void OMPClausePrinter::VisitOMPHintClause(OMPHintClause 
*Node) {
 
 void OMPClausePrinter::VisitOMPInitClause(OMPInitClause *Node) {
   OS << "init(";
-  bool First = true;
-  for (const Expr *E : Node->prefs()) {
-    if (First)
-      OS << "prefer_type(";
-    else
-      OS << ",";
-    E->printPretty(OS, nullptr, Policy);
-    First = false;
-  }
-  if (!First)
+  unsigned NumPrefs = Node->getNumPrefs();
+  if (NumPrefs > 0) {
+    OS << "prefer_type(";
+    if (Node->getHasPreferAttrs()) {
+      // OMP 6.0 brace-grouped form
+      llvm::interleaveComma(
+          llvm::seq<unsigned>(0, NumPrefs), OS, [&](unsigned I) {
+            OMPInitClause::PrefView P = Node->getPref(I);
+            OS << "{";
+            if (P.Fr) {
+              OS << "fr(";
+              P.Fr->printPretty(OS, nullptr, Policy);
+              OS << ")";
+              if (!P.Attrs.empty())
+                OS << ", ";
+            }
+            if (!P.Attrs.empty()) {
+              OS << "attr(";
+              llvm::interleaveComma(P.Attrs, OS, [&](const Expr *A) {
+                A->printPretty(OS, nullptr, Policy);
+              });
+              OS << ")";
+            }
+            OS << "}";
+          });
+    } else {
+      llvm::interleave(
+          llvm::seq<unsigned>(0, NumPrefs), OS,
+          [&](unsigned I) {
+            if (Expr *Fr = Node->getPref(I).Fr)
+              Fr->printPretty(OS, nullptr, Policy);
+          },
+          ",");
+    }
     OS << "), ";
+  }
   if (Node->getIsTarget())
     OS << "target";
   if (Node->getIsTargetSync()) {
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index 7f3c575fb68bb..de844460c0a15 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -3681,6 +3681,55 @@ bool Parser::ParseOpenMPIndirectClause(
   return false;
 }
 
+ExprResult Parser::ParseOMPInteropFrSelector() {
+  ConsumeToken(); // 'fr'
+  BalancedDelimiterTracker FT(*this, tok::l_paren,
+                              tok::annot_pragma_openmp_end);
+  if (FT.expectAndConsume(diag::err_expected_lparen_after, "fr")) {
+    SkipUntil(
+        {tok::comma, tok::r_brace, tok::r_paren, tok::annot_pragma_openmp_end},
+        StopBeforeMatch);
+    return ExprError();
+  }
+  SourceLocation Loc = Tok.getLocation();
+  ExprResult LHS = ParseCastExpression(CastParseKind::AnyCastExpr);
+  ExprResult Arg = ParseRHSOfBinaryExpression(LHS, prec::Conditional);
+  Arg = Actions.ActOnFinishFullExpr(Arg.get(), Loc, /*DiscardedValue=*/false);
+  FT.consumeClose();
+  return Arg;
+}
+
+bool Parser::ParseOMPInteropAttrSelector(SmallVectorImpl<Expr *> &Attrs) {
+  ConsumeToken(); // 'attr'
+  BalancedDelimiterTracker AT(*this, tok::l_paren,
+                              tok::annot_pragma_openmp_end);
+  if (AT.expectAndConsume(diag::err_expected_lparen_after, "attr")) {
+    SkipUntil(
+        {tok::comma, tok::r_brace, tok::r_paren, tok::annot_pragma_openmp_end},
+        StopBeforeMatch);
+    return true;
+  }
+  bool HasError = false;
+  while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::r_brace) &&
+         Tok.isNot(tok::annot_pragma_openmp_end)) {
+    if (Tok.is(tok::string_literal)) {
+      ExprResult S = ParseStringLiteralExpression();
+      if (S.isUsable())
+        Attrs.push_back(S.get());
+      else
+        HasError = true;
+    } else {
+      HasError = true;
+      Diag(Tok, diag::err_expected) << tok::string_literal;
+      ConsumeToken();
+    }
+    if (Tok.is(tok::comma))
+      ConsumeToken();
+  }
+  AT.consumeClose();
+  return HasError;
+}
+
 bool Parser::ParseOMPInteropInfo(OMPInteropInfo &InteropInfo,
                                  OpenMPClauseKind Kind) {
   const Token &Tok = getCurToken();
@@ -3690,9 +3739,8 @@ bool Parser::ParseOMPInteropInfo(OMPInteropInfo 
&InteropInfo,
 
   while (Tok.is(tok::identifier)) {
     // Currently prefer_type is only allowed with 'init' and it must be first.
-    bool PreferTypeAllowed = Kind == OMPC_init &&
-                             InteropInfo.PreferTypes.empty() && !IsTarget &&
-                             !IsTargetSync;
+    bool PreferTypeAllowed = Kind == OMPC_init && InteropInfo.Prefs.empty() &&
+                             !IsTarget && !IsTargetSync;
     if (Tok.getIdentifierInfo()->isStr("target")) {
       // OpenMP 5.1 [2.15.1, interop Construct, Restrictions]
       // Each interop-type may be specified on an action-clause at most
@@ -3715,17 +3763,69 @@ bool Parser::ParseOMPInteropInfo(OMPInteropInfo 
&InteropInfo,
         HasError = true;
 
       while (Tok.isNot(tok::r_paren)) {
-        SourceLocation Loc = Tok.getLocation();
-        ExprResult LHS = ParseCastExpression(CastParseKind::AnyCastExpr);
-        ExprResult PTExpr = ParseRHSOfBinaryExpression(LHS, prec::Conditional);
-        PTExpr = Actions.ActOnFinishFullExpr(PTExpr.get(), Loc,
-                                             /*DiscardedValue=*/false);
-        if (PTExpr.isUsable()) {
-          InteropInfo.PreferTypes.push_back(PTExpr.get());
-        } else {
-          HasError = true;
-          SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
+        // OMP 6.0: { fr(...), attr(...) } brace-grouped pref-spec
+        if (Tok.is(tok::l_brace)) {
+          BalancedDelimiterTracker BT(*this, tok::l_brace,
+                                      tok::annot_pragma_openmp_end);
+          BT.consumeOpen();
+          Expr *FrExpr = nullptr;
+          SmallVector<Expr *, 2> AttrExprs;
+          bool SeenFr = false;
+
+          while (Tok.isNot(tok::r_brace) &&
+                 Tok.isNot(tok::annot_pragma_openmp_end)) {
+            if (!Tok.is(tok::identifier)) {
+              HasError = true;
+              Diag(Tok, diag::err_omp_expected_interop_type);
+              ConsumeToken();
+            } else if (Tok.getIdentifierInfo()->isStr("fr")) {
+              if (SeenFr) {
+                Diag(Tok, diag::err_omp_interop_multiple_fr);
+                HasError = true;
+                ConsumeToken(); // 'fr'
+                SkipUntil(
+                    {tok::comma, tok::r_brace, tok::annot_pragma_openmp_end},
                     StopBeforeMatch);
+                continue;
+              }
+              SeenFr = true;
+              ExprResult Fr = ParseOMPInteropFrSelector();
+              if (Fr.isUsable())
+                FrExpr = Fr.get();
+              else
+                HasError = true;
+            } else if (Tok.getIdentifierInfo()->isStr("attr")) {
+              if (ParseOMPInteropAttrSelector(AttrExprs))
+                HasError = true;
+            } else {
+              HasError = true;
+              Diag(Tok, diag::err_omp_expected_interop_type);
+              ConsumeToken();
+            }
+            if (Tok.is(tok::comma))
+              ConsumeToken();
+          }
+          if (BT.consumeClose())
+            HasError = true;
+
+          InteropInfo.Prefs.push_back({FrExpr, std::move(AttrExprs)});
+          InteropInfo.HasPreferAttrs = true;
+        } else {
+          // OMP 5.1: flat foreign-runtime-id (string or int). Stored as a
+          // pref-spec with Fr=expr and no attr() entries.
+          SourceLocation Loc = Tok.getLocation();
+          ExprResult LHS = ParseCastExpression(CastParseKind::AnyCastExpr);
+          ExprResult PTExpr =
+              ParseRHSOfBinaryExpression(LHS, prec::Conditional);
+          PTExpr = Actions.ActOnFinishFullExpr(PTExpr.get(), Loc,
+                                               /*DiscardedValue=*/false);
+          if (PTExpr.isUsable()) {
+            InteropInfo.Prefs.push_back({PTExpr.get(), {}});
+          } else {
+            HasError = true;
+            SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
+                      StopBeforeMatch);
+          }
         }
 
         if (Tok.is(tok::comma))
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index d6f6bc919a31b..ff3afd932bc27 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -18967,9 +18967,14 @@ OMPClause *SemaOpenMP::ActOnOpenMPInitClause(
   if (!isValidInteropVariable(SemaRef, InteropVar, VarLoc, OMPC_init))
     return nullptr;
 
-  // Check prefer_type values.  These foreign-runtime-id values are either
-  // string literals or constant integral expressions.
-  for (const Expr *E : InteropInfo.PreferTypes) {
+  // Check prefer_type values. fr() arguments are either string literals or
+  // constant integral expressions; null Fr is only valid in OMP 6.0
+  for (const OMPInteropPref &P : InteropInfo.Prefs) {
+    const Expr *E = P.Fr;
+    if (!E) {
+      assert(InteropInfo.HasPreferAttrs && "null Fr requires OMP 6.0 syntax");
+      continue;
+    }
     if (E->isValueDependent() || E->isTypeDependent() ||
         E->isInstantiationDependent() || E->containsUnexpandedParameterPack())
       continue;
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 9c0479fe8aa4f..736a30fe7535e 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -10997,13 +10997,28 @@ OMPClause 
*TreeTransform<Derived>::TransformOMPInitClause(OMPInitClause *C) {
     return nullptr;
 
   OMPInteropInfo InteropInfo(C->getIsTarget(), C->getIsTargetSync());
-  InteropInfo.PreferTypes.reserve(C->varlist_size() - 1);
-  for (Expr *E : llvm::drop_begin(C->varlist())) {
-    ExprResult ER = getDerived().TransformExpr(cast<Expr>(E));
-    if (ER.isInvalid())
-      return nullptr;
-    InteropInfo...
[truncated]

``````````

</details>


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

Reply via email to