[clang] [Clang] Implement P0963R3 "Structured binding declaration as a condition" (PR #130228)

via cfe-commits cfe-commits at lists.llvm.org
Mon Mar 10 01:08:46 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-modules

Author: Younan Zhang (zyn0217)

<details>
<summary>Changes</summary>

Todo:

- [x] Adapt the bytecode interpreter to the new evaluation model

- [x] Tests for CG & Constant evaluation

- [x] Release notes

With this patch, the example shown in https://gcc.godbolt.org/z/3h74oq8zW (the R2 semantics) works now.

---

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


23 Files Affected:

- (modified) clang/docs/ReleaseNotes.rst (+2) 
- (modified) clang/include/clang/AST/DeclCXX.h (+19-8) 
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+6-2) 
- (modified) clang/lib/AST/ASTImporter.cpp (+4-3) 
- (modified) clang/lib/AST/ByteCode/Compiler.cpp (+39-6) 
- (modified) clang/lib/AST/ByteCode/Compiler.h (+1) 
- (modified) clang/lib/AST/DeclCXX.cpp (+12-9) 
- (modified) clang/lib/AST/ExprConstant.cpp (+26-4) 
- (modified) clang/lib/CodeGen/CGDecl.cpp (+9-4) 
- (modified) clang/lib/CodeGen/CGStmt.cpp (+35-3) 
- (modified) clang/lib/CodeGen/CodeGenFunction.cpp (+6-1) 
- (modified) clang/lib/CodeGen/CodeGenFunction.h (+4-1) 
- (modified) clang/lib/Sema/SemaDecl.cpp (+4-3) 
- (modified) clang/lib/Sema/SemaDeclCXX.cpp (+10-7) 
- (modified) clang/lib/Sema/SemaTemplateInstantiateDecl.cpp (+5-3) 
- (modified) clang/lib/Serialization/ASTReaderDecl.cpp (+6-3) 
- (modified) clang/lib/Serialization/ASTWriterDecl.cpp (+1) 
- (modified) clang/test/AST/ByteCode/if.cpp (+1-1) 
- (added) clang/test/CodeGen/p0963r3.cpp (+212) 
- (modified) clang/test/Parser/cxx1z-decomposition.cpp (+6-6) 
- (modified) clang/test/Parser/decomposed-condition.cpp (+12-12) 
- (modified) clang/test/SemaCXX/decomposed-condition.cpp (+11-5) 
- (modified) clang/www/cxx_status.html (+1-1) 


``````````diff
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 37ea963bf337d..bea43ebcedb2f 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -76,6 +76,8 @@ C++2c Feature Support
 
 - Implemented `P1061R10 Structured Bindings can introduce a Pack <https://wg21.link/P1061R10>`_.
 
+- Implemented `P0963R3 Structured binding declaration as a condition <https://wg21.link/P0963R3>`_.
+
 C++23 Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index dbd02ef7f8011..d82d9900945a1 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -4224,15 +4224,18 @@ class DecompositionDecl final
     : public VarDecl,
       private llvm::TrailingObjects<DecompositionDecl, BindingDecl *> {
   /// The number of BindingDecl*s following this object.
-  unsigned NumBindings;
+  unsigned NumBindings : 31;
+
+  LLVM_PREFERRED_TYPE(bool)
+  unsigned IsDecisionVariable : 1;
 
   DecompositionDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
                     SourceLocation LSquareLoc, QualType T,
                     TypeSourceInfo *TInfo, StorageClass SC,
-                    ArrayRef<BindingDecl *> Bindings)
+                    ArrayRef<BindingDecl *> Bindings, bool IsDecisionVariable)
       : VarDecl(Decomposition, C, DC, StartLoc, LSquareLoc, nullptr, T, TInfo,
                 SC),
-        NumBindings(Bindings.size()) {
+        NumBindings(Bindings.size()), IsDecisionVariable(IsDecisionVariable) {
     std::uninitialized_copy(Bindings.begin(), Bindings.end(),
                             getTrailingObjects<BindingDecl *>());
     for (auto *B : Bindings) {
@@ -4253,12 +4256,14 @@ class DecompositionDecl final
 
   static DecompositionDecl *Create(ASTContext &C, DeclContext *DC,
                                    SourceLocation StartLoc,
-                                   SourceLocation LSquareLoc,
-                                   QualType T, TypeSourceInfo *TInfo,
-                                   StorageClass S,
-                                   ArrayRef<BindingDecl *> Bindings);
+                                   SourceLocation LSquareLoc, QualType T,
+                                   TypeSourceInfo *TInfo, StorageClass S,
+                                   ArrayRef<BindingDecl *> Bindings,
+                                   bool IsDecisionVariable);
+
   static DecompositionDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID,
-                                               unsigned NumBindings);
+                                               unsigned NumBindings,
+                                               bool IsDecisionVariable);
 
   // Provide the range of bindings which may have a nested pack.
   llvm::ArrayRef<BindingDecl *> bindings() const {
@@ -4285,6 +4290,12 @@ class DecompositionDecl final
                                             std::move(Bindings));
   }
 
