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