Author: hans
Date: Thu May 26 14:42:56 2016
New Revision: 270897

URL: http://llvm.org/viewvc/llvm-project?rev=270897&view=rev
Log:
Re-commit r270748 "clang-cl: Treat dllimport explicit template instantiation 
definitions as declarations (PR27810, PR27811)"

Also make explicit instantiation decls not apply to nested classes when
targeting MSVC. That dll attributes are not inherited by inner classes
might be the explanation for MSVC's behaviour here.

Modified:
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
    cfe/trunk/test/CodeGenCXX/dllexport.cpp
    cfe/trunk/test/CodeGenCXX/dllimport.cpp
    cfe/trunk/test/CodeGenCXX/explicit-instantiation.cpp
    cfe/trunk/test/SemaTemplate/extern-templates.cpp

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=270897&r1=270896&r2=270897&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu May 26 14:42:56 2016
@@ -7367,6 +7367,29 @@ Sema::ActOnExplicitInstantiation(Scope *
     }
   }
 
+  // In MSVC mode, dllimported explicit instantiation definitions are treated 
as
+  // instantiation declarations for most purposes.
+  bool DLLImportExplicitInstantiationDef = false;
+  if (TSK == TSK_ExplicitInstantiationDefinition &&
+      Context.getTargetInfo().getCXXABI().isMicrosoft()) {
+    // Check for dllimport class template instantiation definitions.
+    bool DLLImport =
+        ClassTemplate->getTemplatedDecl()->getAttr<DLLImportAttr>();
+    for (AttributeList *A = Attr; A; A = A->getNext()) {
+      if (A->getKind() == AttributeList::AT_DLLImport)
+        DLLImport = true;
+      if (A->getKind() == AttributeList::AT_DLLExport) {
+        // dllexport trumps dllimport here.
+        DLLImport = false;
+        break;
+      }
+    }
+    if (DLLImport) {
+      TSK = TSK_ExplicitInstantiationDeclaration;
+      DLLImportExplicitInstantiationDef = true;
+    }
+  }
+
   // Translate the parser's template argument list in our AST format.
   TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc);
   translateTemplateArguments(TemplateArgsIn, TemplateArgs);
@@ -7420,6 +7443,12 @@ Sema::ActOnExplicitInstantiation(Scope *
       Specialization->setLocation(TemplateNameLoc);
       PrevDecl = nullptr;
     }