+  /// The decision variable of a condition that is a structured binding
+  /// declaration is specified in [dcl.struct.bind]p4:
+  ///   If a structured binding declaration appears as a condition, the decision
+  ///   variable of the condition is e.
+  bool isDecisionVariable() const { return IsDecisionVariable; }
+
   void printName(raw_ostream &OS, const PrintingPolicy &Policy) const override;
 
   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 0b121c04cd3c0..fbc91f2eb8dd6 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -529,8 +529,12 @@ def warn_cxx14_compat_decomp_decl : Warning<
 def ext_decomp_decl : ExtWarn<
   "decomposition declarations are a C++17 extension">, InGroup<CXX17>;
 def ext_decomp_decl_cond : ExtWarn<
-  "ISO C++17 does not permit structured binding declaration in a condition">,
-  InGroup<DiagGroup<"binding-in-condition">>;
+  "structured binding declaration in a condition is a C++2c extenstion">,
+  InGroup<CXX26>;
+def warn_cxx26_decomp_decl_cond : Warning<
+  "structured binding declaration in a condition is incompatible with "
+  "C++ standards before C++2c">,
+  InGroup<CXXPre26Compat>, DefaultIgnore;
 def err_decomp_decl_spec : Error<
   "decomposition declaration cannot be declared "
   "%plural{1:'%1'|:with '%1' specifiers}0">;
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 82180486f3c7c..95ca085c5b746 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -4614,9 +4614,10 @@ ExpectedDecl ASTNodeImporter::VisitVarDecl(VarDecl *D) {
             ImportArrayChecked(FromDecomp->bindings(), Bindings.begin()))
       return std::move(Err);
     DecompositionDecl *ToDecomp;
