[clang] 9ce9e4e - [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (#168171)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Mar 6 02:45:20 PST 2026
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 at 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 at 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 at UWithExportTag@@@@QEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI13WithExportTagE14excludedMethodEv
+
+ BasicCase<WithExportTag>().excludedExportedMethod();
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedExportedMethod@?$BasicCase at UWithExportTag@@@@QEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI13WithExportTagE22excludedExportedMethodEv
+
+ BasicCase<NoAttrTag>().excludedMethod();
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$BasicCase at UNoAttrTag@@@@QEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI9NoAttrTagE14excludedMethodEv
+
+ BasicCase<NoAttrTag>().excludedExportedMethod();
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedExportedMethod@?$BasicCase at UNoAttrTag@@@@QEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI9NoAttrTagE22excludedExportedMethodEv
+
+ BasicCase<ImplicitTag>().excludedMethod();
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$BasicCase at UImplicitTag@@@@QEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI11ImplicitTagE14excludedMethodEv
+
+ BasicCase<ImplicitTag>().excludedExportedMethod();
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedExportedMethod@?$BasicCase at 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 at 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 at UNoAttrTag@@@@QEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN19ExportWholeTemplateI9NoAttrTagE14excludedMethodEv
+
+ ExportWholeTemplate<ImplicitTag>().excludedMethod();
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$ExportWholeTemplate at 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 at 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 at UWithExportTag@@@@UEAAXXZ"
+// GNU-DAG: define weak_odr dso_local dllexport void @_ZN11PolymorphicI13WithExportTagE19noAttrVirtualMethodEv
+
+// MSC-DAG: define linkonce_odr dso_local void @"?excludedVirtualMethod@?$Polymorphic at UWithExportTag@@@@UEAAXXZ"
+// GNU-DAG: define linkonce_odr dso_local void @_ZN11PolymorphicI13WithExportTagE21excludedVirtualMethodEv
+
+// MSC-DAG: define linkonce_odr dso_local void @"?excludedExportedVirtualMethod@?$Polymorphic at UWithExportTag@@@@UEAAXXZ"
+// GNU-DAG: define linkonce_odr dso_local void @_ZN11PolymorphicI13WithExportTagE29excludedExportedVirtualMethodEv
+
+template struct Polymorphic<NoAttrTag>;
+// MSC-DAG: @"??_7?$Polymorphic at UNoAttrTag@@@@6B@" = unnamed_addr
+// GNU-DAG: @_ZTV11PolymorphicI9NoAttrTagE = weak_odr dso_local unnamed_addr
+
+// MSC-DAG: define weak_odr dso_local void @"?noAttrVirtualMethod@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ"
+// GNU-DAG: define weak_odr dso_local void @_ZN11PolymorphicI9NoAttrTagE19noAttrVirtualMethodEv
+
+// MSC-DAG: define linkonce_odr dso_local void @"?excludedVirtualMethod@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ"
+// GNU-DAG: define linkonce_odr dso_local void @_ZN11PolymorphicI9NoAttrTagE21excludedVirtualMethodEv
+
+// MSC-DAG: define linkonce_odr dso_local void @"?excludedExportedVirtualMethod@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ"
+// GNU-DAG: define linkonce_odr dso_local void @_ZN11PolymorphicI9NoAttrTagE29excludedExportedVirtualMethodEv
+
+void usePolymorphic() {
+ new Polymorphic<ImplicitTag>();
+ // MSC-DAG: @"??_7?$Polymorphic at UImplicitTag@@@@6B@" = unnamed_addr
+ // GNU-DAG: @_ZTV11PolymorphicI11ImplicitTagE = linkonce_odr dso_local unnamed_addr
+
+ // MSC-DAG: define linkonce_odr dso_local void @"?noAttrVirtualMethod@?$Polymorphic at UImplicitTag@@@@UEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN11PolymorphicI11ImplicitTagE19noAttrVirtualMethodEv
+
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedVirtualMethod@?$Polymorphic at UImplicitTag@@@@UEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN11PolymorphicI11ImplicitTagE21excludedVirtualMethodEv
+
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedExportedVirtualMethod@?$Polymorphic at 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 at 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 at 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 at UWithImportTag@@@@QEAAXXZ"
+ // GNU-DAG: declare dllimport void @_ZN9BasicCaseI13WithImportTagE12noAttrMethodEv
+
+ BasicCase<WithImportTag>().excludedMethod();
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$BasicCase at UWithImportTag@@@@QEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI13WithImportTagE14excludedMethodEv
+
+ BasicCase<WithImportTag>().excludedImportedMethod();
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedImportedMethod@?$BasicCase at UWithImportTag@@@@QEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI13WithImportTagE22excludedImportedMethodEv
+
+ BasicCase<NoAttrTag>().noAttrMethod();
+ // MSC-DAG: declare dso_local void @"?noAttrMethod@?$BasicCase at UNoAttrTag@@@@QEAAXXZ"
+ // GNU-DAG: declare dso_local void @_ZN9BasicCaseI9NoAttrTagE12noAttrMethodEv
+
+ BasicCase<NoAttrTag>().excludedMethod();
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$BasicCase at UNoAttrTag@@@@QEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI9NoAttrTagE14excludedMethodEv
+
+ BasicCase<NoAttrTag>().excludedImportedMethod();
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedImportedMethod@?$BasicCase at UNoAttrTag@@@@QEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI9NoAttrTagE22excludedImportedMethodEv
+
+ BasicCase<ImplicitTag>().noAttrMethod();
+ // MSC-DAG: define linkonce_odr dso_local void @"?noAttrMethod@?$BasicCase at UImplicitTag@@@@QEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI11ImplicitTagE12noAttrMethodEv
+
+ BasicCase<ImplicitTag>().excludedMethod();
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$BasicCase at UImplicitTag@@@@QEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN9BasicCaseI11ImplicitTagE14excludedMethodEv
+
+ BasicCase<ImplicitTag>().excludedImportedMethod();
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedImportedMethod@?$BasicCase at 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 at UNoAttrTag@@@@QEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN19ImportWholeTemplateI9NoAttrTagE14excludedMethodEv
+
+ ImportWholeTemplate<ImplicitTag>().excludedMethod();
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedMethod@?$ImportWholeTemplate at 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 at UWithImportTag@@@@6B@" = unnamed_addr
+ // GNU-DAG: @_ZTV11PolymorphicI13WithImportTagE = external dllimport unnamed_addr
+
+ // MSC-DAG: declare dllimport void @"?noAttrVirtualMethod@?$Polymorphic at UWithImportTag@@@@UEAAXXZ"
+ // NEGATIVE-GNU-NOT: @_ZN11PolymorphicI13WithImportTagE19noAttrVirtualMethodEv
+
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedVirtualMethod@?$Polymorphic at UWithImportTag@@@@UEAAXXZ"
+ // NEGATIVE-GNU-NOT: @_ZN11PolymorphicI13WithImportTagE21excludedVirtualMethodEv
+
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedImportedVirtualMethod@?$Polymorphic at UWithImportTag@@@@UEAAXXZ"
+ // NEGATIVE-GNU-NOT: @_ZN11PolymorphicI13WithImportTagE29excludedImportedVirtualMethodEv
+
+ new Polymorphic<NoAttrTag>();
+ // MSC-DAG: @"??_7?$Polymorphic at UNoAttrTag@@@@6B@" = unnamed_addr
+ // GNU-DAG: @_ZTV11PolymorphicI9NoAttrTagE = external unnamed_addr
+
+ // MSC-DAG: declare dso_local void @"?noAttrVirtualMethod@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ"
+ // NEGATIVE-GNU-NOT: @_ZN11PolymorphicI9NoAttrTagE19noAttrVirtualMethodEv
+
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedVirtualMethod@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ"
+ // NEGATIVE-GNU-NOT: @_ZN11PolymorphicI9NoAttrTagE21excludedVirtualMethodEv
+
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedImportedVirtualMethod@?$Polymorphic at UNoAttrTag@@@@UEAAXXZ"
+ // NEGATIVE-GNU-NOT: @_ZN11PolymorphicI9NoAttrTagE29excludedImportedVirtualMethodEv
+
+ new Polymorphic<ImplicitTag>();
+ // MSC-DAG: @"??_7?$Polymorphic at UImplicitTag@@@@6B@" = unnamed_addr
+ // GNU-DAG: @_ZTV11PolymorphicI11ImplicitTagE = linkonce_odr dso_local unnamed_addr
+
+ // MSC-DAG: define linkonce_odr dso_local void @"?noAttrVirtualMethod@?$Polymorphic at UImplicitTag@@@@UEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN11PolymorphicI11ImplicitTagE19noAttrVirtualMethodEv
+
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedVirtualMethod@?$Polymorphic at UImplicitTag@@@@UEAAXXZ"
+ // GNU-DAG: define linkonce_odr dso_local void @_ZN11PolymorphicI11ImplicitTagE21excludedVirtualMethodEv
+
+ // MSC-DAG: define linkonce_odr dso_local void @"?excludedImportedVirtualMethod@?$Polymorphic at 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 at NonTemplateClass@@QEAAXXZ"
+ // GNU-DAG: declare dllimport void @_ZN16NonTemplateClass22excludedImportedMethodEv
+
+ NonTemplateImportedClass().excludedMethod();
+ // MSC-DAG: declare dllimport void @"?excludedMethod at NonTemplateImportedClass@@QEAAXXZ"
+ // GNU-DAG: declare dllimport void @_ZN24NonTemplateImportedClass14excludedMethodEv
+}
+
More information about the cfe-commits
mailing list