Skip to content

Conversation

erichkeane
Copy link
Collaborator

Expressions/references with 'bounds' are going to need to do initialization significantly differently, so we need to have the initializer and the declaration 'separate' in the future. This patch splits the AST node into two, and normalizes them a bit.

Additionally, since this required significant work on the recipe generation, this patch also does a bit of a refactor to improve readability and future expansion, now that we have a good understanding of how these are going to look.

Expressions/references with 'bounds' are going to need to do
initialization significantly differently, so we need to have the
initializer and the declaration 'separate' in the future.  This patch
splits the AST node into two, and normalizes them a bit.

Additionally, since this required significant work on the recipe
generation, this patch also does a bit of a refactor to improve
readability and future expansion, now that we have a good understanding
of how these are going to look.
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:modules C++20 modules and Clang Header Modules clang:as-a-library libclang and C++ API ClangIR Anything related to the ClangIR project labels Sep 4, 2025
@llvmbot
Copy link
Member

llvmbot commented Sep 4, 2025

@llvm/pr-subscribers-clang-modules

@llvm/pr-subscribers-clang

Author: Erich Keane (erichkeane)

Changes

Expressions/references with 'bounds' are going to need to do initialization significantly differently, so we need to have the initializer and the declaration 'separate' in the future. This patch splits the AST node into two, and normalizes them a bit.

Additionally, since this required significant work on the recipe generation, this patch also does a bit of a refactor to improve readability and future expansion, now that we have a good understanding of how these are going to look.


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

11 Files Affected:

  • (modified) clang/include/clang/AST/OpenACCClause.h (+56-16)
  • (modified) clang/include/clang/Sema/SemaOpenACC.h (+6-15)
  • (modified) clang/lib/AST/OpenACCClause.cpp (+3-3)
  • (modified) clang/lib/AST/StmtProfile.cpp (+12-5)
  • (modified) clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp (+23-4)
  • (modified) clang/lib/Sema/SemaOpenACC.cpp (+188-193)
  • (modified) clang/lib/Sema/SemaOpenACCClause.cpp (+5-11)
  • (modified) clang/lib/Sema/TreeTransform.h (+13-24)
  • (modified) clang/lib/Serialization/ASTReader.cpp (+13-6)
  • (modified) clang/lib/Serialization/ASTWriter.cpp (+11-5)
  • (modified) clang/tools/libclang/CIndex.cpp (+8-5)
diff --git a/clang/include/clang/AST/OpenACCClause.h b/clang/include/clang/AST/OpenACCClause.h
index 2f4aba1cdcd90..081244fe0efb6 100644
--- a/clang/include/clang/AST/OpenACCClause.h
+++ b/clang/include/clang/AST/OpenACCClause.h
@@ -835,19 +835,40 @@ class OpenACCClauseWithVarList : public OpenACCClauseWithExprs {
   ArrayRef<Expr *> getVarList() const { return getExprs(); }
 };
 
+// Represents all the data needed for recipe generation.  The declaration and
+// init are stored separately, because in the case of subscripts, we do the
+// alloca at the level of the base, and the init at the element level.
+struct OpenACCPrivateRecipe {
+  VarDecl *AllocaDecl;
+  Expr *InitExpr;
+
+  OpenACCPrivateRecipe(VarDecl *A, Expr *I) : AllocaDecl(A), InitExpr(I) {
+    assert(!AllocaDecl || AllocaDecl->getInit() == nullptr);
+  }
+
+  bool isSet() const { return AllocaDecl; }
+
+  static OpenACCPrivateRecipe Empty() {
+    return OpenACCPrivateRecipe(nullptr, nullptr);
+  }
+};
+
 class OpenACCPrivateClause final
     : public OpenACCClauseWithVarList,
-      private llvm::TrailingObjects<OpenACCPrivateClause, Expr *, VarDecl *> {
+      private llvm::TrailingObjects<OpenACCPrivateClause, Expr *,
+                                    OpenACCPrivateRecipe> {
   friend TrailingObjects;
 
   OpenACCPrivateClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
                        ArrayRef<Expr *> VarList,
-                       ArrayRef<VarDecl *> InitRecipes, SourceLocation EndLoc)
+                       ArrayRef<OpenACCPrivateRecipe> InitRecipes,
+                       SourceLocation EndLoc)
       : OpenACCClauseWithVarList(OpenACCClauseKind::Private, BeginLoc,
                                  LParenLoc, EndLoc) {
     assert(VarList.size() == InitRecipes.size());
     setExprs(getTrailingObjects<Expr *>(VarList.size()), VarList);
-    llvm::uninitialized_copy(InitRecipes, getTrailingObjects<VarDecl *>());
+    llvm::uninitialized_copy(InitRecipes,
+                             getTrailingObjects<OpenACCPrivateRecipe>());
   }
 
 public:
@@ -856,19 +877,19 @@ class OpenACCPrivateClause final
   }
   // Gets a list of 'made up' `VarDecl` objects that can be used by codegen to
   // ensure that we properly initialize each of these variables.