-    if (GetImportedOrCreateDecl(
-            ToDecomp, FromDecomp, Importer.getToContext(), DC, ToInnerLocStart,
-            Loc, ToType, ToTypeSourceInfo, D->getStorageClass(), Bindings))
+    if (GetImportedOrCreateDecl(ToDecomp, FromDecomp, Importer.getToContext(),
+                                DC, ToInnerLocStart, Loc, ToType,
+                                ToTypeSourceInfo, D->getStorageClass(),
+                                Bindings, FromDecomp->isDecisionVariable()))
       return ToDecomp;
     ToVar = ToDecomp;
   } else {
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 394e39e99a106..213e1a965ff44 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -5104,6 +5104,16 @@ bool Compiler<Emitter>::visitCompoundStmt(const CompoundStmt *S) {
   return Scope.destroyLocals();
 }
 
+template <class Emitter>
+bool Compiler<Emitter>::emitDecompositionVarInit(const DecompositionDecl *DD) {
+  for (auto *BD : DD->bindings())
+    if (auto *KD = BD->getHoldingVar()) {
+      if (!this->visitVarDecl(KD))
+        return false;
+    }
+  return true;
+}
+
 template <class Emitter>
 bool Compiler<Emitter>::visitDeclStmt(const DeclStmt *DS) {
   for (const auto *D : DS->decls()) {
@@ -5118,12 +5128,10 @@ bool Compiler<Emitter>::visitDeclStmt(const DeclStmt *DS) {
       return false;
 
     // Register decomposition decl holding vars.
-    if (const auto *DD = dyn_cast<DecompositionDecl>(VD)) {
-      for (auto *BD : DD->bindings())
-        if (auto *KD = BD->getHoldingVar()) {
-          if (!this->visitVarDecl(KD))
-            return false;
-        }
+    if (const auto *DD = dyn_cast<DecompositionDecl>(VD);
+        DD && !DD->isDecisionVariable()) {
+      if (!this->emitDecompositionVarInit(DD))
+        return false;
     }
   }
 
@@ -5189,6 +5197,12 @@ template <class Emitter> bool Compiler<Emitter>::visitIfStmt(const IfStmt *IS) {
       return false;
   }
 
+  if (auto *DD =
+          dyn_cast_if_present<DecompositionDecl>(IS->getConditionVariable());
+      DD && DD->isDecisionVariable())
+    if (!this->emitDecompositionVarInit(DD))
+      return false;
+
   if (const Stmt *Else = IS->getElse()) {
     LabelTy LabelElse = this->getLabel();
     LabelTy LabelEnd = this->getLabel();
@@ -5249,6 +5263,13 @@ bool Compiler<Emitter>::visitWhileStmt(const WhileStmt *S) {
 
     if (!this->visitBool(Cond))
       return false;
+
+    if (auto *DD =
+            dyn_cast_if_present<DecompositionDecl>(S->getConditionVariable());
+        DD && DD->isDecisionVariable())
+      if (!this->emitDecompositionVarInit(DD))
+        return false;
+
     if (!this->jumpFalse(EndLabel))
       return false;
 
@@ -5330,6 +5351,12 @@ bool Compiler<Emitter>::visitForStmt(const ForStmt *S) {
         return false;
     }
 
+    if (auto *DD =
+            dyn_cast_if_present<DecompositionDecl>(S->getConditionVariable());
+        DD && DD->isDecisionVariable())
+      if (!this->emitDecompositionVarInit(DD))
+        return false;
+
     if (Body && !this->visitStmt(Body))
       return false;
 
@@ -5452,6 +5479,12 @@ bool Compiler<Emitter>::visitSwitchStmt(const SwitchStmt *S) {
   if (!this->emitSetLocal(CondT, CondVar, S))
     return false;
 
+  if (auto *DD =
+          dyn_cast_if_present<DecompositionDecl>(S->getConditionVariable());
+      DD && DD->isDecisionVariable())
+    if (!this->emitDecompositionVarInit(DD))
+      return false;
+
   CaseMap CaseLabels;
   // Create labels and comparison ops for all case statements.
   for (const SwitchCase *SC = S->getSwitchCaseList(); SC;
diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h
index 77fcc3d1b41ce..9bb0ba6e52f16 100644
--- a/clang/lib/AST/ByteCode/Compiler.h
+++ b/clang/lib/AST/ByteCode/Compiler.h
@@ -386,6 +386,7 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
   bool compileUnionAssignmentOperator(const CXXMethodDecl *MD);
 
   bool checkLiteralType(const Expr *E);
+  bool emitDecompositionVarInit(const DecompositionDecl *DD);
 
 protected:
   /// Variable to storage mapping.
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 7eff776882629..fdad1150c8b1a 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -3520,21 +3520,24 @@ DecompositionDecl *DecompositionDecl::Create(ASTContext &C, DeclContext *DC,
                                              SourceLocation LSquareLoc,
                                              QualType T, TypeSourceInfo *TInfo,
                                              StorageClass SC,
-                                             ArrayRef<BindingDecl *> Bindings) {
+                                             ArrayRef<BindingDecl *> Bindings,
+                                             bool IsDecisionVariable) {
   size_t Extra = additionalSizeToAlloc<BindingDecl *>(Bindings.size());
-  return new (C, DC, Extra)
-      DecompositionDecl(C, DC, StartLoc, LSquareLoc, T, TInfo, SC, Bindings);
+  return new (C, DC, Extra) DecompositionDecl(
+      C, DC, StartLoc, LSquareLoc, T, TInfo, SC, Bindings, IsDecisionVariable);
 }
 
-DecompositionDecl *DecompositionDecl::CreateDeserialized(ASTContext &C,
-                                                         GlobalDeclID ID,
-                                                         unsigned NumBindings) {
+DecompositionDecl *
+DecompositionDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID,
+                                      unsigned NumBindings,
+                                      bool IsDecisionVariable) {
   size_t Extra = additionalSizeToAlloc<BindingDecl *>(NumBindings);
-  auto *Result = new (C, ID, Extra)
-      DecompositionDecl(C, nullptr, SourceLocation(), SourceLocation(),
-                        QualType(), nullptr, StorageClass(), {});
+  auto *Result = new (C, ID, Extra) DecompositionDecl(
+      C, nullptr, SourceLocation(), SourceLocation(), QualType(), nullptr,
+      StorageClass(), {}, IsDecisionVariable);
   // Set up and clean out the bindings array.
   Result->NumBindings = NumBindings;
+  Result->IsDecisionVariable = IsDecisionVariable;
   auto *Trail = Result->getTrailingObjects<BindingDecl *>();
   for (unsigned I = 0; I != NumBindings; ++I)
     new (Trail + I) BindingDecl*(nullptr);
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 7244120d1be51..898f8a2fce769 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -5218,16 +5218,28 @@ static bool EvaluateVarDecl(EvalInfo &Info, const VarDecl *VD) {
   return true;
 }
 
+static bool EvaluateDecompositionDeclInit(EvalInfo &Info,
+                                          const DecompositionDecl *DD);
+
 static bool EvaluateDecl(EvalInfo &Info, const Decl *D) {
   bool OK = true;
 
   if (const VarDecl *VD = dyn_cast<VarDecl>(D))
     OK &= EvaluateVarDecl(Info, VD);
 
-  if (const DecompositionDecl *DD = dyn_cast<DecompositionDecl>(D))
-    for (auto *BD : DD->flat_bindings())
-      if (auto *VD = BD->getHoldingVar())
-        OK &= EvaluateDecl(Info, VD);
+  if (const DecompositionDecl *DD = dyn_cast<DecompositionDecl>(D);
+      DD && !DD->isDecisionVariable())
+    OK &= EvaluateDecompositionDeclInit(Info, DD);
+
+  return OK;
+}
+
+static bool EvaluateDecompositionDeclInit(EvalInfo &Info,
+                                          const DecompositionDecl *DD) {
+  bool OK = true;
+  for (auto *BD : DD->flat_bindings())
+    if (auto *VD = BD->getHoldingVar())
+      OK &= EvaluateDecl(Info, VD);
 
   return OK;
 }
@@ -5251,6 +5263,10 @@ static bool EvaluateCond(EvalInfo &Info, const VarDecl *CondDecl,
     return false;
   if (!EvaluateAsBooleanCondition(Cond, Result, Info))
     return false;
+  if (auto *DD = dyn_cast_if_present<DecompositionDecl>(CondDecl);
+      DD && DD->isDecisionVariable() &&
+      !EvaluateDecompositionDeclInit(Info, DD))
+    return false;
   return Scope.destroy();
 }
 
@@ -5335,6 +5351,12 @@ static EvalStmtResult EvaluateSwitch(StmtResult &Result, EvalInfo &Info,
     if (!EvaluateInteger(SS->getCond(), Value, Info))
       return ESR_Failed;
 
+    if (auto *DD =
+            dyn_cast_if_present<DecompositionDecl>(SS->getConditionVariable());
+        DD && DD->isDecisionVariable() &&
+        !EvaluateDecompositionDeclInit(Info, DD))
+      return ESR_Failed;
+
     if (!CondScope.destroy())
       return ESR_Failed;
   }
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 9cd5885aaae51..44d787a85f691 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -164,10 +164,9 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
     assert(VD.isLocalVarDecl() &&
            "Should not see file-scope variables inside a function!");
     EmitVarDecl(VD);
-    if (auto *DD = dyn_cast<DecompositionDecl>(&VD))
-      for (auto *B : DD->flat_bindings())
-        if (auto *HD = B->getHoldingVar())
-          EmitVarDecl(*HD);
+    if (auto *DD = dyn_cast<DecompositionDecl>(&VD);
+        DD && !DD->isDecisionVariable())
+      EmitDecompositionVarInit(*DD);
 
     return;
   }
@@ -2057,6 +2056,12 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
                         /*IsAutoInit=*/false);
 }
 
+void CodeGenFunction::EmitDecompositionVarInit(const DecompositionDecl &DD) {
+  for (auto *B : DD.flat_bindings())
+    if (auto *HD = B->getHoldingVar())
+      EmitVarDecl(*HD);
+}
+
 /// Emit an expression as an initializer for an object (variable, field, etc.)
 /// at the given location.  The expression is not necessarily the normal
 /// initializer for the object, and the address is not necessarily
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index abe799af32c6e..0a49eadbf33d1 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -913,6 +913,11 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
       if (CondConstant)
         incrementProfileCounter(&S);
       if (Executed) {
+        if (auto *DD = dyn_cast_if_present<DecompositionDecl>(
+                S.getConditionVariable())) {
+          assert(DD->isDecisionVariable());
+          EmitDecompositionVarInit(*DD);
+        }
         RunCleanupsScope ExecutedScope(*this);
         EmitStmt(Executed);
       }
@@ -952,10 +957,16 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
   // there is a 'return' within the body, but this is particularly beneficial
   // when one if-stmt is nested within another if-stmt so that all of the MC/DC
   // updates are kept linear and consistent.
-  if (!CGM.getCodeGenOpts().MCDCCoverage)
-    EmitBranchOnBoolExpr(S.getCond(), ThenBlock, ElseBlock, ThenCount, LH);
-  else {
+  if (!CGM.getCodeGenOpts().MCDCCoverage) {
+    EmitBranchOnBoolExpr(S.getCond(), ThenBlock, ElseBlock, ThenCount, LH,
+                         nullptr, S.getConditionVariable());
+  } else {
     llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
+    if (auto *DD =
+            dyn_cast_if_present<DecompositionDecl>(S.getConditionVariable())) {
+      assert(DD->isDecisionVariable());
+      EmitDecompositionVarInit(*DD);
+    }
     Builder.CreateCondBr(BoolCondVal, ThenBlock, ElseBlock);
   }
 
@@ -1099,6 +1110,11 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S,
   // execution of the loop body.
   llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
 
+  if (auto *DD =
+          dyn_cast_if_present<DecompositionDecl>(S.getConditionVariable());
+      DD && DD->isDecisionVariable())
+    EmitDecompositionVarInit(*DD);
+
   // while(1) is common, avoid extra exit blocks.  Be sure
   // to correctly handle break/continue though.
   llvm::ConstantInt *C = dyn_cast<llvm::ConstantInt>(BoolCondVal);
@@ -1332,6 +1348,12 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S,
     // C99 6.8.5p2/p4: The first substatement is executed if the expression
     // compares unequal to 0.  The condition must be a scalar type.
     llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
+
+    if (auto *DD =
+            dyn_cast_if_present<DecompositionDecl>(S.getConditionVariable());
+        DD && DD->isDecisionVariable())
+      EmitDecompositionVarInit(*DD);
+
     llvm::MDNode *Weights =
         createProfileWeightsForLoop(S.getCond(), getProfileCount(S.getBody()));
     if (!Weights && CGM.getCodeGenOpts().OptimizationLevel)
@@ -2229,6 +2251,11 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) {
       if (S.getConditionVariable())
         EmitDecl(*S.getConditionVariable());
 
+      if (auto *DD =
+              dyn_cast_if_present<DecompositionDecl>(S.getConditionVariable());
+          DD && DD->isDecisionVariable())
+        EmitDecompositionVarInit(*DD);
+
       // At this point, we are no longer "within" a switch instance, so
       // we can temporarily enforce this to ensure that any embedded case
       // statements are not emitted.
@@ -2260,6 +2287,11 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) {
     EmitDecl(*S.getConditionVariable());
   llvm::Value *CondV = EmitScalarExpr(S.getCond());
 
+  if (auto *DD =
+          dyn_cast_if_present<DecompositionDecl>(S.getConditionVariable());
+      DD && DD->isDecisionVariable())
+    EmitDecompositionVarInit(*DD);
+
   // Create basic block to hold stuff that comes after switch
   // statement. We also need to create a default block now so that
   // explicit case ranges tests can have a place to jump to on
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index 08165e0b28406..c17a7d308bca8 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -1846,7 +1846,8 @@ void CodeGenFunction::EmitBranchToCounterBlock(
 /// LHS and RHS nodes.
 void CodeGenFunction::EmitBranchOnBoolExpr(
     const Expr *Cond, llvm::BasicBlock *TrueBlock, llvm::BasicBlock *FalseBlock,
-    uint64_t TrueCount, Stmt::Likelihood LH, const Expr *ConditionalOp) {
+    uint64_t TrueCount, Stmt::Likelihood LH, const Expr *ConditionalOp,
+    const VarDecl *ConditionalDecl) {
   Cond = Cond->IgnoreParens();
 
   if (const BinaryOperator *CondBOp = dyn_cast<BinaryOperator>(Cond)) {
@@ -2047,6 +2048,10 @@ void CodeGenFunction::EmitBranchOnBoolExpr(
     CondV = EvaluateExprAsBool(Cond);
   }
 
+  if (auto *DD = dyn_cast_if_present<DecompositionDecl>(ConditionalDecl);
+      DD && DD->isDecisionVariable())
+    EmitDecompositionVarInit(*DD);
+
   // If not at the top of the logical operator nest, update MCDC temp with the
   // boolean result of the evaluated condition.
   if (!MCDCLogOpStack.empty()) {
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 018fc66b72a1e..3586594429da8 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -3474,6 +3474,8 @@ class CodeGenFunction : public CodeGenTypeCache {
   void emitAutoVarTypeCleanup(const AutoVarEmission &emission,
                               QualType::DestructionKind dtorKind);
 
+  void EmitDecompositionVarInit(const DecompositionDecl &var);
+
   /// Emits the alloca and debug information for the size expressions for each
   /// dimension of an array. It registers the association of its (1-dimensional)
   /// QualTypes and size expression's debug node, so that CGDebugInfo can
@@ -5180,7 +5182,8 @@ class CodeGenFunction : public CodeGenTypeCache {
   void EmitBranchOnBoolExpr(const Expr *Cond, llvm::BasicB...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/130228


More information about the cfe-commits mailing list