takuto.ikuta updated this revision to Diff 171916.
takuto.ikuta added a comment.
export/import explicit template instantiation function
https://reviews.llvm.org/D51340
Files:
clang/include/clang/Basic/Attr.td
clang/include/clang/Basic/LangOptions.h
clang/include/clang/Driver/CC1Options.td
clang/include/clang/Driver/CLCompatOptions.td
clang/lib/Driver/ToolChains/Clang.cpp
clang/lib/Frontend/CompilerInvocation.cpp
clang/lib/Sema/SemaDecl.cpp
clang/lib/Sema/SemaDeclCXX.cpp
clang/test/CodeGenCXX/dllexport-no-dllexport-inlines.cpp
Index: clang/test/CodeGenCXX/dllexport-no-dllexport-inlines.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGenCXX/dllexport-no-dllexport-inlines.cpp
@@ -0,0 +1,192 @@
+// RUN: %clang_cc1 %s -fms-extensions -triple x86_64-windows-msvc \
+// RUN: -fno-dllexport-inlines -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() {}
+
+
+// DEFAULT-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();
+}
+
+
+// DEFAULT-DAG: @"?static_x@?2??InclassDefFuncWithStaticLocal@?$TemplateNoExportedClass@VA11@@@@QEAAHXZ@4HA" = weak_odr dso_local dllexport global i32 0, comdat, align 4
+
+
+// Class member function
+
+// check for local static variables
+// NOINLINE-DAG: @"?static_variable@?1??InclassDefFuncWithStaticVariable@NoTemplateExportedClass@@QEAAHXZ@4HA" = weak_odr dso_local dllexport global i32 0, comdat, align 4
+
+// INLINE-DAG: @"?static_variable@?1??InclassDefFuncWithStaticVariable@NoTemplateExportedClass@@QEAAHXZ@4HA" = weak_odr dso_local dllexport global i32 0, comdat, align 4
+
+// NOINLINE-DAG: @"?static_variable@?1??InClassDefFuncWithStaticVariable@ImportedClass@@QEAAHXZ@4HA" = available_externally dllimport global i32 0, align 4
+
+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();
+
+ // DEFAULT-DAG: define weak_odr dso_local dllexport i32 @"?InclassDefFuncWithStaticVariable@NoTemplateExportedClass@@QEAAHXZ"
+ int InclassDefFuncWithStaticVariable() {
+ static int static_variable = 0;
+ ++static_variable;
+ return static_variable;
+ }
+
+ // DEFAULT-DAG: define weak_odr dso_local dllexport i32 @"?InclassDefFunctWithLambdaStaticVariable@NoTemplateExportedClass@@QEAAHXZ"
+ int InclassDefFunctWithLambdaStaticVariable() {
+ return ([]() { static int static_x; return ++static_x; })();
+ }
+
+ // 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{};
+class C33{};
+class D44{};
+
+// INLINE-DAG: define weak_odr dso_local dllexport void @"?InclassDefFunc@?$TemplateExportedClass@VA11@@@@AEAAXXZ"
+// DEFAULT-DAG: define weak_odr dso_local dllexport void @"?OutclassDefFunc@?$TemplateExportedClass@VA11@@@@AEAAXXZ"
+template class __declspec(dllexport) TemplateExportedClass<A11>;
+
+// INLINE-DAG: define weak_odr dso_local dllexport void @"?InclassDefFunc@?$TemplateExportedClass@VB22@@@@AEAAXXZ"
+// DEFAULT-DAG: define weak_odr dso_local dllexport void @"?OutclassDefFunc@?$TemplateExportedClass@VB22@@@@AEAAXXZ
+template class TemplateExportedClass<B22>;
+
+
+template<typename T>
+class TemplateNoExportedClass {
+public:
+ void InclassDefFunc() {}
+ int InclassDefFuncWithStaticLocal() {
+ static int static_x;
+ return ++static_x;
+ }
+ void OutclassDefFunc();
+};
+
+template<typename T> void TemplateNoExportedClass<T>::OutclassDefFunc() {}
+
+// DEFAULT-DAG: define weak_odr dso_local dllexport void @"?InclassDefFunc@?$TemplateNoExportedClass@VA11@@@@QEAAXXZ"
+// DEFAULT-DAG: define weak_odr dso_local dllexport i32 @"?InclassDefFuncWithStaticLocal@?$TemplateNoExportedClass@VA11
+// DEFAULT-DAG: define weak_odr dso_local dllexport void @"?OutclassDefFunc@?$TemplateNoExportedClass@VA11@@@@QEAAXXZ"
+template class __declspec(dllexport) TemplateNoExportedClass<A11>;
+
+// DEFAULT-DAG: define weak_odr dso_local void @"?InclassDefFunc@?$TemplateNoExportedClass@VB22@@@@QEAAXXZ"
+// DEFAULT-DAG: define weak_odr dso_local void @"?OutclassDefFunc@?$TemplateNoExportedClass@VB22@@@@QEAAXXZ"
+template class TemplateNoExportedClass<B22>;
+
+// DEFAULT-DAG: declare dso_local void @"?InclassDefFunc@?$TemplateNoExportedClass@VC33@@@@QEAAXXZ"
+// DEFAULT-NOT: ?OutclassDefFunc@?$TemplateNoExportedClass@VC33@
+extern template class TemplateNoExportedClass<C33>;
+
+// DEFAULT-DAG: declare dllimport void @"?InclassDefFunc@?$TemplateNoExportedClass@VD44@@@@QEAAXXZ"
+// DEFAULT-DAG: declare dllimport i32 @"?InclassDefFuncWithStaticLocal@?$TemplateNoExportedClass@VD44
+// DEFAULT-NOT: ?OutclassDefFunc@?$TemplateNoExportedClass@VD44@
+extern template class __declspec(dllimport) TemplateNoExportedClass<D44>;
+
+void ExplicitTemplateDeclarationUser() {
+ TemplateNoExportedClass<C33> c33;
+ c33.InclassDefFunc();
+
+ TemplateNoExportedClass<D44> d44;
+ d44.InclassDefFunc();
+ d44.InclassDefFuncWithStaticLocal();
+}
+
+class __declspec(dllimport) ImportedClass {
+public:
+ class ImportedInnerClass {
+ public:
+ void OutClassDefFunc();
+ };
+
+ // INLINE-DAG: declare dllimport i32 @"?InClassDefFuncWithStaticVariable@ImportedClass@@QEAAHXZ"(%class.ImportedClass*) #2
+ // NOINLINE-NOT: declare{{.*}}"?InClassDefFuncWithStaticVariable@ImportedClass@@QEAAHXZ"
+ int InClassDefFuncWithStaticVariable() {
+ static int static_variable = 0;
+ ++static_variable;
+ return static_variable;
+ }
+
+ // NOINLINE-DAG: define linkonce_odr dso_local void @"?InClassDefFunc@ImportedClass@@QEAAXXZ"
+ // INLINE-DAG: declare dllimport void @"?InClassDefFunc@ImportedClass@@QEAAXXZ"
+ 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/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -5706,8 +5706,28 @@
continue;
if (!getDLLAttr(Member)) {
- auto *NewAttr =
- cast<InheritableAttr>(ClassAttr->clone(getASTContext()));
+ InheritableAttr *NewAttr = nullptr;
+
+ // Do not export/import inline function when -fno-dllexport-inlines is
+ // passed. But add attribute for later local static var check.
+ if (!getLangOpts().DllExportInlines && MD && MD->isInlined() &&
+ TSK != TSK_ExplicitInstantiationDeclaration &&
+ TSK != TSK_ExplicitInstantiationDefinition) {
+ if (ClassExported) {
+ NewAttr = ::new (getASTContext())
+ DLLExportStaticLocalAttr(ClassAttr->getRange(),
+ getASTContext(),
+ ClassAttr->getSpellingListIndex());
+ } else {
+ NewAttr = ::new (getASTContext())
+ DLLImportStaticLocalAttr(ClassAttr->getRange(),
+ getASTContext(),
+ ClassAttr->getSpellingListIndex());
+ }
+ } else {
+ NewAttr = cast<InheritableAttr>(ClassAttr->clone(getASTContext()));
+ }
+
NewAttr->setInherited(true);
Member->addAttr(NewAttr);
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -11930,14 +11930,40 @@
assert(VD->isStaticLocal());
auto *FD = dyn_cast_or_null<FunctionDecl>(VD->getParentFunctionOrMethod());
+
+ // Find outermost function when VD is in lambda function.
+ while (FD && !getDLLAttr(FD) &&
+ !FD->hasAttr<DLLExportStaticLocalAttr>() &&
+ !FD->hasAttr<DLLImportStaticLocalAttr>()) {
+ FD = dyn_cast_or_null<FunctionDecl>(FD->getParentFunctionOrMethod());
+ }
+
if (!FD)
return;
// Static locals inherit dll attributes from their function.
if (Attr *A = getDLLAttr(FD)) {
auto *NewAttr = cast<InheritableAttr>(A->clone(getASTContext()));
NewAttr->setInherited(true);
VD->addAttr(NewAttr);
+ } else if (Attr *A = FD->getAttr<DLLExportStaticLocalAttr>()) {
+ auto *NewAttr = ::new (getASTContext()) DLLExportAttr(A->getRange(),
+ getASTContext(),
+ A->getSpellingListIndex());
+ NewAttr->setInherited(true);
+ VD->addAttr(NewAttr);
+
+ // Export this function to enforce exporting this static variable even
+ // if it is not used in this compilation unit.
+ if (!FD->hasAttr<DLLExportAttr>())
+ FD->addAttr(NewAttr);
+
+ } else if (Attr *A = FD->getAttr<DLLImportStaticLocalAttr>()) {
+ auto *NewAttr = ::new (getASTContext()) DLLImportAttr(A->getRange(),
+ getASTContext(),
+ A->getSpellingListIndex());
+ NewAttr->setInherited(true);
+ VD->addAttr(NewAttr);
}
}
Index: clang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- clang/lib/Frontend/CompilerInvocation.cpp
+++ clang/lib/Frontend/CompilerInvocation.cpp
@@ -2178,6 +2178,9 @@
}
}
+ if (Args.hasArg(OPT_fno_dllexport_inlines))
+ Opts.DllExportInlines = false;
+
if (const Arg *A = Args.getLastArg(OPT_fcf_protection_EQ)) {
StringRef Name = A->getValue();
if (Name == "full" || Name == "branch") {
Index: clang/lib/Driver/ToolChains/Clang.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Clang.cpp
+++ clang/lib/Driver/ToolChains/Clang.cpp
@@ -5502,6 +5502,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("-fno-dllexport-inlines");
+
Arg *MostGeneralArg = Args.getLastArg(options::OPT__SLASH_vmg);
Arg *BestCaseArg = Args.getLastArg(options::OPT__SLASH_vmb);
if (MostGeneralArg && BestCaseArg)
Index: clang/include/clang/Driver/CLCompatOptions.td
===================================================================
--- clang/include/clang/Driver/CLCompatOptions.td
+++ clang/include/clang/Driver/CLCompatOptions.td
@@ -333,6 +333,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>">;
Index: clang/include/clang/Driver/CC1Options.td
===================================================================
--- clang/include/clang/Driver/CC1Options.td
+++ clang/include/clang/Driver/CC1Options.td
@@ -360,6 +360,7 @@
def msign_return_address_key_EQ : Joined<["-"], "msign-return-address-key=">,
Values<"a_key,b_key">;
def mbranch_target_enforce : Flag<["-"], "mbranch-target-enforce">;
+def fno_dllexport_inlines : Flag<["-"], "fno-dllexport-inlines">;
//===----------------------------------------------------------------------===//
// Dependency Output Options
Index: clang/include/clang/Basic/LangOptions.h
===================================================================
--- clang/include/clang/Basic/LangOptions.h
+++ clang/include/clang/Basic/LangOptions.h
@@ -242,6 +242,9 @@
/// input is a header file (i.e. -x c-header).
bool IsHeaderFile = false;
+ /// If set, dllexported classes dllexport their inline methods.
+ bool DllExportInlines = true;
+
LangOptions();
// Define accessors/mutators for language options of enumeration type.
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -2683,6 +2683,17 @@
let Documentation = [DLLExportDocs];
}
+def DLLExportStaticLocal : InheritableAttr, TargetSpecificAttr<TargetWindows> {
+ // This attribute is used internally only when -fno-dllexport-inlines is
+ // passed. This attribute is added to inline function of class having
+ // dllexport attribute. And if the function has static local variables, this
+ // attribute is used to whether the variables are exported or not. Also if
+ // function has local static variables, the function is dllexported too.
+ let Spellings = [];
+ let Subjects = SubjectList<[Function]>;
+ let Documentation = [Undocumented];
+}
+
def DLLImport : InheritableAttr, TargetSpecificAttr<TargetWindows> {
let Spellings = [Declspec<"dllimport">, GCC<"dllimport">];
let Subjects = SubjectList<[Function, Var, CXXRecord, ObjCInterface]>;
@@ -2699,6 +2710,16 @@
}];
}
+def DLLImportStaticLocal : InheritableAttr, TargetSpecificAttr<TargetWindows> {
+ // This attribute is used internally only when -fno-dllexport-inlines is
+ // passed. This attribute is added to inline function of class having
+ // dllimport attribute. And if the function has static local variables, this
+ // attribute is used to whether the variables are imported or not.
+ let Spellings = [];
+ let Subjects = SubjectList<[Function]>;
+ let Documentation = [Undocumented];
+}
+
def SelectAny : InheritableAttr {
let Spellings = [Declspec<"selectany">, GCC<"selectany">];
let Documentation = [SelectAnyDocs];
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits