r209908 - Start adding support for dllimport/dllexport on classes (PR11170)

Hans Wennborg hans at hanshq.net
Fri May 30 09:59:43 PDT 2014


Author: hans
Date: Fri May 30 11:59:42 2014
New Revision: 209908

URL: http://llvm.org/viewvc/llvm-project?rev=209908&view=rev
Log:
Start adding support for dllimport/dllexport on classes (PR11170)

This implements the central part of support for dllimport/dllexport on
classes: allowing the attribute on class declarations, inheriting it
to class members, and forcing emission of exported members. It's based
on Nico Rieck's patch from http://reviews.llvm.org/D1099.

This patch doesn't propagate dllexport to bases that are template
specializations, which is an interesting problem. It also doesn't
look at the rules when redeclaring classes with different attributes,
I'd like to do that separately.

Differential Revision: http://reviews.llvm.org/D3877

Modified:
    cfe/trunk/include/clang/Basic/Attr.td
    cfe/trunk/lib/CodeGen/CGCXX.cpp
    cfe/trunk/lib/CodeGen/CGClass.cpp
    cfe/trunk/lib/CodeGen/CGVTables.cpp
    cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/test/CodeGenCXX/dllexport.cpp
    cfe/trunk/test/CodeGenCXX/dllimport.cpp
    cfe/trunk/test/SemaCXX/dllexport.cpp
    cfe/trunk/test/SemaCXX/dllimport.cpp

Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=209908&r1=209907&r2=209908&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Fri May 30 11:59:42 2014
@@ -1659,13 +1659,13 @@ def MsStruct : InheritableAttr {
 
 def DLLExport : InheritableAttr, TargetSpecificAttr<TargetWindows> {
   let Spellings = [Declspec<"dllexport">, GCC<"dllexport">];
-  let Subjects = SubjectList<[Function, Var]>;
+  let Subjects = SubjectList<[Function, Var, CXXRecord]>;
   let Documentation = [Undocumented];
 }
 
 def DLLImport : InheritableAttr, TargetSpecificAttr<TargetWindows> {
   let Spellings = [Declspec<"dllimport">, GCC<"dllimport">];
-  let Subjects = SubjectList<[Function, Var]>;
+  let Subjects = SubjectList<[Function, Var, CXXRecord]>;
   let Documentation = [Undocumented];
 }
 

Modified: cfe/trunk/lib/CodeGen/CGCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXX.cpp?rev=209908&r1=209907&r2=209908&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCXX.cpp Fri May 30 11:59:42 2014
@@ -44,6 +44,10 @@ bool CodeGenModule::TryEmitBaseDestructo
   if (!D->hasTrivialBody())
     return true;
 
+  // For exported destructors, we need a full definition.
+  if (D->hasAttr<DLLExportAttr>())
+    return true;
+
   const CXXRecordDecl *Class = D->getParent();
 
   // If we need to manipulate a VTT parameter, give up.

Modified: cfe/trunk/lib/CodeGen/CGClass.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=209908&r1=209907&r2=209908&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGClass.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGClass.cpp Fri May 30 11:59:42 2014
@@ -1425,8 +1425,8 @@ namespace {
 /// in reverse order of their construction.
 void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD,
                                         CXXDtorType DtorType) {
-  assert(!DD->isTrivial() &&
-         "Should not emit dtor epilogue for trivial dtor!");
+  assert((!DD->isTrivial() || DD->hasAttr<DLLExportAttr>()) &&
+         "Should not emit dtor epilogue for non-exported trivial dtor!");
 
   // The deleting-destructor phase just needs to call the appropriate
   // operator delete that Sema picked up.

Modified: cfe/trunk/lib/CodeGen/CGVTables.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVTables.cpp?rev=209908&r1=209907&r2=209908&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGVTables.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGVTables.cpp Fri May 30 11:59:42 2014
@@ -651,18 +651,31 @@ CodeGenModule::getVTableLinkage(const CX
   // internal linkage.
   if (Context.getLangOpts().AppleKext)
     return llvm::Function::InternalLinkage;
-  
+
+  llvm::GlobalVariable::LinkageTypes DiscardableODRLinkage =
+      llvm::GlobalValue::LinkOnceODRLinkage;
+  llvm::GlobalVariable::LinkageTypes NonDiscardableODRLinkage =
+      llvm::GlobalValue::WeakODRLinkage;
+  if (RD->hasAttr<DLLExportAttr>()) {
+    // Cannot discard exported vtables.
+    DiscardableODRLinkage = NonDiscardableODRLinkage;
+  } else if (RD->hasAttr<DLLImportAttr>()) {
+    // Imported vtables are available externally.
+    DiscardableODRLinkage = llvm::GlobalVariable::AvailableExternallyLinkage;
+    NonDiscardableODRLinkage = llvm::GlobalVariable::AvailableExternallyLinkage;
+  }
+
   switch (RD->getTemplateSpecializationKind()) {
   case TSK_Undeclared:
   case TSK_ExplicitSpecialization:
   case TSK_ImplicitInstantiation:
-    return llvm::GlobalVariable::LinkOnceODRLinkage;
+    return DiscardableODRLinkage;
 
   case TSK_ExplicitInstantiationDeclaration:
     llvm_unreachable("Should not have been asked to emit this");
 
   case TSK_ExplicitInstantiationDefinition:
-      return llvm::GlobalVariable::WeakODRLinkage;
+    return NonDiscardableODRLinkage;
   }
 
   llvm_unreachable("Invalid TemplateSpecializationKind!");

Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=209908&r1=209907&r2=209908&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Fri May 30 11:59:42 2014
@@ -203,6 +203,9 @@ public:
 
   void setThunkLinkage(llvm::Function *Thunk, bool ForVTable) override {
     Thunk->setLinkage(llvm::GlobalValue::WeakAnyLinkage);
+
+    // Never dllimport/dllexport thunks.
+    Thunk->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass);
   }
 
   llvm::Value *performThisAdjustment(CodeGenFunction &CGF, llvm::Value *This,
@@ -913,6 +916,7 @@ void MicrosoftCXXABI::emitVTableDefiniti
     VTable->setInitializer(Init);
 
     VTable->setLinkage(Linkage);
+
     CGM.setGlobalVisibility(VTable, RD);
   }
 }
@@ -994,6 +998,10 @@ llvm::GlobalVariable *MicrosoftCXXABI::g
     VTable = CGM.CreateOrReplaceCXXRuntimeVariable(
         Name.str(), ArrayType, llvm::GlobalValue::ExternalLinkage);
     VTable->setUnnamedAddr(true);
+    if (RD->hasAttr<DLLImportAttr>())
+      VTable->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
+    else if (RD->hasAttr<DLLExportAttr>())
+      VTable->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
     break;
   }
 
