Index: cfe/trunk/lib/AST/MicrosoftMangle.cpp =================================================================== --- cfe/trunk/lib/AST/MicrosoftMangle.cpp +++ cfe/trunk/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: cfe/trunk/lib/CodeGen/CGCall.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGCall.cpp +++ cfe/trunk/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: cfe/trunk/lib/CodeGen/CodeGenTypes.h =================================================================== --- cfe/trunk/lib/CodeGen/CodeGenTypes.h +++ cfe/trunk/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: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp =================================================================== --- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp +++ cfe/trunk/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, @@ -1060,9 +1061,29 @@ } } +static bool hasDefaultCXXMethodCC(ASTContext &Context, + const CXXMethodDecl *MD) { + CallingConv ExpectedCallingConv = Context.getDefaultCallingConvention( + /*IsVariadic=*/false, /*IsCXXMethod=*/true); + CallingConv ActualCallingConv = + MD->getType()->getAs()->getCallConv(); + return ExpectedCallingConv == ActualCallingConv; +} + 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()) + if (!hasDefaultCXXMethodCC(getContext(), D) || 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 +3244,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 +3259,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 +3274,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 +3283,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 +3303,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 +3312,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 +3325,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, @@ -3330,14 +3357,9 @@ const CXXConstructorDecl *CD = RD ? CGM.getContext().getCopyConstructorForExceptionObject(RD) : nullptr; CXXCtorType CT = Ctor_Complete; - if (CD) { - CallingConv ExpectedCallingConv = getContext().getDefaultCallingConvention( - /*IsVariadic=*/false, /*IsCXXMethod=*/true); - CallingConv ActualCallingConv = - CD->getType()->getAs()->getCallConv(); - if (ExpectedCallingConv != ActualCallingConv || CD->getNumParams() != 1) + if (CD) + if (!hasDefaultCXXMethodCC(getContext(), CD) || CD->getNumParams() != 1) CT = Ctor_CopyingClosure; - } uint32_t Size = getContext().getTypeSizeInChars(T).getQuantity(); SmallString<256> MangledName; @@ -3358,7 +3380,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: cfe/trunk/lib/Sema/SemaDecl.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp +++ cfe/trunk/lib/Sema/SemaDecl.cpp @@ -12064,6 +12064,24 @@ "Broken injected-class-name"); } +static void getDefaultArgExprsForConstructors(Sema &S, CXXRecordDecl *Class) { + 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 (S.Context.getDefaultArgExprForConstructor(CD, I)) + continue; + + Expr *DefaultArg = S.BuildCXXDefaultArgExpr(Class->getLocation(), CD, + CD->getParamDecl(I)).get(); + S.Context.addDefaultArgExprForConstructor(CD, I, DefaultArg); + } + } +} + void Sema::ActOnTagFinishDefinition(Scope *S, Decl *TagD, SourceLocation RBraceLoc) { AdjustDeclIfTemplate(TagD); @@ -12077,9 +12095,17 @@ 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()) + getDefaultArgExprsForConstructors(*this, Class); + } + // Exit this scope of this tag's definition. PopDeclContext(); Index: cfe/trunk/test/CodeGenCXX/dllexport.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/dllexport.cpp +++ cfe/trunk/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: