Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -9253,6 +9253,8 @@ LateInstantiatedAttrVec *LateAttrs = nullptr, LocalInstantiationScope *OuterMostScope = nullptr); + void InstantiateDefaultCtorDefaultArgs(CXXConstructorDecl *Ctor); + bool usesPartialOrExplicitSpecialization( SourceLocation Loc, ClassTemplateSpecializationDecl *ClassTemplateSpec); Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -13994,6 +13994,16 @@ FD->setInvalidDecl(); } + if (auto *Ctor = dyn_cast(FD)) { + if (Ctor->getTemplateSpecializationKind() == TSK_ExplicitSpecialization && + Ctor->isDefaultConstructor() && + Context.getTargetInfo().getCXXABI().isMicrosoft()) { + // If this is an MS ABI dllexport default constructor, instantiate any + // default arguments. + InstantiateDefaultCtorDefaultArgs(Ctor); + } + } + // See if this is a redefinition. If 'will have body' (or similar) is already // set, then these checks were already performed when it was set. if (!FD->willHaveBody() && !FD->isLateTemplateParsed() && Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -715,6 +715,26 @@ } } +/// 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 Sema::InstantiateDefaultCtorDefaultArgs(CXXConstructorDecl *Ctor) { + assert(Context.getTargetInfo().getCXXABI().isMicrosoft() && + Ctor->isDefaultConstructor()); + unsigned NumParams = Ctor->getNumParams(); + if (NumParams == 0) + return; + DLLExportAttr *Attr = Ctor->getAttr(); + if (!Attr) + return; + for (unsigned I = 0; I != NumParams; ++I) { + (void)CheckCXXDefaultArgExpr(Attr->getLocation(), Ctor, + Ctor->getParamDecl(I)); + DiscardCleanupsInEvaluationContext(); + } +} + /// 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 @@ -4608,27 +4628,6 @@ return cast_or_null(SubstDecl(FD, FD->getParent(), MArgs)); } -/// 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. -static void InstantiateDefaultCtorDefaultArgs(Sema &S, - CXXConstructorDecl *Ctor) { - assert(S.Context.getTargetInfo().getCXXABI().isMicrosoft() && - Ctor->isDefaultConstructor()); - unsigned NumParams = Ctor->getNumParams(); - if (NumParams == 0) - return; - DLLExportAttr *Attr = Ctor->getAttr(); - if (!Attr) - return; - for (unsigned I = 0; I != NumParams; ++I) { - (void)S.CheckCXXDefaultArgExpr(Attr->getLocation(), Ctor, - Ctor->getParamDecl(I)); - S.DiscardCleanupsInEvaluationContext(); - } -} - /// Instantiate the definition of the given function from its /// template. /// @@ -4847,7 +4846,7 @@ // default arguments. if (Context.getTargetInfo().getCXXABI().isMicrosoft() && Ctor->isDefaultConstructor()) { - InstantiateDefaultCtorDefaultArgs(*this, Ctor); + InstantiateDefaultCtorDefaultArgs(Ctor); } } Index: clang/test/CodeGenCXX/dllexport-ctor-closure.cpp =================================================================== --- clang/test/CodeGenCXX/dllexport-ctor-closure.cpp +++ clang/test/CodeGenCXX/dllexport-ctor-closure.cpp @@ -50,6 +50,13 @@ // CHECK-LABEL: define weak_odr dso_local dllexport x86_thiscallcc void @"??_F?$TemplateWithClosure@H@@QAEXXZ"({{.*}}) {{#[0-9]+}} comdat // CHECK: call {{.*}} @"??0?$TemplateWithClosure@H@@QAE@H@Z"({{.*}}, i32 4) +template struct __declspec(dllexport) ExportedTemplateWithClosure { + ExportedTemplateWithClosure(int x = sizeof(T)) {} +}; +template <> ExportedTemplateWithClosure::ExportedTemplateWithClosure(int) {}; +// CHECK-LABEL: define weak_odr dso_local dllexport x86_thiscallcc void @"??_F?$ExportedTemplateWithClosure@H@@QAEXXZ"({{.*}}) {{#[0-9]+}} comdat +// CHECK: call {{.*}} @"??0?$ExportedTemplateWithClosure@H@@QAE@H@Z"({{.*}}, i32 4) + struct __declspec(dllexport) NestedOuter { DELETE_IMPLICIT_MEMBERS(NestedOuter); NestedOuter(void *p = 0) {} Index: clang/test/SemaCXX/dllexport.cpp =================================================================== --- clang/test/SemaCXX/dllexport.cpp +++ clang/test/SemaCXX/dllexport.cpp @@ -792,6 +792,11 @@ }; template struct HasDefaults2; // expected-note {{in instantiation of member function 'HasDefaults2::HasDefaults2' requested here}} +template struct __declspec(dllexport) HasDefaults3 { // expected-note{{in instantiation of default function argument expression for 'HasDefaults3' required here}} + HasDefaults3(int x = sizeof(T)) {} // expected-error {{invalid application of 'sizeof'}} +}; +template <> HasDefaults3::HasDefaults3(int) {}; + #endif //===----------------------------------------------------------------------===//