Index: lib/AST/MicrosoftMangle.cpp =================================================================== --- lib/AST/MicrosoftMangle.cpp +++ lib/AST/MicrosoftMangle.cpp @@ -1640,10 +1640,11 @@ ->getPointeeType(), /*SpelledAsLValue=*/true), Range); + Out << '@'; } else { llvm_unreachable("unexpected constructor closure!"); } - Out << "@Z"; + Out << 'Z'; return; } Out << '@'; Index: lib/CodeGen/CGCall.cpp =================================================================== --- lib/CodeGen/CGCall.cpp +++ lib/CodeGen/CGCall.cpp @@ -347,12 +347,16 @@ } const CGFunctionInfo & -CodeGenTypes::arrangeMSCopyCtorClosure(const CXXConstructorDecl *CD) { +CodeGenTypes::arrangeMSCtorClosure(const CXXConstructorDecl *CD, + CXXCtorType CT) { + assert(CT == Ctor_CopyingClosure || CT == Ctor_DefaultClosure); + CanQual FTP = GetFormalType(CD); SmallVector ArgTys; const CXXRecordDecl *RD = CD->getParent(); ArgTys.push_back(GetThisType(Context, RD)); - ArgTys.push_back(*FTP->param_type_begin()); + if (CT == Ctor_CopyingClosure) + ArgTys.push_back(*FTP->param_type_begin()); if (RD->getNumVBases() > 0) ArgTys.push_back(Context.IntTy); CallingConv CC = Context.getDefaultCallingConvention( Index: lib/CodeGen/CodeGenTypes.h =================================================================== --- lib/CodeGen/CodeGenTypes.h +++ lib/CodeGen/CodeGenTypes.h @@ -264,7 +264,8 @@ const FunctionProtoType *type, RequiredArgs required); const CGFunctionInfo &arrangeMSMemberPointerThunk(const CXXMethodDecl *MD); - const CGFunctionInfo &arrangeMSCopyCtorClosure(const CXXConstructorDecl *CD); + const CGFunctionInfo &arrangeMSCtorClosure(const CXXConstructorDecl *CD, + CXXCtorType CT); const CGFunctionInfo &arrangeFreeFunctionType(CanQual Ty); const CGFunctionInfo &arrangeFreeFunctionType(CanQual Ty); Index: lib/CodeGen/MicrosoftCXXABI.cpp =================================================================== --- lib/CodeGen/MicrosoftCXXABI.cpp +++ lib/CodeGen/MicrosoftCXXABI.cpp @@ -635,7 +635,8 @@ return Fn; } - llvm::Function *getAddrOfCXXCopyCtorClosure(const CXXConstructorDecl *CD); + llvm::Function *getAddrOfCXXCtorClosure(const CXXConstructorDecl *CD, + CXXCtorType CT); llvm::Constant *getCatchableType(QualType T, uint32_t NVOffset = 0, @@ -1063,6 +1064,22 @@ void MicrosoftCXXABI::EmitCXXConstructors(const CXXConstructorDecl *D) { // There's only one constructor type in this ABI. CGM.EmitGlobal(GlobalDecl(D, Ctor_Complete)); + + // Exported default constructors either have a simple call-site where they use + // 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()) { + CallingConv ExpectedCallingConv = getContext().getDefaultCallingConvention( + /*IsVariadic=*/false, /*IsCXXMethod=*/true); + CallingConv ActualCallingConv = + D->getType()->getAs()->getCallConv(); + if (ExpectedCallingConv != ActualCallingConv || D->getNumParams() != 0) { + llvm::Function *Fn = getAddrOfCXXCtorClosure(D, Ctor_DefaultClosure); + Fn->setLinkage(llvm::GlobalValue::WeakODRLinkage); + Fn->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass); + } + } } void MicrosoftCXXABI::EmitVBPtrStores(CodeGenFunction &CGF, @@ -3223,11 +3240,14 @@ } llvm::Function * -MicrosoftCXXABI::getAddrOfCXXCopyCtorClosure(const CXXConstructorDecl *CD) { +MicrosoftCXXABI::getAddrOfCXXCtorClosure(const CXXConstructorDecl *CD, + CXXCtorType CT) { + assert(CT == Ctor_CopyingClosure || CT == Ctor_DefaultClosure); + // Calculate the mangled name. SmallString<256> ThunkName; llvm::raw_svector_ostream Out(ThunkName); - getMangleContext().mangleCXXCtor(CD, Ctor_CopyingClosure, Out); + getMangleContext().mangleCXXCtor(CD, CT, Out); Out.flush(); // If the thunk has been generated previously, just return it. @@ -3235,12 +3255,13 @@ return cast(GV); // Create the llvm::Function. - const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeMSCopyCtorClosure(CD); + const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeMSCtorClosure(CD, CT); llvm::FunctionType *ThunkTy = CGM.getTypes().GetFunctionType(FnInfo); const CXXRecordDecl *RD = CD->getParent(); QualType RecordTy = getContext().getRecordType(RD); llvm::Function *ThunkFn = llvm::Function::Create( ThunkTy, getLinkageForRTTI(RecordTy), ThunkName.str(), &CGM.getModule()); + bool IsCopy = CT == Ctor_CopyingClosure; // Start codegen. CodeGenFunction CGF(CGM); @@ -3249,8 +3270,7 @@ // Build FunctionArgs. FunctionArgList FunctionArgs; - // A copy constructor always starts with a 'this' pointer as its first - // argument. + // A constructor always starts with a 'this' pointer as its first argument. buildThisParam(CGF, FunctionArgs); // Following the 'this' pointer is a reference to the source object that we @@ -3259,11 +3279,12 @@ getContext(), nullptr, SourceLocation(), &getContext().Idents.get("src"), getContext().getLValueReferenceType(RecordTy, /*SpelledAsLValue=*/true)); - FunctionArgs.push_back(&SrcParam); + if (IsCopy) + FunctionArgs.push_back(&SrcParam); - // Copy constructors for classes which utilize virtual bases have an - // additional parameter which indicates whether or not it is being delegated - // to by a more derived constructor. + // Constructors for classes which utilize virtual bases have an additional + // parameter which indicates whether or not it is being delegated to by a more + // derived constructor. ImplicitParamDecl IsMostDerived(getContext(), nullptr, SourceLocation(), &getContext().Idents.get("is_most_derived"), getContext().IntTy); @@ -3278,7 +3299,8 @@ llvm::Value *This = getThisValue(CGF); llvm::Value *SrcVal = - CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(&SrcParam), "src"); + IsCopy ? CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(&SrcParam), "src") + : nullptr; CallArgList Args; @@ -3286,11 +3308,12 @@ Args.add(RValue::get(This), CD->getThisType(getContext())); // Push the src ptr. - Args.add(RValue::get(SrcVal), SrcParam.getType()); + if (SrcVal) + Args.add(RValue::get(SrcVal), SrcParam.getType()); // Add the rest of the default arguments. std::vector ArgVec; - for (unsigned I = 1, E = CD->getNumParams(); I != E; ++I) + for (unsigned I = IsCopy ? 1 : 0, E = CD->getNumParams(); I != E; ++I) ArgVec.push_back(getContext().getDefaultArgExprForConstructor(CD, I)); CodeGenFunction::RunCleanupsScope Cleanups(CGF); @@ -3298,7 +3321,7 @@ const auto *FPT = CD->getType()->castAs(); ConstExprIterator ArgBegin(ArgVec.data()), ArgEnd(ArgVec.data() + ArgVec.size()); - CGF.EmitCallArgs(Args, FPT, ArgBegin, ArgEnd, CD, 1); + CGF.EmitCallArgs(Args, FPT, ArgBegin, ArgEnd, CD, IsCopy ? 1 : 0); // Insert any ABI-specific implicit constructor arguments. unsigned ExtraArgs = addImplicitConstructorArgs(CGF, CD, Ctor_Complete, @@ -3358,7 +3381,7 @@ llvm::Constant *CopyCtor; if (CD) { if (CT == Ctor_CopyingClosure) - CopyCtor = getAddrOfCXXCopyCtorClosure(CD); + CopyCtor = getAddrOfCXXCtorClosure(CD, Ctor_CopyingClosure); else CopyCtor = CGM.getAddrOfCXXStructor(CD, StructorType::Complete); Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -12077,9 +12077,32 @@ RD->completeDefinition(); } - if (isa(Tag)) + if (auto *Class = dyn_cast(Tag)) { FieldCollector->FinishClass(); + // Default constructors that are annotated with __declspec(dllexport) which + // have default arguments or don't use the standard calling convention are + // wrapped with a thunk called the default constructor closure. + if (!Class->getDescribedClassTemplate() && + Context.getTargetInfo().getCXXABI().isMicrosoft()) { + for (Decl *Member : Class->decls()) { + auto *CD = dyn_cast(Member); + if (!CD || !CD->isDefaultConstructor() || !CD->hasAttr()) + continue; + + for (unsigned I = 0, E = CD->getNumParams(); I != E; ++I) { + // Skip any default arguments that we've already instantiated. + if (Context.getDefaultArgExprForConstructor(CD, I)) + continue; + + Expr *DefaultArg = BuildCXXDefaultArgExpr(Class->getLocation(), CD, + CD->getParamDecl(I)).get(); + Context.addDefaultArgExprForConstructor(CD, I, DefaultArg); + } + } + } + } + // Exit this scope of this tag's definition. PopDeclContext(); Index: test/CodeGenCXX/dllexport.cpp =================================================================== --- test/CodeGenCXX/dllexport.cpp +++ test/CodeGenCXX/dllexport.cpp @@ -484,6 +484,28 @@ }; }; +struct CtorWithClosure { + __declspec(dllexport) CtorWithClosure(...) {} +// M32-DAG: define weak_odr dllexport void @"\01??_FCtorWithClosure@@QAEXXZ" +// M32-DAG: %[[this_addr:.*]] = alloca %struct.CtorWithClosure*, align 4 +// M32-DAG: store %struct.CtorWithClosure* %this, %struct.CtorWithClosure** %[[this_addr]], align 4 +// M32-DAG: %[[this:.*]] = load %struct.CtorWithClosure*, %struct.CtorWithClosure** %[[this_addr]] +// M32-DAG: call %struct.CtorWithClosure* (%struct.CtorWithClosure*, ...)* @"\01??0CtorWithClosure@@QAA@ZZ"(%struct.CtorWithClosure* %[[this]]) +// M32-DAG: ret void +}; + +struct __declspec(dllexport) ClassWithClosure { + ClassWithClosure(ClassWithClosure &&) = delete; + ClassWithClosure(ClassWithClosure &) = delete; + ~ClassWithClosure() = delete; + ClassWithClosure(...) {} +// M32-DAG: define weak_odr dllexport void @"\01??_FClassWithClosure@@QAEXXZ" +// M32-DAG: %[[this_addr:.*]] = alloca %struct.ClassWithClosure*, align 4 +// M32-DAG: store %struct.ClassWithClosure* %this, %struct.ClassWithClosure** %[[this_addr]], align 4 +// M32-DAG: %[[this:.*]] = load %struct.ClassWithClosure*, %struct.ClassWithClosure** %[[this_addr]] +// M32-DAG: call %struct.ClassWithClosure* (%struct.ClassWithClosure*, ...)* @"\01??0ClassWithClosure@@QAA@ZZ"(%struct.ClassWithClosure* %[[this]]) +// M32-DAG: ret void +}; struct __declspec(dllexport) T { // Copy assignment operator: