https://github.com/zmodem updated https://github.com/llvm/llvm-project/pull/203554
>From 43f8ddc6e8bf4ac120c9a3f5e1142ab2cdc32d46 Mon Sep 17 00:00:00 2001 From: Hans Wennborg <[email protected]> Date: Fri, 12 Jun 2026 13:26:00 +0200 Subject: [PATCH 01/13] InstantiateDefaultCtorDefaultArgs -> BuildDefaultArgsForCtorClosure and move to SemaDeclCXX.cpp --- clang/include/clang/Sema/Sema.h | 7 ++----- clang/lib/Sema/SemaDecl.cpp | 2 +- clang/lib/Sema/SemaDeclCXX.cpp | 19 ++++++++++++++++++- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 18 +----------------- 4 files changed, 22 insertions(+), 24 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index b8d760e7e0975..4b972d8bf0516 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -14265,11 +14265,8 @@ class Sema final : public SemaBase { LateInstantiatedAttrVec *LateAttrs = nullptr, LocalInstantiationScope *OuterMostScope = nullptr); - /// In the MS ABI, we need to instantiate default arguments of dllexported - /// default constructors along with the constructor definition. This allows IR - /// gen to emit a constructor closure which calls the default constructor with - /// its default arguments. - void InstantiateDefaultCtorDefaultArgs(CXXConstructorDecl *Ctor); + /// XXX: comment + void BuildDefaultArgsForCtorClosure(CXXConstructorDecl *Ctor); bool InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD, ParmVarDecl *Param); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index cddcf3a010279..2255d6141db1e 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -16306,7 +16306,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D, Context.getTargetInfo().getCXXABI().isMicrosoft()) { // If this is an MS ABI dllexport default constructor, instantiate any // default arguments. - InstantiateDefaultCtorDefaultArgs(Ctor); + BuildDefaultArgsForCtorClosure(Ctor); } } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 418ff01f3d98a..f583a765863a4 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -6339,7 +6339,7 @@ static void ReferenceDllExportedMembers(Sema &S, CXXRecordDecl *Class) { if (S.Context.getTargetInfo().getCXXABI().isMicrosoft()) { auto *CD = dyn_cast<CXXConstructorDecl>(MD); if (CD && CD->isDefaultConstructor() && TSK == TSK_Undeclared) { - S.InstantiateDefaultCtorDefaultArgs(CD); + S.BuildDefaultArgsForCtorClosure(CD); } } @@ -19804,3 +19804,20 @@ void Sema::ActOnFinishFunctionDeclarationDeclarator(Declarator &Declarator) { } InventedParameterInfos.pop_back(); } + +void Sema::BuildDefaultArgsForCtorClosure(CXXConstructorDecl *Ctor) { + assert(Context.getTargetInfo().getCXXABI().isMicrosoft() && + Ctor->isDefaultConstructor()); + unsigned NumParams = Ctor->getNumParams(); + if (NumParams == 0) + return; + DLLExportAttr *Attr = Ctor->getAttr<DLLExportAttr>(); + if (!Attr) + return; + for (unsigned I = 0; I != NumParams; ++I) { + (void)CheckCXXDefaultArgExpr(Attr->getLocation(), Ctor, + Ctor->getParamDecl(I)); + CleanupVarDeclMarking(); + } + +} diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 324d6bf3857c7..26ccde0d3315d 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1078,22 +1078,6 @@ void Sema::updateAttrsForLateParsedTemplate(const Decl *Pattern, Decl *Inst) { } } -void Sema::InstantiateDefaultCtorDefaultArgs(CXXConstructorDecl *Ctor) { - assert(Context.getTargetInfo().getCXXABI().isMicrosoft() && - Ctor->isDefaultConstructor()); - unsigned NumParams = Ctor->getNumParams(); - if (NumParams == 0) - return; - DLLExportAttr *Attr = Ctor->getAttr<DLLExportAttr>(); - if (!Attr) - return; - for (unsigned I = 0; I != NumParams; ++I) { - (void)CheckCXXDefaultArgExpr(Attr->getLocation(), Ctor, - Ctor->getParamDecl(I)); - CleanupVarDeclMarking(); - } -} - /// Get the previous declaration of a declaration for the purposes of template /// instantiation. If this finds a previous declaration, then the previous /// declaration of the instantiation of D should be an instantiation of the @@ -5961,7 +5945,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, // default arguments. if (Context.getTargetInfo().getCXXABI().isMicrosoft() && Ctor->isDefaultConstructor()) { - InstantiateDefaultCtorDefaultArgs(Ctor); + BuildDefaultArgsForCtorClosure(Ctor); } } >From 9d30dda8251346958fc6af3df120af53f0cabd79 Mon Sep 17 00:00:00 2001 From: Hans Wennborg <[email protected]> Date: Fri, 12 Jun 2026 14:08:37 +0200 Subject: [PATCH 02/13] add Loc and IsCopy params, use it for CheckCXXThrowOperand too --- clang/include/clang/Sema/Sema.h | 2 +- clang/lib/Sema/SemaDecl.cpp | 3 ++- clang/lib/Sema/SemaDeclCXX.cpp | 24 +++++++++---------- clang/lib/Sema/SemaExprCXX.cpp | 7 +++--- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 3 ++- 5 files changed, 20 insertions(+), 19 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 4b972d8bf0516..84a124aa076fe 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -14266,7 +14266,7 @@ class Sema final : public SemaBase { LocalInstantiationScope *OuterMostScope = nullptr); /// XXX: comment - void BuildDefaultArgsForCtorClosure(CXXConstructorDecl *Ctor); + bool BuildDefaultArgsForCtorClosure(SourceLocation Loc, CXXConstructorDecl *Ctor, bool IsCopy = false); bool InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD, ParmVarDecl *Param); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 2255d6141db1e..67b91609fb609 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -16306,7 +16306,8 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D, Context.getTargetInfo().getCXXABI().isMicrosoft()) { // If this is an MS ABI dllexport default constructor, instantiate any // default arguments. - BuildDefaultArgsForCtorClosure(Ctor); + if (DLLExportAttr *Attr = Ctor->getAttr<DLLExportAttr>()) + BuildDefaultArgsForCtorClosure(Attr->getLocation(), Ctor); } } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index f583a765863a4..9b8ad2390a60a 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -6339,7 +6339,7 @@ static void ReferenceDllExportedMembers(Sema &S, CXXRecordDecl *Class) { if (S.Context.getTargetInfo().getCXXABI().isMicrosoft()) { auto *CD = dyn_cast<CXXConstructorDecl>(MD); if (CD && CD->isDefaultConstructor() && TSK == TSK_Undeclared) { - S.BuildDefaultArgsForCtorClosure(CD); + S.BuildDefaultArgsForCtorClosure(CD->getAttr<DLLExportAttr>()->getLocation(), CD); } } @@ -19805,19 +19805,19 @@ void Sema::ActOnFinishFunctionDeclarationDeclarator(Declarator &Declarator) { InventedParameterInfos.pop_back(); } -void Sema::BuildDefaultArgsForCtorClosure(CXXConstructorDecl *Ctor) { - assert(Context.getTargetInfo().getCXXABI().isMicrosoft() && - Ctor->isDefaultConstructor()); +bool Sema::BuildDefaultArgsForCtorClosure(SourceLocation Loc, CXXConstructorDecl *Ctor, bool IsCopy) { + assert(Context.getTargetInfo().getCXXABI().isMicrosoft()); + unsigned NumParams = Ctor->getNumParams(); if (NumParams == 0) - return; - DLLExportAttr *Attr = Ctor->getAttr<DLLExportAttr>(); - if (!Attr) - return; - for (unsigned I = 0; I != NumParams; ++I) { - (void)CheckCXXDefaultArgExpr(Attr->getLocation(), Ctor, - Ctor->getParamDecl(I)); - CleanupVarDeclMarking(); + return false; + + unsigned FirstParam = IsCopy ? 1 : 0; + for (unsigned I = FirstParam; I != NumParams; ++I) { + if (CheckCXXDefaultArgExpr(Loc, Ctor, Ctor->getParamDecl(I))) + return true; + CleanupVarDeclMarking(); // XXX: still not sure what this does. } + return false; } diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 4e1652462b3ae..59e69314c2803 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -1070,10 +1070,9 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, // We don't keep the instantiated default argument expressions around so // we must rebuild them here. - for (unsigned I = 1, E = CD->getNumParams(); I != E; ++I) { - if (CheckCXXDefaultArgExpr(ThrowLoc, CD, CD->getParamDecl(I))) - return true; - } + // XXX: surprisingly, CD->isCopyConstructor() is not necessarily true here! + if (BuildDefaultArgsForCtorClosure(ThrowLoc, CD, /*IsCopy=*/true)) + return true; } } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 26ccde0d3315d..9d21d5f96b020 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -5945,7 +5945,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, // default arguments. if (Context.getTargetInfo().getCXXABI().isMicrosoft() && Ctor->isDefaultConstructor()) { - BuildDefaultArgsForCtorClosure(Ctor); + if (DLLExportAttr *Attr = Ctor->getAttr<DLLExportAttr>()) + BuildDefaultArgsForCtorClosure(Attr->getLocation(), Ctor); } } >From 89391825c88f8b0abf97f5982fde3cf57a994520 Mon Sep 17 00:00:00 2001 From: Hans Wennborg <[email protected]> Date: Fri, 12 Jun 2026 14:31:21 +0200 Subject: [PATCH 03/13] found one more caller; also use BuildCXXDefaultArgExpr now instead of CheckCXXDefaultArgExpr --- clang/lib/Sema/SemaDeclCXX.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 9b8ad2390a60a..9de72e94e9ec4 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -6392,10 +6392,8 @@ static void checkForMultipleExportedDefaultConstructors(Sema &S, // If the class is non-dependent, mark the default arguments as ODR-used so // that we can properly codegen the constructor closure. if (!Class->isDependentContext()) { - for (ParmVarDecl *PD : CD->parameters()) { - (void)S.CheckCXXDefaultArgExpr(Attr->getLocation(), CD, PD); - S.DiscardCleanupsInEvaluationContext(); - } + S.BuildDefaultArgsForCtorClosure(Attr->getLocation(), CD); + S.DiscardCleanupsInEvaluationContext(); } if (LastExportedDefaultCtor) { @@ -19814,9 +19812,11 @@ bool Sema::BuildDefaultArgsForCtorClosure(SourceLocation Loc, CXXConstructorDecl unsigned FirstParam = IsCopy ? 1 : 0; for (unsigned I = FirstParam; I != NumParams; ++I) { - if (CheckCXXDefaultArgExpr(Loc, Ctor, Ctor->getParamDecl(I))) + ExprResult R = BuildCXXDefaultArgExpr(Loc, Ctor, Ctor->getParamDecl(I)); + if (R.isInvalid()) return true; - CleanupVarDeclMarking(); // XXX: still not sure what this does. + + CleanupVarDeclMarking(); } return false; >From e31da8826f11801af71568cfbf30548c3560f1c2 Mon Sep 17 00:00:00 2001 From: Hans Wennborg <[email protected]> Date: Fri, 12 Jun 2026 14:51:49 +0200 Subject: [PATCH 04/13] start adding it to the ast --- clang/include/clang/AST/DeclCXX.h | 5 +++++ clang/lib/Sema/SemaDeclCXX.cpp | 12 +++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index cc4b4ff9db273..ba9036ef65157 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -2668,6 +2668,11 @@ class CXXConstructorDecl final friend class ASTDeclWriter; friend TrailingObjects; + // FIXME: Just hacking it in here for now. + Expr **CtorClosureArgs = nullptr; + Expr **ctorClosureArgs() const { return CtorClosureArgs; } + void setCtorClosureArgs(Expr **Args) { CtorClosureArgs = Args; } + static CXXConstructorDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID, uint64_t AllocKind); static CXXConstructorDecl * diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 9de72e94e9ec4..8b2286bbd0d23 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -19806,18 +19806,24 @@ void Sema::ActOnFinishFunctionDeclarationDeclarator(Declarator &Declarator) { bool Sema::BuildDefaultArgsForCtorClosure(SourceLocation Loc, CXXConstructorDecl *Ctor, bool IsCopy) { assert(Context.getTargetInfo().getCXXABI().isMicrosoft()); + if (Ctor->ctorClosureArgs()) + return false; + unsigned NumParams = Ctor->getNumParams(); if (NumParams == 0) return false; - unsigned FirstParam = IsCopy ? 1 : 0; + + Expr **Args = new (getASTContext()) Expr*[NumParams - FirstParam]; + for (unsigned I = FirstParam; I != NumParams; ++I) { ExprResult R = BuildCXXDefaultArgExpr(Loc, Ctor, Ctor->getParamDecl(I)); + CleanupVarDeclMarking(); if (R.isInvalid()) return true; - - CleanupVarDeclMarking(); + Args[I - FirstParam] = R.get(); } + Ctor->setCtorClosureArgs(Args); return false; } >From decee090a0bfba3e476970a94b920df44917af17 Mon Sep 17 00:00:00 2001 From: Hans Wennborg <[email protected]> Date: Fri, 12 Jun 2026 15:48:42 +0200 Subject: [PATCH 05/13] serialize/deserialize the CtorClosureArgs --- clang/lib/Sema/SemaDeclCXX.cpp | 5 +++-- clang/lib/Serialization/ASTReaderDecl.cpp | 6 ++++++ clang/lib/Serialization/ASTWriterDecl.cpp | 8 ++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 8b2286bbd0d23..e7a96ad1f390c 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -19814,14 +19814,15 @@ bool Sema::BuildDefaultArgsForCtorClosure(SourceLocation Loc, CXXConstructorDecl return false; unsigned FirstParam = IsCopy ? 1 : 0; - Expr **Args = new (getASTContext()) Expr*[NumParams - FirstParam]; + Expr **Args = new (getASTContext()) Expr*[NumParams]; + Args[0] = nullptr; for (unsigned I = FirstParam; I != NumParams; ++I) { ExprResult R = BuildCXXDefaultArgExpr(Loc, Ctor, Ctor->getParamDecl(I)); CleanupVarDeclMarking(); if (R.isInvalid()) return true; - Args[I - FirstParam] = R.get(); + Args[I] = R.get(); } Ctor->setCtorClosureArgs(Args); diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index fb291a4b0f2c5..8250b5bdec623 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -2333,6 +2333,12 @@ void ASTDeclReader::VisitCXXConstructorDecl(CXXConstructorDecl *D) { *D->getTrailingObjects<InheritedConstructor>() = InheritedConstructor(Shadow, Ctor); } + if (int NumCtorClosureArgs = Record.readInt()) { + Expr **Args = new (Reader.getContext()) Expr*[NumCtorClosureArgs]; + for (int I = 0; I != NumCtorClosureArgs; I++) + Args[I] = cast<Expr>(Record.readStmt()); + D->setCtorClosureArgs(Args); + } VisitCXXMethodDecl(D); } diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 7f5005aa666c7..2ca34561b18a5 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -1774,6 +1774,14 @@ void ASTDeclWriter::VisitCXXConstructorDecl(CXXConstructorDecl *D) { Record.AddDeclRef(Inherited.getConstructor()); } + if (Expr **CtorClosureArgs = D->ctorClosureArgs()) { + Record.push_back(D->getNumParams()); + for (unsigned I = 0, N = D->getNumParams(); I != N; ++I) + Record.AddStmt(CtorClosureArgs[I]); + } else { + Record.push_back(0); + } + VisitCXXMethodDecl(D); Code = serialization::DECL_CXX_CONSTRUCTOR; } >From ff475437ab1d81574b333ed7ab7fae3361571d51 Mon Sep 17 00:00:00 2001 From: Hans Wennborg <[email protected]> Date: Fri, 12 Jun 2026 16:20:19 +0200 Subject: [PATCH 06/13] use ctorClosureArgs() in getAddrOfCXXCtorClosure() --- clang/lib/CodeGen/MicrosoftCXXABI.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index 40c7c00d85395..3de3fd8cbe3c8 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -4207,18 +4207,19 @@ MicrosoftCXXABI::getAddrOfCXXCtorClosure(const CXXConstructorDecl *CD, if (SrcVal) Args.add(RValue::get(SrcVal), SrcParam->getType()); + // Add the rest of the default arguments. SmallVector<const Stmt *, 4> ArgVec; - ArrayRef<ParmVarDecl *> params = CD->parameters().drop_front(IsCopy ? 1 : 0); - for (const ParmVarDecl *PD : params) { - assert(PD->hasDefaultArg() && "ctor closure lacks default args"); - ArgVec.push_back(PD->getDefaultArg()); + for (unsigned I = IsCopy ? 1 : 0, N = CD->getNumParams(); I != N; ++I) { + assert(CD->getParamDecl(I)->hasDefaultArg() && "ctor closure lacks default args"); + assert(CD->ctorClosureArgs()); + ArgVec.push_back(CD->ctorClosureArgs()[I]); } CodeGenFunction::RunCleanupsScope Cleanups(CGF); const auto *FPT = CD->getType()->castAs<FunctionProtoType>(); - CGF.EmitCallArgs(Args, FPT, llvm::ArrayRef(ArgVec), CD, IsCopy ? 1 : 0); + CGF.EmitCallArgs(Args, FPT, ArrayRef(ArgVec), CD, IsCopy ? 1 : 0); // Insert any ABI-specific implicit constructor arguments. AddedStructorArgCounts ExtraArgs = >From 935c664f56b5ea8da11e883fbbc41434838c31fd Mon Sep 17 00:00:00 2001 From: Hans Wennborg <[email protected]> Date: Fri, 12 Jun 2026 16:25:00 +0200 Subject: [PATCH 07/13] gotta use the canonical ctor decl --- clang/include/clang/AST/DeclCXX.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index ba9036ef65157..e22881556e2a3 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -2670,8 +2670,8 @@ class CXXConstructorDecl final // FIXME: Just hacking it in here for now. Expr **CtorClosureArgs = nullptr; - Expr **ctorClosureArgs() const { return CtorClosureArgs; } - void setCtorClosureArgs(Expr **Args) { CtorClosureArgs = Args; } + Expr **ctorClosureArgs() const { return getCanonicalDecl()->CtorClosureArgs; } + void setCtorClosureArgs(Expr **Args) { getCanonicalDecl()->CtorClosureArgs = Args; } static CXXConstructorDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID, uint64_t AllocKind); >From 4461dec7f77f2084b00f089e61e951f96ed42453 Mon Sep 17 00:00:00 2001 From: Hans Wennborg <[email protected]> Date: Fri, 12 Jun 2026 16:40:59 +0200 Subject: [PATCH 08/13] tests --- clang/test/CodeGenCXX/dllexport-ctor-closure.cpp | 9 ++++++++- clang/test/CodeGenCXX/microsoft-abi-throw.cpp | 13 ++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/clang/test/CodeGenCXX/dllexport-ctor-closure.cpp b/clang/test/CodeGenCXX/dllexport-ctor-closure.cpp index 8aeb9b9176fcd..1b4940673f599 100644 --- a/clang/test/CodeGenCXX/dllexport-ctor-closure.cpp +++ b/clang/test/CodeGenCXX/dllexport-ctor-closure.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple i686-windows-msvc -emit-llvm -std=c++14 \ +// RUN: %clang_cc1 -triple i686-windows-msvc -emit-llvm -std=c++20 \ // RUN: -fno-threadsafe-statics -fms-extensions -O1 -mconstructor-aliases \ // RUN: -disable-llvm-passes -o - %s -w -fms-compatibility-version=19.00 | \ // RUN: FileCheck %s @@ -95,3 +95,10 @@ struct __declspec(dllexport) ConstexprDefaultArg { ConstexprDefaultArg(SomeStruct = kConstexprStruct) {} }; // CHECK-LABEL: define weak_odr dso_local dllexport x86_thiscallcc void @"??_FConstexprDefaultArg@@QAEXXZ" + +consteval int constEvalFunc() { return 42; } +struct ConstEvalDefaultArg { + __declspec(dllexport) ConstEvalDefaultArg(int n = constEvalFunc()) {} +}; +// CHECK-LABEL: define weak_odr dso_local dllexport x86_thiscallcc void @"??_FConstEvalDefaultArg@@QAEXXZ" +// CHECK: call {{.*}} @"??0ConstEvalDefaultArg@@QAE@H@Z"({{.*}}, i32 noundef 42) diff --git a/clang/test/CodeGenCXX/microsoft-abi-throw.cpp b/clang/test/CodeGenCXX/microsoft-abi-throw.cpp index 14945ad60f3c1..4fd0df42d8ff5 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-throw.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-throw.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -emit-llvm -o - -triple=i386-pc-win32 -std=c++11 %s -fcxx-exceptions -fms-extensions | FileCheck %s +// RUN: %clang_cc1 -emit-llvm -o - -triple=i386-pc-win32 -std=c++20 %s -fcxx-exceptions -fms-extensions | FileCheck %s // CHECK-DAG: @"??_R0?AUY@@@8" = linkonce_odr global %rtti.TypeDescriptor7 { ptr @"??_7type_info@@6B@", ptr null, [8 x i8] c".?AUY@@\00" }, comdat // CHECK-DAG: @"_CT??_R0?AUY@@@8??0Y@@QAE@ABU0@@Z8" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 4, ptr @"??_R0?AUY@@@8", i32 0, i32 -1, i32 0, i32 8, ptr @"??0Y@@QAE@ABU0@@Z" }, section ".xdata", comdat @@ -71,6 +71,17 @@ void h(Default &d) { throw d; } +consteval int constEvalFunc() { return 123; } +struct DefaultConstEval { + DefaultConstEval(DefaultConstEval&, int = constEvalFunc()); +}; +// CHECK-LABEL: @"??_ODefaultConstEval@@QAEXAAU0@@Z" +// CHECK: call x86_thiscallcc {{.*}} @"??0DefaultConstEval@@QAE@AAU0@H@Z"({{.*}} %[[this]], {{.*}} %[[src]], i32 noundef 123) + +void h2(DefaultConstEval &d) { + throw d; +} + struct DeletedCopy { DeletedCopy(); DeletedCopy(DeletedCopy &&); >From fbe75698ff9cea5d188444439b2cfacb661d2ec9 Mon Sep 17 00:00:00 2001 From: Hans Wennborg <[email protected]> Date: Mon, 15 Jun 2026 15:56:56 +0200 Subject: [PATCH 09/13] use a side table in ASTContext, inspired by DeclAttrs --- clang/include/clang/AST/ASTContext.h | 8 ++++++++ clang/include/clang/AST/DeclCXX.h | 8 +++----- clang/lib/AST/ASTContext.cpp | 13 +++++++++++++ clang/lib/AST/DeclCXX.cpp | 10 ++++++++++ clang/lib/CodeGen/MicrosoftCXXABI.cpp | 12 +++++------- clang/lib/Sema/SemaDeclCXX.cpp | 14 ++++++++------ clang/lib/Serialization/ASTReaderDecl.cpp | 12 +++++++----- clang/lib/Serialization/ASTWriterDecl.cpp | 12 +++++------- 8 files changed, 59 insertions(+), 30 deletions(-) diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index a4ed852d36442..c04b380f9ec5b 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -514,6 +514,9 @@ class ASTContext : public RefCountedBase<ASTContext> { /// Declaration for the CUDA cudaLaunchDevice function. FunctionDecl *cudaLaunchDeviceDecl = nullptr; + llvm::DenseMap<const CXXConstructorDecl *, ArrayRef<CXXDefaultArgExpr *>> + CtorClosureDefaultArgs; + /// Keeps track of all declaration attributes. /// /// Since so few decls have attrs, we keep them in a hash map instead of @@ -1148,6 +1151,11 @@ class ASTContext : public RefCountedBase<ASTContext> { /// Erase the attributes corresponding to the given declaration. void eraseDeclAttrs(const Decl *D); + ArrayRef<CXXDefaultArgExpr *> + getCtorClosureDefaultArgs(const CXXConstructorDecl *CD); + void setCtorClosureDefaultArgs(const CXXConstructorDecl *CD, + ArrayRef<CXXDefaultArgExpr *> Args); + /// Get all ExplicitInstantiationDecls for a given specialization. ArrayRef<ExplicitInstantiationDecl *> getExplicitInstantiationDecls(const NamedDecl *Spec) const; diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index e22881556e2a3..70ef435c4a37b 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -2668,11 +2668,6 @@ class CXXConstructorDecl final friend class ASTDeclWriter; friend TrailingObjects; - // FIXME: Just hacking it in here for now. - Expr **CtorClosureArgs = nullptr; - Expr **ctorClosureArgs() const { return getCanonicalDecl()->CtorClosureArgs; } - void setCtorClosureArgs(Expr **Args) { getCanonicalDecl()->CtorClosureArgs = Args; } - static CXXConstructorDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID, uint64_t AllocKind); static CXXConstructorDecl * @@ -2869,6 +2864,9 @@ class CXXConstructorDecl final return const_cast<CXXConstructorDecl*>(this)->getCanonicalDecl(); } + ArrayRef<CXXDefaultArgExpr*> getCtorClosureDefaultArgs() const; + void setCtorClosureDefaultArgs(ArrayRef<CXXDefaultArgExpr*> Args); + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == CXXConstructor; } diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index abf0cd5e18c2b..a6eb87ab7d8aa 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -989,6 +989,8 @@ void ASTContext::cleanup() { A->second->~AttrVec(); DeclAttrs.clear(); + CtorClosureDefaultArgs.clear(); + for (const auto &Value : ModuleInitializers) Value.second->~PerModuleInitializers(); ModuleInitializers.clear(); @@ -1547,6 +1549,17 @@ void ASTContext::eraseDeclAttrs(const Decl *D) { } } +ArrayRef<CXXDefaultArgExpr *> +ASTContext::getCtorClosureDefaultArgs(const CXXConstructorDecl *CD) { + return CtorClosureDefaultArgs.lookup(CD); +} + +void ASTContext::setCtorClosureDefaultArgs(const CXXConstructorDecl *CD, + ArrayRef<CXXDefaultArgExpr *> Args) { + assert(!CtorClosureDefaultArgs.contains(CD)); + CtorClosureDefaultArgs[CD] = Args; +} + ArrayRef<ExplicitInstantiationDecl *> ASTContext::getExplicitInstantiationDecls(const NamedDecl *Spec) const { auto It = diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index fc8a15287f438..f754c03a75451 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -3132,6 +3132,16 @@ bool CXXConstructorDecl::isSpecializationCopyingObject() const { return ParamType == ClassTy; } +ArrayRef<CXXDefaultArgExpr *> +CXXConstructorDecl::getCtorClosureDefaultArgs() const { + return getASTContext().getCtorClosureDefaultArgs(getCanonicalDecl()); +} + +void CXXConstructorDecl::setCtorClosureDefaultArgs( + ArrayRef<CXXDefaultArgExpr *> Args) { + getASTContext().setCtorClosureDefaultArgs(getCanonicalDecl(), Args); +} + void CXXDestructorDecl::anchor() {} CXXDestructorDecl *CXXDestructorDecl::CreateDeserialized(ASTContext &C, diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index 3de3fd8cbe3c8..6d0e46bac389e 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -4207,14 +4207,12 @@ MicrosoftCXXABI::getAddrOfCXXCtorClosure(const CXXConstructorDecl *CD, if (SrcVal) Args.add(RValue::get(SrcVal), SrcParam->getType()); - - // Add the rest of the default arguments. + // Get the rest of the default arguments. SmallVector<const Stmt *, 4> ArgVec; - for (unsigned I = IsCopy ? 1 : 0, N = CD->getNumParams(); I != N; ++I) { - assert(CD->getParamDecl(I)->hasDefaultArg() && "ctor closure lacks default args"); - assert(CD->ctorClosureArgs()); - ArgVec.push_back(CD->ctorClosureArgs()[I]); - } + for (const CXXDefaultArgExpr *Expr : CD->getCtorClosureDefaultArgs()) + ArgVec.push_back(Expr); + assert(ArgVec.size() == CD->getNumParams() - IsCopy); + CodeGenFunction::RunCleanupsScope Cleanups(CGF); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index e7a96ad1f390c..326609ac5f047 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -19803,10 +19803,12 @@ void Sema::ActOnFinishFunctionDeclarationDeclarator(Declarator &Declarator) { InventedParameterInfos.pop_back(); } -bool Sema::BuildDefaultArgsForCtorClosure(SourceLocation Loc, CXXConstructorDecl *Ctor, bool IsCopy) { +bool Sema::BuildDefaultArgsForCtorClosure(SourceLocation Loc, + CXXConstructorDecl *Ctor, + bool IsCopy) { assert(Context.getTargetInfo().getCXXABI().isMicrosoft()); - if (Ctor->ctorClosureArgs()) + if (!Ctor->getCtorClosureDefaultArgs().empty()) return false; unsigned NumParams = Ctor->getNumParams(); @@ -19814,17 +19816,17 @@ bool Sema::BuildDefaultArgsForCtorClosure(SourceLocation Loc, CXXConstructorDecl return false; unsigned FirstParam = IsCopy ? 1 : 0; - Expr **Args = new (getASTContext()) Expr*[NumParams]; - Args[0] = nullptr; + CXXDefaultArgExpr **Args = + new (getASTContext()) CXXDefaultArgExpr *[NumParams - FirstParam]; for (unsigned I = FirstParam; I != NumParams; ++I) { ExprResult R = BuildCXXDefaultArgExpr(Loc, Ctor, Ctor->getParamDecl(I)); CleanupVarDeclMarking(); if (R.isInvalid()) return true; - Args[I] = R.get(); + Args[I - FirstParam] = cast<CXXDefaultArgExpr>(R.get()); } - Ctor->setCtorClosureArgs(Args); + Ctor->setCtorClosureDefaultArgs(ArrayRef(Args, NumParams - FirstParam)); return false; } diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 8250b5bdec623..a25e58e434bf2 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -2333,11 +2333,13 @@ void ASTDeclReader::VisitCXXConstructorDecl(CXXConstructorDecl *D) { *D->getTrailingObjects<InheritedConstructor>() = InheritedConstructor(Shadow, Ctor); } - if (int NumCtorClosureArgs = Record.readInt()) { - Expr **Args = new (Reader.getContext()) Expr*[NumCtorClosureArgs]; - for (int I = 0; I != NumCtorClosureArgs; I++) - Args[I] = cast<Expr>(Record.readStmt()); - D->setCtorClosureArgs(Args); + + if (unsigned NumArgs = Record.readUInt32()) { + CXXDefaultArgExpr **Args = + new (Reader.getContext()) CXXDefaultArgExpr *[NumArgs]; + for (unsigned I = 0; I != NumArgs; I++) + Args[I] = cast<CXXDefaultArgExpr>(Record.readStmt()); + D->setCtorClosureDefaultArgs(ArrayRef(Args, NumArgs)); } VisitCXXMethodDecl(D); diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 2ca34561b18a5..f271769d8edf6 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -1774,13 +1774,11 @@ void ASTDeclWriter::VisitCXXConstructorDecl(CXXConstructorDecl *D) { Record.AddDeclRef(Inherited.getConstructor()); } - if (Expr **CtorClosureArgs = D->ctorClosureArgs()) { - Record.push_back(D->getNumParams()); - for (unsigned I = 0, N = D->getNumParams(); I != N; ++I) - Record.AddStmt(CtorClosureArgs[I]); - } else { - Record.push_back(0); - } + ArrayRef<CXXDefaultArgExpr *> CtorClosureDefaultArgs = + D->getCtorClosureDefaultArgs(); + Record.push_back((unsigned)CtorClosureDefaultArgs.size()); + for (CXXDefaultArgExpr *Arg : CtorClosureDefaultArgs) + Record.writeStmtRef(Arg); VisitCXXMethodDecl(D); Code = serialization::DECL_CXX_CONSTRUCTOR; >From 1649f009e83553a1ca7162994730a29e194120b5 Mon Sep 17 00:00:00 2001 From: Hans Wennborg <[email protected]> Date: Mon, 15 Jun 2026 16:09:01 +0200 Subject: [PATCH 10/13] tidy --- clang/include/clang/Sema/Sema.h | 4 ++-- clang/lib/Sema/SemaDecl.cpp | 2 +- clang/lib/Sema/SemaDeclCXX.cpp | 10 +++++----- clang/lib/Sema/SemaExprCXX.cpp | 3 +-- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 2 +- 5 files changed, 10 insertions(+), 11 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 84a124aa076fe..2a099bb7b6280 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -14265,8 +14265,8 @@ class Sema final : public SemaBase { LateInstantiatedAttrVec *LateAttrs = nullptr, LocalInstantiationScope *OuterMostScope = nullptr); - /// XXX: comment - bool BuildDefaultArgsForCtorClosure(SourceLocation Loc, CXXConstructorDecl *Ctor, bool IsCopy = false); + bool BuildCtorClosureDefaultArgs(SourceLocation Loc, CXXConstructorDecl *Ctor, + bool IsCopy = false); bool InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD, ParmVarDecl *Param); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 67b91609fb609..7dae03f748261 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -16307,7 +16307,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D, // If this is an MS ABI dllexport default constructor, instantiate any // default arguments. if (DLLExportAttr *Attr = Ctor->getAttr<DLLExportAttr>()) - BuildDefaultArgsForCtorClosure(Attr->getLocation(), Ctor); + BuildCtorClosureDefaultArgs(Attr->getLocation(), Ctor); } } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 326609ac5f047..06169ce43f8a2 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -6339,7 +6339,8 @@ static void ReferenceDllExportedMembers(Sema &S, CXXRecordDecl *Class) { if (S.Context.getTargetInfo().getCXXABI().isMicrosoft()) { auto *CD = dyn_cast<CXXConstructorDecl>(MD); if (CD && CD->isDefaultConstructor() && TSK == TSK_Undeclared) { - S.BuildDefaultArgsForCtorClosure(CD->getAttr<DLLExportAttr>()->getLocation(), CD); + S.BuildCtorClosureDefaultArgs( + CD->getAttr<DLLExportAttr>()->getLocation(), CD); } } @@ -6392,7 +6393,7 @@ static void checkForMultipleExportedDefaultConstructors(Sema &S, // If the class is non-dependent, mark the default arguments as ODR-used so // that we can properly codegen the constructor closure. if (!Class->isDependentContext()) { - S.BuildDefaultArgsForCtorClosure(Attr->getLocation(), CD); + S.BuildCtorClosureDefaultArgs(Attr->getLocation(), CD); S.DiscardCleanupsInEvaluationContext(); } @@ -19803,9 +19804,8 @@ void Sema::ActOnFinishFunctionDeclarationDeclarator(Declarator &Declarator) { InventedParameterInfos.pop_back(); } -bool Sema::BuildDefaultArgsForCtorClosure(SourceLocation Loc, - CXXConstructorDecl *Ctor, - bool IsCopy) { +bool Sema::BuildCtorClosureDefaultArgs(SourceLocation Loc, + CXXConstructorDecl *Ctor, bool IsCopy) { assert(Context.getTargetInfo().getCXXABI().isMicrosoft()); if (!Ctor->getCtorClosureDefaultArgs().empty()) diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 59e69314c2803..3c3f140cf6def 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -1070,8 +1070,7 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, // We don't keep the instantiated default argument expressions around so // we must rebuild them here. - // XXX: surprisingly, CD->isCopyConstructor() is not necessarily true here! - if (BuildDefaultArgsForCtorClosure(ThrowLoc, CD, /*IsCopy=*/true)) + if (BuildCtorClosureDefaultArgs(ThrowLoc, CD, /*IsCopy=*/true)) return true; } } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 9d21d5f96b020..b261d3d6881a2 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -5946,7 +5946,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, if (Context.getTargetInfo().getCXXABI().isMicrosoft() && Ctor->isDefaultConstructor()) { if (DLLExportAttr *Attr = Ctor->getAttr<DLLExportAttr>()) - BuildDefaultArgsForCtorClosure(Attr->getLocation(), Ctor); + BuildCtorClosureDefaultArgs(Attr->getLocation(), Ctor); } } >From a24bad3ba0058fd9329edf157f0d7e56b83bfd9e Mon Sep 17 00:00:00 2001 From: Hans Wennborg <[email protected]> Date: Mon, 15 Jun 2026 16:24:26 +0200 Subject: [PATCH 11/13] evil test case --- clang/test/CodeGenCXX/microsoft-abi-throw.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/clang/test/CodeGenCXX/microsoft-abi-throw.cpp b/clang/test/CodeGenCXX/microsoft-abi-throw.cpp index 4fd0df42d8ff5..2c4bdd9869831 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-throw.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-throw.cpp @@ -82,6 +82,16 @@ void h2(DefaultConstEval &d) { throw d; } +// This will generate both the default constructor closure and the copy constructor closure -- for the same constructor. +struct DefaultCtorIsCopyCtor; +const DefaultCtorIsCopyCtor& foo(); +struct DefaultCtorIsCopyCtor { + __declspec(dllexport) DefaultCtorIsCopyCtor(const DefaultCtorIsCopyCtor& = foo(), int = 42) {} +}; +void h3(DefaultCtorIsCopyCtor &d) { + throw d; +} + struct DeletedCopy { DeletedCopy(); DeletedCopy(DeletedCopy &&); >From 2a62be8f9cbb36d81dfebf23b2fb39a47540e48e Mon Sep 17 00:00:00 2001 From: Hans Wennborg <[email protected]> Date: Mon, 15 Jun 2026 16:59:33 +0200 Subject: [PATCH 12/13] handle the evil test case (both copy and default ctor closures) --- clang/lib/CodeGen/MicrosoftCXXABI.cpp | 3 ++- clang/lib/Sema/SemaDeclCXX.cpp | 18 ++++++++++++------ clang/test/CodeGenCXX/microsoft-abi-throw.cpp | 7 ++++++- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index 6d0e46bac389e..f5f6f359101ae 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -4209,7 +4209,8 @@ MicrosoftCXXABI::getAddrOfCXXCtorClosure(const CXXConstructorDecl *CD, // Get the rest of the default arguments. SmallVector<const Stmt *, 4> ArgVec; - for (const CXXDefaultArgExpr *Expr : CD->getCtorClosureDefaultArgs()) + for (const CXXDefaultArgExpr *Expr : + CD->getCtorClosureDefaultArgs().drop_front(IsCopy ? 1 : 0)) ArgVec.push_back(Expr); assert(ArgVec.size() == CD->getNumParams() - IsCopy); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 06169ce43f8a2..a83664d887408 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -19808,25 +19808,31 @@ bool Sema::BuildCtorClosureDefaultArgs(SourceLocation Loc, CXXConstructorDecl *Ctor, bool IsCopy) { assert(Context.getTargetInfo().getCXXABI().isMicrosoft()); - if (!Ctor->getCtorClosureDefaultArgs().empty()) + if (!Ctor->getCtorClosureDefaultArgs().empty()) { + // If we build args for default constructor closures, those will have + // been generated *before* building args for any copy constructor closures. + assert(IsCopy || Ctor->getCtorClosureDefaultArgs()[0] != nullptr); return false; + } unsigned NumParams = Ctor->getNumParams(); if (NumParams == 0) return false; - unsigned FirstParam = IsCopy ? 1 : 0; CXXDefaultArgExpr **Args = - new (getASTContext()) CXXDefaultArgExpr *[NumParams - FirstParam]; + new (getASTContext()) CXXDefaultArgExpr *[NumParams]; + + if (IsCopy) + Args[0] = nullptr; // Copy ctor closure will provide the first argument. - for (unsigned I = FirstParam; I != NumParams; ++I) { + for (unsigned I = IsCopy ? 1 : 0; I != NumParams; ++I) { ExprResult R = BuildCXXDefaultArgExpr(Loc, Ctor, Ctor->getParamDecl(I)); CleanupVarDeclMarking(); if (R.isInvalid()) return true; - Args[I - FirstParam] = cast<CXXDefaultArgExpr>(R.get()); + Args[I] = cast<CXXDefaultArgExpr>(R.get()); } - Ctor->setCtorClosureDefaultArgs(ArrayRef(Args, NumParams - FirstParam)); + Ctor->setCtorClosureDefaultArgs(ArrayRef(Args, NumParams)); return false; } diff --git a/clang/test/CodeGenCXX/microsoft-abi-throw.cpp b/clang/test/CodeGenCXX/microsoft-abi-throw.cpp index 2c4bdd9869831..b37e2c2deec9d 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-throw.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-throw.cpp @@ -86,11 +86,16 @@ void h2(DefaultConstEval &d) { struct DefaultCtorIsCopyCtor; const DefaultCtorIsCopyCtor& foo(); struct DefaultCtorIsCopyCtor { - __declspec(dllexport) DefaultCtorIsCopyCtor(const DefaultCtorIsCopyCtor& = foo(), int = 42) {} + __declspec(dllexport) DefaultCtorIsCopyCtor(const DefaultCtorIsCopyCtor& = foo(), int = 456) {} }; void h3(DefaultCtorIsCopyCtor &d) { throw d; } +// CHECK-LABEL: @"??_FDefaultCtorIsCopyCtor@@QAEXXZ" +// CHECK: %[[foo:.*]] = call {{.*}} @"?foo@@YAABUDefaultCtorIsCopyCtor@@XZ" +// CHECK: call {{.*}} @"??0DefaultCtorIsCopyCtor@@QAE@ABU0@H@Z"({{.*}} %[[foo]], i32 noundef 456) +// CHECK-LABEL: @"??_ODefaultCtorIsCopyCtor@@QAEXABU0@@Z" +// CHECK: call {{.*}} @"??0DefaultCtorIsCopyCtor@@QAE@ABU0@H@Z"({{.*}} i32 noundef 456) struct DeletedCopy { DeletedCopy(); >From 9512c46fa833c6b18bb3e4055fd4e424f0b80f77 Mon Sep 17 00:00:00 2001 From: Hans Wennborg <[email protected]> Date: Mon, 15 Jun 2026 17:11:31 +0200 Subject: [PATCH 13/13] format --- clang/include/clang/AST/DeclCXX.h | 4 ++-- clang/lib/CodeGen/MicrosoftCXXABI.cpp | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 70ef435c4a37b..7d14241ba024a 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -2864,8 +2864,8 @@ class CXXConstructorDecl final return const_cast<CXXConstructorDecl*>(this)->getCanonicalDecl(); } - ArrayRef<CXXDefaultArgExpr*> getCtorClosureDefaultArgs() const; - void setCtorClosureDefaultArgs(ArrayRef<CXXDefaultArgExpr*> Args); + ArrayRef<CXXDefaultArgExpr *> getCtorClosureDefaultArgs() const; + void setCtorClosureDefaultArgs(ArrayRef<CXXDefaultArgExpr *> Args); // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index f5f6f359101ae..d324580036f6a 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -4214,7 +4214,6 @@ MicrosoftCXXABI::getAddrOfCXXCtorClosure(const CXXConstructorDecl *CD, ArgVec.push_back(Expr); assert(ArgVec.size() == CD->getNumParams() - IsCopy); - CodeGenFunction::RunCleanupsScope Cleanups(CGF); const auto *FPT = CD->getType()->castAs<FunctionProtoType>(); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
