https://github.com/kikairoya updated https://github.com/llvm/llvm-project/pull/168171
>From 949abf8addb865099cb92b2f58abc885144965f5 Mon Sep 17 00:00:00 2001 From: kikairoya <[email protected]> Date: Thu, 5 Mar 2026 21:37:35 +0900 Subject: [PATCH 1/6] pretest --- ...t_instantiation.exclude_from_dllexport.cpp | 206 ++++++++++++++++++ ...t_instantiation.exclude_from_dllimport.cpp | 205 +++++++++++++++++ 2 files changed, 411 insertions(+) create mode 100644 clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp create mode 100644 clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp diff --git a/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp new file mode 100644 index 0000000000000..f417140b0301e --- /dev/null +++ b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp @@ -0,0 +1,206 @@ +// RUN: rm -rf %t.dir && mkdir %t.dir && cd %t.dir +// +// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s > x86_64-win32.ll +// RUN: FileCheck %s --check-prefixes=MSC < x86_64-win32.ll +// RUN: FileCheck %s --check-prefixes=UNDESIRED-MSC --implicit-check-not=notToBeInstantiated < x86_64-win32.ll +// +// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s > x86_64-mingw.ll +// RUN: FileCheck %s --check-prefixes=GNU < x86_64-mingw.ll +// RUN: FileCheck %s --check-prefixes=UNDESIRED-GNU --implicit-check-not=notToBeInstantiated < x86_64-mingw.ll +// +// RUN: %clang_cc1 -triple x86_64-cygwin -emit-llvm -o - %s > x86_64-cygwin.ll +// RUN: FileCheck %s --check-prefixes=GNU < x86_64-cygwin.ll +// RUN: FileCheck %s --check-prefixes=UNDESIRED-GNU --implicit-check-not=notToBeInstantiated < x86_64-cygwin.ll + +// Because --implicit-check-not doesn't work with -DAG checks, negative checks +// are performed on another independent path. +// UNDESIRED-MSC: $"?notToBeInstantiated@?$BasicCase@UWithExportTag@@@@QEAAXXZ" = comdat any +// UNDESIRED-GNU: $_ZN9BasicCaseI13WithExportTagE19notToBeInstantiatedEv = comdat any +// UNDESIRED-MSC: $"?notToBeInstantiated_withExport@?$BasicCase@UWithExportTag@@@@QEAAXXZ" = comdat any +// UNDESIRED-GNU: $_ZN9BasicCaseI13WithExportTagE30notToBeInstantiated_withExportEv = comdat any +// UNDESIRED-MSC: $"?notToBeInstantiated@?$ExportWholeTemplate@UNoAttrTag@@@@QEAAXXZ" = comdat any +// UNDESIRED-GNU: $_ZN19ExportWholeTemplateI9NoAttrTagE19notToBeInstantiatedEv = comdat any +// UNDESIRED-MSC: $"?notToBeInstantiated@?$Polymorphic@UWithExportTag@@@@QEAAXXZ" = comdat any +// UNDESIRED-GNU: $_ZN11PolymorphicI13WithExportTagE19notToBeInstantiatedEv = comdat any +// UNDESIRED-MSC: $"?notToBeInstantiated_withExport@?$Polymorphic@UWithExportTag@@@@QEAAXXZ" = comdat any +// UNDESIRED-GNU: $_ZN11PolymorphicI13WithExportTagE30notToBeInstantiated_withExportEv = comdat any + +#define EXCLUDE_ATTR __attribute__((exclude_from_explicit_instantiation)) + +struct NoAttrTag {}; +struct WithExportTag {}; +struct ImplicitTag {}; + +// Test that __declspec(dllexport) doesn't instantiate entities marked with +// the exclude_from_explicit_instantiation attribute. +template <class T> +struct BasicCase { + void noAttrMethod() {} + EXCLUDE_ATTR void excludedMethod() {} + EXCLUDE_ATTR __declspec(dllexport) void excludedExportedMethod() {} + EXCLUDE_ATTR void notToBeInstantiated() {} + EXCLUDE_ATTR __declspec(dllexport) void notToBeInstantiated_withExport() {} +}; + +/// Test that an exported explicit instantiation definition causes to export +/// non-exclued methods (i.e., noAttrMethod) only. +template struct __declspec(dllexport) BasicCase<WithExportTag>; +// MSC-DAG: define weak_odr dso_local dllexport void @"?noAttrMethod@?$BasicCase@UWithExportTag@@@@QEAAXXZ" +// GNU-DAG: define weak_odr dso_local dllexport void @_ZN9BasicCaseI13WithExportTagE12noAttrMethodEv + +// UNDESIRED-MSC: define weak_odr dso_local dllexport void @"?notToBeInstantiated@?$BasicCase@UWithExportTag@@@@QEAAXXZ" +// UNDESIRED-GNU: define weak_odr dso_local dllexport void @_ZN9BasicCaseI13WithExportTagE19notToBeInstantiatedEv + +// UNDESIRED-MSC: define weak_odr dso_local dllexport void @"?notToBeInstantiated_withExport@?$BasicCase@UWithExportTag@@@@QEAAXXZ" +// UNDESIRED-GNU: define weak_odr dso_local dllexport void @_ZN9BasicCaseI13WithExportTagE30notToBeInstantiated_withExportEv + +/// Test that a non-exported explicit instantiation definition instantiates +/// non-exclued methods but not exports. +template struct BasicCase<NoAttrTag>; +// MSC-DAG: define weak_odr dso_local void @"?noAttrMethod@?$BasicCase@UNoAttrTag@@@@QEAAXXZ" +// GNU-DAG: define weak_odr dso_local void @_ZN9BasicCaseI9NoAttrTagE12noAttrMethodEv + +/// Test that an excluded method isn't exported even if the previous explicit +/// instantiation definition or the method itself is exported. +/// A never-called method `notToBeInstantiated` makes sure that an excluded +/// method isn't instantiated unexpectedly. +void useBasicCase() { + BasicCase<WithExportTag>().excludedMethod(); + // MSC-DAG: define weak_odr dso_local dllexport void @"?excludedMethod@?$BasicCase@UWithExportTag@@@@QEAAXXZ" + // GNU-DAG: define weak_odr dso_local dllexport void @_ZN9BasicCaseI13WithExportTagE14excludedMethodEv + + BasicCase<WithExportTag>().excludedExportedMethod(); + // MSC-DAG: define weak_odr dso_local dllexport void @"?excludedExportedMethod@?$BasicCase@UWithExportTag@@@@QEAAXXZ" + // GNU-DAG: define weak_odr dso_local dllexport void @_ZN9BasicCaseI13WithExportTagE22excludedExportedMethodEv + + BasicCase<NoAttrTag>().excludedMethod(); + // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$BasicCase@UNoAttrTag@@@@QEAAXXZ" + // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI9NoAttrTagE14excludedMethodEv + + BasicCase<NoAttrTag>().excludedExportedMethod(); + // MSC-DAG: define linkonce_odr dso_local void @"?excludedExportedMethod@?$BasicCase@UNoAttrTag@@@@QEAAXXZ" + // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI9NoAttrTagE22excludedExportedMethodEv + + BasicCase<ImplicitTag>().excludedMethod(); + // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$BasicCase@UImplicitTag@@@@QEAAXXZ" + // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI11ImplicitTagE14excludedMethodEv + + BasicCase<ImplicitTag>().excludedExportedMethod(); + // MSC-DAG: define linkonce_odr dso_local void @"?excludedExportedMethod@?$BasicCase@UImplicitTag@@@@QEAAXXZ" + // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI11ImplicitTagE22excludedExportedMethodEv +} + +// Test that a class-level dllexport attribute won't affect to excluded methods. +template <class T> +struct __declspec(dllexport) ExportWholeTemplate { + void noAttrMethod() {} + EXCLUDE_ATTR void excludedMethod() {} + EXCLUDE_ATTR void excludedNoinlineMethod(); + EXCLUDE_ATTR void notToBeInstantiated() {} +}; + +// MSVC and MinGW disagree on whether an inline method of a class-level exported +// template should be exported. +template <typename T> void ExportWholeTemplate<T>::excludedNoinlineMethod() {} + +template struct ExportWholeTemplate<NoAttrTag>; +// MSC-DAG: define weak_odr dso_local dllexport void @"?noAttrMethod@?$ExportWholeTemplate@UNoAttrTag@@@@QEAAXXZ" +// GNU-DAG: define weak_odr dso_local dllexport void @_ZN19ExportWholeTemplateI9NoAttrTagE12noAttrMethodEv + +// UNDESIRED-MSC: define weak_odr dso_local dllexport void @"?notToBeInstantiated@?$ExportWholeTemplate@UNoAttrTag@@@@QEAAXXZ" +// UNDESIRED-GNU: define weak_odr dso_local dllexport void @_ZN19ExportWholeTemplateI9NoAttrTagE19notToBeInstantiatedEv + +void useExportWholeTemplate() { + ExportWholeTemplate<NoAttrTag>().excludedMethod(); + // MSC-DAG: define weak_odr dso_local dllexport void @"?excludedMethod@?$ExportWholeTemplate@UNoAttrTag@@@@QEAAXXZ" + // GNU-DAG: define weak_odr dso_local dllexport void @_ZN19ExportWholeTemplateI9NoAttrTagE14excludedMethodEv + + ExportWholeTemplate<NoAttrTag>().excludedNoinlineMethod(); + // MSC-DAG: define weak_odr dso_local dllexport void @"?excludedNoinlineMethod@?$ExportWholeTemplate@UNoAttrTag@@@@QEAAXXZ" + // GNU-DAG: define weak_odr dso_local dllexport void @_ZN19ExportWholeTemplateI9NoAttrTagE22excludedNoinlineMethodEv + + ExportWholeTemplate<ImplicitTag>().excludedMethod(); + // MSC-DAG: define weak_odr dso_local dllexport void @"?excludedMethod@?$ExportWholeTemplate@UImplicitTag@@@@QEAAXXZ" + // GNU-DAG: define linkonce_odr dso_local void @_ZN19ExportWholeTemplateI11ImplicitTagE14excludedMethodEv + + ExportWholeTemplate<ImplicitTag>().excludedNoinlineMethod(); + // MSC-DAG: define weak_odr dso_local dllexport void @"?excludedNoinlineMethod@?$ExportWholeTemplate@UImplicitTag@@@@QEAAXXZ" + // GNU-DAG: define weak_odr dso_local dllexport void @_ZN19ExportWholeTemplateI11ImplicitTagE22excludedNoinlineMethodEv +} + +// Interaction with VTables. +template <class T> +struct Polymorphic { + EXCLUDE_ATTR explicit Polymorphic() = default; + virtual void noAttrVirtualMethod() {} + EXCLUDE_ATTR virtual void excludedVirtualMethod() {} + EXCLUDE_ATTR __declspec(dllexport) virtual void excludedExportedVirtualMethod() {} + EXCLUDE_ATTR void notToBeInstantiated() {} + EXCLUDE_ATTR __declspec(dllexport) void notToBeInstantiated_withExport() {} +}; + +template struct __declspec(dllexport) Polymorphic<WithExportTag>; +// MSC-DAG: @"??_7?$Polymorphic@UWithExportTag@@@@6B@" = dllexport unnamed_addr +// GNU-DAG: @_ZTV11PolymorphicI13WithExportTagE = weak_odr dso_local dllexport unnamed_addr + +// MSC-DAG: define weak_odr dso_local dllexport void @"?noAttrVirtualMethod@?$Polymorphic@UWithExportTag@@@@UEAAXXZ" +// GNU-DAG: define weak_odr dso_local dllexport void @_ZN11PolymorphicI13WithExportTagE19noAttrVirtualMethodEv + +// MSC-DAG: define weak_odr dso_local dllexport void @"?excludedVirtualMethod@?$Polymorphic@UWithExportTag@@@@UEAAXXZ" +// GNU-DAG: define weak_odr dso_local dllexport void @_ZN11PolymorphicI13WithExportTagE21excludedVirtualMethodEv + +// MSC-DAG: define weak_odr dso_local dllexport void @"?excludedExportedVirtualMethod@?$Polymorphic@UWithExportTag@@@@UEAAXXZ" +// GNU-DAG: define weak_odr dso_local dllexport void @_ZN11PolymorphicI13WithExportTagE29excludedExportedVirtualMethodEv + +// UNDESIRED-MSC: define weak_odr dso_local dllexport void @"?notToBeInstantiated@?$Polymorphic@UWithExportTag@@@@QEAAXXZ" +// UNDESIRED-GNU: define weak_odr dso_local dllexport void @_ZN11PolymorphicI13WithExportTagE19notToBeInstantiatedEv + +// UNDESIRED-MSC: define weak_odr dso_local dllexport void @"?notToBeInstantiated_withExport@?$Polymorphic@UWithExportTag@@@@QEAAXXZ" +// UNDESIRED-GNU: define weak_odr dso_local dllexport void @_ZN11PolymorphicI13WithExportTagE30notToBeInstantiated_withExportEv + +template struct Polymorphic<NoAttrTag>; +// MSC-DAG: @"??_7?$Polymorphic@UNoAttrTag@@@@6B@" = unnamed_addr +// GNU-DAG: @_ZTV11PolymorphicI9NoAttrTagE = weak_odr dso_local unnamed_addr + +// MSC-DAG: define weak_odr dso_local void @"?noAttrVirtualMethod@?$Polymorphic@UNoAttrTag@@@@UEAAXXZ" +// GNU-DAG: define weak_odr dso_local void @_ZN11PolymorphicI9NoAttrTagE19noAttrVirtualMethodEv + +// MSC-DAG: define linkonce_odr dso_local void @"?excludedVirtualMethod@?$Polymorphic@UNoAttrTag@@@@UEAAXXZ" +// GNU-DAG: define linkonce_odr dso_local void @_ZN11PolymorphicI9NoAttrTagE21excludedVirtualMethodEv + +// MSC-DAG: define linkonce_odr dso_local void @"?excludedExportedVirtualMethod@?$Polymorphic@UNoAttrTag@@@@UEAAXXZ" +// GNU-DAG: define linkonce_odr dso_local void @_ZN11PolymorphicI9NoAttrTagE29excludedExportedVirtualMethodEv + +void usePolymorphic() { + new Polymorphic<ImplicitTag>(); + // MSC-DAG: @"??_7?$Polymorphic@UImplicitTag@@@@6B@" = unnamed_addr + // GNU-DAG: @_ZTV11PolymorphicI11ImplicitTagE = linkonce_odr dso_local unnamed_addr + + // MSC-DAG: define linkonce_odr dso_local void @"?noAttrVirtualMethod@?$Polymorphic@UImplicitTag@@@@UEAAXXZ" + // GNU-DAG: define linkonce_odr dso_local void @_ZN11PolymorphicI11ImplicitTagE19noAttrVirtualMethodEv + + // MSC-DAG: define linkonce_odr dso_local void @"?excludedVirtualMethod@?$Polymorphic@UImplicitTag@@@@UEAAXXZ" + // GNU-DAG: define linkonce_odr dso_local void @_ZN11PolymorphicI11ImplicitTagE21excludedVirtualMethodEv + + // MSC-DAG: define linkonce_odr dso_local void @"?excludedExportedVirtualMethod@?$Polymorphic@UImplicitTag@@@@UEAAXXZ" + // GNU-DAG: define linkonce_odr dso_local void @_ZN11PolymorphicI11ImplicitTagE29excludedExportedVirtualMethodEv +} + +/// Test that the DLL attrribute wins over the exclude attribute on a +/// non-template context. +struct NonTemplateClass { + EXCLUDE_ATTR __declspec(dllexport) void excludedExportedMethod(); +}; + +void NonTemplateClass::excludedExportedMethod() {} +// MSC-DAG: define dso_local dllexport void @"?excludedExportedMethod@NonTemplateClass@@QEAAXXZ" +// GNU-DAG: define dso_local dllexport void @_ZN16NonTemplateClass22excludedExportedMethodEv + +/// The same, but exporting whole class. +struct __declspec(dllexport) NonTemplateExportedClass { + EXCLUDE_ATTR void excludedMethod(); +}; + +void NonTemplateExportedClass::excludedMethod() {} +// MSC-DAG: define dso_local dllexport void @"?excludedMethod@NonTemplateExportedClass@@QEAAXXZ" +// GNU-DAG: define dso_local dllexport void @_ZN24NonTemplateExportedClass14excludedMethodEv diff --git a/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp new file mode 100644 index 0000000000000..dd9347f27cbfc --- /dev/null +++ b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp @@ -0,0 +1,205 @@ +// RUN: rm -rf %t.dir && mkdir %t.dir && cd %t.dir +// +// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s > x86_64-win32.ll +// RUN: FileCheck %s --check-prefixes=MSC < x86_64-win32.ll +// RUN: FileCheck %s --check-prefixes=UNDESIRED-MSC --implicit-check-not=notToBeInstantiated < x86_64-win32.ll +// +// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s > x86_64-mingw.ll +// RUN: FileCheck %s --check-prefixes=GNU < x86_64-mingw.ll +// RUN: FileCheck %s --check-prefixes=NEGATIVE-GNU,UNDESIRED-GNU --implicit-check-not=notToBeInstantiated < x86_64-mingw.ll +// +// RUN: %clang_cc1 -triple x86_64-cygwin -emit-llvm -o - %s > x86_64-cygwin.ll +// RUN: FileCheck %s --check-prefixes=GNU < x86_64-cygwin.ll +// RUN: FileCheck %s --check-prefixes=NEGATIVE-GNU,UNDESIRED-GNU --implicit-check-not=notToBeInstantiated < x86_64-cygwin.ll + +// Because --implicit-check-not doesn't work with -DAG checks, negative checks +// are performed on another independent path. + +#define EXCLUDE_ATTR __attribute__((exclude_from_explicit_instantiation)) + +struct NoAttrTag {}; +struct WithImportTag {}; +struct ImplicitTag {}; + +// Test that __declspec(dllimport) doesn't instantiate entities marked with +// the exclude_from_explicit_instantiation attribute. +template <class T> +struct BasicCase { + void noAttrMethod() {} + EXCLUDE_ATTR void excludedMethod() {} + EXCLUDE_ATTR __declspec(dllimport) void excludedImportedMethod() {} + EXCLUDE_ATTR void notToBeInstantiated() {} + EXCLUDE_ATTR __declspec(dllimport) void notToBeInstantiated_withImport() {} + void notToBeInstantiated_noAttr() {} +}; + +extern template struct __declspec(dllimport) BasicCase<WithImportTag>; +extern template struct BasicCase<NoAttrTag>; + +/// Test that an excluded method isn't imported even if the previous explicit +/// instantiation declaration or the method itself is imported. +/// A never-called method `notToBeInstantiated` makes sure that an excluded +/// method isn't instantiated unexpectedly. +void useBaseCase() { + BasicCase<WithImportTag>().noAttrMethod(); + // MSC-DAG: declare dllimport void @"?noAttrMethod@?$BasicCase@UWithImportTag@@@@QEAAXXZ" + // GNU-DAG: declare dllimport void @_ZN9BasicCaseI13WithImportTagE12noAttrMethodEv + + BasicCase<WithImportTag>().excludedMethod(); + // MSC-DAG: declare dllimport void @"?excludedMethod@?$BasicCase@UWithImportTag@@@@QEAAXXZ" + // GNU-DAG: declare dllimport void @_ZN9BasicCaseI13WithImportTagE14excludedMethodEv + + BasicCase<WithImportTag>().excludedImportedMethod(); + // MSC-DAG: declare dllimport void @"?excludedImportedMethod@?$BasicCase@UWithImportTag@@@@QEAAXXZ" + // GNU-DAG: declare dllimport void @_ZN9BasicCaseI13WithImportTagE22excludedImportedMethodEv + + BasicCase<NoAttrTag>().noAttrMethod(); + // MSC-DAG: declare dso_local void @"?noAttrMethod@?$BasicCase@UNoAttrTag@@@@QEAAXXZ" + // GNU-DAG: declare dso_local void @_ZN9BasicCaseI9NoAttrTagE12noAttrMethodEv + + BasicCase<NoAttrTag>().excludedMethod(); + // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$BasicCase@UNoAttrTag@@@@QEAAXXZ" + // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI9NoAttrTagE14excludedMethodEv + + BasicCase<NoAttrTag>().excludedImportedMethod(); + // MSC-DAG: define linkonce_odr dso_local void @"?excludedImportedMethod@?$BasicCase@UNoAttrTag@@@@QEAAXXZ" + // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI9NoAttrTagE22excludedImportedMethodEv + + BasicCase<ImplicitTag>().noAttrMethod(); + // MSC-DAG: define linkonce_odr dso_local void @"?noAttrMethod@?$BasicCase@UImplicitTag@@@@QEAAXXZ" + // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI11ImplicitTagE12noAttrMethodEv + + BasicCase<ImplicitTag>().excludedMethod(); + // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$BasicCase@UImplicitTag@@@@QEAAXXZ" + // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI11ImplicitTagE14excludedMethodEv + + BasicCase<ImplicitTag>().excludedImportedMethod(); + // MSC-DAG: define linkonce_odr dso_local void @"?excludedImportedMethod@?$BasicCase@UImplicitTag@@@@QEAAXXZ" + // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI11ImplicitTagE22excludedImportedMethodEv +} + +// Test that a class-level dllimport attribute won't affect to excluded methods. +template <class T> +struct __declspec(dllimport) ImportWholeTemplate { + void noAttrMethod() {} + EXCLUDE_ATTR void excludedMethod() {} + EXCLUDE_ATTR void excludedNoinlineMethod(); + EXCLUDE_ATTR void notToBeInstantiated() {} + void notToBeInstantiated_noAttr() {} +}; + +// MSVC and MinGW disagree on whether an inline method of a class-level imported +// template should be imported. +template <typename T> void ImportWholeTemplate<T>::excludedNoinlineMethod() {} + +extern template struct ImportWholeTemplate<NoAttrTag>; + +void useImportWholeTemplate() { + ImportWholeTemplate<NoAttrTag>().excludedMethod(); + // MSC-DAG: declare dllimport void @"?excludedMethod@?$ImportWholeTemplate@UNoAttrTag@@@@QEAAXXZ" + // GNU-DAG: declare dllimport void @_ZN19ImportWholeTemplateI9NoAttrTagE14excludedMethodEv + + ImportWholeTemplate<NoAttrTag>().excludedNoinlineMethod(); + // MSC-DAG: declare dllimport void @"?excludedNoinlineMethod@?$ImportWholeTemplate@UNoAttrTag@@@@QEAAXXZ" + // GNU-DAG: declare dllimport void @_ZN19ImportWholeTemplateI9NoAttrTagE22excludedNoinlineMethodEv + + ImportWholeTemplate<ImplicitTag>().excludedMethod(); + // MSC-DAG: declare dllimport void @"?excludedMethod@?$ImportWholeTemplate@UImplicitTag@@@@QEAAXXZ" + // GNU-DAG: define linkonce_odr dso_local void @_ZN19ImportWholeTemplateI11ImplicitTagE14excludedMethodEv + + ImportWholeTemplate<ImplicitTag>().excludedNoinlineMethod(); + // MSC-DAG: declare dllimport void @"?excludedNoinlineMethod@?$ImportWholeTemplate@UImplicitTag@@@@QEAAXXZ" + // GNU-DAG: declare dllimport void @_ZN19ImportWholeTemplateI11ImplicitTagE22excludedNoinlineMethodEv +} + +template <class T> +struct Polymorphic { + EXCLUDE_ATTR explicit Polymorphic() {} + virtual void noAttrVirtualMethod() {} + EXCLUDE_ATTR virtual void excludedVirtualMethod() {} + EXCLUDE_ATTR __declspec(dllimport) virtual void excludedImportedVirtualMethod() {} + EXCLUDE_ATTR void notToBeInstantiated() {} + EXCLUDE_ATTR __declspec(dllimport) void notToBeInstantiated_withImport() {} + void notToBeInstantiated_noAttr() {} +}; + +extern template struct __declspec(dllimport) Polymorphic<WithImportTag>; +extern template struct Polymorphic<NoAttrTag>; + +/// For the MSVC ABI: +/// A call to an excluded constructor implicitly instantiates the VTable, which +/// triggers the instantiation of all virtual methods, regardless of the exclude +/// attribute. Therefore, the `MSC-DAG` checks are repeated four times for each +/// specialization: once for the VTable and three times for the all three +/// virtual methods of the class template. +/// +/// For the Itanium ABI: +/// An implicit instantiation declaration suppresses emitting the VTable, so +/// virtual member functions won't be instantiated. Therefore, for `WithImportTag` +/// and `NoAttrTag` specializations, that have an explicit instantiation +/// declaration, only one `GNU-DAG` check to verify the VTable and three +/// `NEGATIVE-GNU-NOT` checks to ensure the virtual methods are not emitted +/// anywhere are placed. For the `ImplicitTag` specialization, `GNU-DAG` checks +/// are placed four times, since the virtual methods are implicitly instantiated. +/// +void usePolymorphic() { + new Polymorphic<WithImportTag>(); + // UNDESIRED-MSC-NOT: @"??_{{.}}?$Polymorphic@UWithImportTag@@@@6B@" = unnamed_addr + // UNDESIRED-GNU-NOT: @_ZTV11PolymorphicI13WithImportTagE = external dllimport unnamed_addr + + // UNDESIRED-MSC-NOT: @"?noAttrVirtualMethod@?$Polymorphic@UWithImportTag@@@@UEAAXXZ" + // NEGATIVE-GNU-NOT: @_ZN11PolymorphicI13WithImportTagE19noAttrVirtualMethodEv + + // UNDESIRED-MSC-NOT: @"?excludedVirtualMethod@?$Polymorphic@UWithImportTag@@@@UEAAXXZ" + // NEGATIVE-GNU-NOT: @_ZN11PolymorphicI13WithImportTagE21excludedVirtualMethodEv + + // UNDESIRED-MSC-NOT: @"?excludedImportedVirtualMethod@?$Polymorphic@UWithImportTag@@@@UEAAXXZ" + // NEGATIVE-GNU-NOT: @_ZN11PolymorphicI13WithImportTagE29excludedImportedVirtualMethodEv + + new Polymorphic<NoAttrTag>(); + // MSC-DAG: @"??_7?$Polymorphic@UNoAttrTag@@@@6B@" = unnamed_addr + // GNU-DAG: @_ZTV11PolymorphicI9NoAttrTagE = external unnamed_addr + + // MSC-DAG: declare dso_local void @"?noAttrVirtualMethod@?$Polymorphic@UNoAttrTag@@@@UEAAXXZ" + // NEGATIVE-GNU-NOT: @_ZN11PolymorphicI9NoAttrTagE19noAttrVirtualMethodEv + + // MSC-DAG: declare dso_local void @"?excludedVirtualMethod@?$Polymorphic@UNoAttrTag@@@@UEAAXXZ" + // NEGATIVE-GNU-NOT: @_ZN11PolymorphicI9NoAttrTagE21excludedVirtualMethodEv + + // MSC-DAG: declare dso_local void @"?excludedImportedVirtualMethod@?$Polymorphic@UNoAttrTag@@@@UEAAXXZ" + // NEGATIVE-GNU-NOT: @_ZN11PolymorphicI9NoAttrTagE29excludedImportedVirtualMethodEv + + new Polymorphic<ImplicitTag>(); + // MSC-DAG: @"??_7?$Polymorphic@UImplicitTag@@@@6B@" = unnamed_addr + // GNU-DAG: @_ZTV11PolymorphicI11ImplicitTagE = linkonce_odr dso_local unnamed_addr + + // MSC-DAG: define linkonce_odr dso_local void @"?noAttrVirtualMethod@?$Polymorphic@UImplicitTag@@@@UEAAXXZ" + // GNU-DAG: define linkonce_odr dso_local void @_ZN11PolymorphicI11ImplicitTagE19noAttrVirtualMethodEv + + // MSC-DAG: define linkonce_odr dso_local void @"?excludedVirtualMethod@?$Polymorphic@UImplicitTag@@@@UEAAXXZ" + // GNU-DAG: define linkonce_odr dso_local void @_ZN11PolymorphicI11ImplicitTagE21excludedVirtualMethodEv + + // MSC-DAG: define linkonce_odr dso_local void @"?excludedImportedVirtualMethod@?$Polymorphic@UImplicitTag@@@@UEAAXXZ" + // GNU-DAG: define linkonce_odr dso_local void @_ZN11PolymorphicI11ImplicitTagE29excludedImportedVirtualMethodEv +} + +/// Test that the DLL attrribute wins over the exclude attribute on a +/// non-template context. +struct NonTemplateClass { + EXCLUDE_ATTR __declspec(dllimport) void excludedImportedMethod(); +}; + +struct __declspec(dllimport) NonTemplateImportedClass { + EXCLUDE_ATTR void excludedMethod(); +}; + +void useNonTemplateClass() { + NonTemplateClass().excludedImportedMethod(); + // MSC-DAG: declare dllimport void @"?excludedImportedMethod@NonTemplateClass@@QEAAXXZ" + // GNU-DAG: declare dllimport void @_ZN16NonTemplateClass22excludedImportedMethodEv + + NonTemplateImportedClass().excludedMethod(); + // MSC-DAG: declare dllimport void @"?excludedMethod@NonTemplateImportedClass@@QEAAXXZ" + // GNU-DAG: declare dllimport void @_ZN24NonTemplateImportedClass14excludedMethodEv +} + >From b892bb596e6a0d9548b49c8d1026405349b618ff Mon Sep 17 00:00:00 2001 From: kikairoya <[email protected]> Date: Thu, 5 Mar 2026 21:37:36 +0900 Subject: [PATCH 2/6] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport Attaching `__declspec(dllexport/dllimport)` to explicit instantiation declaration made its whole member instantiated even if they were `__attribute__((__exclude_from_explicit_instantation__))`. Such members should not be instantiated nor be exported to avoid symbol leakage or duplication. --- clang/lib/Sema/SemaDeclCXX.cpp | 5 ++ ...t_instantiation.exclude_from_dllexport.cpp | 55 +++++-------------- ...t_instantiation.exclude_from_dllimport.cpp | 32 +++++------ 3 files changed, 36 insertions(+), 56 deletions(-) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 5837ecd6b9163..fdf3898ba52e5 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -6592,6 +6592,11 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { // seem to be true in practice? for (Decl *Member : Class->decls()) { + if ((TSK == TSK_ExplicitInstantiationDeclaration || + TSK == TSK_ExplicitInstantiationDefinition) && + Member->hasAttr<ExcludeFromExplicitInstantiationAttr>()) + continue; + VarDecl *VD = dyn_cast<VarDecl>(Member); CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member); diff --git a/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp index f417140b0301e..7ee64a2c75b6c 100644 --- a/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp +++ b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp @@ -2,28 +2,18 @@ // // RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s > x86_64-win32.ll // RUN: FileCheck %s --check-prefixes=MSC < x86_64-win32.ll -// RUN: FileCheck %s --check-prefixes=UNDESIRED-MSC --implicit-check-not=notToBeInstantiated < x86_64-win32.ll +// RUN: FileCheck %s --implicit-check-not=notToBeInstantiated < x86_64-win32.ll // // RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s > x86_64-mingw.ll // RUN: FileCheck %s --check-prefixes=GNU < x86_64-mingw.ll -// RUN: FileCheck %s --check-prefixes=UNDESIRED-GNU --implicit-check-not=notToBeInstantiated < x86_64-mingw.ll +// RUN: FileCheck %s --implicit-check-not=notToBeInstantiated < x86_64-mingw.ll // // RUN: %clang_cc1 -triple x86_64-cygwin -emit-llvm -o - %s > x86_64-cygwin.ll // RUN: FileCheck %s --check-prefixes=GNU < x86_64-cygwin.ll -// RUN: FileCheck %s --check-prefixes=UNDESIRED-GNU --implicit-check-not=notToBeInstantiated < x86_64-cygwin.ll +// RUN: FileCheck %s --implicit-check-not=notToBeInstantiated < x86_64-cygwin.ll // Because --implicit-check-not doesn't work with -DAG checks, negative checks // are performed on another independent path. -// UNDESIRED-MSC: $"?notToBeInstantiated@?$BasicCase@UWithExportTag@@@@QEAAXXZ" = comdat any -// UNDESIRED-GNU: $_ZN9BasicCaseI13WithExportTagE19notToBeInstantiatedEv = comdat any -// UNDESIRED-MSC: $"?notToBeInstantiated_withExport@?$BasicCase@UWithExportTag@@@@QEAAXXZ" = comdat any -// UNDESIRED-GNU: $_ZN9BasicCaseI13WithExportTagE30notToBeInstantiated_withExportEv = comdat any -// UNDESIRED-MSC: $"?notToBeInstantiated@?$ExportWholeTemplate@UNoAttrTag@@@@QEAAXXZ" = comdat any -// UNDESIRED-GNU: $_ZN19ExportWholeTemplateI9NoAttrTagE19notToBeInstantiatedEv = comdat any -// UNDESIRED-MSC: $"?notToBeInstantiated@?$Polymorphic@UWithExportTag@@@@QEAAXXZ" = comdat any -// UNDESIRED-GNU: $_ZN11PolymorphicI13WithExportTagE19notToBeInstantiatedEv = comdat any -// UNDESIRED-MSC: $"?notToBeInstantiated_withExport@?$Polymorphic@UWithExportTag@@@@QEAAXXZ" = comdat any -// UNDESIRED-GNU: $_ZN11PolymorphicI13WithExportTagE30notToBeInstantiated_withExportEv = comdat any #define EXCLUDE_ATTR __attribute__((exclude_from_explicit_instantiation)) @@ -48,12 +38,6 @@ template struct __declspec(dllexport) BasicCase<WithExportTag>; // MSC-DAG: define weak_odr dso_local dllexport void @"?noAttrMethod@?$BasicCase@UWithExportTag@@@@QEAAXXZ" // GNU-DAG: define weak_odr dso_local dllexport void @_ZN9BasicCaseI13WithExportTagE12noAttrMethodEv -// UNDESIRED-MSC: define weak_odr dso_local dllexport void @"?notToBeInstantiated@?$BasicCase@UWithExportTag@@@@QEAAXXZ" -// UNDESIRED-GNU: define weak_odr dso_local dllexport void @_ZN9BasicCaseI13WithExportTagE19notToBeInstantiatedEv - -// UNDESIRED-MSC: define weak_odr dso_local dllexport void @"?notToBeInstantiated_withExport@?$BasicCase@UWithExportTag@@@@QEAAXXZ" -// UNDESIRED-GNU: define weak_odr dso_local dllexport void @_ZN9BasicCaseI13WithExportTagE30notToBeInstantiated_withExportEv - /// Test that a non-exported explicit instantiation definition instantiates /// non-exclued methods but not exports. template struct BasicCase<NoAttrTag>; @@ -66,12 +50,12 @@ template struct BasicCase<NoAttrTag>; /// method isn't instantiated unexpectedly. void useBasicCase() { BasicCase<WithExportTag>().excludedMethod(); - // MSC-DAG: define weak_odr dso_local dllexport void @"?excludedMethod@?$BasicCase@UWithExportTag@@@@QEAAXXZ" - // GNU-DAG: define weak_odr dso_local dllexport void @_ZN9BasicCaseI13WithExportTagE14excludedMethodEv + // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$BasicCase@UWithExportTag@@@@QEAAXXZ" + // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI13WithExportTagE14excludedMethodEv BasicCase<WithExportTag>().excludedExportedMethod(); - // MSC-DAG: define weak_odr dso_local dllexport void @"?excludedExportedMethod@?$BasicCase@UWithExportTag@@@@QEAAXXZ" - // GNU-DAG: define weak_odr dso_local dllexport void @_ZN9BasicCaseI13WithExportTagE22excludedExportedMethodEv + // MSC-DAG: define linkonce_odr dso_local void @"?excludedExportedMethod@?$BasicCase@UWithExportTag@@@@QEAAXXZ" + // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI13WithExportTagE22excludedExportedMethodEv BasicCase<NoAttrTag>().excludedMethod(); // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$BasicCase@UNoAttrTag@@@@QEAAXXZ" @@ -107,17 +91,14 @@ template struct ExportWholeTemplate<NoAttrTag>; // MSC-DAG: define weak_odr dso_local dllexport void @"?noAttrMethod@?$ExportWholeTemplate@UNoAttrTag@@@@QEAAXXZ" // GNU-DAG: define weak_odr dso_local dllexport void @_ZN19ExportWholeTemplateI9NoAttrTagE12noAttrMethodEv -// UNDESIRED-MSC: define weak_odr dso_local dllexport void @"?notToBeInstantiated@?$ExportWholeTemplate@UNoAttrTag@@@@QEAAXXZ" -// UNDESIRED-GNU: define weak_odr dso_local dllexport void @_ZN19ExportWholeTemplateI9NoAttrTagE19notToBeInstantiatedEv - void useExportWholeTemplate() { ExportWholeTemplate<NoAttrTag>().excludedMethod(); - // MSC-DAG: define weak_odr dso_local dllexport void @"?excludedMethod@?$ExportWholeTemplate@UNoAttrTag@@@@QEAAXXZ" - // GNU-DAG: define weak_odr dso_local dllexport void @_ZN19ExportWholeTemplateI9NoAttrTagE14excludedMethodEv + // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$ExportWholeTemplate@UNoAttrTag@@@@QEAAXXZ" + // GNU-DAG: define linkonce_odr dso_local void @_ZN19ExportWholeTemplateI9NoAttrTagE14excludedMethodEv ExportWholeTemplate<NoAttrTag>().excludedNoinlineMethod(); - // MSC-DAG: define weak_odr dso_local dllexport void @"?excludedNoinlineMethod@?$ExportWholeTemplate@UNoAttrTag@@@@QEAAXXZ" - // GNU-DAG: define weak_odr dso_local dllexport void @_ZN19ExportWholeTemplateI9NoAttrTagE22excludedNoinlineMethodEv + // MSC-DAG: define linkonce_odr dso_local void @"?excludedNoinlineMethod@?$ExportWholeTemplate@UNoAttrTag@@@@QEAAXXZ" + // GNU-DAG: define linkonce_odr dso_local void @_ZN19ExportWholeTemplateI9NoAttrTagE22excludedNoinlineMethodEv ExportWholeTemplate<ImplicitTag>().excludedMethod(); // MSC-DAG: define weak_odr dso_local dllexport void @"?excludedMethod@?$ExportWholeTemplate@UImplicitTag@@@@QEAAXXZ" @@ -146,17 +127,11 @@ template struct __declspec(dllexport) Polymorphic<WithExportTag>; // MSC-DAG: define weak_odr dso_local dllexport void @"?noAttrVirtualMethod@?$Polymorphic@UWithExportTag@@@@UEAAXXZ" // GNU-DAG: define weak_odr dso_local dllexport void @_ZN11PolymorphicI13WithExportTagE19noAttrVirtualMethodEv -// MSC-DAG: define weak_odr dso_local dllexport void @"?excludedVirtualMethod@?$Polymorphic@UWithExportTag@@@@UEAAXXZ" -// GNU-DAG: define weak_odr dso_local dllexport void @_ZN11PolymorphicI13WithExportTagE21excludedVirtualMethodEv - -// MSC-DAG: define weak_odr dso_local dllexport void @"?excludedExportedVirtualMethod@?$Polymorphic@UWithExportTag@@@@UEAAXXZ" -// GNU-DAG: define weak_odr dso_local dllexport void @_ZN11PolymorphicI13WithExportTagE29excludedExportedVirtualMethodEv - -// UNDESIRED-MSC: define weak_odr dso_local dllexport void @"?notToBeInstantiated@?$Polymorphic@UWithExportTag@@@@QEAAXXZ" -// UNDESIRED-GNU: define weak_odr dso_local dllexport void @_ZN11PolymorphicI13WithExportTagE19notToBeInstantiatedEv +// MSC-DAG: define linkonce_odr dso_local void @"?excludedVirtualMethod@?$Polymorphic@UWithExportTag@@@@UEAAXXZ" +// GNU-DAG: define linkonce_odr dso_local void @_ZN11PolymorphicI13WithExportTagE21excludedVirtualMethodEv -// UNDESIRED-MSC: define weak_odr dso_local dllexport void @"?notToBeInstantiated_withExport@?$Polymorphic@UWithExportTag@@@@QEAAXXZ" -// UNDESIRED-GNU: define weak_odr dso_local dllexport void @_ZN11PolymorphicI13WithExportTagE30notToBeInstantiated_withExportEv +// MSC-DAG: define linkonce_odr dso_local void @"?excludedExportedVirtualMethod@?$Polymorphic@UWithExportTag@@@@UEAAXXZ" +// GNU-DAG: define linkonce_odr dso_local void @_ZN11PolymorphicI13WithExportTagE29excludedExportedVirtualMethodEv template struct Polymorphic<NoAttrTag>; // MSC-DAG: @"??_7?$Polymorphic@UNoAttrTag@@@@6B@" = unnamed_addr diff --git a/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp index dd9347f27cbfc..f6ca73d4cb847 100644 --- a/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp +++ b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp @@ -2,15 +2,15 @@ // // RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s > x86_64-win32.ll // RUN: FileCheck %s --check-prefixes=MSC < x86_64-win32.ll -// RUN: FileCheck %s --check-prefixes=UNDESIRED-MSC --implicit-check-not=notToBeInstantiated < x86_64-win32.ll +// RUN: FileCheck %s --implicit-check-not=notToBeInstantiated < x86_64-win32.ll // // RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s > x86_64-mingw.ll // RUN: FileCheck %s --check-prefixes=GNU < x86_64-mingw.ll -// RUN: FileCheck %s --check-prefixes=NEGATIVE-GNU,UNDESIRED-GNU --implicit-check-not=notToBeInstantiated < x86_64-mingw.ll +// RUN: FileCheck %s --check-prefixes=NEGATIVE-GNU --implicit-check-not=notToBeInstantiated < x86_64-mingw.ll // // RUN: %clang_cc1 -triple x86_64-cygwin -emit-llvm -o - %s > x86_64-cygwin.ll // RUN: FileCheck %s --check-prefixes=GNU < x86_64-cygwin.ll -// RUN: FileCheck %s --check-prefixes=NEGATIVE-GNU,UNDESIRED-GNU --implicit-check-not=notToBeInstantiated < x86_64-cygwin.ll +// RUN: FileCheck %s --check-prefixes=NEGATIVE-GNU --implicit-check-not=notToBeInstantiated < x86_64-cygwin.ll // Because --implicit-check-not doesn't work with -DAG checks, negative checks // are performed on another independent path. @@ -46,12 +46,12 @@ void useBaseCase() { // GNU-DAG: declare dllimport void @_ZN9BasicCaseI13WithImportTagE12noAttrMethodEv BasicCase<WithImportTag>().excludedMethod(); - // MSC-DAG: declare dllimport void @"?excludedMethod@?$BasicCase@UWithImportTag@@@@QEAAXXZ" - // GNU-DAG: declare dllimport void @_ZN9BasicCaseI13WithImportTagE14excludedMethodEv + // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$BasicCase@UWithImportTag@@@@QEAAXXZ" + // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI13WithImportTagE14excludedMethodEv BasicCase<WithImportTag>().excludedImportedMethod(); - // MSC-DAG: declare dllimport void @"?excludedImportedMethod@?$BasicCase@UWithImportTag@@@@QEAAXXZ" - // GNU-DAG: declare dllimport void @_ZN9BasicCaseI13WithImportTagE22excludedImportedMethodEv + // MSC-DAG: define linkonce_odr dso_local void @"?excludedImportedMethod@?$BasicCase@UWithImportTag@@@@QEAAXXZ" + // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI13WithImportTagE22excludedImportedMethodEv BasicCase<NoAttrTag>().noAttrMethod(); // MSC-DAG: declare dso_local void @"?noAttrMethod@?$BasicCase@UNoAttrTag@@@@QEAAXXZ" @@ -96,12 +96,12 @@ extern template struct ImportWholeTemplate<NoAttrTag>; void useImportWholeTemplate() { ImportWholeTemplate<NoAttrTag>().excludedMethod(); - // MSC-DAG: declare dllimport void @"?excludedMethod@?$ImportWholeTemplate@UNoAttrTag@@@@QEAAXXZ" - // GNU-DAG: declare dllimport void @_ZN19ImportWholeTemplateI9NoAttrTagE14excludedMethodEv + // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$ImportWholeTemplate@UNoAttrTag@@@@QEAAXXZ" + // GNU-DAG: define linkonce_odr dso_local void @_ZN19ImportWholeTemplateI9NoAttrTagE14excludedMethodEv ImportWholeTemplate<NoAttrTag>().excludedNoinlineMethod(); - // MSC-DAG: declare dllimport void @"?excludedNoinlineMethod@?$ImportWholeTemplate@UNoAttrTag@@@@QEAAXXZ" - // GNU-DAG: declare dllimport void @_ZN19ImportWholeTemplateI9NoAttrTagE22excludedNoinlineMethodEv + // MSC-DAG: define linkonce_odr dso_local void @"?excludedNoinlineMethod@?$ImportWholeTemplate@UNoAttrTag@@@@QEAAXXZ" + // GNU-DAG: define linkonce_odr dso_local void @_ZN19ImportWholeTemplateI9NoAttrTagE22excludedNoinlineMethodEv ImportWholeTemplate<ImplicitTag>().excludedMethod(); // MSC-DAG: declare dllimport void @"?excludedMethod@?$ImportWholeTemplate@UImplicitTag@@@@QEAAXXZ" @@ -144,16 +144,16 @@ extern template struct Polymorphic<NoAttrTag>; /// void usePolymorphic() { new Polymorphic<WithImportTag>(); - // UNDESIRED-MSC-NOT: @"??_{{.}}?$Polymorphic@UWithImportTag@@@@6B@" = unnamed_addr - // UNDESIRED-GNU-NOT: @_ZTV11PolymorphicI13WithImportTagE = external dllimport unnamed_addr + // MSC-DAG: @"??_S?$Polymorphic@UWithImportTag@@@@6B@" = unnamed_addr + // GNU-DAG: @_ZTV11PolymorphicI13WithImportTagE = external dllimport unnamed_addr - // UNDESIRED-MSC-NOT: @"?noAttrVirtualMethod@?$Polymorphic@UWithImportTag@@@@UEAAXXZ" + // MSC-DAG: declare dllimport void @"?noAttrVirtualMethod@?$Polymorphic@UWithImportTag@@@@UEAAXXZ" // NEGATIVE-GNU-NOT: @_ZN11PolymorphicI13WithImportTagE19noAttrVirtualMethodEv - // UNDESIRED-MSC-NOT: @"?excludedVirtualMethod@?$Polymorphic@UWithImportTag@@@@UEAAXXZ" + // MSC-DAG: declare dso_local void @"?excludedVirtualMethod@?$Polymorphic@UWithImportTag@@@@UEAAXXZ" // NEGATIVE-GNU-NOT: @_ZN11PolymorphicI13WithImportTagE21excludedVirtualMethodEv - // UNDESIRED-MSC-NOT: @"?excludedImportedVirtualMethod@?$Polymorphic@UWithImportTag@@@@UEAAXXZ" + // MSC-DAG: declare dso_local void @"?excludedImportedVirtualMethod@?$Polymorphic@UWithImportTag@@@@UEAAXXZ" // NEGATIVE-GNU-NOT: @_ZN11PolymorphicI13WithImportTagE29excludedImportedVirtualMethodEv new Polymorphic<NoAttrTag>(); >From baafdd7160e22e17bd3cf24a7c9bf32148cef4e7 Mon Sep 17 00:00:00 2001 From: kikairoya <[email protected]> Date: Thu, 5 Mar 2026 21:37:37 +0900 Subject: [PATCH 3/6] instantiate vtable --- clang/lib/Sema/SemaDeclCXX.cpp | 16 ++++++++++++++-- ...icit_instantiation.exclude_from_dllimport.cpp | 8 ++++---- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index fdf3898ba52e5..8173a4b53a679 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -19124,8 +19124,20 @@ bool Sema::DefineUsedVTables() { } } - if (IsExplicitInstantiationDeclaration) - DefineVTable = false; + if (IsExplicitInstantiationDeclaration) { + const bool HasExcludeFromExplicitInstantiation = + llvm::any_of(Class->methods(), [](CXXMethodDecl *method) { + // If the class has a member function declared with + // `__attribute__((exclude_from_explicit_instantiation))`, the + // explicit instantiation declaration should not suppress emitting + // the vtable, since the corresponding explicit instantiation + // definition might not emit the vtable if a triggering method is + // excluded. + return method->hasAttr<ExcludeFromExplicitInstantiationAttr>(); + }); + if (!HasExcludeFromExplicitInstantiation) + DefineVTable = false; + } } // The exception specifications for all virtual members may be needed even diff --git a/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp index f6ca73d4cb847..f2dd22f53ac08 100644 --- a/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp +++ b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp @@ -150,10 +150,10 @@ void usePolymorphic() { // MSC-DAG: declare dllimport void @"?noAttrVirtualMethod@?$Polymorphic@UWithImportTag@@@@UEAAXXZ" // NEGATIVE-GNU-NOT: @_ZN11PolymorphicI13WithImportTagE19noAttrVirtualMethodEv - // MSC-DAG: declare dso_local void @"?excludedVirtualMethod@?$Polymorphic@UWithImportTag@@@@UEAAXXZ" + // MSC-DAG: define linkonce_odr dso_local void @"?excludedVirtualMethod@?$Polymorphic@UWithImportTag@@@@UEAAXXZ" // NEGATIVE-GNU-NOT: @_ZN11PolymorphicI13WithImportTagE21excludedVirtualMethodEv - // MSC-DAG: declare dso_local void @"?excludedImportedVirtualMethod@?$Polymorphic@UWithImportTag@@@@UEAAXXZ" + // MSC-DAG: define linkonce_odr dso_local void @"?excludedImportedVirtualMethod@?$Polymorphic@UWithImportTag@@@@UEAAXXZ" // NEGATIVE-GNU-NOT: @_ZN11PolymorphicI13WithImportTagE29excludedImportedVirtualMethodEv new Polymorphic<NoAttrTag>(); @@ -163,10 +163,10 @@ void usePolymorphic() { // MSC-DAG: declare dso_local void @"?noAttrVirtualMethod@?$Polymorphic@UNoAttrTag@@@@UEAAXXZ" // NEGATIVE-GNU-NOT: @_ZN11PolymorphicI9NoAttrTagE19noAttrVirtualMethodEv - // MSC-DAG: declare dso_local void @"?excludedVirtualMethod@?$Polymorphic@UNoAttrTag@@@@UEAAXXZ" + // MSC-DAG: define linkonce_odr dso_local void @"?excludedVirtualMethod@?$Polymorphic@UNoAttrTag@@@@UEAAXXZ" // NEGATIVE-GNU-NOT: @_ZN11PolymorphicI9NoAttrTagE21excludedVirtualMethodEv - // MSC-DAG: declare dso_local void @"?excludedImportedVirtualMethod@?$Polymorphic@UNoAttrTag@@@@UEAAXXZ" + // MSC-DAG: define linkonce_odr dso_local void @"?excludedImportedVirtualMethod@?$Polymorphic@UNoAttrTag@@@@UEAAXXZ" // NEGATIVE-GNU-NOT: @_ZN11PolymorphicI9NoAttrTagE29excludedImportedVirtualMethodEv new Polymorphic<ImplicitTag>(); >From c642266f1574870db7509ac10d14544b8e96c289 Mon Sep 17 00:00:00 2001 From: kikairoya <[email protected]> Date: Thu, 5 Mar 2026 23:25:11 +0900 Subject: [PATCH 4/6] not to use temporaries in %t.dir --- ...t_instantiation.exclude_from_dllexport.cpp | 23 ++++++++++--------- ...t_instantiation.exclude_from_dllimport.cpp | 23 ++++++++++--------- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp index 7ee64a2c75b6c..d958db5f5cf78 100644 --- a/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp +++ b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp @@ -1,16 +1,17 @@ -// RUN: rm -rf %t.dir && mkdir %t.dir && cd %t.dir +// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=MSC +// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | \ +// RUN: FileCheck %s --implicit-check-not=notToBeInstantiated // -// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s > x86_64-win32.ll -// RUN: FileCheck %s --check-prefixes=MSC < x86_64-win32.ll -// RUN: FileCheck %s --implicit-check-not=notToBeInstantiated < x86_64-win32.ll +// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=GNU +// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | \ +// RUN: FileCheck %s --implicit-check-not=notToBeInstantiated // -// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s > x86_64-mingw.ll -// RUN: FileCheck %s --check-prefixes=GNU < x86_64-mingw.ll -// RUN: FileCheck %s --implicit-check-not=notToBeInstantiated < x86_64-mingw.ll -// -// RUN: %clang_cc1 -triple x86_64-cygwin -emit-llvm -o - %s > x86_64-cygwin.ll -// RUN: FileCheck %s --check-prefixes=GNU < x86_64-cygwin.ll -// RUN: FileCheck %s --implicit-check-not=notToBeInstantiated < x86_64-cygwin.ll +// RUN: %clang_cc1 -triple x86_64-cygwin -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=GNU +// RUN: %clang_cc1 -triple x86_64-cygwin -emit-llvm -o - %s | \ +// RUN: FileCheck %s --implicit-check-not=notToBeInstantiated // Because --implicit-check-not doesn't work with -DAG checks, negative checks // are performed on another independent path. diff --git a/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp index f2dd22f53ac08..87439af227393 100644 --- a/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp +++ b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp @@ -1,16 +1,17 @@ -// RUN: rm -rf %t.dir && mkdir %t.dir && cd %t.dir +// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=MSC +// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | \ +// RUN: FileCheck %s --implicit-check-not=notToBeInstantiated // -// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s > x86_64-win32.ll -// RUN: FileCheck %s --check-prefixes=MSC < x86_64-win32.ll -// RUN: FileCheck %s --implicit-check-not=notToBeInstantiated < x86_64-win32.ll +// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=GNU +// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=NEGATIVE-GNU --implicit-check-not=notToBeInstantiated // -// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s > x86_64-mingw.ll -// RUN: FileCheck %s --check-prefixes=GNU < x86_64-mingw.ll -// RUN: FileCheck %s --check-prefixes=NEGATIVE-GNU --implicit-check-not=notToBeInstantiated < x86_64-mingw.ll -// -// RUN: %clang_cc1 -triple x86_64-cygwin -emit-llvm -o - %s > x86_64-cygwin.ll -// RUN: FileCheck %s --check-prefixes=GNU < x86_64-cygwin.ll -// RUN: FileCheck %s --check-prefixes=NEGATIVE-GNU --implicit-check-not=notToBeInstantiated < x86_64-cygwin.ll +// RUN: %clang_cc1 -triple x86_64-cygwin -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=GNU +// RUN: %clang_cc1 -triple x86_64-cygwin -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=NEGATIVE-GNU --implicit-check-not=notToBeInstantiated // Because --implicit-check-not doesn't work with -DAG checks, negative checks // are performed on another independent path. >From 2eec31bc919530c32cc691a0315e7df790e763db Mon Sep 17 00:00:00 2001 From: kikairoya <[email protected]> Date: Thu, 5 Mar 2026 23:26:42 +0900 Subject: [PATCH 5/6] exclude-attr affects class-level dll-attr also --- clang/lib/Sema/SemaDeclCXX.cpp | 3 +-- ...e_from_explicit_instantiation.exclude_from_dllexport.cpp | 6 +++--- ...e_from_explicit_instantiation.exclude_from_dllimport.cpp | 6 +++--- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 8173a4b53a679..d5c207cd7481b 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -6592,8 +6592,7 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { // seem to be true in practice? for (Decl *Member : Class->decls()) { - if ((TSK == TSK_ExplicitInstantiationDeclaration || - TSK == TSK_ExplicitInstantiationDefinition) && + if (isTemplateInstantiation(TSK) && Member->hasAttr<ExcludeFromExplicitInstantiationAttr>()) continue; diff --git a/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp index d958db5f5cf78..aa4165af975fe 100644 --- a/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp +++ b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp @@ -102,12 +102,12 @@ void useExportWholeTemplate() { // GNU-DAG: define linkonce_odr dso_local void @_ZN19ExportWholeTemplateI9NoAttrTagE22excludedNoinlineMethodEv ExportWholeTemplate<ImplicitTag>().excludedMethod(); - // MSC-DAG: define weak_odr dso_local dllexport void @"?excludedMethod@?$ExportWholeTemplate@UImplicitTag@@@@QEAAXXZ" + // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$ExportWholeTemplate@UImplicitTag@@@@QEAAXXZ" // GNU-DAG: define linkonce_odr dso_local void @_ZN19ExportWholeTemplateI11ImplicitTagE14excludedMethodEv ExportWholeTemplate<ImplicitTag>().excludedNoinlineMethod(); - // MSC-DAG: define weak_odr dso_local dllexport void @"?excludedNoinlineMethod@?$ExportWholeTemplate@UImplicitTag@@@@QEAAXXZ" - // GNU-DAG: define weak_odr dso_local dllexport void @_ZN19ExportWholeTemplateI11ImplicitTagE22excludedNoinlineMethodEv + // MSC-DAG: define linkonce_odr dso_local void @"?excludedNoinlineMethod@?$ExportWholeTemplate@UImplicitTag@@@@QEAAXXZ" + // GNU-DAG: define linkonce_odr dso_local void @_ZN19ExportWholeTemplateI11ImplicitTagE22excludedNoinlineMethodEv } // Interaction with VTables. diff --git a/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp index 87439af227393..2bd64046d905e 100644 --- a/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp +++ b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp @@ -105,12 +105,12 @@ void useImportWholeTemplate() { // GNU-DAG: define linkonce_odr dso_local void @_ZN19ImportWholeTemplateI9NoAttrTagE22excludedNoinlineMethodEv ImportWholeTemplate<ImplicitTag>().excludedMethod(); - // MSC-DAG: declare dllimport void @"?excludedMethod@?$ImportWholeTemplate@UImplicitTag@@@@QEAAXXZ" + // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$ImportWholeTemplate@UImplicitTag@@@@QEAAXXZ" // GNU-DAG: define linkonce_odr dso_local void @_ZN19ImportWholeTemplateI11ImplicitTagE14excludedMethodEv ImportWholeTemplate<ImplicitTag>().excludedNoinlineMethod(); - // MSC-DAG: declare dllimport void @"?excludedNoinlineMethod@?$ImportWholeTemplate@UImplicitTag@@@@QEAAXXZ" - // GNU-DAG: declare dllimport void @_ZN19ImportWholeTemplateI11ImplicitTagE22excludedNoinlineMethodEv + // MSC-DAG: define linkonce_odr dso_local void @"?excludedNoinlineMethod@?$ImportWholeTemplate@UImplicitTag@@@@QEAAXXZ" + // GNU-DAG: define linkonce_odr dso_local void @_ZN19ImportWholeTemplateI11ImplicitTagE22excludedNoinlineMethodEv } template <class T> >From ed72a85381f0583d5c5d63228944ee55f1f85c06 Mon Sep 17 00:00:00 2001 From: kikairoya <[email protected]> Date: Thu, 5 Mar 2026 23:27:41 +0900 Subject: [PATCH 6/6] omit redundant noinline checks --- ...xplicit_instantiation.exclude_from_dllexport.cpp | 13 ------------- ...xplicit_instantiation.exclude_from_dllimport.cpp | 13 ------------- 2 files changed, 26 deletions(-) diff --git a/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp index aa4165af975fe..f041e587f5ace 100644 --- a/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp +++ b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp @@ -80,14 +80,9 @@ template <class T> struct __declspec(dllexport) ExportWholeTemplate { void noAttrMethod() {} EXCLUDE_ATTR void excludedMethod() {} - EXCLUDE_ATTR void excludedNoinlineMethod(); EXCLUDE_ATTR void notToBeInstantiated() {} }; -// MSVC and MinGW disagree on whether an inline method of a class-level exported -// template should be exported. -template <typename T> void ExportWholeTemplate<T>::excludedNoinlineMethod() {} - template struct ExportWholeTemplate<NoAttrTag>; // MSC-DAG: define weak_odr dso_local dllexport void @"?noAttrMethod@?$ExportWholeTemplate@UNoAttrTag@@@@QEAAXXZ" // GNU-DAG: define weak_odr dso_local dllexport void @_ZN19ExportWholeTemplateI9NoAttrTagE12noAttrMethodEv @@ -97,17 +92,9 @@ void useExportWholeTemplate() { // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$ExportWholeTemplate@UNoAttrTag@@@@QEAAXXZ" // GNU-DAG: define linkonce_odr dso_local void @_ZN19ExportWholeTemplateI9NoAttrTagE14excludedMethodEv - ExportWholeTemplate<NoAttrTag>().excludedNoinlineMethod(); - // MSC-DAG: define linkonce_odr dso_local void @"?excludedNoinlineMethod@?$ExportWholeTemplate@UNoAttrTag@@@@QEAAXXZ" - // GNU-DAG: define linkonce_odr dso_local void @_ZN19ExportWholeTemplateI9NoAttrTagE22excludedNoinlineMethodEv - ExportWholeTemplate<ImplicitTag>().excludedMethod(); // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$ExportWholeTemplate@UImplicitTag@@@@QEAAXXZ" // GNU-DAG: define linkonce_odr dso_local void @_ZN19ExportWholeTemplateI11ImplicitTagE14excludedMethodEv - - ExportWholeTemplate<ImplicitTag>().excludedNoinlineMethod(); - // MSC-DAG: define linkonce_odr dso_local void @"?excludedNoinlineMethod@?$ExportWholeTemplate@UImplicitTag@@@@QEAAXXZ" - // GNU-DAG: define linkonce_odr dso_local void @_ZN19ExportWholeTemplateI11ImplicitTagE22excludedNoinlineMethodEv } // Interaction with VTables. diff --git a/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp index 2bd64046d905e..d445d0252d905 100644 --- a/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp +++ b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp @@ -84,15 +84,10 @@ template <class T> struct __declspec(dllimport) ImportWholeTemplate { void noAttrMethod() {} EXCLUDE_ATTR void excludedMethod() {} - EXCLUDE_ATTR void excludedNoinlineMethod(); EXCLUDE_ATTR void notToBeInstantiated() {} void notToBeInstantiated_noAttr() {} }; -// MSVC and MinGW disagree on whether an inline method of a class-level imported -// template should be imported. -template <typename T> void ImportWholeTemplate<T>::excludedNoinlineMethod() {} - extern template struct ImportWholeTemplate<NoAttrTag>; void useImportWholeTemplate() { @@ -100,17 +95,9 @@ void useImportWholeTemplate() { // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$ImportWholeTemplate@UNoAttrTag@@@@QEAAXXZ" // GNU-DAG: define linkonce_odr dso_local void @_ZN19ImportWholeTemplateI9NoAttrTagE14excludedMethodEv - ImportWholeTemplate<NoAttrTag>().excludedNoinlineMethod(); - // MSC-DAG: define linkonce_odr dso_local void @"?excludedNoinlineMethod@?$ImportWholeTemplate@UNoAttrTag@@@@QEAAXXZ" - // GNU-DAG: define linkonce_odr dso_local void @_ZN19ImportWholeTemplateI9NoAttrTagE22excludedNoinlineMethodEv - ImportWholeTemplate<ImplicitTag>().excludedMethod(); // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$ImportWholeTemplate@UImplicitTag@@@@QEAAXXZ" // GNU-DAG: define linkonce_odr dso_local void @_ZN19ImportWholeTemplateI11ImplicitTagE14excludedMethodEv - - ImportWholeTemplate<ImplicitTag>().excludedNoinlineMethod(); - // MSC-DAG: define linkonce_odr dso_local void @"?excludedNoinlineMethod@?$ImportWholeTemplate@UImplicitTag@@@@QEAAXXZ" - // GNU-DAG: define linkonce_odr dso_local void @_ZN19ImportWholeTemplateI11ImplicitTagE22excludedNoinlineMethodEv } template <class T> _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
