DmitryPolukhin updated this revision to Diff 63950.
DmitryPolukhin marked 2 inline comments as done.
DmitryPolukhin added a comment.

- defer var generation if their type is class with dllimport.


http://reviews.llvm.org/D22034

Files:
  include/clang/AST/DeclCXX.h
  lib/AST/DeclCXX.cpp
  lib/AST/ExprConstant.cpp
  lib/AST/MicrosoftMangle.cpp
  lib/CodeGen/CGVTables.cpp
  lib/CodeGen/CodeGenModule.cpp
  lib/CodeGen/MicrosoftCXXABI.cpp
  lib/Sema/SemaDeclCXX.cpp
  test/CodeGenCXX/dllimport-rtti.cpp
  test/CodeGenCXX/dllimport.cpp

Index: test/CodeGenCXX/dllimport.cpp
===================================================================
--- test/CodeGenCXX/dllimport.cpp
+++ test/CodeGenCXX/dllimport.cpp
@@ -620,9 +620,31 @@
 struct __declspec(dllimport) W { virtual void foo() {} };
 USECLASS(W)
 // vftable:
-// MO1-DAG: @"\01??_SW@@6B@" = linkonce_odr unnamed_addr constant [1 x i8*] [i8* bitcast (void (%struct.W*)* @"\01?foo@W@@UAEXXZ" to i8*)]
+// MO1-DAG: @"\01??_7W@@6B@" = external dllimport unnamed_addr constant [1 x i8*]
 // GO1-DAG: @_ZTV1W = available_externally dllimport unnamed_addr constant [3 x i8*] [i8* null, i8* null, i8* bitcast (void (%struct.W*)* @_ZN1W3fooEv to i8*)]
 
+struct __declspec(dllimport) W2 {
+  virtual ~W2();
+  virtual void foo() {}
+};
+USECLASS(W2)
+// vftable:
+// MO1-DAG: @"\01??_SW2@@6B@" = linkonce_odr unnamed_addr constant [2 x i8*]
+// GO1-DAG: @_ZTV2W2 = external dllimport unnamed_addr constant [5 x i8*]
+
+struct __declspec(dllimport) W3 {
+  virtual void fn() const {
+  }
+  constexpr W3() = default;
+};
+
+W3 w3;
+W3& w3r = w3;
+
+constexpr W3 cw3;
+const W3 &cw3r = cw3;
+// MO1-DAG: @"\01??_SW3@@6B@" = linkonce_odr unnamed_addr constant [1 x i8*]
+
 struct __declspec(dllimport) KeyFuncClass {
   constexpr KeyFuncClass() {}
   virtual void foo();
Index: test/CodeGenCXX/dllimport-rtti.cpp
===================================================================
--- test/CodeGenCXX/dllimport-rtti.cpp
+++ test/CodeGenCXX/dllimport-rtti.cpp
@@ -4,16 +4,25 @@
 struct __declspec(dllimport) S {
   virtual void f() {}
 } s;
-// MSVC: [[VF_S:.*]] = private unnamed_addr constant [2 x i8*]
-// MSVC-DAG: @"\01??_SS@@6B@" = unnamed_addr alias i8*, getelementptr inbounds ([2 x i8*], [2 x i8*]* [[VF_S]], i32 0, i32 1)
+// MSVC-DAG: @"\01??_7S@@6B@" = external dllimport unnamed_addr constant [2 x i8*]
 // MSVC-DAG: @"\01??_R0?AUS@@@8" = linkonce_odr
 // MSVC-DAG: @"\01??_R1A@?0A@EA@S@@8" = linkonce_odr
 // MSVC-DAG: @"\01??_R2S@@8" = linkonce_odr
 // MSVC-DAG: @"\01??_R3S@@8" = linkonce_odr
 
 // GNU-DAG: @_ZTV1S = available_externally dllimport
 // GNU-DAG: @_ZTI1S = external dllimport
 
+struct __declspec(dllimport) S2 {
+  virtual void f() {}
+  virtual ~S2() {}
+} s2;
+// MSVC-DAG: [[VF_S2:.*]] = private unnamed_addr constant [3 x i8*] [i8* bitcast (%rtti.CompleteObjectLocator* @"\01??_R4S2@@6B@" to i8*)
+// MSVC-DAG: @"\01??_SS2@@6B@" = unnamed_addr alias i8*, getelementptr inbounds ([3 x i8*], [3 x i8*]* [[VF_S2]], i32 0, i32 1)
+// MSVC-DAG: @"\01??_R0?AUS2@@@8" = linkonce_odr
+// MSVC-DAG: @"\01??_R1A@?0A@EA@S2@@8" = linkonce_odr
+// MSVC-DAG: @"\01??_R2S2@@8" = linkonce_odr
+
 struct U : S {
 } u;
 
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -4809,6 +4809,17 @@
     }
   }
 
+  if (!ClassExported) {
+    if (Class->getTemplateSpecializationKind() != TSK_Undeclared)
+      Class->setNeedLocalVFTable();
+    if (const CXXDestructorDecl *Destructor = Class->getDestructor()) {
+      // Classes with dllimport attribute needs local vftable if they have
+      // virtual d-tor.
+      if (Destructor->isVirtual())
+        Class->setNeedLocalVFTable();
+    }
+  }
+
   if (ClassExported)
     DelayedDllExportClasses.push_back(Class);
 }
Index: lib/CodeGen/MicrosoftCXXABI.cpp
===================================================================
--- lib/CodeGen/MicrosoftCXXABI.cpp
+++ lib/CodeGen/MicrosoftCXXABI.cpp
@@ -1670,9 +1670,13 @@
   //
   // Because of this unique behavior, we maintain this logic here instead of
   // getVTableLinkage.
-  llvm::GlobalValue::LinkageTypes VFTableLinkage =
-      RD->hasAttr<DLLImportAttr>() ? llvm::GlobalValue::LinkOnceODRLinkage
-                                   : CGM.getVTableLinkage(RD);
+  llvm::GlobalValue::LinkageTypes VFTableLinkage = CGM.getVTableLinkage(RD);
+  if (RD->hasAttr<DLLImportAttr>()) {
+    if (RD->getNeedLocalVFTable())
+      VFTableLinkage = llvm::GlobalValue::LinkOnceODRLinkage;
+    else
+      VFTableLinkage = llvm::GlobalValue::ExternalLinkage;
+  }
   bool VFTableComesFromAnotherTU =
       llvm::GlobalValue::isAvailableExternallyLinkage(VFTableLinkage) ||
       llvm::GlobalValue::isExternalLinkage(VFTableLinkage);
@@ -1745,7 +1749,9 @@
   if (C)
     VTable->setComdat(C);
 
-  if (RD->hasAttr<DLLExportAttr>())
+  if (RD->hasAttr<DLLImportAttr>() && !RD->getNeedLocalVFTable())
+    VFTable->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
+  else if (RD->hasAttr<DLLExportAttr>())
     VFTable->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
 
   VFTablesMap[ID] = VFTable;
Index: lib/CodeGen/CodeGenModule.cpp
===================================================================
--- lib/CodeGen/CodeGenModule.cpp
+++ lib/CodeGen/CodeGenModule.cpp
@@ -1447,12 +1447,19 @@
       // Implicit template instantiations may change linkage if they are later
       // explicitly instantiated, so they should not be emitted eagerly.
       return false;
