From: Hans Wennborg Date: Sun, 24 Aug 2014 00:12:36 +0000 (+0000) Subject: Don't assert on different DLL attributes in template and explicit instantiation ... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=852eed5f0c761aa46f4e8dffb0432f81ab1dc9fa;p=clang Don't assert on different DLL attributes in template and explicit instantiation (PR20137) We would previously assert (a decl cannot have two DLL attributes) on this code: template struct __declspec(dllimport) S { T f() { return T(); } }; template struct __declspec(dllexport) S; The problem was that when instantiating, we would take the attribute from the template even if the instantiation itself already had an attribute. Also, don't inherit DLL attributes from the template to its members before instantiation, as the attribute may change. I couldn't figure out what MinGW does here, so I'm leaving that open. At least we're not asserting anymore. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@216340 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 5e789fe20e..6a48162502 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -4437,6 +4437,28 @@ static void checkDLLAttribute(Sema &S, CXXRecordDecl *Class) { if (!ClassAttr) return; + if (S.Context.getTargetInfo().getCXXABI().isMicrosoft() && + !ClassAttr->isInherited()) { + // Diagnose dll attributes on members of class with dll attribute. + for (Decl *Member : Class->decls()) { + if (!isa(Member) && !isa(Member)) + continue; + InheritableAttr *MemberAttr = getDLLAttr(Member); + if (!MemberAttr || MemberAttr->isInherited() || Member->isInvalidDecl()) + continue; + + S.Diag(MemberAttr->getLocation(), + diag::err_attribute_dll_member_of_dll_class) + << MemberAttr << ClassAttr; + S.Diag(ClassAttr->getLocation(), diag::note_previous_attribute); + Member->setInvalidDecl(); + } + } + + if (Class->getDescribedClassTemplate()) + // Don't inherit dll attribute until the template is instantiated. + return; + bool ClassExported = ClassAttr->getKind() == attr::DLLExport; // Force declaration of implicit members so they can inherit the attribute. @@ -4467,17 +4489,7 @@ static void checkDLLAttribute(Sema &S, CXXRecordDecl *Class) { continue; } - if (InheritableAttr *MemberAttr = getDLLAttr(Member)) { - if (S.Context.getTargetInfo().getCXXABI().isMicrosoft() && - !MemberAttr->isInherited() && !ClassAttr->isInherited()) { - S.Diag(MemberAttr->getLocation(), - diag::err_attribute_dll_member_of_dll_class) - << MemberAttr << ClassAttr; - S.Diag(ClassAttr->getLocation(), diag::note_previous_attribute); - Member->setInvalidDecl(); - continue; - } - } else { + if (!getDLLAttr(Member)) { auto *NewAttr = cast(ClassAttr->clone(S.getASTContext())); NewAttr->setInherited(true); diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 747eaf6d96..c27a243041 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -183,6 +183,14 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, continue; } + // Existing DLL attribute on the instantiation takes precedence. + if (TmplAttr->getKind() == attr::DLLExport || + TmplAttr->getKind() == attr::DLLImport) { + if (New->hasAttr() || New->hasAttr()) { + continue; + } + } + assert(!TmplAttr->isPackExpansion()); if (TmplAttr->isLateParsed() && LateAttrs) { // Late parsed attributes must be instantiated and attached after the diff --git a/test/CodeGenCXX/dllexport.cpp b/test/CodeGenCXX/dllexport.cpp index c46401239d..3daacf065b 100644 --- a/test/CodeGenCXX/dllexport.cpp +++ b/test/CodeGenCXX/dllexport.cpp @@ -600,6 +600,12 @@ USEMEMFUNC(PartiallySpecializedExportedClassTemplate2, f); // M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?f@?$PartiallySpecializedExportedClassTemplate2@PAX@@QAEXXZ" // G32-DAG: declare dllimport x86_thiscallcc void @_ZN42PartiallySpecializedExportedClassTemplate2IPvE1fEv +// Attributes on the instantiation take precedence over attributes on the template. +template struct __declspec(dllimport) ExplicitlyInstantiatedWithDifferentAttr { void f() {} }; +template struct __declspec(dllexport) ExplicitlyInstantiatedWithDifferentAttr; +USEMEMFUNC(ExplicitlyInstantiatedWithDifferentAttr, f); +// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?f@?$ExplicitlyInstantiatedWithDifferentAttr@H@@QAEXXZ" + //===----------------------------------------------------------------------===// // Classes with template base classes diff --git a/test/CodeGenCXX/dllimport.cpp b/test/CodeGenCXX/dllimport.cpp index 3292a9fa38..3ba7f96382 100644 --- a/test/CodeGenCXX/dllimport.cpp +++ b/test/CodeGenCXX/dllimport.cpp @@ -693,6 +693,12 @@ USEMEMFUNC(PartiallySpecializedImportedClassTemplate, f); // M32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @"\01?f@?$PartiallySpecializedImportedClassTemplate@PAX@@QAEXXZ" // G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN41PartiallySpecializedImportedClassTemplateIPvE1fEv +// Attributes on the instantiation take precedence over attributes on the template. +template struct __declspec(dllexport) ExplicitlyInstantiatedWithDifferentAttr { void f() {} }; +template struct __declspec(dllimport) ExplicitlyInstantiatedWithDifferentAttr; +USEMEMFUNC(ExplicitlyInstantiatedWithDifferentAttr, f); +// M32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @"\01?f@?$ExplicitlyInstantiatedWithDifferentAttr@H@@QAEXXZ" + //===----------------------------------------------------------------------===// // Classes with template base classes diff --git a/test/SemaCXX/dllimport.cpp b/test/SemaCXX/dllimport.cpp index d66c12d77d..875cf1e5ea 100644 --- a/test/SemaCXX/dllimport.cpp +++ b/test/SemaCXX/dllimport.cpp @@ -981,7 +981,7 @@ class __declspec(dllimport) ImportClassWithDllMember { // expected-error@+4{{attribute 'dllimport' cannot be applied to member of 'dllexport' class}} // expected-error@+4{{attribute 'dllexport' cannot be applied to member of 'dllexport' class}} #endif -class __declspec(dllexport) ExportClassWithDllMember { +template class __declspec(dllexport) ExportClassWithDllMember { void __declspec(dllimport) foo(); void __declspec(dllexport) bar(); };