rnk updated this revision to Diff 83059. rnk added a comment. simplify
https://reviews.llvm.org/D28274 Files: lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/CodeGenCXX/dllexport.cpp test/SemaCXX/default-arg-closures.cpp test/SemaCXX/dllexport.cpp
Index: test/SemaCXX/dllexport.cpp =================================================================== --- test/SemaCXX/dllexport.cpp +++ test/SemaCXX/dllexport.cpp @@ -741,6 +741,27 @@ ClassWithMultipleDefaultCtors(int = 40) {} // expected-error{{'__declspec(dllexport)' cannot be applied to more than one default constructor}} ClassWithMultipleDefaultCtors(int = 30, ...) {} // expected-note{{declared here}} }; +template <typename T> +struct ClassTemplateWithMultipleDefaultCtors { + __declspec(dllexport) ClassTemplateWithMultipleDefaultCtors(int = 40) {} // expected-error{{'__declspec(dllexport)' cannot be applied to more than one default constructor}} + __declspec(dllexport) ClassTemplateWithMultipleDefaultCtors(int = 30, ...) {} // expected-note{{declared here}} +}; + +template <typename T> struct HasDefaults { + HasDefaults(int x = sizeof(T)) {} // expected-error {{invalid application of 'sizeof'}} +}; +template struct __declspec(dllexport) HasDefaults<char>; + +template struct +__declspec(dllexport) // expected-note {{in instantiation of default function argument expression for 'HasDefaults<void>' required here}} +HasDefaults<void>; // expected-note {{in instantiation of member function 'HasDefaults<void>::HasDefaults' requested here}} + +template <typename T> struct HasDefaults2 { + __declspec(dllexport) // expected-note {{in instantiation of default function argument expression for 'HasDefaults2<void>' required here}} + HasDefaults2(int x = sizeof(T)) {} // expected-error {{invalid application of 'sizeof'}} +}; +template struct HasDefaults2<void>; // expected-note {{in instantiation of member function 'HasDefaults2<void>::HasDefaults2' requested here}} + #endif //===----------------------------------------------------------------------===// Index: test/SemaCXX/default-arg-closures.cpp =================================================================== --- test/SemaCXX/default-arg-closures.cpp +++ test/SemaCXX/default-arg-closures.cpp @@ -4,16 +4,15 @@ // instantiating and checking the semantics of default arguments. Make sure we // do that right. -// FIXME: Don't diagnose this issue twice. template <typename T> -struct DependentDefaultCtorArg { // expected-note {{in instantiation of default function argument}} - // expected-error@+1 2 {{type 'int' cannot be used prior to '::' because it has no members}} +struct DependentDefaultCtorArg { + // expected-error@+1 {{type 'int' cannot be used prior to '::' because it has no members}} DependentDefaultCtorArg(int n = T::error); }; struct __declspec(dllexport) // expected-note {{due to 'ExportDefaultCtorClosure' being dllexported}} -ExportDefaultCtorClosure // expected-note {{implicit default constructor for 'ExportDefaultCtorClosure' first required here}} -: DependentDefaultCtorArg<int> // expected-note {{in instantiation of template class}} +ExportDefaultCtorClosure // expected-note {{in instantiation of default function argument expression for 'DependentDefaultCtorArg<int>' required here}} expected-note {{implicit default constructor for 'ExportDefaultCtorClosure' first required here}} +: DependentDefaultCtorArg<int> {}; template <typename T> Index: test/CodeGenCXX/dllexport.cpp =================================================================== --- test/CodeGenCXX/dllexport.cpp +++ test/CodeGenCXX/dllexport.cpp @@ -515,6 +515,18 @@ // M32-DAG: ret void }; +template <typename T> struct TemplateWithClosure { + TemplateWithClosure(int x = sizeof(T)) {} +}; +extern template struct TemplateWithClosure<char>; +template struct __declspec(dllexport) TemplateWithClosure<char>; +extern template struct TemplateWithClosure<int>; +template struct __declspec(dllexport) TemplateWithClosure<int>; +// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01??_F?$TemplateWithClosure@D@@QAEXXZ"({{.*}}) {{#[0-9]+}} comdat +// M32-DAG: call {{.*}} @"\01??0?$TemplateWithClosure@D@@QAE@H@Z"({{.*}}, i32 1) +// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01??_F?$TemplateWithClosure@H@@QAEXXZ"({{.*}}) {{#[0-9]+}} comdat +// M32-DAG: call {{.*}} @"\01??0?$TemplateWithClosure@H@@QAE@H@Z"({{.*}}, i32 4) + struct __declspec(dllexport) NestedOuter { DELETE_IMPLICIT_MEMBERS(NestedOuter); NestedOuter(void *p = 0) {} Index: lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiateDecl.cpp +++ lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3616,6 +3616,27 @@ return false; } +/// 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<DLLExportAttr>(); + if (!Attr) + return; + for (unsigned I = 0; I != NumParams; ++I) { + (void)S.CheckCXXDefaultArgExpr(Attr->getLocation(), Ctor, + Ctor->getParamDecl(I)); + S.DiscardCleanupsInEvaluationContext(); + } +} + /// \brief Instantiate the definition of the given function from its /// template. /// @@ -3793,11 +3814,17 @@ TemplateArgs)) return; - // If this is a constructor, instantiate the member initializers. - if (const CXXConstructorDecl *Ctor = - dyn_cast<CXXConstructorDecl>(PatternDecl)) { - InstantiateMemInitializers(cast<CXXConstructorDecl>(Function), Ctor, + if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(Function)) { + // If this is a constructor, instantiate the member initializers. + InstantiateMemInitializers(Ctor, cast<CXXConstructorDecl>(PatternDecl), TemplateArgs); + + // If this is an MS ABI dllexport default constructor, instantiate any + // default arguments. + if (Context.getTargetInfo().getCXXABI().isMicrosoft() && + Ctor->isDefaultConstructor()) { + InstantiateDefaultCtorDefaultArgs(*this, Ctor); + } } // Instantiate the function body. Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -5395,6 +5395,26 @@ } } +static void checkForMultipleExportedDefaultConstructors(Sema &S, CXXRecordDecl *Class) { + CXXConstructorDecl *LastExportedDefaultCtor = nullptr; + for (Decl *Member : Class->decls()) { + // Look for exported default constructors. + auto *CD = dyn_cast<CXXConstructorDecl>(Member); + if (!CD || !CD->isDefaultConstructor() || !CD->hasAttr<DLLExportAttr>()) + continue; + + if (LastExportedDefaultCtor) { + S.Diag(LastExportedDefaultCtor->getLocation(), + diag::err_attribute_dll_ambiguous_default_ctor) + << Class; + S.Diag(CD->getLocation(), diag::note_entity_declared_at) + << CD->getDeclName(); + return; + } + LastExportedDefaultCtor = CD; + } +} + /// \brief Check class-level dllimport/dllexport attribute. void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { Attr *ClassAttr = getDLLAttr(Class); @@ -10362,64 +10382,11 @@ DelayedExceptionSpecChecks.clear(); return; } - } -} - -static void checkDefaultArgExprsForConstructors(Sema &S, CXXRecordDecl *Class) { - // Don't do anything for template patterns. - if (Class->getDescribedClassTemplate()) - return; - - CallingConv ExpectedCallingConv = S.Context.getDefaultCallingConvention( - /*IsVariadic=*/false, /*IsCXXMethod=*/true); - - CXXConstructorDecl *LastExportedDefaultCtor = nullptr; - for (Decl *Member : Class->decls()) { - auto *CD = dyn_cast<CXXConstructorDecl>(Member); - if (!CD) { - // Recurse on nested classes. - if (auto *NestedRD = dyn_cast<CXXRecordDecl>(Member)) - checkDefaultArgExprsForConstructors(S, NestedRD); - continue; - } else if (!CD->isDefaultConstructor() || !CD->hasAttr<DLLExportAttr>()) { - continue; - } - - CallingConv ActualCallingConv = - CD->getType()->getAs<FunctionProtoType>()->getCallConv(); - - // Skip default constructors with typical calling conventions and no default - // arguments. - unsigned NumParams = CD->getNumParams(); - if (ExpectedCallingConv == ActualCallingConv && NumParams == 0) - continue; - - if (LastExportedDefaultCtor) { - S.Diag(LastExportedDefaultCtor->getLocation(), - diag::err_attribute_dll_ambiguous_default_ctor) << Class; - S.Diag(CD->getLocation(), diag::note_entity_declared_at) - << CD->getDeclName(); - return; - } - LastExportedDefaultCtor = CD; - - for (unsigned I = 0; I != NumParams; ++I) { - (void)S.CheckCXXDefaultArgExpr(Class->getLocation(), CD, - CD->getParamDecl(I)); - S.DiscardCleanupsInEvaluationContext(); - } + checkForMultipleExportedDefaultConstructors(*this, Record); } } void Sema::ActOnFinishCXXNonNestedClass(Decl *D) { - auto *RD = dyn_cast<CXXRecordDecl>(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()) - checkDefaultArgExprsForConstructors(*this, RD); - referenceDLLExportedClassMethods(); }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits