diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 02b73e9113fa..a70e16cce18c 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -5395,13 +5395,31 @@ static void ReferenceDllExportedMethods(Sema &S, CXXRecordDecl *Class) { } } -static void checkForMultipleExportedDefaultConstructors(Sema &S, CXXRecordDecl *Class) { +static void checkForMultipleExportedDefaultConstructors(Sema &S, + CXXRecordDecl *Class) { + // Only the MS ABI has default constructor closures, so we don't need to do + // this semantic checking anywhere else. + if (!S.Context.getTargetInfo().getCXXABI().isMicrosoft()) + return; + CXXConstructorDecl *LastExportedDefaultCtor = nullptr; for (Decl *Member : Class->decls()) { // Look for exported default constructors. auto *CD = dyn_cast(Member); - if (!CD || !CD->isDefaultConstructor() || !CD->hasAttr()) + if (!CD || !CD->isDefaultConstructor()) continue; + auto *Attr = CD->getAttr(); + if (!Attr) + continue; + + // 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(); + } + } if (LastExportedDefaultCtor) { S.Diag(LastExportedDefaultCtor->getLocation(), diff --git a/clang/test/CodeGenCXX/dllexport-ctor-closure.cpp b/clang/test/CodeGenCXX/dllexport-ctor-closure.cpp index 24a2ba6bdea2..4fae7e10e8b6 100644 --- a/clang/test/CodeGenCXX/dllexport-ctor-closure.cpp +++ b/clang/test/CodeGenCXX/dllexport-ctor-closure.cpp @@ -61,3 +61,22 @@ struct __declspec(dllexport) NestedOuter { // CHECK-LABEL: define weak_odr dllexport x86_thiscallcc void @"\01??_FNestedOuter@@QAEXXZ"({{.*}}) {{#[0-9]+}} comdat // CHECK-LABEL: define weak_odr dllexport x86_thiscallcc void @"\01??_FNestedInner@NestedOuter@@QAEXXZ"({{.*}}) {{#[0-9]+}} comdat + +struct HasDtor { + ~HasDtor(); + int o; +}; +struct HasImplicitDtor1 { HasDtor o; }; +struct HasImplicitDtor2 { HasDtor o; }; +struct __declspec(dllexport) CtorClosureInline { + CtorClosureInline(const HasImplicitDtor1 &v = {}) {} +}; +struct __declspec(dllexport) CtorClosureOutOfLine { + CtorClosureOutOfLine(const HasImplicitDtor2 &v = {}); +}; +CtorClosureOutOfLine::CtorClosureOutOfLine(const HasImplicitDtor2 &v) {} + +// CHECK-LABEL: define weak_odr dllexport x86_thiscallcc void @"\01??_FCtorClosureInline@@QAEXXZ" +// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"\01??1HasImplicitDtor1@@QAE@XZ" +// CHECK-LABEL: define weak_odr dllexport x86_thiscallcc void @"\01??_FCtorClosureOutOfLine@@QAEXXZ" +// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"\01??1HasImplicitDtor2@@QAE@XZ"