Author: Tomohiro Kashiwada Date: 2026-03-06T11:45:14+01:00 New Revision: 9ce9e4e6c19bed1781db2c20fae7f24c905438e9
URL: https://github.com/llvm/llvm-project/commit/9ce9e4e6c19bed1781db2c20fae7f24c905438e9 DIFF: https://github.com/llvm/llvm-project/commit/9ce9e4e6c19bed1781db2c20fae7f24c905438e9.diff LOG: [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (#168171) 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. Fixes #40363 Fixes #66909 Added: clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp Modified: clang/lib/Sema/SemaDeclCXX.cpp Removed: ################################################################################ diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 68f27dce84fe3..2ae6e5de0e3ee 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -6605,6 +6605,10 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { // seem to be true in practice? for (Decl *Member : Class->decls()) { + if (isTemplateInstantiation(TSK) && + Member->hasAttr<ExcludeFromExplicitInstantiationAttr>()) + continue; + VarDecl *VD = dyn_cast<VarDecl>(Member); CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member); @@ -19176,8 +19180,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_dllexport.cpp b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp new file mode 100644 index 0000000000000..f041e587f5ace --- /dev/null +++ b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp @@ -0,0 +1,169 @@ +// 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-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-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. + +#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 + +/// 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 linkonce_odr dso_local void @"?excludedMethod@?$BasicCase@UWithExportTag@@@@QEAAXXZ" + // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI13WithExportTagE14excludedMethodEv + + BasicCase<WithExportTag>().excludedExportedMethod(); + // 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" + // 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 notToBeInstantiated() {} +}; + +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 + +void useExportWholeTemplate() { + ExportWholeTemplate<NoAttrTag>().excludedMethod(); + // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$ExportWholeTemplate@UNoAttrTag@@@@QEAAXXZ" + // GNU-DAG: define linkonce_odr dso_local void @_ZN19ExportWholeTemplateI9NoAttrTagE14excludedMethodEv + + ExportWholeTemplate<ImplicitTag>().excludedMethod(); + // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$ExportWholeTemplate@UImplicitTag@@@@QEAAXXZ" + // GNU-DAG: define linkonce_odr dso_local void @_ZN19ExportWholeTemplateI11ImplicitTagE14excludedMethodEv +} + +// 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 linkonce_odr dso_local void @"?excludedVirtualMethod@?$Polymorphic@UWithExportTag@@@@UEAAXXZ" +// GNU-DAG: define linkonce_odr dso_local void @_ZN11PolymorphicI13WithExportTagE21excludedVirtualMethodEv + +// 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 +// 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..d445d0252d905 --- /dev/null +++ b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp @@ -0,0 +1,193 @@ +// 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-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-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. + +#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: define linkonce_odr dso_local void @"?excludedMethod@?$BasicCase@UWithImportTag@@@@QEAAXXZ" + // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI13WithImportTagE14excludedMethodEv + + BasicCase<WithImportTag>().excludedImportedMethod(); + // 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" + // 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 notToBeInstantiated() {} + void notToBeInstantiated_noAttr() {} +}; + +extern template struct ImportWholeTemplate<NoAttrTag>; + +void useImportWholeTemplate() { + ImportWholeTemplate<NoAttrTag>().excludedMethod(); + // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$ImportWholeTemplate@UNoAttrTag@@@@QEAAXXZ" + // GNU-DAG: define linkonce_odr dso_local void @_ZN19ImportWholeTemplateI9NoAttrTagE14excludedMethodEv + + ImportWholeTemplate<ImplicitTag>().excludedMethod(); + // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$ImportWholeTemplate@UImplicitTag@@@@QEAAXXZ" + // GNU-DAG: define linkonce_odr dso_local void @_ZN19ImportWholeTemplateI11ImplicitTagE14excludedMethodEv +} + +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>(); + // MSC-DAG: @"??_S?$Polymorphic@UWithImportTag@@@@6B@" = unnamed_addr + // GNU-DAG: @_ZTV11PolymorphicI13WithImportTagE = external dllimport unnamed_addr + + // MSC-DAG: declare dllimport void @"?noAttrVirtualMethod@?$Polymorphic@UWithImportTag@@@@UEAAXXZ" + // NEGATIVE-GNU-NOT: @_ZN11PolymorphicI13WithImportTagE19noAttrVirtualMethodEv + + // MSC-DAG: define linkonce_odr dso_local void @"?excludedVirtualMethod@?$Polymorphic@UWithImportTag@@@@UEAAXXZ" + // NEGATIVE-GNU-NOT: @_ZN11PolymorphicI13WithImportTagE21excludedVirtualMethodEv + + // MSC-DAG: define linkonce_odr dso_local void @"?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: define linkonce_odr dso_local void @"?excludedVirtualMethod@?$Polymorphic@UNoAttrTag@@@@UEAAXXZ" + // NEGATIVE-GNU-NOT: @_ZN11PolymorphicI9NoAttrTagE21excludedVirtualMethodEv + + // MSC-DAG: define linkonce_odr 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 +} + _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
