takuto.ikuta updated this revision to Diff 164822.
takuto.ikuta added a comment.

I'm trying to handle local static var correctly.


https://reviews.llvm.org/D51340

Files:
  clang/include/clang/Driver/CLCompatOptions.td
  clang/include/clang/Sema/Sema.h
  clang/lib/Driver/ToolChains/Clang.cpp
  clang/lib/Sema/Sema.cpp
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/lib/Sema/SemaTemplate.cpp
  clang/test/CodeGenCXX/dllexport-import-fvisibility-inlines-hidden.cpp
  clang/test/CodeGenCXX/hidden-dllimport.cpp

Index: clang/test/CodeGenCXX/hidden-dllimport.cpp
===================================================================
--- clang/test/CodeGenCXX/hidden-dllimport.cpp
+++ clang/test/CodeGenCXX/hidden-dllimport.cpp
@@ -1,8 +1,8 @@
 // RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -emit-llvm -fvisibility-inlines-hidden -o - %s | FileCheck %s
 
-// We used to declare this hidden dllimport, which is contradictory.
+// We don't declare this hidden dllimport.
 
-// CHECK: declare dllimport void @"?bar@foo@@QEAAXXZ"(%struct.foo*)
+// CHECK-NOT: declare dllimport void @"?bar@foo@@QEAAXXZ"(%struct.foo*)
 
 struct __attribute__((dllimport)) foo {
   void bar() {}
Index: clang/test/CodeGenCXX/dllexport-import-fvisibility-inlines-hidden.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGenCXX/dllexport-import-fvisibility-inlines-hidden.cpp
@@ -0,0 +1,162 @@
+// RUN: %clang_cc1 %s -fms-extensions -triple x86_64-windows-msvc       \
+// RUN:     -fvisibility-inlines-hidden -emit-llvm -O0 -o - |           \
+// RUN:     FileCheck --check-prefix=DEFAULT --check-prefix=NOINLINE %s
+
+// RUN: %clang_cc1 %s -fms-extensions -triple x86_64-windows-msvc       \
+// RUN:     -emit-llvm -O0 -o - |                                       \
+// RUN:     FileCheck --check-prefix=DEFAULT --check-prefix=INLINE %s
+
+
+// Function
+
+// DEFAULT-DAG: define dso_local dllexport void @"?NormalFunction@@YAXXZ"()
+void __declspec(dllexport) NormalFunction() {}
+
+
+// NOINLINE-DAG: define weak_odr hidden dllexport void @"?AlwaysInlineFunction@@YAXXZ"
+// INLINE-DAG: define weak_odr dso_local dllexport void @"?AlwaysInlineFunction@@YAXXZ"
+__forceinline void __declspec(dllexport) AlwaysInlineFunction() {}
+
+// DEFAULT-DAG: @"?static_variable@?1??AlwaysInlineWithStaticVariableExported@@YAHXZ@4HA" = weak_odr dso_local dllexport global i32 0, comdat, align 4
+__forceinline int __declspec(dllexport) AlwaysInlineWithStaticVariableExported() {
+  static int static_variable = 0;
+  ++static_variable;
+  return static_variable;
+}
+
+// DEFAULT-DAG: @"?static_variable@?1??AlwaysInlineWithStaticVariableImported@@YAHXZ@4HA" = available_externally dllimport global i32 0, align 4
+__forceinline int __declspec(dllimport) AlwaysInlineWithStaticVariableImported() {
+  static int static_variable = 0;
+  ++static_variable;
+  return static_variable;
+}
+
+int ImportedFunctionUser() {
+  return AlwaysInlineWithStaticVariableImported();
+}
+
+// Class member function
+
+// check for local static variables
+// DEFAULT-DAG: @"?static_variable@?1??InclassDefFuncWithStaticVariable@NoTemplateExportedClass@@QEAAHXZ@4HA" = weak_odr dso_local dllexport global i32 0, comdat, align 4
+// DEFAULT-DAG: @"?static_variable@?1??InlineOutclassDefFuncWithStaticVariable@NoTemplateExportedClass@@QEAAHXZ@4HA" = weak_odr dso_local dllexport global i32 0, comdat, align 4
+
+// local static var in ImportedClass
+// NOINLINE-DAG: @"?static_variable@?1??InClassDefFuncWithStaticVariable@ImportedClass@@QEAAHXZ@4HA" = available_externally dllimport global i32 0, align 4
+// INLINE-NOT: static_variable@?1??InClassDefFuncWithStaticVariable@ImportedClass@@
+
+class __declspec(dllexport) NoTemplateExportedClass {
+ public:
+  // DEFAULT-NOT: NoTemplateExportedClass@NoTemplateExportedClass@@
+  NoTemplateExportedClass() = default;
+
+  // NOINLINE-NOT: InclassDefFunc@NoTemplateExportedClass
+  // INLINE-DAG: define weak_odr dso_local dllexport void @"?InclassDefFunc@NoTemplateExportedClass@@
+  void InclassDefFunc() {}
+
+  int f();
+
+  // INLINE-DAG: define weak_odr dso_local dllexport i32 @"?InclassDefFuncWithStaticVariable@NoTemplateExportedClass@@QEAAHXZ"
+  // NOINLINE-DAG: define weak_odr hidden dllexport i32 @"?InclassDefFuncWithStaticVariable@NoTemplateExportedClass@@QEAAHXZ"
+  int InclassDefFuncWithStaticVariable() {
+    static int static_variable = 0;
+    ++static_variable;
+    return static_variable;
+  }
+
+  // DEFAULT-NOT: InlineOutclassDefFuncWihtoutDefinition
+  __forceinline void InlineOutclassDefFuncWihtoutDefinition();
+
+  // DEFAULT-NOT: InlineOutclassDefFunc@NoTemplateExportedClass@@
+  __forceinline void InlineOutclassDefFunc();
+
+  // DEFAULT-NOT: InlineOutclassDefFuncWithStaticVariable@NoTemplateExportedClass@@
+  __forceinline int InlineOutclassDefFuncWithStaticVariable();
+
+  // DEFAULT-DAG: define dso_local dllexport void @"?OutclassDefFunc@NoTemplateExportedClass@@QEAAXXZ"
+  void OutclassDefFunc();
+};
+
+void NoTemplateExportedClass::OutclassDefFunc() {}
+
+__forceinline void NoTemplateExportedClass::InlineOutclassDefFunc() {}
+
+__forceinline int NoTemplateExportedClass::InlineOutclassDefFuncWithStaticVariable() {
+  static int static_variable = 0;
+  return ++static_variable;
+}
+
+void __declspec(dllexport) NoTemplateExportedClassUser() {
+  NoTemplateExportedClass a;
+  a.InlineOutclassDefFunc();
+}
+
+template<typename T>
+class __declspec(dllexport) TemplateExportedClass {
+  void InclassDefFunc() {}
+  void OutclassDefFunc();
+
+  T templateValue;
+};
+
+// DEFAULT-NOT: define dso_local dllexport void @"?OutclassDefFunc@NoTemplateExportedClass@@
+template<typename T> void TemplateExportedClass<T>::OutclassDefFunc() {}
+
+class A11{};
+class B22{};
+
+// DEFAULT-DAG: define weak_odr dso_local dllexport void @"?InclassDefFunc@?$TemplateExportedClass@VA11@@
+// DEFAULT-DAG: define weak_odr dso_local dllexport void @"?OutclassDefFunc@?$TemplateExportedClass@VA11@@
+template class __declspec(dllexport) TemplateExportedClass<A11>;
+
+// DEFAULT-DAG: define weak_odr dso_local dllexport void @"?InclassDefFunc@?$TemplateExportedClass@VB22@@
+// DEFAULT-DAG: define weak_odr dso_local dllexport void @"?OutclassDefFunc@?$TemplateExportedClass@VB22@@
+template class TemplateExportedClass<B22>;
+
+
+template<typename T>
+class TemplateNoExportedClass {
+  void InclassDefFunc() {}
+  void OutclassDefFunc();
+};
+
+template<typename T> void TemplateNoExportedClass<T>::OutclassDefFunc() {}
+
+// DEFAULT-DAG: define weak_odr dso_local dllexport void @"?InclassDefFunc@?$TemplateNoExportedClass@VA11@@
+// DEFAULT-DAG: define weak_odr dso_local dllexport void @"?OutclassDefFunc@?$TemplateNoExportedClass@VA11@@
+template class __declspec(dllexport) TemplateNoExportedClass<A11>;
+
+// DEFAULT-DAG: define weak_odr dso_local void @"?InclassDefFunc@?$TemplateNoExportedClass@VB22@@
+// DEFAULT-DAG: define weak_odr dso_local void @"?OutclassDefFunc@?$TemplateNoExportedClass@VB22@@
+template class TemplateNoExportedClass<B22>;
+
+
+class __declspec(dllimport) ImportedClass {
+public:
+  class ImportedInnerClass {
+   public:
+    void OutClassDefFunc();
+  };
+
+  // INLINE-DAG: declare dllimport i32 @"?InClassDefFuncWithStaticVariable@ImportedClass@@QEAAHXZ"(%class.ImportedClass*)
+  // NOINLINE-NOT dllimport .* InClassDefFuncWithStaticVariable@ImportedClass
+  int InClassDefFuncWithStaticVariable() {
+    static int static_variable = 0;
+    ++static_variable;
+    return static_variable;
+  }
+
+  // INLINE-DAG: declare dllimport void @"?InClassDefFunc@ImportedClass@
+  // NOINLINE-NOT: dllimport .* InClassDefFunc@ImportedClass@
+  void InClassDefFunc() {
+    i.OutClassDefFunc();
+  }
+  ImportedInnerClass i;
+};
+
+int InClassDefFuncUser() {
+  // This is necessary for declare statement of ImportedClass::InClassDefFunc().
+  ImportedClass c;
+  c.InClassDefFunc();
+  return c.InClassDefFuncWithStaticVariable();
+}
Index: clang/lib/Sema/SemaTemplate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplate.cpp
+++ clang/lib/Sema/SemaTemplate.cpp
@@ -8554,8 +8554,8 @@
               "on Def without dllexport or dllimport");
 
   // We reject explicit instantiations in class scope, so there should