+
+    if (PrevDecl_TSK == TSK_ExplicitInstantiationDeclaration &&
+        DLLImportExplicitInstantiationDef) {
+      // The new specialization might add a dllimport attribute.
+      HasNoEffect = false;
+    }
   }
 
   if (!Specialization) {
@@ -7497,11 +7526,11 @@ Sema::ActOnExplicitInstantiation(Scope *
                                        Specialization->getDefinition());
   if (Def) {
     TemplateSpecializationKind Old_TSK = Def->getTemplateSpecializationKind();
-
     // Fix a TSK_ExplicitInstantiationDeclaration followed by a
     // TSK_ExplicitInstantiationDefinition
     if (Old_TSK == TSK_ExplicitInstantiationDeclaration &&
-        TSK == TSK_ExplicitInstantiationDefinition) {
+        (TSK == TSK_ExplicitInstantiationDefinition ||
+         DLLImportExplicitInstantiationDef)) {
       // FIXME: Need to notify the ASTMutationListener that we did this.
       Def->setTemplateSpecializationKind(TSK);
 

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=270897&r1=270896&r2=270897&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Thu May 26 14:42:56 2016
@@ -2542,6 +2542,13 @@ Sema::InstantiateClassMembers(SourceLoca
                                                 == TSK_ExplicitSpecialization)
         continue;
 
+      if (Context.getTargetInfo().getCXXABI().isMicrosoft() &&
+          TSK == TSK_ExplicitInstantiationDeclaration) {
+        // In MSVC mode, explicit instantiation decl of the outer class doesn't
+        // affect the inner class.
+        continue;
+      }
+
       if (CheckSpecializationInstantiationRedecl(PointOfInstantiation, TSK, 
                                                  Record, 
                                         
MSInfo->getTemplateSpecializationKind(),

Modified: cfe/trunk/test/CodeGenCXX/dllexport.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/dllexport.cpp?rev=270897&r1=270896&r2=270897&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/dllexport.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/dllexport.cpp Thu May 26 14:42:56 2016
@@ -844,6 +844,11 @@ struct __declspec(dllexport) B {
 // M32-DAG: define weak_odr dllexport x86_thiscallcc void 
@"\01??_FB@pr26490@@QAEXXZ"
 }
 
+// dllexport trumps dllexport on an explicit instantiation.
+template <typename T> struct ExplicitInstantiationTwoAttributes { void f() {} 
};
+template struct __declspec(dllexport) __declspec(dllimport) 
ExplicitInstantiationTwoAttributes<int>;
+// M32-DAG: define weak_odr dllexport x86_thiscallcc void 
@"\01?f@?$ExplicitInstantiationTwoAttributes@H@@QAEXXZ"
+
 
 
//===----------------------------------------------------------------------===//
 // Classes with template base classes
@@ -958,14 +963,6 @@ template struct ExplicitInstantiationDec
 // M32-DAG: define weak_odr dllexport x86_thiscallcc void 
@"\01?func@?$ExplicitInstantiationDeclTemplateBase@H@@QAEXXZ"
 // G32-DAG: define weak_odr x86_thiscallcc void 
@_ZN37ExplicitInstantiationDeclTemplateBaseIiE4funcEv
 
-template <typename T> struct ExplicitInstantiationDeclTemplateBase2 { void 
func() {} };
-extern template struct ExplicitInstantiationDeclTemplateBase2<int>;
-struct __declspec(dllexport) DerivedFromExplicitInstantiationDeclTemplateBase2 
: public ExplicitInstantiationDeclTemplateBase2<int> {};
-template struct __declspec(dllimport) 
ExplicitInstantiationDeclTemplateBase2<int>;
-USEMEMFUNC(ExplicitInstantiationDeclTemplateBase2<int>, func)
-// M32-DAG: define weak_odr dllexport x86_thiscallcc void 
@"\01?func@?$ExplicitInstantiationDeclTemplateBase2@H@@QAEXXZ"
-// G32-DAG: define weak_odr x86_thiscallcc void 
@_ZN38ExplicitInstantiationDeclTemplateBase2IiE4funcEv
-
 // PR26076
 struct LayerSelectionBound;
 template <typename> struct Selection {};

Modified: cfe/trunk/test/CodeGenCXX/dllimport.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/dllimport.cpp?rev=270897&r1=270896&r2=270897&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/dllimport.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/dllimport.cpp Thu May 26 14:42:56 2016
@@ -656,7 +656,7 @@ namespace DontUseDtorAlias {
 
 namespace Vtordisp {
   // Don't dllimport the vtordisp.
-  // MO1-DAG: define linkonce_odr x86_thiscallcc void 
@"\01?f@?$C@D@Vtordisp@@$4PPPPPPPM@A@AEXXZ"
+  // MO1-DAG: define linkonce_odr x86_thiscallcc void 
@"\01?f@?$C@H@Vtordisp@@$4PPPPPPPM@A@AEXXZ"
 
   class Base {
     virtual void f() {}
@@ -667,7 +667,7 @@ namespace Vtordisp {
     C() {}
     virtual void f() {}
   };
-  template class C<char>;
+  USECLASS(C<int>);
 }
 
 namespace ClassTemplateStaticDef {
@@ -698,26 +698,31 @@ namespace PR19933 {
   template <typename T> struct A { static NonPOD x; };
   template <typename T> NonPOD A<T>::x;
   template struct __declspec(dllimport) A<int>;
-  // MSC-DAG: @"\01?x@?$A@H@PR19933@@2UNonPOD@2@A" = available_externally 
dllimport global %"struct.PR19933::NonPOD" zeroinitializer
+  USEVARTYPE(NonPOD, A<int>::x);
+  // MSC-DAG: @"\01?x@?$A@H@PR19933@@2UNonPOD@2@A" = external dllimport global 
%"struct.PR19933::NonPOD"
 
   int f();
   template <typename T> struct B { static int x; };
   template <typename T> int B<T>::x = f();
   template struct __declspec(dllimport) B<int>;
-  // MSC-DAG: @"\01?x@?$B@H@PR19933@@2HA" = available_externally dllimport 
global i32 0
+  USEVAR(B<int>::x);
+  // MSC-DAG: @"\01?x@?$B@H@PR19933@@2HA" = external dllimport global i32
 
   constexpr int g() { return 42; }
   template <typename T> struct C { static int x; };
   template <typename T> int C<T>::x = g();
   template struct __declspec(dllimport) C<int>;
-  // MSC-DAG: @"\01?x@?$C@H@PR19933@@2HA" = available_externally dllimport 
global i32 42
+  USEVAR(C<int>::x);
+  // MSC-DAG: @"\01?x@?$C@H@PR19933@@2HA" = external dllimport global i32
 
   template <int I> struct D { static int x, y; };
   template <int I> int D<I>::x = I + 1;
   template <int I> int D<I>::y = I + f();
   template struct __declspec(dllimport) D<42>;
-  // MSC-DAG: @"\01?x@?$D@$0CK@@PR19933@@2HA" = available_externally dllimport 
global i32 43
-  // MSC-DAG: @"\01?y@?$D@$0CK@@PR19933@@2HA" = available_externally dllimport 
global i32 0
+  USEVAR(D<42>::x);
+  USEVAR(D<42>::y);
+  // MSC-DAG: @"\01?x@?$D@$0CK@@PR19933@@2HA" = external dllimport global i32
+  // MSC-DAG: @"\01?y@?$D@$0CK@@PR19933@@2HA" = external dllimport global i32
 }
 
 namespace PR21355 {
@@ -805,6 +810,36 @@ template struct __declspec(dllimport) PR
 USEMEMFUNC(PR23770BaseTemplate<int>, f);
 // M32-DAG: declare dllimport x86_thiscallcc void 
@"\01?f@?$PR23770BaseTemplate@H@@QAEXXZ"
 
+namespace PR27810 {
+  template <class T>
+  struct basic_ostream {
+    struct sentry {
+      sentry() { }
+      void foo() { }
+    };
+  };
+  template class __declspec(dllimport) basic_ostream<char>;
+  // The explicit instantiation definition acts as an explicit instantiation
+  // *declaration*, dllimport is not inherited by the inner class, and no
+  // functions are emitted unless they are used.
+
+  USEMEMFUNC(basic_ostream<char>::sentry, foo);
+  // M32-DAG: define linkonce_odr x86_thiscallcc void 
@"\01?foo@sentry@?$basic_ostream@D@PR27810@@QAEXXZ"
+  // M32-NOT: ??0sentry@?$basic_ostream@D@PR27810@@QAE@XZ
+}
+
+namespace PR27811 {
+  template <class T> struct codecvt {
+    virtual ~codecvt() { }
+  };
+  template class __declspec(dllimport) codecvt<char>;
+
+  // dllimport means this explicit instantiation definition gets treated as a
+  // declaration. Thus, the vtable should not be marked used, and in fact
+  // nothing for this class should be emitted at all since it's not used.
+  // M32-NOT: codecvt
+}
+
 
//===----------------------------------------------------------------------===//
 // Classes with template base classes
 
//===----------------------------------------------------------------------===//

Modified: cfe/trunk/test/CodeGenCXX/explicit-instantiation.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/explicit-instantiation.cpp?rev=270897&r1=270896&r2=270897&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/explicit-instantiation.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/explicit-instantiation.cpp Thu May 26 14:42:56 
2016
@@ -1,5 +1,6 @@
 // RUN: %clang_cc1 -emit-llvm -triple i686-pc-linux-gnu -std=c++1y -o - %s | 
FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-OPT
 // RUN: %clang_cc1 -emit-llvm -triple i686-pc-linux-gnu -std=c++1y -O3 
-disable-llvm-optzns -o - %s | FileCheck %s --check-prefix=CHECK 
--check-prefix=CHECK-OPT
+// RUN: %clang_cc1 -emit-llvm -triple i686-pc-win32 -std=c++1y -o - %s | 
FileCheck %s --check-prefix=CHECK-MS
 
 // This check logically is attached to 'template int S<int>::i;' below.
 // CHECK: @_ZN1SIiE1iE = weak_odr global i32
@@ -103,6 +104,28 @@ int g() { return S<int>().f(); }
 template struct S<int>;
 }
 
+namespace NestedClasses {
+  // Check how explicit instantiation of an outer class affects the inner 
class.
+  template <typename T> struct Outer {
+    struct Inner {
+      void f() {}
+    };
+  };
+
+  // Explicit instantiation definition of Outer causes explicit instantiation
+  // definition of Inner.
+  template struct Outer<int>;
+  // CHECK: define weak_odr void @_ZN13NestedClasses5OuterIiE5Inner1fEv
+  // CHECK-MS: define weak_odr x86_thiscallcc void 
@"\01?f@Inner@?$Outer@H@NestedClasses@@QAEXXZ"
+
+  // Explicit instantiation declaration of Outer causes explicit instantiation
+  // declaration of Inner, but not in MSVC mode.
+  extern template struct Outer<char>;
+  auto use = &Outer<char>::Inner::f;
+  // CHECK: {{declare|define available_externally}} void 
@_ZN13NestedClasses5OuterIcE5Inner1fEv
+  // CHECK-MS: define linkonce_odr x86_thiscallcc void 
@"\01?f@Inner@?$Outer@D@NestedClasses@@QAEXXZ"
+}
+
 // Check that we emit definitions from explicit instantiations even when they
 // occur prior to the definition itself.
 template <typename T> struct S {

Modified: cfe/trunk/test/SemaTemplate/extern-templates.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/extern-templates.cpp?rev=270897&r1=270896&r2=270897&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/extern-templates.cpp (original)
+++ cfe/trunk/test/SemaTemplate/extern-templates.cpp Thu May 26 14:42:56 2016
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple i686-pc-win32 -fsyntax-only -verify %s -DMS
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu-pc-win32 -fsyntax-only 
-verify %s
 
 template<typename T>
 class X0 {
@@ -21,12 +22,20 @@ extern template class X0<int*>;
 
 template<typename T>
 void X0<T>::Inner::g(T t) {
-  t = 17; // expected-error{{incompatible}}
+#ifdef MS
+  t = 17; // expected-error{{assigning to 'long *' from incompatible}} 
expected-error{{assigning to 'int *' from incompatible}}
+#else
+  t = 17; // expected-error{{assigning to 'long *' from incompatible}}
+#endif
 }
 
 void test_intptr(X0<int*> xi, X0<int*>::Inner xii) {
   xi.f(0);
+#ifdef MS
+  xii.g(0); // expected-note {{instantiation}}
+#else
   xii.g(0);
+#endif
 }
 
 extern template class X0<long*>; 


_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to