]> granicus.if.org Git - clang/commitdiff
Don't assert on different DLL attributes in template and explicit instantiation ...
authorHans Wennborg <hans@hanshq.net>
Sun, 24 Aug 2014 00:12:36 +0000 (00:12 +0000)
committerHans Wennborg <hans@hanshq.net>
Sun, 24 Aug 2014 00:12:36 +0000 (00:12 +0000)
We would previously assert (a decl cannot have two DLL attributes) on this code:

  template <typename T> struct __declspec(dllimport) S { T f() { return T(); } };
  template struct __declspec(dllexport) S<int>;

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

lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
test/CodeGenCXX/dllexport.cpp
test/CodeGenCXX/dllimport.cpp
test/SemaCXX/dllimport.cpp

index 5e789fe20ed578b47df10abdf50dddd3a3930afe..6a48162502cb670bb0f41a6270142d0bd1ebe634 100644 (file)
@@ -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<VarDecl>(Member) && !isa<CXXMethodDecl>(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<InheritableAttr>(ClassAttr->clone(S.getASTContext()));
       NewAttr->setInherited(true);
index 747eaf6d96fa966f575cb2bcc7cc9e0c05870fab..c27a2430415314290969ac2b21ddbc6a6cc1db9f 100644 (file)
@@ -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<DLLExportAttr>() || New->hasAttr<DLLImportAttr>()) {
+        continue;
+      }
+    }
+
     assert(!TmplAttr->isPackExpansion());
     if (TmplAttr->isLateParsed() && LateAttrs) {
       // Late parsed attributes must be instantiated and attached after the
index c46401239d507cc99772012af8c9193f484a11c3..3daacf065b3297c114ca3b9f61159d21a4dc6ac8 100644 (file)
@@ -600,6 +600,12 @@ USEMEMFUNC(PartiallySpecializedExportedClassTemplate2<void*>, 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 <typename T> struct __declspec(dllimport) ExplicitlyInstantiatedWithDifferentAttr { void f() {} };
+template struct __declspec(dllexport) ExplicitlyInstantiatedWithDifferentAttr<int>;
+USEMEMFUNC(ExplicitlyInstantiatedWithDifferentAttr<int>, f);
+// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?f@?$ExplicitlyInstantiatedWithDifferentAttr@H@@QAEXXZ"
+
 
 //===----------------------------------------------------------------------===//
 // Classes with template base classes
index 3292a9fa38adc05156670403373ca4fc47abb08e..3ba7f963823fa3f1aa967a5127931d9bf5889c2f 100644 (file)
@@ -693,6 +693,12 @@ USEMEMFUNC(PartiallySpecializedImportedClassTemplate<void*>, 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 <typename T> struct __declspec(dllexport) ExplicitlyInstantiatedWithDifferentAttr { void f() {} };
+template struct __declspec(dllimport) ExplicitlyInstantiatedWithDifferentAttr<int>;
+USEMEMFUNC(ExplicitlyInstantiatedWithDifferentAttr<int>, f);
+// M32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @"\01?f@?$ExplicitlyInstantiatedWithDifferentAttr@H@@QAEXXZ"
+
 
 //===----------------------------------------------------------------------===//
 // Classes with template base classes
index d66c12d77d9929271363d2fd8adb3a9983594f13..875cf1e5ea8d6dc5573bf9a7c9eb7aa0959d5f33 100644 (file)
@@ -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 <typename T> class __declspec(dllexport) ExportClassWithDllMember {
   void __declspec(dllimport) foo();
   void __declspec(dllexport) bar();
 };