r216145 - MS ABI: Don't always instantiate all members of dllexported class templates (PR20163)

Hans Wennborg hans at hanshq.net
Wed Aug 20 18:14:01 PDT 2014


Author: hans
Date: Wed Aug 20 20:14:01 2014
New Revision: 216145

URL: http://llvm.org/viewvc/llvm-project?rev=216145&view=rev
Log:
MS ABI: Don't always instantiate all members of dllexported class templates (PR20163)

Normally we mark all members of exported classes referenced to get them emitted.

However, MSVC doesn't do this for class templates that are implicitly specialized or
just have an explicit instantiation declaration. For such specializations, the members
are emitted when referenced.

The exception is the case when the dllexport attribute is propagated from a base class
to a base class template that doesn't have an explicit attribute: in this case all
methods of the base class template do get instantiated.

Modified:
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/test/CodeGenCXX/dllexport.cpp
    cfe/trunk/test/SemaCXX/dllexport.cpp

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=216145&r1=216144&r2=216145&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Aug 20 20:14:01 2014
@@ -4432,6 +4432,9 @@ static void checkDLLAttribute(Sema &S, C
   // FIXME: MSVC's docs say all bases must be exportable, but this doesn't
   // seem to be true in practice?
 
+  TemplateSpecializationKind TSK =
+    Class->getTemplateSpecializationKind();
+
   for (Decl *Member : Class->decls()) {
     VarDecl *VD = dyn_cast<VarDecl>(Member);
     CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member);
@@ -4471,7 +4474,14 @@ static void checkDLLAttribute(Sema &S, C
     if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member)) {
       if (ClassExported) {
         if (MD->isUserProvided()) {
-          // Instantiate non-default methods.
+          // Instantiate non-default methods..
+
+          // .. except for certain kinds of template specializations.
+          if (TSK == TSK_ExplicitInstantiationDeclaration)
+            continue;
+          if (TSK == TSK_ImplicitInstantiation && !ClassAttr->isInherited())
+            continue;
+
           S.MarkFunctionReferenced(Class->getLocation(), MD);
         } else if (!MD->isTrivial() || MD->isExplicitlyDefaulted() ||
                    MD->isCopyAssignmentOperator() ||

Modified: cfe/trunk/test/CodeGenCXX/dllexport.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/dllexport.cpp?rev=216145&r1=216144&r2=216145&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/dllexport.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/dllexport.cpp Wed Aug 20 20:14:01 2014
@@ -509,11 +509,9 @@ USEVAR(T::b)
 int T::c;
 
 template <typename T> struct __declspec(dllexport) U { void foo() {} };
-// The U<int> specialization below must cause the following to be emitted:
-// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?foo@?$U at H@@QAEXXZ"
-// M32-DAG: define weak_odr dllexport x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.U* @"\01??4?$U at H@@QAEAAU0 at ABU0@@Z"
 struct __declspec(dllexport) V : public U<int> { };
-
+// U<int>'s assignment operator is emitted.
+// M32-DAG: define weak_odr dllexport x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.U* @"\01??4?$U at H@@QAEAAU0 at ABU0@@Z"
 
 struct __declspec(dllexport) W { virtual void foo() {} };
 // Default ctor:
@@ -618,6 +616,7 @@ USEMEMFUNC(DerivedFromTemplate, func)
 
 // ExportedTemplate is explicitly exported.
 struct __declspec(dllexport) DerivedFromExportedTemplate : public ExportedClassTemplate<int> {};
+USEMEMFUNC(DerivedFromExportedTemplate, func)
 // M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?func@?$ExportedClassTemplate at H@@QAEXXZ"
 // G32-DAG: define weak_odr dllexport x86_thiscallcc void @_ZN21ExportedClassTemplateIiE4funcEv
 

Modified: cfe/trunk/test/SemaCXX/dllexport.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/dllexport.cpp?rev=216145&r1=216144&r2=216145&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/dllexport.cpp (original)
+++ cfe/trunk/test/SemaCXX/dllexport.cpp Wed Aug 20 20:14:01 2014
@@ -327,6 +327,49 @@ template <typename T> struct __declspec(
 template <typename T> struct ExpliciallySpecializedClassTemplate {};
 template <> struct __declspec(dllexport) ExpliciallySpecializedClassTemplate<int> { void f() {} };
 
+// Don't instantiate class members of implicitly instantiated templates, even if they are exported.
+struct IncompleteType;
+template <typename T> struct __declspec(dllexport) ImplicitlyInstantiatedExportedTemplate {
+  int f() { return sizeof(T); } // no-error
+};
+ImplicitlyInstantiatedExportedTemplate<IncompleteType> implicitlyInstantiatedExportedTemplate;
+
+// Don't instantiate class members of templates with explicit instantiation declarations, even if they are exported.
+struct IncompleteType2;
+template <typename T> struct __declspec(dllexport) ExportedTemplateWithExplicitInstantiationDecl {
+  int f() { return sizeof(T); } // no-error
+};
+extern template struct ExportedTemplateWithExplicitInstantiationDecl<IncompleteType2>;
+
+// Instantiate class members for explicitly instantiated exported templates.
+struct IncompleteType3; // expected-note{{forward declaration of 'IncompleteType3'}}
+template <typename T> struct __declspec(dllexport) ExplicitlyInstantiatedExportedTemplate {
+  int f() { return sizeof(T); } // expected-error{{invalid application of 'sizeof' to an incomplete type 'IncompleteType3'}}
+};
+template struct ExplicitlyInstantiatedExportedTemplate<IncompleteType3>; // expected-note{{in instantiation of member function 'ExplicitlyInstantiatedExportedTemplate<IncompleteType3>::f' requested here}}
+
+// In MS mode, instantiate members of class templates that are base classes of exported classes.
+#ifdef MS
+  // expected-note at +3{{forward declaration of 'IncompleteType4'}}
+  // expected-note at +3{{in instantiation of member function 'BaseClassTemplateOfExportedClass<IncompleteType4>::f' requested here}}
+#endif
+struct IncompleteType4;
+template <typename T> struct BaseClassTemplateOfExportedClass {
+#ifdef MS
+  // expected-error at +2{{invalid application of 'sizeof' to an incomplete type 'IncompleteType4'}}
+#endif
+  int f() { return sizeof(T); };
+};
+struct __declspec(dllexport) ExportedBaseClass : public BaseClassTemplateOfExportedClass<IncompleteType4> {};
+
+// Don't instantiate members of explicitly exported class templates that are base classes of exported classes.
+struct IncompleteType5;
+template <typename T> struct __declspec(dllexport) ExportedBaseClassTemplateOfExportedClass {
+  int f() { return sizeof(T); }; // no-error
+};
+struct __declspec(dllexport) ExportedBaseClass2 : public ExportedBaseClassTemplateOfExportedClass<IncompleteType5> {};
+
+
 
 //===----------------------------------------------------------------------===//
 // Classes with template base classes





More information about the cfe-commits mailing list