-  if (const auto *VD = dyn_cast<VarDecl>(Global))
+  if (const auto *VD = dyn_cast<VarDecl>(Global)) {
     if (Context.getInlineVariableDefinitionKind(VD) ==
         ASTContext::InlineVariableDefinitionKind::WeakUnknown)
       // A definition of an inline constexpr static data member may change
       // linkage later if it's redeclared outside the class.
       return false;
+    // In Microsoft ABI mode we have to defer variable definition to check
+    // if class needs local vftable.
+    if (Context.getTargetInfo().getCXXABI().isMicrosoft())
+      if (const auto *CD = VD->getType()->getAsCXXRecordDecl())
+        if (CD->hasAttr<DLLImportAttr>())
+          return false;
+  }
   // If OpenMP is enabled and threadprivates must be generated like TLS, delay
   // codegen for global variables, because they may be marked as threadprivate.
   if (LangOpts.OpenMP && LangOpts.OpenMPUseTLS &&
Index: lib/CodeGen/CGVTables.cpp
===================================================================
--- lib/CodeGen/CGVTables.cpp
+++ lib/CodeGen/CGVTables.cpp
@@ -845,8 +845,11 @@
 
   // We always synthesize vtables if they are needed in the MS ABI. MSVC doesn't
   // emit them even if there is an explicit template instantiation.
-  if (CGM.getTarget().getCXXABI().isMicrosoft())
-    return false;
+  if (CGM.getTarget().getCXXABI().isMicrosoft()) {
+    // But try to use dllexported vftable if we don't need local one in some
+    // context.
+    return RD->hasAttr<DLLImportAttr>() && !RD->getNeedLocalVFTable();
+  }
 
   // If we have an explicit instantiation declaration (and not a
   // definition), the vtable is defined elsewhere.
Index: lib/AST/MicrosoftMangle.cpp
===================================================================
--- lib/AST/MicrosoftMangle.cpp
+++ lib/AST/MicrosoftMangle.cpp
@@ -2602,7 +2602,7 @@
   // is always '6' for vftables.
   msvc_hashing_ostream MHO(Out);
   MicrosoftCXXNameMangler Mangler(*this, MHO);
-  if (Derived->hasAttr<DLLImportAttr>())
+  if (Derived->hasAttr<DLLImportAttr>() && Derived->getNeedLocalVFTable())
     Mangler.getStream() << "\01??_S";
   else
     Mangler.getStream() << "\01??_7";
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -5759,6 +5759,11 @@
                            APValue &Result, EvalInfo &Info) {
   assert(E->isRValue() && E->getType()->isRecordType() &&
          "can't evaluate expression as a record rvalue");
+  // The class will need local vftable because true const cannot use dllimported
+  // load time const.
+  if (Info.EvalMode == EvalInfo::EM_ConstantExpression)
+    if (auto *CD = E->getType()->getAsCXXRecordDecl())
+      CD->setNeedLocalVFTable();
   return RecordExprEvaluator(Info, This, Result).Visit(E);
 }
 
Index: lib/AST/DeclCXX.cpp
===================================================================
--- lib/AST/DeclCXX.cpp
+++ lib/AST/DeclCXX.cpp
@@ -71,8 +71,8 @@
       ImplicitCopyAssignmentHasConstParam(true),
       HasDeclaredCopyConstructorWithConstParam(false),
       HasDeclaredCopyAssignmentWithConstParam(false), IsLambda(false),
-      IsParsingBaseSpecifiers(false), NumBases(0), NumVBases(0), Bases(),
-      VBases(), Definition(D), FirstFriend() {}
+      IsParsingBaseSpecifiers(false), NeedLocalVFTable(false), NumBases(0),
+      NumVBases(0), Bases(), VBases(), Definition(D), FirstFriend() {}
 
 CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const {
   return Bases.get(Definition->getASTContext().getExternalSource());
Index: include/clang/AST/DeclCXX.h
===================================================================
--- include/clang/AST/DeclCXX.h
+++ include/clang/AST/DeclCXX.h
@@ -459,6 +459,9 @@
     /// \brief Whether we are currently parsing base specifiers.
     unsigned IsParsingBaseSpecifiers : 1;
 
+    /// \brief Whether class with dllimport attribute needs local vftable.
+    unsigned NeedLocalVFTable : 1;
+
     /// \brief The number of base class specifiers in Bases.
     unsigned NumBases;
 
@@ -705,6 +708,9 @@
     return data().IsParsingBaseSpecifiers;
   }
 
+  void setNeedLocalVFTable() { data().NeedLocalVFTable = true; }
+  bool getNeedLocalVFTable() const { return data().NeedLocalVFTable; }
+
   /// \brief Sets the base classes of this struct or class.
   void setBases(CXXBaseSpecifier const * const *Bases, unsigned NumBases);
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to