David said he was using the November CTP of MSVC to observe the move assignment
operator getting exported. I've updated the patch so we export it too.
http://reviews.llvm.org/D3877
Files:
include/clang/Basic/Attr.td
lib/CodeGen/CGCXX.cpp
lib/CodeGen/CGVTables.cpp
lib/CodeGen/MicrosoftCXXABI.cpp
lib/Sema/SemaDeclCXX.cpp
test/CodeGenCXX/dllexport.cpp
test/CodeGenCXX/dllimport.cpp
test/SemaCXX/dllexport.cpp
test/SemaCXX/dllimport.cpp
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -1659,13 +1659,13 @@
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];
}
Index: lib/CodeGen/CGCXX.cpp
===================================================================
--- lib/CodeGen/CGCXX.cpp
+++ lib/CodeGen/CGCXX.cpp
@@ -44,6 +44,10 @@
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.
Index: lib/CodeGen/CGVTables.cpp
===================================================================
--- lib/CodeGen/CGVTables.cpp
+++ lib/CodeGen/CGVTables.cpp
@@ -651,18 +651,31 @@
// 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 functions.
+ DiscardableODRLinkage = NonDiscardableODRLinkage;
+ } else if (RD->hasAttr<DLLImportAttr>()) {
+ // Imported functions 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!");
Index: lib/CodeGen/MicrosoftCXXABI.cpp
===================================================================
--- lib/CodeGen/MicrosoftCXXABI.cpp
+++ lib/CodeGen/MicrosoftCXXABI.cpp
@@ -203,6 +203,9 @@
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,12 @@
VTable->setInitializer(Init);
VTable->setLinkage(Linkage);
+
+ if (RD->hasAttr<DLLImportAttr>())
+ VTable->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
+ else if (RD->hasAttr<DLLExportAttr>())
+ VTable->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
+
CGM.setGlobalVisibility(VTable, RD);
}
}
@@ -1218,6 +1227,11 @@
llvm::Constant *Init = llvm::ConstantArray::get(VBTableType, Offsets);
GV->setInitializer(Init);
+ if (RD->hasAttr<DLLImportAttr>())
+ GV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
+ else if (RD->hasAttr<DLLExportAttr>())
+ GV->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
+
// Set the right visibility.
CGM.setGlobalVisibility(GV, RD);
}
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -4348,6 +4348,66 @@
}
}
+/// \brief Get the dllimport/dllexport attribute from a declaration.
+static Attr *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>())
+ return Export;
+ 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.
+ }
+ 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.
@@ -4512,6 +4572,8 @@
// 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
Index: test/CodeGenCXX/dllexport.cpp
===================================================================
--- test/CodeGenCXX/dllexport.cpp
+++ test/CodeGenCXX/dllexport.cpp
@@ -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 {};
@@ -21,7 +23,6 @@
#define INSTVAR(var) template int var;
#define INST(func) template void func();
-
//===----------------------------------------------------------------------===//
// Globals
//===----------------------------------------------------------------------===//
@@ -447,3 +448,84 @@
// 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@S@@QAEXXZ"
+
+ struct T {
+ void __declspec(dllexport) a() {}
+ // M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?a@T@S@@QAEXXZ"
+ };
+};
+
+
+struct __declspec(dllexport) T {
+ // Copy assignment operator:
+ // M32-DAG: define weak_odr dllexport x86_thiscallcc nonnull %struct.T* @"\01??4T@@QAEAAU0@ABU0@@Z"
+
+ // Explicitly defaulted copy constructur:
+ T(const T&) = default;
+ // M32-DAG: define weak_odr dllexport x86_thiscallcc %struct.T* @"\01??0T@@QAE@ABU0@@Z"
+
+ void a() {}
+ // M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?a@T@@QAEXXZ"
+
+ static int b;
+ // M32-DAG: @"\01?b@T@@2HA" = external dllexport global i32
+
+ static int c;
+ // M32-DAG: @"\01?c@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@H@@QAEXXZ"
+// M32-DAG: define weak_odr dllexport x86_thiscallcc nonnull %struct.U* @"\01??4?$U@H@@QAEAAU0@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@XZ"
+// Copy ctor:
+// M32-DAG: define weak_odr dllexport x86_thiscallcc %struct.W* @"\01??0W@@QAE@ABU0@@Z"
+// vftable:
+// M32-DAG: @"\01??_7W@@6B@" = weak_odr dllexport unnamed_addr constant [1 x i8*] [i8* bitcast (void (%struct.W*)* @"\01?foo@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@Z"
+
+
+// The user-defined dtor does get exported:
+// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01??1Z@@UAE@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@DontUseDtorAlias@@QAE@XZ"
+}
Index: test/CodeGenCXX/dllimport.cpp
===================================================================
--- test/CodeGenCXX/dllimport.cpp
+++ test/CodeGenCXX/dllimport.cpp
@@ -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 @@
#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 @@
// 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@T@@QAEXXZ"
+
+ static int b;
+ // MO1-DAG: @"\01?b@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@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@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@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@DontUseDtorAlias@@QAE@XZ"
+ USECLASS(B)
+}
+
+namespace Vtordisp {
+ // Don't dllimport the vtordisp.
+ // MO1-DAG: define weak x86_thiscallcc void @"\01?f@?$C@D@Vtordisp@@$4PPPPPPPM@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>;
+}
Index: test/SemaCXX/dllexport.cpp
===================================================================
--- test/SemaCXX/dllexport.cpp
+++ test/SemaCXX/dllexport.cpp
@@ -16,13 +16,13 @@
// 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
@@ -307,6 +307,14 @@
//===----------------------------------------------------------------------===//
+// Classes
+//===----------------------------------------------------------------------===//
+
+class __declspec(dllexport) ClassDecl;
+
+class __declspec(dllexport) ClassDef { };
+
+//===----------------------------------------------------------------------===//
// Precedence
//===----------------------------------------------------------------------===//
@@ -734,3 +742,5 @@
template<typename T> template<typename U> __declspec(dllexport) void CTMTR<T>::staticDef() {} // expected-error{{redeclaration of 'CTMTR::staticDef' cannot add 'dllexport' attribute}}
template<typename T> template<typename U> __declspec(dllexport) inline void CTMTR<T>::staticInlineDef() {} // expected-error{{redeclaration of 'CTMTR::staticInlineDef' cannot add 'dllexport' attribute}}
template<typename T> template<typename U> __declspec(dllexport) void CTMTR<T>::staticInlineDecl() {} // expected-error{{redeclaration of 'CTMTR::staticInlineDecl' cannot add 'dllexport' attribute}}
+
+// FIXME: Precedence rules seem to be different for classes.
Index: test/SemaCXX/dllimport.cpp
===================================================================
--- test/SemaCXX/dllimport.cpp
+++ test/SemaCXX/dllimport.cpp
@@ -15,13 +15,13 @@
// 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
@@ -355,7 +355,6 @@
template<> __declspec(dllimport) inline void funcTmpl<ExplicitSpec_InlineDef_Imported>() {}
-
//===----------------------------------------------------------------------===//
// Class members
//===----------------------------------------------------------------------===//
@@ -744,3 +743,14 @@
// expected-error@-1{{dllimport cannot be applied to non-inline function definition}}
template<typename T> template<typename U> __declspec(dllimport) inline void CTMTR<T>::staticInlineDef() {} // expected-error{{redeclaration of 'CTMTR::staticInlineDef' cannot add 'dllimport' attribute}}
template<typename T> template<typename U> __declspec(dllimport) void CTMTR<T>::staticInlineDecl() {} // expected-error{{redeclaration of 'CTMTR::staticInlineDecl' cannot add 'dllimport' attribute}}
+
+
+
+
+//===----------------------------------------------------------------------===//
+// Classes
+//===----------------------------------------------------------------------===//
+
+class __declspec(dllimport) ClassDecl;
+
+class __declspec(dllimport) ClassDef { };
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits