r209908 - Start adding support for dllimport/dllexport on classes (PR11170)
Alp Toker
alp at nuanti.com
Fri May 30 12:28:29 PDT 2014
On 30/05/2014 19:59, Hans Wennborg wrote:
> 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!");
Instead of changing all these isTrivial() checks, did you consider
making special members under the DllExport attribute non-trivial e.g.
from within SpecialMemberIsTrivial()?
Seems to work and have more consistent semantics if that's what we're
going for.
Alp.
>
> // 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 { };
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
--
http://www.nuanti.com
the browser experts
More information about the cfe-commits
mailing list