[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