-  // never be any delayed exported classes to worry about.
-  assert(S.DelayedDllExportClasses.empty() &&
+  // never be any delayed exported/imported classes to worry about.
+  assert(S.DelayedDllExportImportClasses.empty() &&
          "delayed exports present at explicit instantiation");
   S.checkClassLevelDLLAttribute(Def);
 
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -5485,20 +5485,84 @@
   }
 }
 
+namespace {
+class AttrLocalStaticVars : public StmtVisitor<AttrLocalStaticVars, bool> {
+  Sema &SemaRef;
+  Attr *ClassAttr;
+
+ public:
+  AttrLocalStaticVars(Sema &S, Attr *A) : SemaRef(S), ClassAttr(A) {}
+
+  bool VisitChildren(Stmt *S) {
+    for (Stmt *Child : S->children()) {
+      if (Child && Visit(Child))
+        return true;
+    }
+    return false;
+  }
+
+  bool VisitDeclStmt(DeclStmt *DS) {
+    bool HasStatic = VisitChildren(DS);
+    for (Decl *D : DS->decls()) {
+      if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+        if (VD->isStaticLocal()) {
+          auto *NewAttr =
+              cast<InheritableAttr>(ClassAttr->clone(SemaRef.getASTContext()));
+          NewAttr->setInherited(true);
+          VD->addAttr(NewAttr);
+          HasStatic = true;
+        }
+      }
+    }
+    return HasStatic;
+  }
+
+
+  bool VisitStmt(Stmt *S) {
+    return VisitChildren(S);
+  }
+};
+}
+
 static void ReferenceDllExportedMembers(Sema &S, CXXRecordDecl *Class) {
   Attr *ClassAttr = getDLLAttr(Class);
   if (!ClassAttr)
     return;
 
-  assert(ClassAttr->getKind() == attr::DLLExport);
-
   TemplateSpecializationKind TSK = Class->getTemplateSpecializationKind();
 
   if (TSK == TSK_ExplicitInstantiationDeclaration)
     // Don't go any further if this is just an explicit instantiation
     // declaration.
     return;
 
+  for (Decl *Member : Class->decls()) {
+    auto *MD = dyn_cast<CXXMethodDecl>(Member);
+    if (!MD)
+      continue;
+
+    if (MD->isInlined() && S.Context.getTargetInfo().getCXXABI().isMicrosoft() &&
+        S.getLangOpts().InlineVisibilityHidden &&
+        TSK != TSK_ExplicitInstantiationDefinition &&
+        !Member->getAttr<DLLExportAttr>() && MD->getBody()) {
+      // Export or import local static var for inline function.
+      AttrLocalStaticVars ALSV(S, ClassAttr);
+
+      if (ALSV.Visit(MD->getBody()) && ClassAttr->getKind() == attr::DLLExport) {
+        // Class is dllexported, export inline function having local static var too.
+        // This is necessary to have instantiation of local static var.
+        auto *NewAttr =
+            cast<InheritableAttr>(ClassAttr->clone(S.getASTContext()));
+        NewAttr->setInherited(true);
+        MD->addAttr(NewAttr);
+      }
+    }
+  }
+
+  if (ClassAttr->getKind() == attr::DLLImport) {
+    return;
+  }
+
   for (Decl *Member : Class->decls()) {
     // Defined static variables that are members of an exported base
     // class must be marked export too.
@@ -5686,6 +5750,16 @@
             !Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment())
           continue;
 
+        if (Context.getTargetInfo().getCXXABI().isMicrosoft() &&
+            getLangOpts().InlineVisibilityHidden &&
+            Class->getTemplateSpecializationKind() != TSK_ExplicitInstantiationDeclaration &&
+            Class->getTemplateSpecializationKind() != TSK_ExplicitInstantiationDefinition &&
+
+            // Check local static variable later.
+            MD->willHaveBody()) {
+          continue;
+        }
+
         // MSVC versions before 2015 don't export the move assignment operators
         // and move constructor, so don't attempt to import/export them if
         // we have a definition.
@@ -5734,8 +5808,7 @@
     }
   }
 