-  ArrayRef<VarDecl *> getInitRecipes() {
-    return ArrayRef<VarDecl *>{getTrailingObjects<VarDecl *>(),
-                               getExprs().size()};
+  ArrayRef<OpenACCPrivateRecipe> getInitRecipes() {
+    return ArrayRef<OpenACCPrivateRecipe>{
+        getTrailingObjects<OpenACCPrivateRecipe>(), getExprs().size()};
   }
 
-  ArrayRef<VarDecl *> getInitRecipes() const {
-    return ArrayRef<VarDecl *>{getTrailingObjects<VarDecl *>(),
-                               getExprs().size()};
+  ArrayRef<OpenACCPrivateRecipe> getInitRecipes() const {
+    return ArrayRef<OpenACCPrivateRecipe>{
+        getTrailingObjects<OpenACCPrivateRecipe>(), getExprs().size()};
   }
 
   static OpenACCPrivateClause *
   Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
-         ArrayRef<Expr *> VarList, ArrayRef<VarDecl *> InitRecipes,
+         ArrayRef<Expr *> VarList, ArrayRef<OpenACCPrivateRecipe> InitRecipes,
          SourceLocation EndLoc);
 
   size_t numTrailingObjects(OverloadToken<Expr *>) const {
@@ -879,11 +900,20 @@ class OpenACCPrivateClause final
 // A 'pair' to stand in for the recipe.  RecipeDecl is the main declaration, and
 // InitFromTemporary is the 'temp' declaration we put in to be 'copied from'.
 struct OpenACCFirstPrivateRecipe {
-  VarDecl *RecipeDecl, *InitFromTemporary;
-  OpenACCFirstPrivateRecipe(VarDecl *R, VarDecl *T)
-      : RecipeDecl(R), InitFromTemporary(T) {}
-  OpenACCFirstPrivateRecipe(std::pair<VarDecl *, VarDecl *> p)
-      : RecipeDecl(p.first), InitFromTemporary(p.second) {}
+  VarDecl *AllocaDecl;
+  Expr *InitExpr;
+  VarDecl *InitFromTemporary;
+  OpenACCFirstPrivateRecipe(VarDecl *A, Expr *I, VarDecl *T)
+      : AllocaDecl(A), InitExpr(I), InitFromTemporary(T) {
+    assert(!AllocaDecl || AllocaDecl->getInit() == nullptr);
+    assert(!InitFromTemporary || InitFromTemporary->getInit() == nullptr);
+  }
+
+  bool isSet() const { return AllocaDecl; }
+
+  static OpenACCFirstPrivateRecipe Empty() {
+    return OpenACCFirstPrivateRecipe(nullptr, nullptr, nullptr);
+  }
 };
 
 class OpenACCFirstPrivateClause final
@@ -1253,8 +1283,18 @@ class OpenACCCreateClause final
 // A structure to stand in for the recipe on a reduction.  RecipeDecl is the
 // 'main' declaration used for initializaiton, which is fixed. 
 struct OpenACCReductionRecipe {
-  VarDecl *RecipeDecl;
+  VarDecl *AllocaDecl;
+  Expr *InitExpr;
   // TODO: OpenACC: this should eventually have the operations here too.
+
+  OpenACCReductionRecipe(VarDecl *A, Expr *I) : AllocaDecl(A), InitExpr(I) {
+    assert(!AllocaDecl || AllocaDecl->getInit() == nullptr);
+  }
+
+  bool isSet() const { return AllocaDecl; }
+  static OpenACCReductionRecipe Empty() {
+    return OpenACCReductionRecipe(nullptr, nullptr);
+  }
 };
 
 class OpenACCReductionClause final
diff --git a/clang/include/clang/Sema/SemaOpenACC.h b/clang/include/clang/Sema/SemaOpenACC.h
index 42e86582c3b06..09fdf75fbbd09 100644
--- a/clang/include/clang/Sema/SemaOpenACC.h
+++ b/clang/include/clang/Sema/SemaOpenACC.h
@@ -15,6 +15,7 @@
 #define LLVM_CLANG_SEMA_SEMAOPENACC_H
 
 #include "clang/AST/DeclGroup.h"
+#include "clang/AST/OpenACCClause.h"
 #include "clang/AST/StmtOpenACC.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/OpenACCKinds.h"
@@ -237,21 +238,11 @@ class SemaOpenACC : public SemaBase {
                                 SourceLocation ClauseLoc,
                                 ArrayRef<const OpenACCClause *> Clauses);
 
-  // Creates a VarDecl with a proper default init for the purposes of a
-  // `private`/'firstprivate'/'reduction' clause, so it can be used to generate
-  // a recipe later.
-  //  The first entry is the recipe itself, the second is any required
-  //  'temporary' created for the init (in the case of a copy), such as with
-  //  firstprivate.
-  std::pair<VarDecl *, VarDecl *> CreateInitRecipe(OpenACCClauseKind CK,
-                                                   const Expr *VarExpr) {
-    assert(CK != OpenACCClauseKind::Reduction);
-    return CreateInitRecipe(CK, OpenACCReductionOperator::Invalid, VarExpr);
-  }
-  std::pair<VarDecl *, VarDecl *>
-  CreateInitRecipe(OpenACCClauseKind CK,
-                   OpenACCReductionOperator ReductionOperator,
-                   const Expr *VarExpr);
+  OpenACCPrivateRecipe CreatePrivateInitRecipe(const Expr *VarExpr);
+  OpenACCFirstPrivateRecipe CreateFirstPrivateInitRecipe(const Expr *VarExpr);
+  OpenACCReductionRecipe
+  CreateReductionInitRecipe(OpenACCReductionOperator ReductionOperator,
+                            const Expr *VarExpr);
 
 public:
   ComputeConstructInfo &getActiveComputeConstructInfo() {
diff --git a/clang/lib/AST/OpenACCClause.cpp b/clang/lib/AST/OpenACCClause.cpp
index 9a9ede467331e..6c4bc7c274eaa 100644
--- a/clang/lib/AST/OpenACCClause.cpp
+++ b/clang/lib/AST/OpenACCClause.cpp
@@ -317,11 +317,11 @@ OpenACCTileClause *OpenACCTileClause::Create(const ASTContext &C,
 OpenACCPrivateClause *
 OpenACCPrivateClause::Create(const ASTContext &C, SourceLocation BeginLoc,
                              SourceLocation LParenLoc, ArrayRef<Expr *> VarList,
-                             ArrayRef<VarDecl *> InitRecipes,
+                             ArrayRef<OpenACCPrivateRecipe> InitRecipes,
                              SourceLocation EndLoc) {
   assert(VarList.size() == InitRecipes.size());
-  void *Mem =
-      C.Allocate(OpenACCPrivateClause::totalSizeToAlloc<Expr *, VarDecl *>(
+  void *Mem = C.Allocate(
+      OpenACCPrivateClause::totalSizeToAlloc<Expr *, OpenACCPrivateRecipe>(
           VarList.size(), InitRecipes.size()));
   return new (Mem)
       OpenACCPrivateClause(BeginLoc, LParenLoc, VarList, InitRecipes, EndLoc);
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 2035fa7635f2a..1bc21062203cb 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -2636,8 +2636,11 @@ void OpenACCClauseProfiler::VisitPrivateClause(
     const OpenACCPrivateClause &Clause) {
   VisitClauseWithVarList(Clause);
 
-  for (auto *VD : Clause.getInitRecipes())
-    Profiler.VisitDecl(VD);
+  for (auto &Recipe : Clause.getInitRecipes()) {
+    Profiler.VisitDecl(Recipe.AllocaDecl);
+    if (Recipe.InitExpr)
+      Profiler.VisitExpr(Recipe.InitExpr);
+  }
 }
 
 void OpenACCClauseProfiler::VisitFirstPrivateClause(
@@ -2645,7 +2648,9 @@ void OpenACCClauseProfiler::VisitFirstPrivateClause(
   VisitClauseWithVarList(Clause);
 
   for (auto &Recipe : Clause.getInitRecipes()) {
-    Profiler.VisitDecl(Recipe.RecipeDecl);
+    Profiler.VisitDecl(Recipe.AllocaDecl);
+    if (Recipe.InitExpr)
+      Profiler.VisitExpr(Recipe.InitExpr);
     Profiler.VisitDecl(Recipe.InitFromTemporary);
   }
 }
@@ -2750,11 +2755,13 @@ void OpenACCClauseProfiler::VisitReductionClause(
   VisitClauseWithVarList(Clause);
 
   for (auto &Recipe : Clause.getRecipes()) {
-    Profiler.VisitDecl(Recipe.RecipeDecl);
+    Profiler.VisitDecl(Recipe.AllocaDecl);
+    if (Recipe.InitExpr)
+      Profiler.VisitExpr(Recipe.InitExpr);
     // TODO: OpenACC: Make sure we remember to update this when we figure out
     // what we're adding for the operation recipe, in the meantime, a static
     // assert will make sure we don't add something.
-    static_assert(sizeof(OpenACCReductionRecipe) == sizeof(int *));
+    static_assert(sizeof(OpenACCReductionRecipe) == 2 * sizeof(int *));
   }
 }
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp b/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp
index 41834da8a86c3..0022befa3b562 100644
--- a/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp
@@ -1280,10 +1280,16 @@ class OpenACCClauseCIREmitter final
 
         {
           mlir::OpBuilder::InsertionGuard guardCase(builder);
+          // TODO: OpenACC: At the moment this is a bit of a hacky way of doing
+          // this, and won't work when we get to bounds/etc. Do this for now to
+          // limit the scope of this refactor.
+          VarDecl *allocaDecl = varRecipe.AllocaDecl;
+          allocaDecl->setInit(varRecipe.InitExpr);
+          allocaDecl->setInitStyle(VarDecl::CallInit);
+
           auto recipe = getOrCreateRecipe<mlir::acc::PrivateRecipeOp>(
-              cgf.getContext(), varExpr, varRecipe, /*temporary=*/nullptr,
+              cgf.getContext(), varExpr, allocaDecl, /*temporary=*/nullptr,
               OpenACCReductionOperator::Invalid,
-
               Decl::castToDeclContext(cgf.curFuncDecl), opInfo.baseType,
               privateOp.getResult());
           // TODO: OpenACC: The dialect is going to change in the near future to
@@ -1316,8 +1322,15 @@ class OpenACCClauseCIREmitter final
 
         {
           mlir::OpBuilder::InsertionGuard guardCase(builder);
+          // TODO: OpenACC: At the moment this is a bit of a hacky way of doing
+          // this, and won't work when we get to bounds/etc. Do this for now to
+          // limit the scope of this refactor.
+          VarDecl *allocaDecl = varRecipe.AllocaDecl;
+          allocaDecl->setInit(varRecipe.InitExpr);
+          allocaDecl->setInitStyle(VarDecl::CallInit);
+
           auto recipe = getOrCreateRecipe<mlir::acc::FirstprivateRecipeOp>(
-              cgf.getContext(), varExpr, varRecipe.RecipeDecl,
+              cgf.getContext(), varExpr, allocaDecl,
               varRecipe.InitFromTemporary, OpenACCReductionOperator::Invalid,
               Decl::castToDeclContext(cgf.curFuncDecl), opInfo.baseType,
               firstPrivateOp.getResult());
@@ -1353,9 +1366,15 @@ class OpenACCClauseCIREmitter final
 
         {
           mlir::OpBuilder::InsertionGuard guardCase(builder);
+          // TODO: OpenACC: At the moment this is a bit of a hacky way of doing
+          // this, and won't work when we get to bounds/etc. Do this for now to
+          // limit the scope of this refactor.
+          VarDecl *allocaDecl = varRecipe.AllocaDecl;
+          allocaDecl->setInit(varRecipe.InitExpr);
+          allocaDecl->setInitStyle(VarDecl::CallInit);
 
           auto recipe = getOrCreateRecipe<mlir::acc::ReductionRecipeOp>(
-              cgf.getContext(), varExpr, varRecipe.RecipeDecl,
+              cgf.getContext(), varExpr, allocaDecl,
               /*temporary=*/nullptr, clause.getReductionOp(),
               Decl::castToDeclContext(cgf.curFuncDecl), opInfo.baseType,
               reductionOp.getResult());
diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp
index 5082e2c272ebd..fbd8022cd68ba 100644
--- a/clang/lib/Sema/SemaOpenACC.cpp
+++ b/clang/lib/Sema/SemaOpenACC.cpp
@@ -2590,9 +2590,11 @@ SemaOpenACC::ActOnOpenACCAsteriskSizeExpr(SourceLocation AsteriskLoc) {
 }
 
 namespace {
-enum class InitKind { Zero, One, AllOnes, Least, Largest };
+enum class InitKind { Invalid, Zero, One, AllOnes, Least, Largest };
 llvm::APFloat getInitFloatValue(ASTContext &Context, InitKind IK, QualType Ty) {
   switch (IK) {
+  case InitKind::Invalid:
+    llvm_unreachable("invalid init kind");
   case InitKind::Zero:
     return llvm::APFloat::getZero(Context.getFloatTypeSemantics(Ty));
   case InitKind::One:
@@ -2604,13 +2606,14 @@ llvm::APFloat getInitFloatValue(ASTContext &Context, InitKind IK, QualType Ty) {
                                      /*Negative=*/true);
   case InitKind::Largest:
     return llvm::APFloat::getLargest(Context.getFloatTypeSemantics(Ty));
-    break;
   }
   llvm_unreachable("unknown init kind");
 }
 
 llvm::APInt getInitIntValue(ASTContext &Context, InitKind IK, QualType Ty) {
   switch (IK) {
+  case InitKind::Invalid:
+    llvm_unreachable("invalid init kind");
   case InitKind::Zero:
     return llvm::APInt(Context.getIntWidth(Ty), 0);
   case InitKind::One:
@@ -2625,7 +2628,6 @@ llvm::APInt getInitIntValue(ASTContext &Context, InitKind IK, QualType Ty) {
     if (Ty->isSignedIntegerOrEnumerationType())
       return llvm::APInt::getSignedMaxValue(Context.getIntWidth(Ty));
     return llvm::APInt::getMaxValue(Context.getIntWidth(Ty));
-    break;
   }
   llvm_unreachable("unknown init kind");
 }
@@ -2635,6 +2637,16 @@ llvm::APInt getInitIntValue(ASTContext &Context, InitKind IK, QualType Ty) {
 Expr *GenerateReductionInitRecipeExpr(ASTContext &Context,
                                       SourceRange ExprRange, QualType Ty,
                                       InitKind IK) {
+  if (IK == InitKind::Invalid)
+    return nullptr;
+
+  if (IK == InitKind::Zero) {
+    Expr *InitExpr = new (Context)
+        InitListExpr(Context, ExprRange.getBegin(), {}, ExprRange.getEnd());
+    InitExpr->setType(Context.VoidTy);
+    return InitExpr;
+  }
+
   Ty = Ty.getCanonicalType();
   llvm::SmallVector<Expr *> Exprs;
 
@@ -2712,219 +2724,202 @@ Expr *GenerateReductionInitRecipeExpr(ASTContext &Context,
   return InitExpr;
 }
 
-} // namespace
-
-std::pair<VarDecl *, VarDecl *>
-SemaOpenACC::CreateInitRecipe(OpenACCClauseKind CK,
-                              OpenACCReductionOperator ReductionOperator,
-                              const Expr *VarExpr) {
-  // Strip off any array subscripts/array section exprs to get to the type of
-  // the variable.
+const Expr *StripOffBounds(const Expr *VarExpr) {
   while (isa_and_present<ArraySectionExpr, ArraySubscriptExpr>(VarExpr)) {
     if (const auto *AS = dyn_cast<ArraySectionExpr>(VarExpr))
       VarExpr = AS->getBase()->IgnoreParenImpCasts();
     else if (const auto *Sub = dyn_cast<ArraySubscriptExpr>(VarExpr))
       VarExpr = Sub->getBase()->IgnoreParenImpCasts();
   }
+  return VarExpr;
+}
+
+VarDecl *CreateAllocaDecl(ASTContext &Ctx, DeclContext *DC,
+                          SourceLocation BeginLoc, IdentifierInfo *VarName,
+                          QualType VarTy) {
+  return VarDecl::Create(Ctx, DC, BeginLoc, BeginLoc, VarName, VarTy,
+                         Ctx.getTrivialTypeSourceInfo(VarTy), SC_Auto);
+}
+
+ExprResult FinishValueInit(Sema &S, InitializedEntity &Entity,
+                           SourceLocation Loc, QualType VarTy, Expr *InitExpr) {
+  if (!InitExpr)
+    return ExprEmpty();
+
+  InitializationKind Kind =
+      InitializationKind::CreateForInit(Loc, /*DirectInit=*/true, InitExpr);
+  InitializationSequence InitSeq(S, Entity, Kind, InitExpr,
+                                 /*TopLevelOfInitList=*/false,
+                                 /*TreatUnavailableAsInvalid=*/false);
+
+  return InitSeq.Perform(S, Entity, Kind, InitExpr, &VarTy);
+}
+
+} // namespace
+
+OpenACCPrivateRecipe SemaOpenACC::CreatePrivateInitRecipe(const Expr *VarExpr) {
+  VarExpr = StripOffBounds(VarExpr);
 
-  // If for some reason the expression is invalid, or this is dependent, just
-  // fill in with nullptr.  We'll count on TreeTransform to make this if
-  // necessary.
   if (!VarExpr || VarExpr->getType()->isDependentType())
-    return {nullptr, nullptr};
+    return OpenACCPrivateRecipe::Empty();
 
   QualType VarTy =
       VarExpr->getType().getNonReferenceType().getUnqualifiedType();
 
-  IdentifierInfo *VarName = [&]() {
-    switch (CK) {
-    case OpenACCClauseKind::Private:
-      return &getASTContext().Idents.get("openacc.private.init");
-    case OpenACCClauseKind::FirstPrivate:
-      return &getASTContext().Idents.get("openacc.firstprivate.init");
-    case OpenACCClauseKind::Reduction:
-      return &getASTContext().Idents.get("openacc.reduction.init");
-    default:
-      llvm_unreachable("Unknown clause kind?");
-    }
-  }();
+  // TODO: OpenACC: for arrays/bounds versions, we're going to have to do a
+  // different initializer, but for now we can go ahead with this.
 
-  VarDecl *Recipe = VarDecl::Create(
+  VarDecl *AllocaDecl = CreateAllocaDecl(
       getASTContext(), SemaRef.getCurContext(), VarExpr->getBeginLoc(),
-      VarExpr->getBeginLoc(), VarName, VarTy,
-      getASTContext().getTrivialTypeSourceInfo(VarTy), SC_Auto);
-
-  ExprResult Init;
-  VarDecl *Temporary = nullptr;
-  {
-    // Trap errors so we don't get weird ones here. If we can't init, we'll just
-    // swallow the errors.
-    Sema::TentativeAnalysisScope Trap{SemaRef};
-    InitializedEntity Entity = InitializedEntity::InitializeVariable(Recipe);
-
-    auto FinishValueInit = [&](Expr *InitExpr) {
-      if (InitExpr) {
-        InitializationKind Kind = InitializationKind::CreateForInit(
-            Recipe->getLocation(), /*DirectInit=*/true, InitExpr);
-        InitializationSequence InitSeq(SemaRef.SemaRef, Entity, Kind, InitExpr,
-                                       /*TopLevelOfInitList=*/false,
-                                       /*TreatUnavailableAsInvalid=*/false);
-        return InitSeq.Perform(SemaRef.SemaRef, Entity, Kind, InitExpr, &VarTy);
-      }
-      return ExprEmpty();
-    };
+      &getASTContext().Idents.get("openacc.private.init"), VarTy);
 
-    if (CK == OpenACCClauseKind::Private) {
-      InitializationKind Kind =
-          InitializationKind::CreateDefault(Recipe->getLocation());
-
-      InitializationSequence InitSeq(SemaRef.SemaRef, Entity, Kind, {});
-      Init = InitSeq.Perform(SemaRef.SemaRef, Entity, Kind, {});
-    } else if (CK == OpenACCClauseKind::FirstPrivate) {
-      // Create a VarDecl to be the 'copied-from' for the copy section of the
-      // recipe. This allows us to make the association so that we can use the
-      // standard 'generation' ability of the init.
-      Temporary = VarDecl::Create(
-          getASTContext(), SemaRef.getCurContext(), VarExpr->getBeginLoc(),
-          VarExpr->getBeginLoc(), &getASTContext().Idents.get("openacc.temp"),
-          VarTy, getASTContext().getTrivialTypeSourceInfo(VarTy), SC_Auto);
-      auto *TemporaryDRE = DeclRefExpr::Create(
-          getASTContext(), NestedNameSpecifierLoc{}, SourceLocation{},
-          Temporary,
-          /*ReferstoEnclosingVariableOrCapture=*/false,
-          DeclarationNameInfo{DeclarationName{Temporary->getDeclName()},
-                              VarExpr->getBeginLoc()},
-          VarTy, clang::VK_LValue, Temporary, nullptr, NOUR_None);
-
-      Expr *InitExpr = nullptr;
-
-      if (const auto *ArrTy = getASTContext().getAsConstantArrayType(VarTy)) {
-        // Arrays need to have each individua...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Sep 4, 2025

@llvm/pr-subscribers-clangir

Author: Erich Keane (erichkeane)

Changes

Expressions/references with 'bounds' are going to need to do initialization significantly differently, so we need to have the initializer and the declaration 'separate' in the future. This patch splits the AST node into two, and normalizes them a bit.

Additionally, since this required significant work on the recipe generation, this patch also does a bit of a refactor to improve readability and future expansion, now that we have a good understanding of how these are going to look.


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

11 Files Affected:

  • (modified) clang/include/clang/AST/OpenACCClause.h (+56-16)
  • (modified) clang/include/clang/Sema/SemaOpenACC.h (+6-15)
  • (modified) clang/lib/AST/OpenACCClause.cpp (+3-3)
  • (modified) clang/lib/AST/StmtProfile.cpp (+12-5)
  • (modified) clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp (+23-4)
  • (modified) clang/lib/Sema/SemaOpenACC.cpp (+188-193)
  • (modified) clang/lib/Sema/SemaOpenACCClause.cpp (+5-11)
  • (modified) clang/lib/Sema/TreeTransform.h (+13-24)
  • (modified) clang/lib/Serialization/ASTReader.cpp (+13-6)
  • (modified) clang/lib/Serialization/ASTWriter.cpp (+11-5)
  • (modified) clang/tools/libclang/CIndex.cpp (+8-5)
diff --git a/clang/include/clang/AST/OpenACCClause.h b/clang/include/clang/AST/OpenACCClause.h
index 2f4aba1cdcd90..081244fe0efb6 100644
--- a/clang/include/clang/AST/OpenACCClause.h
+++ b/clang/include/clang/AST/OpenACCClause.h
@@ -835,19 +835,40 @@ class OpenACCClauseWithVarList : public OpenACCClauseWithExprs {
   ArrayRef<Expr *> getVarList() const { return getExprs(); }
 };
 
+// Represents all the data needed for recipe generation.  The declaration and
+// init are stored separately, because in the case of subscripts, we do the
+// alloca at the level of the base, and the init at the element level.
+struct OpenACCPrivateRecipe {
+  VarDecl *AllocaDecl;
+  Expr *InitExpr;
+
+  OpenACCPrivateRecipe(VarDecl *A, Expr *I) : AllocaDecl(A), InitExpr(I) {
+    assert(!AllocaDecl || AllocaDecl->getInit() == nullptr);
+  }
+
+  bool isSet() const { return AllocaDecl; }
+
+  static OpenACCPrivateRecipe Empty() {
+    return OpenACCPrivateRecipe(nullptr, nullptr);
+  }
+};
+
 class OpenACCPrivateClause final
     : public OpenACCClauseWithVarList,
-      private llvm::TrailingObjects<OpenACCPrivateClause, Expr *, VarDecl *> {
+      private llvm::TrailingObjects<OpenACCPrivateClause, Expr *,
+                                    OpenACCPrivateRecipe> {
   friend TrailingObjects;
 
   OpenACCPrivateClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
                        ArrayRef<Expr *> VarList,
-                       ArrayRef<VarDecl *> InitRecipes, SourceLocation EndLoc)
+                       ArrayRef<OpenACCPrivateRecipe> InitRecipes,
+                       SourceLocation EndLoc)
       : OpenACCClauseWithVarList(OpenACCClauseKind::Private, BeginLoc,
                                  LParenLoc, EndLoc) {
     assert(VarList.size() == InitRecipes.size());
     setExprs(getTrailingObjects<Expr *>(VarList.size()), VarList);
-    llvm::uninitialized_copy(InitRecipes, getTrailingObjects<VarDecl *>());
+    llvm::uninitialized_copy(InitRecipes,
+                             getTrailingObjects<OpenACCPrivateRecipe>());
   }
 
 public:
@@ -856,19 +877,19 @@ class OpenACCPrivateClause final
   }
   // Gets a list of 'made up' `VarDecl` objects that can be used by codegen to
   // ensure that we properly initialize each of these variables.
-  ArrayRef<VarDecl *> getInitRecipes() {
-    return ArrayRef<VarDecl *>{getTrailingObjects<VarDecl *>(),
-                               getExprs().size()};
+  ArrayRef<OpenACCPrivateRecipe> getInitRecipes() {
+    return ArrayRef<OpenACCPrivateRecipe>{
+        getTrailingObjects<OpenACCPrivateRecipe>(), getExprs().size()};
   }
 
-  ArrayRef<VarDecl *> getInitRecipes() const {
-    return ArrayRef<VarDecl *>{getTrailingObjects<VarDecl *>(),
-                               getExprs().size()};
+  ArrayRef<OpenACCPrivateRecipe> getInitRecipes() const {
+    return ArrayRef<OpenACCPrivateRecipe>{
+        getTrailingObjects<OpenACCPrivateRecipe>(), getExprs().size()};
   }
 
   static OpenACCPrivateClause *
   Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
-         ArrayRef<Expr *> VarList, ArrayRef<VarDecl *> InitRecipes,
+         ArrayRef<Expr *> VarList, ArrayRef<OpenACCPrivateRecipe> InitRecipes,
          SourceLocation EndLoc);
 
   size_t numTrailingObjects(OverloadToken<Expr *>) const {
@@ -879,11 +900,20 @@ class OpenACCPrivateClause final
 // A 'pair' to stand in for the recipe.  RecipeDecl is the main declaration, and
 // InitFromTemporary is the 'temp' declaration we put in to be 'copied from'.
 struct OpenACCFirstPrivateRecipe {
-  VarDecl *RecipeDecl, *InitFromTemporary;
-  OpenACCFirstPrivateRecipe(VarDecl *R, VarDecl *T)
-      : RecipeDecl(R), InitFromTemporary(T) {}
-  OpenACCFirstPrivateRecipe(std::pair<VarDecl *, VarDecl *> p)
-      : RecipeDecl(p.first), InitFromTemporary(p.second) {}
+  VarDecl *AllocaDecl;
+  Expr *InitExpr;
+  VarDecl *InitFromTemporary;
+  OpenACCFirstPrivateRecipe(VarDecl *A, Expr *I, VarDecl *T)
+      : AllocaDecl(A), InitExpr(I), InitFromTemporary(T) {
+    assert(!AllocaDecl || AllocaDecl->getInit() == nullptr);
+    assert(!InitFromTemporary || InitFromTemporary->getInit() == nullptr);
+  }
+
+  bool isSet() const { return AllocaDecl; }
+
+  static OpenACCFirstPrivateRecipe Empty() {
+    return OpenACCFirstPrivateRecipe(nullptr, nullptr, nullptr);
+  }
 };
 
 class OpenACCFirstPrivateClause final
@@ -1253,8 +1283,18 @@ class OpenACCCreateClause final
 // A structure to stand in for the recipe on a reduction.  RecipeDecl is the
 // 'main' declaration used for initializaiton, which is fixed. 
 struct OpenACCReductionRecipe {
-  VarDecl *RecipeDecl;
+  VarDecl *AllocaDecl;
+  Expr *InitExpr;
   // TODO: OpenACC: this should eventually have the operations here too.
+
+  OpenACCReductionRecipe(VarDecl *A, Expr *I) : AllocaDecl(A), InitExpr(I) {
+    assert(!AllocaDecl || AllocaDecl->getInit() == nullptr);
+  }
+
+  bool isSet() const { return AllocaDecl; }
+  static OpenACCReductionRecipe Empty() {
+    return OpenACCReductionRecipe(nullptr, nullptr);
+  }
 };
 
 class OpenACCReductionClause final
diff --git a/clang/include/clang/Sema/SemaOpenACC.h b/clang/include/clang/Sema/SemaOpenACC.h
index 42e86582c3b06..09fdf75fbbd09 100644
--- a/clang/include/clang/Sema/SemaOpenACC.h
+++ b/clang/include/clang/Sema/SemaOpenACC.h
@@ -15,6 +15,7 @@
 #define LLVM_CLANG_SEMA_SEMAOPENACC_H
 
 #include "clang/AST/DeclGroup.h"
+#include "clang/AST/OpenACCClause.h"
 #include "clang/AST/StmtOpenACC.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/OpenACCKinds.h"
@@ -237,21 +238,11 @@ class SemaOpenACC : public SemaBase {
                                 SourceLocation ClauseLoc,
                                 ArrayRef<const OpenACCClause *> Clauses);
 
-  // Creates a VarDecl with a proper default init for the purposes of a
-  // `private`/'firstprivate'/'reduction' clause, so it can be used to generate
-  // a recipe later.
-  //  The first entry is the recipe itself, the second is any required
-  //  'temporary' created for the init (in the case of a copy), such as with
-  //  firstprivate.
-  std::pair<VarDecl *, VarDecl *> CreateInitRecipe(OpenACCClauseKind CK,
-                                                   const Expr *VarExpr) {
-    assert(CK != OpenACCClauseKind::Reduction);
-    return CreateInitRecipe(CK, OpenACCReductionOperator::Invalid, VarExpr);
-  }
-  std::pair<VarDecl *, VarDecl *>
-  CreateInitRecipe(OpenACCClauseKind CK,
-                   OpenACCReductionOperator ReductionOperator,
-                   const Expr *VarExpr);
+  OpenACCPrivateRecipe CreatePrivateInitRecipe(const Expr *VarExpr);
+  OpenACCFirstPrivateRecipe CreateFirstPrivateInitRecipe(const Expr *VarExpr);
+  OpenACCReductionRecipe
+  CreateReductionInitRecipe(OpenACCReductionOperator ReductionOperator,
+                            const Expr *VarExpr);
 
 public:
   ComputeConstructInfo &getActiveComputeConstructInfo() {
diff --git a/clang/lib/AST/OpenACCClause.cpp b/clang/lib/AST/OpenACCClause.cpp
index 9a9ede467331e..6c4bc7c274eaa 100644
--- a/clang/lib/AST/OpenACCClause.cpp
+++ b/clang/lib/AST/OpenACCClause.cpp
@@ -317,11 +317,11 @@ OpenACCTileClause *OpenACCTileClause::Create(const ASTContext &C,
 OpenACCPrivateClause *
 OpenACCPrivateClause::Create(const ASTContext &C, SourceLocation BeginLoc,
                              SourceLocation LParenLoc, ArrayRef<Expr *> VarList,
-                             ArrayRef<VarDecl *> InitRecipes,
+                             ArrayRef<OpenACCPrivateRecipe> InitRecipes,
                              SourceLocation EndLoc) {
   assert(VarList.size() == InitRecipes.size());
-  void *Mem =
-      C.Allocate(OpenACCPrivateClause::totalSizeToAlloc<Expr *, VarDecl *>(
+  void *Mem = C.Allocate(
+      OpenACCPrivateClause::totalSizeToAlloc<Expr *, OpenACCPrivateRecipe>(
           VarList.size(), InitRecipes.size()));
   return new (Mem)
       OpenACCPrivateClause(BeginLoc, LParenLoc, VarList, InitRecipes, EndLoc);
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 2035fa7635f2a..1bc21062203cb 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -2636,8 +2636,11 @@ void OpenACCClauseProfiler::VisitPrivateClause(
     const OpenACCPrivateClause &Clause) {
   VisitClauseWithVarList(Clause);
 
-  for (auto *VD : Clause.getInitRecipes())
-    Profiler.VisitDecl(VD);
+  for (auto &Recipe : Clause.getInitRecipes()) {
+    Profiler.VisitDecl(Recipe.AllocaDecl);
+    if (Recipe.InitExpr)
+      Profiler.VisitExpr(Recipe.InitExpr);
+  }
 }
 
 void OpenACCClauseProfiler::VisitFirstPrivateClause(
@@ -2645,7 +2648,9 @@ void OpenACCClauseProfiler::VisitFirstPrivateClause(
   VisitClauseWithVarList(Clause);
 
   for (auto &Recipe : Clause.getInitRecipes()) {
-    Profiler.VisitDecl(Recipe.RecipeDecl);
+    Profiler.VisitDecl(Recipe.AllocaDecl);
+    if (Recipe.InitExpr)
+      Profiler.VisitExpr(Recipe.InitExpr);
     Profiler.VisitDecl(Recipe.InitFromTemporary);
   }
 }
@@ -2750,11 +2755,13 @@ void OpenACCClauseProfiler::VisitReductionClause(
   VisitClauseWithVarList(Clause);
 
   for (auto &Recipe : Clause.getRecipes()) {
-    Profiler.VisitDecl(Recipe.RecipeDecl);
+    Profiler.VisitDecl(Recipe.AllocaDecl);
+    if (Recipe.InitExpr)
+      Profiler.VisitExpr(Recipe.InitExpr);
     // TODO: OpenACC: Make sure we remember to update this when we figure out
     // what we're adding for the operation recipe, in the meantime, a static
     // assert will make sure we don't add something.
-    static_assert(sizeof(OpenACCReductionRecipe) == sizeof(int *));
+    static_assert(sizeof(OpenACCReductionRecipe) == 2 * sizeof(int *));
   }
 }
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp b/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp
index 41834da8a86c3..0022befa3b562 100644
--- a/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp
@@ -1280,10 +1280,16 @@ class OpenACCClauseCIREmitter final
 
         {
           mlir::OpBuilder::InsertionGuard guardCase(builder);
+          // TODO: OpenACC: At the moment this is a bit of a hacky way of doing
+          // this, and won't work when we get to bounds/etc. Do this for now to
+          // limit the scope of this refactor.
+          VarDecl *allocaDecl = varRecipe.AllocaDecl;
+          allocaDecl->setInit(varRecipe.InitExpr);
+          allocaDecl->setInitStyle(VarDecl::CallInit);
+
           auto recipe = getOrCreateRecipe<mlir::acc::PrivateRecipeOp>(
-              cgf.getContext(), varExpr, varRecipe, /*temporary=*/nullptr,
+              cgf.getContext(), varExpr, allocaDecl, /*temporary=*/nullptr,
               OpenACCReductionOperator::Invalid,
-
               Decl::castToDeclContext(cgf.curFuncDecl), opInfo.baseType,
               privateOp.getResult());
           // TODO: OpenACC: The dialect is going to change in the near future to
@@ -1316,8 +1322,15 @@ class OpenACCClauseCIREmitter final
 
         {
           mlir::OpBuilder::InsertionGuard guardCase(builder);
+          // TODO: OpenACC: At the moment this is a bit of a hacky way of doing
+          // this, and won't work when we get to bounds/etc. Do this for now to
+          // limit the scope of this refactor.
+          VarDecl *allocaDecl = varRecipe.AllocaDecl;
+          allocaDecl->setInit(varRecipe.InitExpr);
+          allocaDecl->setInitStyle(VarDecl::CallInit);
+
           auto recipe = getOrCreateRecipe<mlir::acc::FirstprivateRecipeOp>(
-              cgf.getContext(), varExpr, varRecipe.RecipeDecl,
+              cgf.getContext(), varExpr, allocaDecl,
               varRecipe.InitFromTemporary, OpenACCReductionOperator::Invalid,
               Decl::castToDeclContext(cgf.curFuncDecl), opInfo.baseType,
               firstPrivateOp.getResult());
@@ -1353,9 +1366,15 @@ class OpenACCClauseCIREmitter final
 
         {
           mlir::OpBuilder::InsertionGuard guardCase(builder);
+          // TODO: OpenACC: At the moment this is a bit of a hacky way of doing
+          // this, and won't work when we get to bounds/etc. Do this for now to
+          // limit the scope of this refactor.
+          VarDecl *allocaDecl = varRecipe.AllocaDecl;
+          allocaDecl->setInit(varRecipe.InitExpr);
+          allocaDecl->setInitStyle(VarDecl::CallInit);
 
           auto recipe = getOrCreateRecipe<mlir::acc::ReductionRecipeOp>(
-              cgf.getContext(), varExpr, varRecipe.RecipeDecl,
+              cgf.getContext(), varExpr, allocaDecl,
               /*temporary=*/nullptr, clause.getReductionOp(),
               Decl::castToDeclContext(cgf.curFuncDecl), opInfo.baseType,
               reductionOp.getResult());
diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp
index 5082e2c272ebd..fbd8022cd68ba 100644
--- a/clang/lib/Sema/SemaOpenACC.cpp
+++ b/clang/lib/Sema/SemaOpenACC.cpp
@@ -2590,9 +2590,11 @@ SemaOpenACC::ActOnOpenACCAsteriskSizeExpr(SourceLocation AsteriskLoc) {
 }
 
 namespace {
-enum class InitKind { Zero, One, AllOnes, Least, Largest };
+enum class InitKind { Invalid, Zero, One, AllOnes, Least, Largest };
 llvm::APFloat getInitFloatValue(ASTContext &Context, InitKind IK, QualType Ty) {
   switch (IK) {
+  case InitKind::Invalid:
+    llvm_unreachable("invalid init kind");
   case InitKind::Zero:
     return llvm::APFloat::getZero(Context.getFloatTypeSemantics(Ty));
   case InitKind::One:
@@ -2604,13 +2606,14 @@ llvm::APFloat getInitFloatValue(ASTContext &Context, InitKind IK, QualType Ty) {
                                      /*Negative=*/true);
   case InitKind::Largest:
     return llvm::APFloat::getLargest(Context.getFloatTypeSemantics(Ty));
-    break;
   }
   llvm_unreachable("unknown init kind");
 }
 
 llvm::APInt getInitIntValue(ASTContext &Context, InitKind IK, QualType Ty) {
   switch (IK) {
+  case InitKind::Invalid:
+    llvm_unreachable("invalid init kind");
   case InitKind::Zero:
     return llvm::APInt(Context.getIntWidth(Ty), 0);
   case InitKind::One:
@@ -2625,7 +2628,6 @@ llvm::APInt getInitIntValue(ASTContext &Context, InitKind IK, QualType Ty) {
     if (Ty->isSignedIntegerOrEnumerationType())
       return llvm::APInt::getSignedMaxValue(Context.getIntWidth(Ty));
     return llvm::APInt::getMaxValue(Context.getIntWidth(Ty));
-    break;
   }
   llvm_unreachable("unknown init kind");
 }
@@ -2635,6 +2637,16 @@ llvm::APInt getInitIntValue(ASTContext &Context, InitKind IK, QualType Ty) {
 Expr *GenerateReductionInitRecipeExpr(ASTContext &Context,
                                       SourceRange ExprRange, QualType Ty,
                                       InitKind IK) {
+  if (IK == InitKind::Invalid)
+    return nullptr;
+
+  if (IK == InitKind::Zero) {
+    Expr *InitExpr = new (Context)
+        InitListExpr(Context, ExprRange.getBegin(), {}, ExprRange.getEnd());
+    InitExpr->setType(Context.VoidTy);
+    return InitExpr;
+  }
+
   Ty = Ty.getCanonicalType();
   llvm::SmallVector<Expr *> Exprs;
 
@@ -2712,219 +2724,202 @@ Expr *GenerateReductionInitRecipeExpr(ASTContext &Context,
   return InitExpr;
 }
 
-} // namespace
-
-std::pair<VarDecl *, VarDecl *>
-SemaOpenACC::CreateInitRecipe(OpenACCClauseKind CK,
-                              OpenACCReductionOperator ReductionOperator,
-                              const Expr *VarExpr) {
-  // Strip off any array subscripts/array section exprs to get to the type of
-  // the variable.
+const Expr *StripOffBounds(const Expr *VarExpr) {
   while (isa_and_present<ArraySectionExpr, ArraySubscriptExpr>(VarExpr)) {
     if (const auto *AS = dyn_cast<ArraySectionExpr>(VarExpr))
       VarExpr = AS->getBase()->IgnoreParenImpCasts();
     else if (const auto *Sub = dyn_cast<ArraySubscriptExpr>(VarExpr))
       VarExpr = Sub->getBase()->IgnoreParenImpCasts();
   }
+  return VarExpr;
+}
+
+VarDecl *CreateAllocaDecl(ASTContext &Ctx, DeclContext *DC,
+                          SourceLocation BeginLoc, IdentifierInfo *VarName,
+                          QualType VarTy) {
+  return VarDecl::Create(Ctx, DC, BeginLoc, BeginLoc, VarName, VarTy,
+                         Ctx.getTrivialTypeSourceInfo(VarTy), SC_Auto);
+}
+
+ExprResult FinishValueInit(Sema &S, InitializedEntity &Entity,
+                           SourceLocation Loc, QualType VarTy, Expr *InitExpr) {
+  if (!InitExpr)
+    return ExprEmpty();
+
+  InitializationKind Kind =
+      InitializationKind::CreateForInit(Loc, /*DirectInit=*/true, InitExpr);
+  InitializationSequence InitSeq(S, Entity, Kind, InitExpr,
+                                 /*TopLevelOfInitList=*/false,
+                                 /*TreatUnavailableAsInvalid=*/false);
+
+  return InitSeq.Perform(S, Entity, Kind, InitExpr, &VarTy);
+}
+
+} // namespace
+
+OpenACCPrivateRecipe SemaOpenACC::CreatePrivateInitRecipe(const Expr *VarExpr) {
+  VarExpr = StripOffBounds(VarExpr);
 
-  // If for some reason the expression is invalid, or this is dependent, just
-  // fill in with nullptr.  We'll count on TreeTransform to make this if
-  // necessary.
   if (!VarExpr || VarExpr->getType()->isDependentType())
-    return {nullptr, nullptr};
+    return OpenACCPrivateRecipe::Empty();
 
   QualType VarTy =
       VarExpr->getType().getNonReferenceType().getUnqualifiedType();
 
-  IdentifierInfo *VarName = [&]() {
-    switch (CK) {
-    case OpenACCClauseKind::Private:
-      return &getASTContext().Idents.get("openacc.private.init");
-    case OpenACCClauseKind::FirstPrivate:
-      return &getASTContext().Idents.get("openacc.firstprivate.init");
-    case OpenACCClauseKind::Reduction:
-      return &getASTContext().Idents.get("openacc.reduction.init");
-    default:
-      llvm_unreachable("Unknown clause kind?");
-    }
-  }();
+  // TODO: OpenACC: for arrays/bounds versions, we're going to have to do a
+  // different initializer, but for now we can go ahead with this.
 
-  VarDecl *Recipe = VarDecl::Create(
+  VarDecl *AllocaDecl = CreateAllocaDecl(
       getASTContext(), SemaRef.getCurContext(), VarExpr->getBeginLoc(),
-      VarExpr->getBeginLoc(), VarName, VarTy,
-      getASTContext().getTrivialTypeSourceInfo(VarTy), SC_Auto);
-
-  ExprResult Init;
-  VarDecl *Temporary = nullptr;
-  {
-    // Trap errors so we don't get weird ones here. If we can't init, we'll just
-    // swallow the errors.
-    Sema::TentativeAnalysisScope Trap{SemaRef};
-    InitializedEntity Entity = InitializedEntity::InitializeVariable(Recipe);
-
-    auto FinishValueInit = [&](Expr *InitExpr) {
-      if (InitExpr) {
-        InitializationKind Kind = InitializationKind::CreateForInit(
-            Recipe->getLocation(), /*DirectInit=*/true, InitExpr);
-        InitializationSequence InitSeq(SemaRef.SemaRef, Entity, Kind, InitExpr,
-                                       /*TopLevelOfInitList=*/false,
-                                       /*TreatUnavailableAsInvalid=*/false);
-        return InitSeq.Perform(SemaRef.SemaRef, Entity, Kind, InitExpr, &VarTy);
-      }
-      return ExprEmpty();
-    };
+      &getASTContext().Idents.get("openacc.private.init"), VarTy);
 
-    if (CK == OpenACCClauseKind::Private) {
-      InitializationKind Kind =
-          InitializationKind::CreateDefault(Recipe->getLocation());
-
-      InitializationSequence InitSeq(SemaRef.SemaRef, Entity, Kind, {});
-      Init = InitSeq.Perform(SemaRef.SemaRef, Entity, Kind, {});
-    } else if (CK == OpenACCClauseKind::FirstPrivate) {
-      // Create a VarDecl to be the 'copied-from' for the copy section of the
-      // recipe. This allows us to make the association so that we can use the
-      // standard 'generation' ability of the init.
-      Temporary = VarDecl::Create(
-          getASTContext(), SemaRef.getCurContext(), VarExpr->getBeginLoc(),
-          VarExpr->getBeginLoc(), &getASTContext().Idents.get("openacc.temp"),
-          VarTy, getASTContext().getTrivialTypeSourceInfo(VarTy), SC_Auto);
-      auto *TemporaryDRE = DeclRefExpr::Create(
-          getASTContext(), NestedNameSpecifierLoc{}, SourceLocation{},
-          Temporary,
-          /*ReferstoEnclosingVariableOrCapture=*/false,
-          DeclarationNameInfo{DeclarationName{Temporary->getDeclName()},
-                              VarExpr->getBeginLoc()},
-          VarTy, clang::VK_LValue, Temporary, nullptr, NOUR_None);
-
-      Expr *InitExpr = nullptr;
-
-      if (const auto *ArrTy = getASTContext().getAsConstantArrayType(VarTy)) {
-        // Arrays need to have each individua...
[truncated]

Copy link
Contributor

@andykaylor andykaylor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@erichkeane erichkeane merged commit 1a16bc1 into llvm:main Sep 4, 2025
17 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented Sep 4, 2025

LLVM Buildbot has detected a new failure on builder cross-project-tests-sie-ubuntu-dwarf5 running on doug-worker-1b while building clang at step 6 "test-build-unified-tree-check-cross-project".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/163/builds/25924

Here is the relevant piece of the build log for the reference
Step 6 (test-build-unified-tree-check-cross-project) failure: test (failure)
******************** TEST 'cross-project-tests :: debuginfo-tests/dexter/feature_tests/commands/perfect/limit_steps/limit_steps_expect_loop.cpp' FAILED ********************
Exit Code: 2

Command Output (stderr):
--
clang++ -O0 -glldb -std=gnu++11 /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/llvm-project/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/perfect/limit_steps/limit_steps_expect_loop.cpp -o /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/build/projects/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/perfect/limit_steps/Output/limit_steps_expect_loop.cpp.tmp # RUN: at line 5
+ clang++ -O0 -glldb -std=gnu++11 /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/llvm-project/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/perfect/limit_steps/limit_steps_expect_loop.cpp -o /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/build/projects/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/perfect/limit_steps/Output/limit_steps_expect_loop.cpp.tmp
"/usr/bin/python3.10" "/home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/llvm-project/cross-project-tests/debuginfo-tests/dexter/dexter.py" test --fail-lt 1.0 -w --debugger lldb-dap --lldb-executable "/home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/build/bin/lldb-dap" --binary /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/build/projects/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/perfect/limit_steps/Output/limit_steps_expect_loop.cpp.tmp -- /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/llvm-project/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/perfect/limit_steps/limit_steps_expect_loop.cpp | /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/build/bin/FileCheck /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/llvm-project/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/perfect/limit_steps/limit_steps_expect_loop.cpp # RUN: at line 6
+ /usr/bin/python3.10 /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/llvm-project/cross-project-tests/debuginfo-tests/dexter/dexter.py test --fail-lt 1.0 -w --debugger lldb-dap --lldb-executable /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/build/bin/lldb-dap --binary /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/build/projects/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/perfect/limit_steps/Output/limit_steps_expect_loop.cpp.tmp -- /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/llvm-project/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/perfect/limit_steps/limit_steps_expect_loop.cpp
+ /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/build/bin/FileCheck /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/llvm-project/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/perfect/limit_steps/limit_steps_expect_loop.cpp

--

********************


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:as-a-library libclang and C++ API clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:modules C++20 modules and Clang Header Modules clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants