Index: clang/include/clang/Driver/CLCompatOptions.td =================================================================== --- clang/include/clang/Driver/CLCompatOptions.td +++ clang/include/clang/Driver/CLCompatOptions.td @@ -301,6 +301,8 @@ MetaVarName<"">; 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<"">; 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/lib/Sema/SemaDeclCXX.cpp =================================================================== --- clang/lib/Sema/SemaDeclCXX.cpp +++ clang/lib/Sema/SemaDeclCXX.cpp @@ -5686,6 +5686,13 @@ !Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment()) continue; + if (Context.getTargetInfo().getCXXABI().isMicrosoft() && + getLangOpts().InlineVisibilityHidden && + Class->getTemplateSpecializationKind() != TSK_ExplicitInstantiationDeclaration && + Class->getTemplateSpecializationKind() != TSK_ExplicitInstantiationDefinition) { + 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. Index: clang/test/CodeGenCXX/dllexport-no-inline.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/dllexport-no-inline.cpp @@ -0,0 +1,148 @@ +// 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() {} + +// Class member function + +// check for local static variables +// NOINLINE-DAG: @"?static_variable@?1??InclassDefFuncWithStaticVariable@NoTemplateExportedClass@@QEAAHXZ@4HA" = linkonce_odr dso_local 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_const_variable@?1??InclassDefFuncWithStaticVariable@NoTemplateExportedClass@@QEAAHXZ@4HB" = linkonce_odr dso_local constant i32 1, comdat, align 4 +// INLINE-DAG: @"?static_const_variable@?1??InclassDefFuncWithStaticVariable@NoTemplateExportedClass@@QEAAHXZ@4HB" = weak_odr dso_local dllexport constant i32 1, comdat, align 4 +// NOINLINE-DAG: @"?static_const_array@?1??InclassDefFuncWithStaticVariable@NoTemplateExportedClass@@QEAAHXZ@4QBHB" = linkonce_odr dso_local constant [3 x i32] [i32 1, i32 2, i32 3], comdat, align 4 +// INLINE-DAG: @"?static_const_array@?1??InclassDefFuncWithStaticVariable@NoTemplateExportedClass@@QEAAHXZ@4QBHB" = weak_odr dso_local dllexport constant [3 x i32] [i32 1, i32 2, i32 3], comdat, align 4 +// NOINLINE-DAG: @"?static_variable_non_const_cse@?1??InclassDefFuncWithStaticVariable@NoTemplateExportedClass@@QEAAHXZ@4HA" = linkonce_odr dso_local global i32 4, comdat, align 4 +// INLINE-DAG: @"?static_variable_non_const_cse@?1??InclassDefFuncWithStaticVariable@NoTemplateExportedClass@@QEAAHXZ@4HA" = weak_odr dso_local dllexport global i32 4, comdat, align 4 +// NOINLINE-DAG: @"?static_variable@?1??InlineOutclassDefFuncWithStaticVariable@NoTemplateExportedClass@@QEAAHXZ@4HA" = linkonce_odr dso_local global i32 0, comdat, align 4 +// INLINE-DAG: @"?static_variable@?1??InlineOutclassDefFuncWithStaticVariable@NoTemplateExportedClass@@QEAAHXZ@4HA" = weak_odr dso_local dllexport global i32 0, comdat, 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(); + + // NOINLINE-NOT: InclassDefFuncWithStaticVariable@NoTemplateExportedClass + // INLINE-DAG: define weak_odr dso_local dllexport i32 @"?InclassDefFuncWithStaticVariable@NoTemplateExportedClass@@ + int InclassDefFuncWithStaticVariable() { + static int static_variable = f(); + static const int static_const_variable = 1; + // DEFAULT-NOT: static_constexpr_variable + static constexpr int static_constexpr_variable = 2; + static const int static_const_array[] = {1, 2, 3}; + static int static_variable_non_const_cse = 4; + + ++static_variable_non_const_cse; + ++static_variable; + return static_const_variable + static_constexpr_variable + + static_const_array[0] + static_variable_non_const_cse; + } + + // 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; +} + +int __declspec(dllexport) NoTemplateExportedClassUser() { + NoTemplateExportedClass a; + a.InlineOutclassDefFunc(); + return a.InclassDefFuncWithStaticVariable() + a.InlineOutclassDefFuncWithStaticVariable(); +} + +template +class __declspec(dllexport) TemplateExportedClass { + void InclassDefFunc() {} + void OutclassDefFunc(); + + T templateValue; +}; + +// DEFAULT-NOT: define dso_local dllexport void @"?OutclassDefFunc@NoTemplateExportedClass@@ +template void TemplateExportedClass::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; + +// 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; + + +template +class TemplateNoExportedClass { + void InclassDefFunc() {} + void OutclassDefFunc(); +}; + +template void TemplateNoExportedClass::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; + +// 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; + + +class __declspec(dllimport) ImportedClass { +public: + class ImportedInnerClass { + public: + void OutClassDefFunc(); + }; + + // INLINE-DAG: declare dllimport void @"?InClassDefFunc@ImportedClass@ + // NOINLINE-NOT: dllimport .* InClassDefFunc@ImportedClass@ + void InClassDefFunc() { + i.OutClassDefFunc(); + } + ImportedInnerClass i; +}; + +void InClassDefFuncUser() { + // This is necessary for declare statement of ImportedClass::InClassDefFunc(). + ImportedClass c; + c.InClassDefFunc(); +} 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() {}