@@ -1169,6 +1177,12 @@ MicrosoftCXXABI::getAddrOfVBTable(const
   llvm::GlobalVariable *GV =
       CGM.CreateOrReplaceCXXRuntimeVariable(Name, VBTableType, Linkage);
   GV->setUnnamedAddr(true);
+
+  if (RD->hasAttr<DLLImportAttr>())
+    GV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
+  else if (RD->hasAttr<DLLExportAttr>())
+    GV->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
+
   return GV;
 }
 

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=209908&r1=209907&r2=209908&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Fri May 30 11:59:42 2014
@@ -4350,6 +4350,8 @@ static void CheckAbstractClassUsage(Abst
 
 /// \brief Return a DLL attribute from the declaration.
 static InheritableAttr *getDLLAttr(Decl *D) {
+  assert(!(D->hasAttr<DLLImportAttr>() && D->hasAttr<DLLExportAttr>()) &&
+         "A declaration cannot be both dllimport and dllexport.");
   if (auto *Import = D->getAttr<DLLImportAttr>())
     return Import;
   if (auto *Export = D->getAttr<DLLExportAttr>())
@@ -4357,6 +4359,59 @@ static InheritableAttr *getDLLAttr(Decl
   return nullptr;
 }
 
+/// \brief Check class-level dllimport/dllexport attribute.
+static void checkDLLAttribute(Sema &S, CXXRecordDecl *Class) {
+  Attr *ClassAttr = getDLLAttr(Class);
+  if (!ClassAttr)
+    return;
+
+  bool ClassExported = ClassAttr->getKind() == attr::DLLExport;
+
+  // Force declaration of implicit members so they can inherit the attribute.
+  S.ForceDeclarationOfImplicitMembers(Class);
+
+  // FIXME: MSVC's docs say all bases must be exportable, but this doesn't
+  // seem to be true in practice?
+
+  // FIXME: We also need to propagate the attribute upwards to class template
+  // specialization bases.
+
+  for (Decl *Member : Class->decls()) {
+    if (getDLLAttr(Member)) {
+      // FIXME: Error about importing/exporting individual members.
+    }
+
+    if (!isa<CXXMethodDecl>(Member) && !isa<VarDecl>(Member))
+      continue;
+
+    auto *NewAttr = cast<InheritableAttr>(ClassAttr->clone(S.getASTContext()));
+    NewAttr->setInherited(true);
+    Member->addAttr(NewAttr);
+
+    if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member)) {
+      if (ClassExported) {
+        if (MD->isDeleted())
+          continue;
+
+        if (MD->isUserProvided()) {
+          // Instantiate non-default methods.
+          S.MarkFunctionReferenced(Class->getLocation(), MD);
+        } else if (!MD->isTrivial() || MD->isExplicitlyDefaulted() ||
+                   MD->isCopyAssignmentOperator() ||
+                   MD->isMoveAssignmentOperator()) {
+          // Instantiate non-trival or explicitly defaulted methods, and the
+          // copy assignment / move assignment operators.
+          S.MarkFunctionReferenced(Class->getLocation(), MD);
+          // Resolve its exception specification; CodeGen needs it.
+          auto *FPT = MD->getType()->getAs<FunctionProtoType>();
+          S.ResolveExceptionSpec(Class->getLocation(), FPT);
+          S.ActOnFinishInlineMethodDef(MD);
+        }
+      }
+    }
+  }
+}
+
 /// \brief Perform semantic checks on a class definition that has been
 /// completing, introducing implicitly-declared members, checking for
 /// abstract types, etc.
