From: Reid Kleckner Date: Tue, 17 Mar 2015 19:00:50 +0000 (+0000) Subject: MS ABI: Delay default constructor closure checking until the outermost class scope... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c52bc77bc2cfa12189352cb6af9874cbdcad6663;p=clang MS ABI: Delay default constructor closure checking until the outermost class scope ends Previously, we would error out on this code because the default argument wasn't parsed until the end of Outer: struct __declspec(dllexport) Outer { struct __declspec(dllexport) Inner { Inner(void *p = 0); }; }; Now we do the checking on the closing brace of Outer instead of Inner. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@232519 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 9beff2612b..30d35f61c2 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -5012,6 +5012,7 @@ public: SourceLocation RBrac, AttributeList *AttrList); void ActOnFinishCXXMemberDecls(); + void ActOnFinishCXXMethodDefs(Decl *D); void ActOnReenterCXXMethodParameter(Scope *S, ParmVarDecl *Param); unsigned ActOnReenterTemplateScope(Scope *S, Decl *Template); diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp index 89f0d4fa3b..6ab57f430f 100644 --- a/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/lib/CodeGen/MicrosoftCXXABI.cpp @@ -3309,6 +3309,8 @@ MicrosoftCXXABI::getAddrOfCXXCtorClosure(const CXXConstructorDecl *CD, QualType RecordTy = getContext().getRecordType(RD); llvm::Function *ThunkFn = llvm::Function::Create( ThunkTy, getLinkageForRTTI(RecordTy), ThunkName.str(), &CGM.getModule()); + ThunkFn->setCallingConv(static_cast( + FnInfo.getEffectiveCallingConvention())); bool IsCopy = CT == Ctor_CopyingClosure; // Start codegen. diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 4e58ca345f..d5497085f2 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -2915,6 +2915,10 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, ParseLexedMemberInitializers(getCurrentClass()); ParseLexedMethodDefs(getCurrentClass()); PrevTokLocation = SavedPrevTokLocation; + + // We've finished parsing everything, including default argument + // initializers. + Actions.ActOnFinishCXXMethodDefs(TagDecl); } if (TagDecl) diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 01bd42ce80..32e3924e35 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -12067,24 +12067,6 @@ void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD, "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); @@ -12098,17 +12080,9 @@ void Sema::ActOnTagFinishDefinition(Scope *S, Decl *TagD, RD->completeDefinition(); } - if (auto *Class = dyn_cast(Tag)) { + if (isa(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(); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 45ba685d11..4e64595e11 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -9421,6 +9421,44 @@ void Sema::ActOnFinishCXXMemberDecls() { } } +static void getDefaultArgExprsForConstructors(Sema &S, CXXRecordDecl *Class) { + // Don't do anything for template patterns. + if (Class->getDescribedClassTemplate()) + return; + + for (Decl *Member : Class->decls()) { + auto *CD = dyn_cast(Member); + if (!CD) { + // Recurse on nested classes. + if (auto *NestedRD = dyn_cast(Member)) + getDefaultArgExprsForConstructors(S, NestedRD); + continue; + } else if (!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::ActOnFinishCXXMethodDefs(Decl *D) { + auto *RD = dyn_cast(D); + + // 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 (RD && Context.getTargetInfo().getCXXABI().isMicrosoft()) + getDefaultArgExprsForConstructors(*this, RD); +} + void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl, CXXDestructorDecl *Destructor) { assert(getLangOpts().CPlusPlus11 && diff --git a/test/CodeGenCXX/dllexport.cpp b/test/CodeGenCXX/dllexport.cpp index 60d37ef0a8..c71ab5c67d 100644 --- a/test/CodeGenCXX/dllexport.cpp +++ b/test/CodeGenCXX/dllexport.cpp @@ -486,7 +486,7 @@ struct S { struct CtorWithClosure { __declspec(dllexport) CtorWithClosure(...) {} -// M32-DAG: define weak_odr dllexport void @"\01??_FCtorWithClosure@@QAEXXZ" +// M32-DAG: define weak_odr dllexport x86_thiscallcc 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]] @@ -494,12 +494,16 @@ struct CtorWithClosure { // M32-DAG: ret void }; +#define DELETE_IMPLICIT_MEMBERS(ClassName) \ + ClassName(ClassName &&) = delete; \ + ClassName(ClassName &) = delete; \ + ~ClassName() = delete; \ + ClassName &operator=(ClassName &) = delete + struct __declspec(dllexport) ClassWithClosure { - ClassWithClosure(ClassWithClosure &&) = delete; - ClassWithClosure(ClassWithClosure &) = delete; - ~ClassWithClosure() = delete; + DELETE_IMPLICIT_MEMBERS(ClassWithClosure); ClassWithClosure(...) {} -// M32-DAG: define weak_odr dllexport void @"\01??_FClassWithClosure@@QAEXXZ" +// M32-DAG: define weak_odr dllexport x86_thiscallcc 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]] @@ -507,6 +511,18 @@ struct __declspec(dllexport) ClassWithClosure { // M32-DAG: ret void }; +struct __declspec(dllexport) NestedOuter { + DELETE_IMPLICIT_MEMBERS(NestedOuter); + NestedOuter(void *p = 0) {} + struct __declspec(dllexport) NestedInner { + DELETE_IMPLICIT_MEMBERS(NestedInner); + NestedInner(void *p = 0) {} + }; +}; + +// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01??_FNestedOuter@@QAEXXZ" +// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01??_FNestedInner@NestedOuter@@QAEXXZ" + struct __declspec(dllexport) T { // Copy assignment operator: // M32-DAG: define weak_odr dllexport x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.T* @"\01??4T@@QAEAAU0@ABU0@@Z"