Author: vangthao95
Date: 2026-09-05T09:11:54+02:00
New Revision: 1943eaf4faa33a5eace0900f5aa1e6b92ef80624

URL: 
https://github.com/llvm/llvm-project/commit/1943eaf4faa33a5eace0900f5aa1e6b92ef80624
DIFF: 
https://github.com/llvm/llvm-project/commit/1943eaf4faa33a5eace0900f5aa1e6b92ef80624.diff

LOG: [clang][Sema] Check exported default constructors in nested classes 
(#214275)

Teach Clang to check exported default constructors declared in nested
classes. This prepares Microsoft ABI constructor closures for
non-dependent nested classes before CodeGen.

This fixes a failure seen when compiling PyTorch on Windows. An exported
nested
class with defaults for every constructor parameter caused Clang to emit
its
constructor closure without cached default arguments and assert in
MicrosoftCXXABI.cpp.

Assisted by: GPT-5.6 Sol

(cherry picked from commit 1b782da49ae976dbb59607b95b49a1465e2cfef9)

Added: 
    

Modified: 
    clang/lib/Sema/SemaDeclCXX.cpp
    clang/test/CodeGenCXX/dllexport-ctor-closure-nested.cpp
    clang/test/PCH/dllexport-default-arg-closure.cpp
    clang/test/SemaCXX/default-arg-closures.cpp
    clang/test/SemaCXX/dllexport.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 685412d681680..b0669c602d249 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -6383,8 +6383,19 @@ static void 
checkForMultipleExportedDefaultConstructors(Sema &S,
   if (!S.Context.getTargetInfo().getCXXABI().isMicrosoft())
     return;
 
+  if (Class->isInvalidDecl())
+    return;
+
   CXXConstructorDecl *LastExportedDefaultCtor = nullptr;
   for (Decl *Member : Class->decls()) {
+    // Nested classes finish delayed default argument parsing with the 
outermost
+    // class, so check each nested definition here.
+    if (auto *NestedClass = dyn_cast<CXXRecordDecl>(Member)) {
+      if (NestedClass->isThisDeclarationADefinition())
+        checkForMultipleExportedDefaultConstructors(S, NestedClass);
+      continue;
+    }
+
     // Look for exported default constructors.
     auto *CD = dyn_cast<CXXConstructorDecl>(Member);
     if (!CD || !CD->isDefaultConstructor())

diff  --git a/clang/test/CodeGenCXX/dllexport-ctor-closure-nested.cpp 
b/clang/test/CodeGenCXX/dllexport-ctor-closure-nested.cpp
index 36dab8600e21b..e949bc82686c7 100644
--- a/clang/test/CodeGenCXX/dllexport-ctor-closure-nested.cpp
+++ b/clang/test/CodeGenCXX/dllexport-ctor-closure-nested.cpp
@@ -18,3 +18,14 @@ struct __declspec(dllexport) CtorClosureOuter {
 
 // CHECK-LABEL: $"??1HasImplicitDtor1@@QAE@XZ" = comdat any
 // CHECK-LABEL: define weak_odr dso_local dllexport x86_thiscallcc void 
@"??_FCtorClosureInner@CtorClosureOuter@@QAEXXZ"({{.*}}) {{#[0-9]+}} comdat
+
+// Member-level dllexport on a nested default constructor needs constructor
+// closure default arguments before the enclosing class is emitted.
+struct MemberExportedCtorClosureOuter {
+  struct MemberExportedCtorClosureInner {
+    __declspec(dllexport) MemberExportedCtorClosureInner(
+        const HasImplicitDtor1 &v = {}) {}
+  };
+};
+
+// CHECK-LABEL: define weak_odr dso_local dllexport x86_thiscallcc void 
@"??_FMemberExportedCtorClosureInner@MemberExportedCtorClosureOuter@@QAEXXZ"({{.*}})
 {{#[0-9]+}} comdat

diff  --git a/clang/test/PCH/dllexport-default-arg-closure.cpp 
b/clang/test/PCH/dllexport-default-arg-closure.cpp
index b5ac7815b8111..b56d166e8d9f3 100644
--- a/clang/test/PCH/dllexport-default-arg-closure.cpp
+++ b/clang/test/PCH/dllexport-default-arg-closure.cpp
@@ -20,6 +20,15 @@ struct __declspec(dllexport) Foo {
 // CHECK: define weak_odr dso_local dllexport void 
@"??_FFoo@@QEAAXXZ"(ptr{{.*}})
 // CHECK:   call noundef ptr @"??0Foo@@QEAA@W4E@0@@Z"(ptr {{.*}}, i32 noundef 
0)
 
+struct PCHMemberExportOuter {
+  struct Inner {
+    enum E { E0 } e;
+    __declspec(dllexport) Inner(E e = E0) : e(e) {}
+  };
+};
+
+// CHECK: define weak_odr dso_local dllexport void 
@"??_FInner@PCHMemberExportOuter@@QEAAXXZ"(ptr{{.*}})
+
 #else
 
 

diff  --git a/clang/test/SemaCXX/default-arg-closures.cpp 
b/clang/test/SemaCXX/default-arg-closures.cpp
index 676bd486105f9..86c44f0ead9f7 100644
--- a/clang/test/SemaCXX/default-arg-closures.cpp
+++ b/clang/test/SemaCXX/default-arg-closures.cpp
@@ -25,6 +25,15 @@ struct DependentDefaultCopyArg {
 struct HasMember {
   enum { member = 0 };
 };
+
+template <typename T>
+struct NestedDependentDefaultCtorArg {
+  struct Inner {
+    __declspec(dllexport) Inner(int n = T::member) {}
+  };
+};
+NestedDependentDefaultCtorArg<HasMember>::Inner ValidNestedDependentArg;
+
 void UseDependentArg() { throw DependentDefaultCopyArg<HasMember>(); }
 
 void ErrorInDependentArg() {

diff  --git a/clang/test/SemaCXX/dllexport.cpp 
b/clang/test/SemaCXX/dllexport.cpp
index d625b15557762..70e7f1398ad05 100644
--- a/clang/test/SemaCXX/dllexport.cpp
+++ b/clang/test/SemaCXX/dllexport.cpp
@@ -746,6 +746,20 @@ struct ClassTemplateWithMultipleDefaultCtors {
   __declspec(dllexport) ClassTemplateWithMultipleDefaultCtors(int = 30, ...) 
{} // ms-note{{declared here}}
 };
 
+struct ClassWithNestedMultipleDefaultCtors {
+  struct Nested {
+    __declspec(dllexport) Nested(int = 40) {}      // 
ms-error{{'__declspec(dllexport)' cannot be applied to more than one default 
constructor}}
+    __declspec(dllexport) Nested(int = 30, ...) {} // ms-note{{declared here}}
+  };
+};
+
+struct ClassWithNestedObviousMultipleDefaultCtors {
+  struct Nested {
+    __declspec(dllexport) Nested() {}    // ms-error{{'__declspec(dllexport)' 
cannot be applied to more than one default constructor}}
+    __declspec(dllexport) Nested(...) {} // ms-note{{declared here}}
+  };
+};
+
 template <typename T> struct HasDefaults {
   HasDefaults(int x = sizeof(T)) {} // ms-error {{invalid application of 
'sizeof'}}
 };


        
_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to