diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/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); diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -1244,12 +1244,14 @@ // the typical calling convention and have a single 'this' pointer for an // argument -or- they get a wrapper function which appropriately thunks to the // real default constructor. This thunk is the default constructor closure. - if (D->hasAttr() && D->isDefaultConstructor()) + if (D->hasAttr() && D->isDefaultConstructor() && + D->isDefined()) { if (!hasDefaultCXXMethodCC(getContext(), D) || D->getNumParams() != 0) { llvm::Function *Fn = getAddrOfCXXCtorClosure(D, Ctor_DefaultClosure); Fn->setLinkage(llvm::GlobalValue::WeakODRLinkage); CGM.setGVProperties(Fn, D); } + } } void MicrosoftCXXABI::EmitVBPtrStores(CodeGenFunction &CGF, diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/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() && diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/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); } } diff --git a/clang/test/CodeGenCXX/dllexport-ctor-closure.cpp b/clang/test/CodeGenCXX/dllexport-ctor-closure.cpp --- a/clang/test/CodeGenCXX/dllexport-ctor-closure.cpp +++ b/clang/test/CodeGenCXX/dllexport-ctor-closure.cpp @@ -50,6 +50,14 @@ // 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); // Don't try to emit the closure for a declaration. +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) {} diff --git a/clang/test/SemaCXX/dllexport.cpp b/clang/test/SemaCXX/dllexport.cpp --- a/clang/test/SemaCXX/dllexport.cpp +++ b/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 //===----------------------------------------------------------------------===//