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

Reply via email to