@@ -4521,6 +4576,8 @@ void Sema::CheckCompletedCXXClass(CXXRec
   //   instantiated (e.g. meta-functions). This doesn't apply to classes that
   //   have inheriting constructors.
   DeclareInheritingConstructors(Record);
+
+  checkDLLAttribute(*this, Record);
 }
 
 /// Look up the special member function that would be called by a special

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=209908&r1=209907&r2=209908&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Fri May 30 11:59:42 2014
@@ -11284,7 +11284,7 @@ void Sema::MarkFunctionReferenced(Source
     Constructor = cast<CXXConstructorDecl>(Constructor->getFirstDecl());
     if (Constructor->isDefaulted() && !Constructor->isDeleted()) {
       if (Constructor->isDefaultConstructor()) {
-        if (Constructor->isTrivial())
+        if (Constructor->isTrivial() && !Constructor->hasAttr<DLLExportAttr>())
           return;
         DefineImplicitDefaultConstructor(Loc, Constructor);
       } else if (Constructor->isCopyConstructor()) {

Modified: cfe/trunk/test/CodeGenCXX/dllexport.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/dllexport.cpp?rev=209908&r1=209907&r2=209908&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/dllexport.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/dllexport.cpp Fri May 30 11:59:42 2014
@@ -3,6 +3,8 @@
 // RUN: %clang_cc1 -triple i686-windows-gnu    -emit-llvm -std=c++1y -O0 -o - %s | FileCheck --check-prefix=GNU --check-prefix=G32 %s
 // RUN: %clang_cc1 -triple x86_64-windows-gnu  -emit-llvm -std=c++1y -O0 -o - %s | FileCheck --check-prefix=GNU --check-prefix=G64 %s
 
+// RUN: %clang_cc1 -triple i686-pc-win32 -O1 -mconstructor-aliases -std=c++1y -emit-llvm -o - %s | FileCheck %s --check-prefix=MSC --check-prefix=M32
+
 // Helper structs to make templates more expressive.
 struct ImplicitInst_Exported {};
 struct ExplicitDecl_Exported {};
@@ -447,3 +449,91 @@ void __declspec(dllexport) precedenceRed
 // GNU-DAG: define dllexport void @_Z17precedenceRedecl2v()
 void __declspec(dllexport) precedenceRedecl2();
 void __declspec(dllimport) precedenceRedecl2() {}
+
+
+
+//===----------------------------------------------------------------------===//
+// Classes
+//===----------------------------------------------------------------------===//
+
+struct S {
+  void __declspec(dllexport) a() {}
+  // M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?a at S@@QAEXXZ"
+
+  struct T {
+    void __declspec(dllexport) a() {}
+    // M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?a at T@S@@QAEXXZ"
+  };
+};
+
+
+struct __declspec(dllexport) T {
+  // Copy assignment operator:
+  // M32-DAG: define weak_odr dllexport x86_thiscallcc nonnull %struct.T* @"\01??4T@@QAEAAU0 at ABU0@@Z"
+
+  // Explicitly defaulted copy constructur:
+  T(const T&) = default;
+  // M32-DAG: define weak_odr dllexport x86_thiscallcc %struct.T* @"\01??0T@@QAE at ABU0@@Z"
+
+  void a() {}
+  // M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?a at T@@QAEXXZ"
+
+  static int b;
+  // M32-DAG: @"\01?b at T@@2HA" = external dllexport global i32
+
+  static int c;
+  // M32-DAG: @"\01?c at T@@2HA" = dllexport global i32 0, align 4
+};
+
+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 nonnull %struct.U* @"\01??4?$U at H@@QAEAAU0 at ABU0@@Z"
+struct __declspec(dllexport) V : public U<int> { };
+
+
+struct __declspec(dllexport) W { virtual void foo() {} };
+// Default ctor:
+// M32-DAG: define weak_odr dllexport x86_thiscallcc %struct.W* @"\01??0W@@QAE at XZ"
+// Copy ctor:
+// M32-DAG: define weak_odr dllexport x86_thiscallcc %struct.W* @"\01??0W@@QAE at ABU0@@Z"
+// vftable:
+// M32-DAG: @"\01??_7W@@6B@" = weak_odr dllexport unnamed_addr constant [1 x i8*] [i8* bitcast (void (%struct.W*)* @"\01?foo at W@@UAEXXZ" to i8*)]
+
+struct __declspec(dllexport) X : public virtual W {};
+// vbtable:
+// M32-DAG: @"\01??_8X@@7B@" = weak_odr dllexport unnamed_addr constant [2 x i32] [i32 0, i32 4]
+
+struct __declspec(dllexport) Y {
+  // Move assignment operator:
+  // M32-DAG: define weak_odr dllexport x86_thiscallcc nonnull %struct.Y* @"\01??4Y@@QAEAAU0@$$QAU0@@Z"
+
+  int x;
+};
+
+struct __declspec(dllexport) Z { virtual ~Z() {} };
+// The scalar deleting dtor does not get exported:
+// M32-DAG: define linkonce_odr x86_thiscallcc void @"\01??_GZ@@UAEPAXI at Z"
+
+
+// The user-defined dtor does get exported:
+// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01??1Z@@UAE at XZ"
+
+namespace DontUseDtorAlias {
+  struct __declspec(dllexport) A { ~A(); };
+  struct __declspec(dllexport) B : A { ~B(); };
+  A::~A() { }
+  B::~B() { }
+  // Emit a real definition of B's constructor; don't alias it to A's.
+  // M32-DAG: define dllexport x86_thiscallcc void @"\01??1B at DontUseDtorAlias@@QAE at XZ"
+}
+
+struct __declspec(dllexport) DefaultedCtorsDtors {
+  DefaultedCtorsDtors() = default;
+  // M32-DAG: define weak_odr dllexport x86_thiscallcc %struct.DefaultedCtorsDtors* @"\01??0DefaultedCtorsDtors@@QAE at XZ"
+  ~DefaultedCtorsDtors() = default;
+  // M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01??1DefaultedCtorsDtors@@QAE at XZ"
+};

Modified: cfe/trunk/test/CodeGenCXX/dllimport.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/dllimport.cpp?rev=209908&r1=209907&r2=209908&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/dllimport.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/dllimport.cpp Fri May 30 11:59:42 2014
@@ -1,9 +1,9 @@
-// RUN: %clang_cc1 -triple i686-windows-msvc   -emit-llvm -std=c++1y -O0 -o - %s -DMSABI | FileCheck --check-prefix=MSC --check-prefix=M32 %s
-// RUN: %clang_cc1 -triple x86_64-windows-msvc -emit-llvm -std=c++1y -O0 -o - %s -DMSABI | FileCheck --check-prefix=MSC --check-prefix=M64 %s
-// RUN: %clang_cc1 -triple i686-windows-gnu    -emit-llvm -std=c++1y -O0 -o - %s         | FileCheck --check-prefix=GNU --check-prefix=G32 %s
-// RUN: %clang_cc1 -triple x86_64-windows-gnu  -emit-llvm -std=c++1y -O0 -o - %s         | FileCheck --check-prefix=GNU --check-prefix=G64 %s
-// RUN: %clang_cc1 -triple i686-windows-msvc   -emit-llvm -std=c++1y -O1 -o - %s -DMSABI | FileCheck --check-prefix=MO1 %s
-// RUN: %clang_cc1 -triple i686-windows-gnu    -emit-llvm -std=c++1y -O1 -o - %s         | FileCheck --check-prefix=GO1 %s
+// RUN: %clang_cc1 -triple i686-windows-msvc   -fno-rtti -emit-llvm -std=c++1y -O0 -o - %s -DMSABI | FileCheck --check-prefix=MSC --check-prefix=M32 %s
+// RUN: %clang_cc1 -triple x86_64-windows-msvc -fno-rtti -emit-llvm -std=c++1y -O0 -o - %s -DMSABI | FileCheck --check-prefix=MSC --check-prefix=M64 %s
+// RUN: %clang_cc1 -triple i686-windows-gnu    -fno-rtti -emit-llvm -std=c++1y -O0 -o - %s         | FileCheck --check-prefix=GNU --check-prefix=G32 %s
+// RUN: %clang_cc1 -triple x86_64-windows-gnu  -fno-rtti -emit-llvm -std=c++1y -O0 -o - %s         | FileCheck --check-prefix=GNU --check-prefix=G64 %s
+// RUN: %clang_cc1 -triple i686-windows-msvc   -fno-rtti -emit-llvm -std=c++1y -O1 -o - %s -DMSABI | FileCheck --check-prefix=MO1 %s
+// RUN: %clang_cc1 -triple i686-windows-gnu    -fno-rtti -emit-llvm -std=c++1y -O1 -o - %s         | FileCheck --check-prefix=GO1 %s
 
 // Helper structs to make templates more expressive.
 struct ImplicitInst_Imported {};
@@ -21,8 +21,8 @@ struct ExplicitSpec_NotImported {};
 #define USEVARTYPE(type, var) type UNIQ(use)() { return var; }
 #define USEVAR(var) USEVARTYPE(int, var)
 #define USE(func) void UNIQ(use)() { func(); }
-
-
+#define USEMEMFUNC(class, func) void (class::*UNIQ(use)())() { return &class::func; }
+#define USECLASS(class) void UNIQ(USE)() { class x; }
 
 //===----------------------------------------------------------------------===//
 // Globals
@@ -501,3 +501,69 @@ USE(funcTmpl<ExplicitSpec_Imported>)
 // GO1-DAG: define available_externally dllimport void @_Z8funcTmplI31ExplicitSpec_InlineDef_ImportedEvv()
 template<> __declspec(dllimport) inline void funcTmpl<ExplicitSpec_InlineDef_Imported>() {}
 USE(funcTmpl<ExplicitSpec_InlineDef_Imported>)
+
+
+
+//===----------------------------------------------------------------------===//
+// Classes
+//===----------------------------------------------------------------------===//
+
+struct __declspec(dllimport) T {
+  void a() {}
+  // MO1-DAG: define available_externally dllimport x86_thiscallcc void @"\01?a at T@@QAEXXZ"
+
+  static int b;
+  // MO1-DAG: @"\01?b at T@@2HA" = external dllimport global i32
+};
+USEMEMFUNC(T, a)
+USEVAR(T::b)
+
+template <typename T> struct __declspec(dllimport) U { void foo() {} };
+// MO1-DAG: define available_externally dllimport x86_thiscallcc void @"\01?foo@?$U at H@@QAEXXZ"
+struct __declspec(dllimport) V : public U<int> { };
+USEMEMFUNC(V, foo)
+
+struct __declspec(dllimport) W { virtual void foo() {} };
+USECLASS(W)
+// vftable:
+// MO1-DAG: @"\01??_7W@@6B@" = available_externally dllimport unnamed_addr constant [1 x i8*] [i8* bitcast (void (%struct.W*)* @"\01?foo at W@@UAEXXZ" to i8*)]
+
+struct __declspec(dllimport) X : public virtual W {};
+USECLASS(X)
+// vbtable:
+// MO1-DAG: @"\01??_8X@@7B@" = available_externally dllimport unnamed_addr constant [2 x i32] [i32 0, i32 4]
+
+struct __declspec(dllimport) Y {
+  int x;
+};
+
+struct __declspec(dllimport) Z { virtual ~Z() {} };
+USECLASS(Z)
+// User-defined dtor:
+// MO1-DAG: define available_externally dllimport x86_thiscallcc void @"\01??1Z@@UAE at XZ"
+
+namespace DontUseDtorAlias {
+  struct __declspec(dllimport) A { ~A(); };
+  struct __declspec(dllimport) B : A { ~B(); };
+  inline A::~A() { }
+  inline B::~B() { }
+  // Emit a real definition of B's constructor; don't alias it to A's.
+  // MO1-DAG: available_externally dllimport x86_thiscallcc void @"\01??1B at DontUseDtorAlias@@QAE at XZ"
+  USECLASS(B)
+}
+
+namespace Vtordisp {
+  // Don't dllimport the vtordisp.
+  // MO1-DAG: define weak x86_thiscallcc void @"\01?f@?$C at D@Vtordisp@@$4PPPPPPPM at A@AEXXZ"
+
+  class Base {
+    virtual void f() {}
+  };
+  template <typename T>
+  class __declspec(dllimport) C : virtual public Base {
+  public:
+    C() {}
+    virtual void f() {}
+  };
+  template class C<char>;
+}

Modified: cfe/trunk/test/SemaCXX/dllexport.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/dllexport.cpp?rev=209908&r1=209907&r2=209908&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/dllexport.cpp (original)
+++ cfe/trunk/test/SemaCXX/dllexport.cpp Fri May 30 11:59:42 2014
@@ -16,13 +16,13 @@ struct External { int v; };
 
 
 // Invalid usage.
-__declspec(dllexport) typedef int typedef1; // expected-warning{{'dllexport' attribute only applies to variables and functions}}
-typedef __declspec(dllexport) int typedef2; // expected-warning{{'dllexport' attribute only applies to variables and functions}}
-typedef int __declspec(dllexport) typedef3; // expected-warning{{'dllexport' attribute only applies to variables and functions}}
-typedef __declspec(dllexport) void (*FunTy)(); // expected-warning{{'dllexport' attribute only applies to variables and functions}}
-enum __declspec(dllexport) Enum {}; // expected-warning{{'dllexport' attribute only applies to variables and functions}}
+__declspec(dllexport) typedef int typedef1; // expected-warning{{'dllexport' attribute only applies to variables, functions and classes}}
+typedef __declspec(dllexport) int typedef2; // expected-warning{{'dllexport' attribute only applies to variables, functions and classes}}
+typedef int __declspec(dllexport) typedef3; // expected-warning{{'dllexport' attribute only applies to variables, functions and classes}}
+typedef __declspec(dllexport) void (*FunTy)(); // expected-warning{{'dllexport' attribute only applies to variables, functions and classes}}
+enum __declspec(dllexport) Enum {}; // expected-warning{{'dllexport' attribute only applies to variables, functions and classes}}
 #if __has_feature(cxx_strong_enums)
-  enum class __declspec(dllexport) EnumClass {}; // expected-warning{{'dllexport' attribute only applies to variables and functions}}
+  enum class __declspec(dllexport) EnumClass {}; // expected-warning{{'dllexport' attribute only applies to variables, functions and classes}}
 #endif
 
 
@@ -311,6 +311,14 @@ template<> __declspec(dllexport) inline
 
 
 //===----------------------------------------------------------------------===//
+// Classes
+//===----------------------------------------------------------------------===//
+
+class __declspec(dllexport) ClassDecl;
+
+class __declspec(dllexport) ClassDef { };
+
+//===----------------------------------------------------------------------===//
 // Precedence
 //===----------------------------------------------------------------------===//
 
@@ -385,7 +393,7 @@ private:
   __declspec(dllexport)                void privateDef();
 public:
 
-  __declspec(dllexport)                int  Field; // expected-warning{{'dllexport' attribute only applies to variables and functions}}
+  __declspec(dllexport)                int  Field; // expected-warning{{'dllexport' attribute only applies to variables, functions and classes}}
   __declspec(dllexport) static         int  StaticField;
   __declspec(dllexport) static         int  StaticFieldDef;
   __declspec(dllexport) static  const  int  StaticConstField;
@@ -771,7 +779,7 @@ private:
   __declspec(dllexport)                void privateDef();
 public:
 
-  __declspec(dllexport)                int  Field; // expected-warning{{'dllexport' attribute only applies to variables and functions}}
+  __declspec(dllexport)                int  Field; // expected-warning{{'dllexport' attribute only applies to variables, functions and classes}}
   __declspec(dllexport) static         int  StaticField;
   __declspec(dllexport) static         int  StaticFieldDef;
   __declspec(dllexport) static  const  int  StaticConstField;
@@ -907,3 +915,5 @@ template<typename T> template<typename U
 template<typename T> template<typename U> __declspec(dllexport) const  int  CTMTR<T>::StaticConstField = 1;  // expected-error{{redeclaration of 'CTMTR::StaticConstField' cannot add 'dllexport' attribute}}
 template<typename T> template<typename U> __declspec(dllexport) constexpr int CTMTR<T>::ConstexprField;      // expected-error{{redeclaration of 'CTMTR::ConstexprField' cannot add 'dllexport' attribute}}
 #endif // __has_feature(cxx_variable_templates)
+
+// FIXME: Precedence rules seem to be different for classes.

Modified: cfe/trunk/test/SemaCXX/dllimport.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/dllimport.cpp?rev=209908&r1=209907&r2=209908&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/dllimport.cpp (original)
+++ cfe/trunk/test/SemaCXX/dllimport.cpp Fri May 30 11:59:42 2014
@@ -15,13 +15,13 @@ namespace { struct Internal {}; }
 
 
 // Invalid usage.
-__declspec(dllimport) typedef int typedef1; // expected-warning{{'dllimport' attribute only applies to variables and functions}}
-typedef __declspec(dllimport) int typedef2; // expected-warning{{'dllimport' attribute only applies to variables and functions}}
-typedef int __declspec(dllimport) typedef3; // expected-warning{{'dllimport' attribute only applies to variables and functions}}
-typedef __declspec(dllimport) void (*FunTy)(); // expected-warning{{'dllimport' attribute only applies to variables and functions}}
-enum __declspec(dllimport) Enum {}; // expected-warning{{'dllimport' attribute only applies to variables and functions}}
+__declspec(dllimport) typedef int typedef1; // expected-warning{{'dllimport' attribute only applies to variables, functions and classes}}
+typedef __declspec(dllimport) int typedef2; // expected-warning{{'dllimport' attribute only applies to variables, functions and classes}}
+typedef int __declspec(dllimport) typedef3; // expected-warning{{'dllimport' attribute only applies to variables, functions and classes}}
+typedef __declspec(dllimport) void (*FunTy)(); // expected-warning{{'dllimport' attribute only applies to variables, functions and classes}}
+enum __declspec(dllimport) Enum {}; // expected-warning{{'dllimport' attribute only applies to variables, functions and classes}}
 #if __has_feature(cxx_strong_enums)
-  enum class __declspec(dllimport) EnumClass {}; // expected-warning{{'dllimport' attribute only applies to variables and functions}}
+  enum class __declspec(dllimport) EnumClass {}; // expected-warning{{'dllimport' attribute only applies to variables, functions and classes}}
 #endif
 
 
@@ -362,7 +362,6 @@ template<> __declspec(dllimport) void fu
 template<> __declspec(dllimport) inline void funcTmpl<ExplicitSpec_InlineDef_Imported>() {}
 
 
-
 //===----------------------------------------------------------------------===//
 // Class members
 //===----------------------------------------------------------------------===//
@@ -396,7 +395,7 @@ private:
   __declspec(dllimport)                void privateDecl();
 public:
 
-  __declspec(dllimport)                int  Field; // expected-warning{{'dllimport' attribute only applies to variables and functions}}
+  __declspec(dllimport)                int  Field; // expected-warning{{'dllimport' attribute only applies to variables, functions and classes}}
   __declspec(dllimport) static         int  StaticField;
   __declspec(dllimport) static         int  StaticFieldDef; // expected-note{{attribute is here}}
   __declspec(dllimport) static  const  int  StaticConstField;
@@ -794,7 +793,7 @@ private:
   __declspec(dllimport)                void privateDecl();
 public:
 
-  __declspec(dllimport)                int  Field; // expected-warning{{'dllimport' attribute only applies to variables and functions}}
+  __declspec(dllimport)                int  Field; // expected-warning{{'dllimport' attribute only applies to variables, functions and classes}}
   __declspec(dllimport) static         int  StaticField;
   __declspec(dllimport) static         int  StaticFieldDef; // expected-note{{attribute is here}}
   __declspec(dllimport) static  const  int  StaticConstField;
@@ -945,3 +944,13 @@ template<typename T> template<typename U
                                                                                                              // expected-error at -1{{definition of dllimport static field not allowed}}
                                                                                                              // expected-note at -2{{attribute is here}}
 #endif // __has_feature(cxx_variable_templates)
+
+
+
+//===----------------------------------------------------------------------===//
+// Classes
+//===----------------------------------------------------------------------===//
+
+class __declspec(dllimport) ClassDecl;
+
+class __declspec(dllimport) ClassDef { };





More information about the cfe-commits mailing list