-  if (ClassExported)
-    DelayedDllExportClasses.push_back(Class);
+  DelayedDllExportImportClasses.push_back(Class);
 }
 
 /// Perform propagation of DLL attributes from a derived class to a
@@ -11222,11 +11295,11 @@
 }
 
 void Sema::referenceDLLExportedClassMethods() {
-  if (!DelayedDllExportClasses.empty()) {
+  if (!DelayedDllExportImportClasses.empty()) {
     // Calling ReferenceDllExportedMembers might cause the current function to
     // be called again, so use a local copy of DelayedDllExportClasses.
     SmallVector<CXXRecordDecl *, 4> WorkList;
-    std::swap(DelayedDllExportClasses, WorkList);
+    std::swap(DelayedDllExportImportClasses, WorkList);
     for (CXXRecordDecl *Class : WorkList)
       ReferenceDllExportedMembers(*this, Class);
   }
Index: clang/lib/Sema/Sema.cpp
===================================================================
--- clang/lib/Sema/Sema.cpp
+++ clang/lib/Sema/Sema.cpp
@@ -926,8 +926,8 @@
   assert(DelayedEquivalentExceptionSpecChecks.empty());
   assert(DelayedDefaultedMemberExceptionSpecs.empty());
 
-  // All dllexport classes should have been processed already.
-  assert(DelayedDllExportClasses.empty());
+  // All dllexport/dllimport classes should have been processed already.
+  assert(DelayedDllExportImportClasses.empty());
 
   // Remove file scoped decls that turned out to be used.
   UnusedFileScopedDecls.erase(
Index: clang/lib/Driver/ToolChains/Clang.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Clang.cpp
+++ clang/lib/Driver/ToolChains/Clang.cpp
@@ -5238,6 +5238,11 @@
   if (VolatileOptionID == options::OPT__SLASH_volatile_ms)
     CmdArgs.push_back("-fms-volatile");
 
+  if (Args.hasFlag(options::OPT__SLASH_Zc_dllexportInlines_,
+                   options::OPT__SLASH_Zc_dllexportInlines,
+                   false))
+    CmdArgs.push_back("-fvisibility-inlines-hidden");
+
   Arg *MostGeneralArg = Args.getLastArg(options::OPT__SLASH_vmg);
   Arg *BestCaseArg = Args.getLastArg(options::OPT__SLASH_vmb);
   if (MostGeneralArg && BestCaseArg)
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -10638,7 +10638,7 @@
 
   // Emitting members of dllexported classes is delayed until the class
   // (including field initializers) is fully parsed.
-  SmallVector<CXXRecordDecl*, 4> DelayedDllExportClasses;
+  SmallVector<CXXRecordDecl*, 4> DelayedDllExportImportClasses;
 
 private:
   class SavePendingParsedClassStateRAII {
@@ -10653,7 +10653,7 @@
       assert(S.DelayedDefaultedMemberExceptionSpecs.empty() &&
              "there shouldn't be any pending delayed defaulted member "
              "exception specs");
-      assert(S.DelayedDllExportClasses.empty() &&
+      assert(S.DelayedDllExportImportClasses.empty() &&
              "there shouldn't be any pending delayed DLL export classes");
       swapSavedState();
     }
@@ -10666,16 +10666,16 @@
         SavedEquivalentExceptionSpecChecks;
     decltype(DelayedDefaultedMemberExceptionSpecs)
         SavedDefaultedMemberExceptionSpecs;
-    decltype(DelayedDllExportClasses) SavedDllExportClasses;
+    decltype(DelayedDllExportImportClasses) SavedDllExportImportClasses;
 
     void swapSavedState() {
       SavedOverridingExceptionSpecChecks.swap(
           S.DelayedOverridingExceptionSpecChecks);
       SavedEquivalentExceptionSpecChecks.swap(
           S.DelayedEquivalentExceptionSpecChecks);
       SavedDefaultedMemberExceptionSpecs.swap(
           S.DelayedDefaultedMemberExceptionSpecs);
-      SavedDllExportClasses.swap(S.DelayedDllExportClasses);
+      SavedDllExportImportClasses.swap(S.DelayedDllExportImportClasses);
     }
   };
 
Index: clang/include/clang/Driver/CLCompatOptions.td
===================================================================
--- clang/include/clang/Driver/CLCompatOptions.td
+++ clang/include/clang/Driver/CLCompatOptions.td
@@ -301,6 +301,8 @@
   MetaVarName<"<filename>">;
 def _SLASH_Y_ : CLFlag<"Y-">,
   HelpText<"Disable precompiled headers, overrides /Yc and /Yu">;
+def _SLASH_Zc_dllexportInlines : CLFlag<"Zc:dllexportInlines">;
+def _SLASH_Zc_dllexportInlines_ : CLFlag<"Zc:dllexportInlines-">;
 def _SLASH_Fp : CLJoined<"Fp">,
   HelpText<"Set pch filename (with /Yc and /Yu)">, MetaVarName<"<filename>">;
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to