[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2026-02-07 Thread Tomohiro Kashiwada via cfe-commits


@@ -0,0 +1,181 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-cygwin-emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+
+// Test that __declspec(dllexport) doesn't instantiate entities marked with
+// the exclude_from_explicit_instantiation attribute unless marked as 
dllexport explicitly.
+
+// Silence --implicit-check-not=dllexport.
+// MSC: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// MSC: source_filename = {{.*}}exclude_from_dllexport.cpp
+// GNU: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// GNU: source_filename = {{.*}}exclude_from_dllexport.cpp
+
+#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION 
__attribute__((exclude_from_explicit_instantiation))
+
+template 
+struct C {
+  // This will be instantiated explicitly as an exported function because it
+  // inherits dllexport from the class instantiation.
+  void to_be_exported();
+
+  // This will be instantiated implicitly as an exported function because it is
+  // marked as dllexport explicitly.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) void 
to_be_exported_explicitly();
+
+  // This will be instantiated implicitly but won't be exported.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_exported();
+
+  // This won't be instantiated.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_instantiated();
+};
+
+template  void C::to_be_exported() {}
+template  void C::to_be_exported_explicitly() {}
+template  void C::not_to_be_exported() {}
+template  void C::not_to_be_instantiated() {}

kikairoya wrote:

No, we can't. Clang doesn't export/import inline methods in MinGW mode.

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2026-02-07 Thread Tomohiro Kashiwada via cfe-commits


@@ -0,0 +1,171 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-cygwin-emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+
+// Test that __declspec(dllexport) doesn't instantiate entities marked with
+// the exclude_from_explicit_instantiation attribute unless marked as 
dllexport explicitly.
+
+// MSC: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// MSC: source_filename = {{.*}}exclude_from_dllexport.cpp
+// GNU: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// GNU: source_filename = {{.*}}exclude_from_dllexport.cpp

kikairoya wrote:

I think that using explicitly `-NOT`s needs to repeat them 3 times; nearby the 
explicit instantiation, immediately after the caller function to catch implicit 
instantiations, and the end of the module to catch instantiations via the 
vtable.

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2026-02-07 Thread Tomohiro Kashiwada via cfe-commits


@@ -0,0 +1,181 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-cygwin-emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+
+// Test that __declspec(dllexport) doesn't instantiate entities marked with
+// the exclude_from_explicit_instantiation attribute unless marked as 
dllexport explicitly.
+
+// Silence --implicit-check-not=dllexport.
+// MSC: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// MSC: source_filename = {{.*}}exclude_from_dllexport.cpp
+// GNU: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// GNU: source_filename = {{.*}}exclude_from_dllexport.cpp
+
+#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION 
__attribute__((exclude_from_explicit_instantiation))

kikairoya wrote:

It's just copied from 
`attr-exclude_from_explicit_instantiation.dont_assume_extern_instantiation.cpp`.
 I'll shorten the name.

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2026-02-07 Thread Tomohiro Kashiwada via cfe-commits


@@ -0,0 +1,181 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-cygwin-emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+
+// Test that __declspec(dllexport) doesn't instantiate entities marked with
+// the exclude_from_explicit_instantiation attribute unless marked as 
dllexport explicitly.
+
+// Silence --implicit-check-not=dllexport.
+// MSC: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// MSC: source_filename = {{.*}}exclude_from_dllexport.cpp
+// GNU: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// GNU: source_filename = {{.*}}exclude_from_dllexport.cpp
+
+#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION 
__attribute__((exclude_from_explicit_instantiation))
+
+template 
+struct C {
+  // This will be instantiated explicitly as an exported function because it
+  // inherits dllexport from the class instantiation.
+  void to_be_exported();
+
+  // This will be instantiated implicitly as an exported function because it is
+  // marked as dllexport explicitly.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) void 
to_be_exported_explicitly();
+
+  // This will be instantiated implicitly but won't be exported.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_exported();
+
+  // This won't be instantiated.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_instantiated();
+};
+
+template  void C::to_be_exported() {}
+template  void C::to_be_exported_explicitly() {}
+template  void C::not_to_be_exported() {}
+template  void C::not_to_be_instantiated() {}
+
+// Attach the attribute to class template declaration instead of instantiation 
declaration.
+template 
+struct __declspec(dllexport) D {
+  // This will be exported if and only if no explicit instantiations are 
provided.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void 
to_be_exported_iff_no_explicit_instantiation();
+};
+
+template  void D::to_be_exported_iff_no_explicit_instantiation() {}
+
+// Interaction with VTables.
+template 
+struct E {
+  // This will be instanciated by the explicit template instantiation 
definition.
+  virtual void to_be_exported();
+
+  // This will be instantiated by the VTable definition, regardless of
+  // `exclude_from_explicit_instantiation`.
+  // The dllexport attribute won't be inherited.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION virtual void to_be_instantiated();
+
+  // This too, but will be exported by the member attribute.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) virtual void 
to_be_exported_explicitly();
+};
+
+template  void E::to_be_exported() {}
+template  void E::to_be_instantiated() {}
+template  void E::to_be_exported_explicitly() {}
+
+// MSC: $"?to_be_exported@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_exported@?$E@H@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_exported@?$E@I@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_explicitly@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?not_to_be_exported@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_iff_no_explicit_instantiation@?$D@H@@QEAAXXZ" = 
comdat any
+// MSC: $"?to_be_exported_iff_no_explicit_instantiation@?$D@I@@QEAAXXZ" = 
comdat any
+// MSC: $"?to_be_instantiated@?$E@H@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_explicitly@?$E@H@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_instantiated@?$E@I@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_explicitly@?$E@I@@UEAAXXZ" = comdat any
+// GNU: $_ZN1CIiE14to_be_exportedEv = comdat any
+// GNU: $_ZN1EIiE14to_be_exportedEv = comdat any
+// GNU: $_ZN1EIjE14to_be_exportedEv = comdat any
+// GNU: $_ZN1CIiE25to_be_exported_explicitlyEv = comdat any
+// GNU: $_ZN1CIiE18not_to_be_exportedEv = comdat any
+// GNU: $_ZN1DIiE44to_be_exported_iff_no_explicit_instantiationEv = comdat any
+// GNU: $_ZN1DIjE44to_be_exported_iff_no_explicit_instantiationEv = comdat any
+// GNU: $_ZN1EIiE18to_be_instantiatedEv = comdat any
+// GNU: $_ZN1EIiE25to_be_exported_explicitlyEv = comdat any
+// GNU: $_ZN1EIjE18to_be_instantiatedEv = comdat any
+// GNU: $_ZN1EIjE25to_be_exported_explicitlyEv = comdat any
+
+// MSC: @0 = private unnamed_addr constant {{.*}}, comdat($"??_7?$E@H@@6B@")
+// MSC: @1 = private unnamed_addr constant {{.*}}, comdat($"??_7?$E@I@@6B@")
+// MSC: @"??_7?$E@H@@6B@" = dllexport unnamed_addr
+// MSC: @"??_7?$E@I@@6B@" = unnamed_addr
+// GNU: @_ZTV1EIiE = weak_odr dso_local dllexport unnamed_addr constant 
{{.*}}, comdat
+// GNU: @_ZTV1EIjE = weak_odr dso_local unnamed_addr constant {{.*}}, comdat
+
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr 
@"??4?$C@H@@QEAAAEAU0@AEBU0@@Z"
+// MSC: define weak_odr 

[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2026-02-07 Thread Tomohiro Kashiwada via cfe-commits


@@ -0,0 +1,181 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-cygwin-emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport

kikairoya wrote:

They use different mangled names, particularly the constructors and the vtables 
can't be globbed with a simple regex.
Some of the checks can be merged with a common `--check-prefix`.

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2026-02-07 Thread Tomohiro Kashiwada via cfe-commits

https://github.com/kikairoya commented:

I'm sorry for my delay.

Some of the feedback relates to use of `--implicit-check-not`, but I 
think`--implicit-check-not` is necessary to catch unintended imports/exports, 
which is important since this PR fixes the unexpected imports/exports.
Something like `--implicit-check-not-regex="(define|declare).*to_be_"` could 
reduce redundant checks. What do you think about adding such a feature to `lit`?

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2026-02-07 Thread Tomohiro Kashiwada via cfe-commits

https://github.com/kikairoya edited 
https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2026-01-21 Thread Hans Wennborg via cfe-commits


@@ -0,0 +1,181 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-cygwin-emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+
+// Test that __declspec(dllexport) doesn't instantiate entities marked with
+// the exclude_from_explicit_instantiation attribute unless marked as 
dllexport explicitly.
+
+// Silence --implicit-check-not=dllexport.
+// MSC: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// MSC: source_filename = {{.*}}exclude_from_dllexport.cpp
+// GNU: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// GNU: source_filename = {{.*}}exclude_from_dllexport.cpp
+
+#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION 
__attribute__((exclude_from_explicit_instantiation))
+
+template 
+struct C {
+  // This will be instantiated explicitly as an exported function because it
+  // inherits dllexport from the class instantiation.
+  void to_be_exported();
+
+  // This will be instantiated implicitly as an exported function because it is
+  // marked as dllexport explicitly.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) void 
to_be_exported_explicitly();
+
+  // This will be instantiated implicitly but won't be exported.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_exported();
+
+  // This won't be instantiated.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_instantiated();
+};
+
+template  void C::to_be_exported() {}
+template  void C::to_be_exported_explicitly() {}
+template  void C::not_to_be_exported() {}
+template  void C::not_to_be_instantiated() {}
+
+// Attach the attribute to class template declaration instead of instantiation 
declaration.
+template 
+struct __declspec(dllexport) D {
+  // This will be exported if and only if no explicit instantiations are 
provided.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void 
to_be_exported_iff_no_explicit_instantiation();
+};
+
+template  void D::to_be_exported_iff_no_explicit_instantiation() {}
+
+// Interaction with VTables.
+template 
+struct E {
+  // This will be instanciated by the explicit template instantiation 
definition.
+  virtual void to_be_exported();
+
+  // This will be instantiated by the VTable definition, regardless of
+  // `exclude_from_explicit_instantiation`.
+  // The dllexport attribute won't be inherited.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION virtual void to_be_instantiated();
+
+  // This too, but will be exported by the member attribute.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) virtual void 
to_be_exported_explicitly();
+};
+
+template  void E::to_be_exported() {}
+template  void E::to_be_instantiated() {}
+template  void E::to_be_exported_explicitly() {}

zmodem wrote:

Same.

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2026-01-21 Thread Hans Wennborg via cfe-commits


@@ -0,0 +1,181 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-cygwin-emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+
+// Test that __declspec(dllexport) doesn't instantiate entities marked with
+// the exclude_from_explicit_instantiation attribute unless marked as 
dllexport explicitly.
+
+// Silence --implicit-check-not=dllexport.
+// MSC: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// MSC: source_filename = {{.*}}exclude_from_dllexport.cpp
+// GNU: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// GNU: source_filename = {{.*}}exclude_from_dllexport.cpp
+
+#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION 
__attribute__((exclude_from_explicit_instantiation))
+
+template 
+struct C {
+  // This will be instantiated explicitly as an exported function because it
+  // inherits dllexport from the class instantiation.
+  void to_be_exported();
+
+  // This will be instantiated implicitly as an exported function because it is
+  // marked as dllexport explicitly.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) void 
to_be_exported_explicitly();
+
+  // This will be instantiated implicitly but won't be exported.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_exported();
+
+  // This won't be instantiated.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_instantiated();
+};
+
+template  void C::to_be_exported() {}
+template  void C::to_be_exported_explicitly() {}
+template  void C::not_to_be_exported() {}
+template  void C::not_to_be_instantiated() {}

zmodem wrote:

Could we just define them inline to improve readability?

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2026-01-21 Thread Hans Wennborg via cfe-commits


@@ -0,0 +1,181 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-cygwin-emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+
+// Test that __declspec(dllexport) doesn't instantiate entities marked with
+// the exclude_from_explicit_instantiation attribute unless marked as 
dllexport explicitly.
+
+// Silence --implicit-check-not=dllexport.
+// MSC: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// MSC: source_filename = {{.*}}exclude_from_dllexport.cpp
+// GNU: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// GNU: source_filename = {{.*}}exclude_from_dllexport.cpp
+
+#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION 
__attribute__((exclude_from_explicit_instantiation))
+
+template 
+struct C {
+  // This will be instantiated explicitly as an exported function because it
+  // inherits dllexport from the class instantiation.
+  void to_be_exported();
+
+  // This will be instantiated implicitly as an exported function because it is
+  // marked as dllexport explicitly.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) void 
to_be_exported_explicitly();
+
+  // This will be instantiated implicitly but won't be exported.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_exported();
+
+  // This won't be instantiated.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_instantiated();
+};
+
+template  void C::to_be_exported() {}
+template  void C::to_be_exported_explicitly() {}
+template  void C::not_to_be_exported() {}
+template  void C::not_to_be_instantiated() {}
+
+// Attach the attribute to class template declaration instead of instantiation 
declaration.
+template 
+struct __declspec(dllexport) D {
+  // This will be exported if and only if no explicit instantiations are 
provided.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void 
to_be_exported_iff_no_explicit_instantiation();
+};
+
+template  void D::to_be_exported_iff_no_explicit_instantiation() {}
+
+// Interaction with VTables.
+template 
+struct E {
+  // This will be instanciated by the explicit template instantiation 
definition.
+  virtual void to_be_exported();
+
+  // This will be instantiated by the VTable definition, regardless of
+  // `exclude_from_explicit_instantiation`.
+  // The dllexport attribute won't be inherited.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION virtual void to_be_instantiated();
+
+  // This too, but will be exported by the member attribute.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) virtual void 
to_be_exported_explicitly();
+};
+
+template  void E::to_be_exported() {}
+template  void E::to_be_instantiated() {}
+template  void E::to_be_exported_explicitly() {}
+
+// MSC: $"?to_be_exported@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_exported@?$E@H@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_exported@?$E@I@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_explicitly@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?not_to_be_exported@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_iff_no_explicit_instantiation@?$D@H@@QEAAXXZ" = 
comdat any
+// MSC: $"?to_be_exported_iff_no_explicit_instantiation@?$D@I@@QEAAXXZ" = 
comdat any
+// MSC: $"?to_be_instantiated@?$E@H@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_explicitly@?$E@H@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_instantiated@?$E@I@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_explicitly@?$E@I@@UEAAXXZ" = comdat any
+// GNU: $_ZN1CIiE14to_be_exportedEv = comdat any
+// GNU: $_ZN1EIiE14to_be_exportedEv = comdat any
+// GNU: $_ZN1EIjE14to_be_exportedEv = comdat any
+// GNU: $_ZN1CIiE25to_be_exported_explicitlyEv = comdat any
+// GNU: $_ZN1CIiE18not_to_be_exportedEv = comdat any
+// GNU: $_ZN1DIiE44to_be_exported_iff_no_explicit_instantiationEv = comdat any
+// GNU: $_ZN1DIjE44to_be_exported_iff_no_explicit_instantiationEv = comdat any
+// GNU: $_ZN1EIiE18to_be_instantiatedEv = comdat any
+// GNU: $_ZN1EIiE25to_be_exported_explicitlyEv = comdat any
+// GNU: $_ZN1EIjE18to_be_instantiatedEv = comdat any
+// GNU: $_ZN1EIjE25to_be_exported_explicitlyEv = comdat any
+
+// MSC: @0 = private unnamed_addr constant {{.*}}, comdat($"??_7?$E@H@@6B@")
+// MSC: @1 = private unnamed_addr constant {{.*}}, comdat($"??_7?$E@I@@6B@")
+// MSC: @"??_7?$E@H@@6B@" = dllexport unnamed_addr
+// MSC: @"??_7?$E@I@@6B@" = unnamed_addr
+// GNU: @_ZTV1EIiE = weak_odr dso_local dllexport unnamed_addr constant 
{{.*}}, comdat
+// GNU: @_ZTV1EIjE = weak_odr dso_local unnamed_addr constant {{.*}}, comdat
+
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr 
@"??4?$C@H@@QEAAAEAU0@AEBU0@@Z"
+// MSC: define weak_odr 

[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2026-01-21 Thread Hans Wennborg via cfe-commits

https://github.com/zmodem commented:

Thanks! I think the code looks good, but I think we can simplify the tests. 
I've focused on the first file, but the comments apply to both.

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2026-01-21 Thread Hans Wennborg via cfe-commits

https://github.com/zmodem edited 
https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2026-01-21 Thread Hans Wennborg via cfe-commits


@@ -0,0 +1,181 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-cygwin-emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+
+// Test that __declspec(dllexport) doesn't instantiate entities marked with
+// the exclude_from_explicit_instantiation attribute unless marked as 
dllexport explicitly.
+
+// Silence --implicit-check-not=dllexport.
+// MSC: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// MSC: source_filename = {{.*}}exclude_from_dllexport.cpp
+// GNU: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// GNU: source_filename = {{.*}}exclude_from_dllexport.cpp
+
+#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION 
__attribute__((exclude_from_explicit_instantiation))
+
+template 
+struct C {
+  // This will be instantiated explicitly as an exported function because it
+  // inherits dllexport from the class instantiation.
+  void to_be_exported();
+
+  // This will be instantiated implicitly as an exported function because it is
+  // marked as dllexport explicitly.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) void 
to_be_exported_explicitly();
+
+  // This will be instantiated implicitly but won't be exported.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_exported();
+
+  // This won't be instantiated.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_instantiated();
+};
+
+template  void C::to_be_exported() {}
+template  void C::to_be_exported_explicitly() {}
+template  void C::not_to_be_exported() {}
+template  void C::not_to_be_instantiated() {}
+
+// Attach the attribute to class template declaration instead of instantiation 
declaration.
+template 
+struct __declspec(dllexport) D {
+  // This will be exported if and only if no explicit instantiations are 
provided.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void 
to_be_exported_iff_no_explicit_instantiation();
+};
+
+template  void D::to_be_exported_iff_no_explicit_instantiation() {}
+
+// Interaction with VTables.
+template 
+struct E {
+  // This will be instanciated by the explicit template instantiation 
definition.
+  virtual void to_be_exported();
+
+  // This will be instantiated by the VTable definition, regardless of
+  // `exclude_from_explicit_instantiation`.
+  // The dllexport attribute won't be inherited.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION virtual void to_be_instantiated();
+
+  // This too, but will be exported by the member attribute.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) virtual void 
to_be_exported_explicitly();
+};
+
+template  void E::to_be_exported() {}
+template  void E::to_be_instantiated() {}
+template  void E::to_be_exported_explicitly() {}
+
+// MSC: $"?to_be_exported@?$C@H@@QEAAXXZ" = comdat any

zmodem wrote:

There are a lot of checks here, and I'm not sure all of them are interesting. I 
think we should check just the function definitions.

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2026-01-21 Thread Hans Wennborg via cfe-commits


@@ -0,0 +1,181 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-cygwin-emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+
+// Test that __declspec(dllexport) doesn't instantiate entities marked with
+// the exclude_from_explicit_instantiation attribute unless marked as 
dllexport explicitly.
+
+// Silence --implicit-check-not=dllexport.
+// MSC: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// MSC: source_filename = {{.*}}exclude_from_dllexport.cpp
+// GNU: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// GNU: source_filename = {{.*}}exclude_from_dllexport.cpp
+
+#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION 
__attribute__((exclude_from_explicit_instantiation))
+
+template 
+struct C {
+  // This will be instantiated explicitly as an exported function because it
+  // inherits dllexport from the class instantiation.
+  void to_be_exported();
+
+  // This will be instantiated implicitly as an exported function because it is
+  // marked as dllexport explicitly.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) void 
to_be_exported_explicitly();
+
+  // This will be instantiated implicitly but won't be exported.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_exported();
+
+  // This won't be instantiated.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_instantiated();
+};
+
+template  void C::to_be_exported() {}
+template  void C::to_be_exported_explicitly() {}
+template  void C::not_to_be_exported() {}
+template  void C::not_to_be_instantiated() {}
+
+// Attach the attribute to class template declaration instead of instantiation 
declaration.
+template 
+struct __declspec(dllexport) D {
+  // This will be exported if and only if no explicit instantiations are 
provided.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void 
to_be_exported_iff_no_explicit_instantiation();
+};
+
+template  void D::to_be_exported_iff_no_explicit_instantiation() {}
+
+// Interaction with VTables.
+template 
+struct E {
+  // This will be instanciated by the explicit template instantiation 
definition.
+  virtual void to_be_exported();
+
+  // This will be instantiated by the VTable definition, regardless of
+  // `exclude_from_explicit_instantiation`.
+  // The dllexport attribute won't be inherited.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION virtual void to_be_instantiated();
+
+  // This too, but will be exported by the member attribute.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) virtual void 
to_be_exported_explicitly();
+};
+
+template  void E::to_be_exported() {}
+template  void E::to_be_instantiated() {}
+template  void E::to_be_exported_explicitly() {}
+
+// MSC: $"?to_be_exported@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_exported@?$E@H@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_exported@?$E@I@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_explicitly@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?not_to_be_exported@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_iff_no_explicit_instantiation@?$D@H@@QEAAXXZ" = 
comdat any
+// MSC: $"?to_be_exported_iff_no_explicit_instantiation@?$D@I@@QEAAXXZ" = 
comdat any
+// MSC: $"?to_be_instantiated@?$E@H@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_explicitly@?$E@H@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_instantiated@?$E@I@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_explicitly@?$E@I@@UEAAXXZ" = comdat any
+// GNU: $_ZN1CIiE14to_be_exportedEv = comdat any
+// GNU: $_ZN1EIiE14to_be_exportedEv = comdat any
+// GNU: $_ZN1EIjE14to_be_exportedEv = comdat any
+// GNU: $_ZN1CIiE25to_be_exported_explicitlyEv = comdat any
+// GNU: $_ZN1CIiE18not_to_be_exportedEv = comdat any
+// GNU: $_ZN1DIiE44to_be_exported_iff_no_explicit_instantiationEv = comdat any
+// GNU: $_ZN1DIjE44to_be_exported_iff_no_explicit_instantiationEv = comdat any
+// GNU: $_ZN1EIiE18to_be_instantiatedEv = comdat any
+// GNU: $_ZN1EIiE25to_be_exported_explicitlyEv = comdat any
+// GNU: $_ZN1EIjE18to_be_instantiatedEv = comdat any
+// GNU: $_ZN1EIjE25to_be_exported_explicitlyEv = comdat any
+
+// MSC: @0 = private unnamed_addr constant {{.*}}, comdat($"??_7?$E@H@@6B@")
+// MSC: @1 = private unnamed_addr constant {{.*}}, comdat($"??_7?$E@I@@6B@")
+// MSC: @"??_7?$E@H@@6B@" = dllexport unnamed_addr
+// MSC: @"??_7?$E@I@@6B@" = unnamed_addr
+// GNU: @_ZTV1EIiE = weak_odr dso_local dllexport unnamed_addr constant 
{{.*}}, comdat
+// GNU: @_ZTV1EIjE = weak_odr dso_local unnamed_addr constant {{.*}}, comdat
+
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr 
@"??4?$C@H@@QEAAAEAU0@AEBU0@@Z"
+// MSC: define weak_odr 

[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2026-01-21 Thread Hans Wennborg via cfe-commits


@@ -0,0 +1,181 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-cygwin-emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+
+// Test that __declspec(dllexport) doesn't instantiate entities marked with
+// the exclude_from_explicit_instantiation attribute unless marked as 
dllexport explicitly.
+
+// Silence --implicit-check-not=dllexport.
+// MSC: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// MSC: source_filename = {{.*}}exclude_from_dllexport.cpp
+// GNU: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// GNU: source_filename = {{.*}}exclude_from_dllexport.cpp
+
+#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION 
__attribute__((exclude_from_explicit_instantiation))
+
+template 
+struct C {
+  // This will be instantiated explicitly as an exported function because it
+  // inherits dllexport from the class instantiation.
+  void to_be_exported();
+
+  // This will be instantiated implicitly as an exported function because it is
+  // marked as dllexport explicitly.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) void 
to_be_exported_explicitly();
+
+  // This will be instantiated implicitly but won't be exported.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_exported();
+
+  // This won't be instantiated.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_instantiated();
+};
+
+template  void C::to_be_exported() {}
+template  void C::to_be_exported_explicitly() {}
+template  void C::not_to_be_exported() {}
+template  void C::not_to_be_instantiated() {}
+
+// Attach the attribute to class template declaration instead of instantiation 
declaration.
+template 
+struct __declspec(dllexport) D {
+  // This will be exported if and only if no explicit instantiations are 
provided.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void 
to_be_exported_iff_no_explicit_instantiation();
+};
+
+template  void D::to_be_exported_iff_no_explicit_instantiation() {}
+
+// Interaction with VTables.
+template 
+struct E {
+  // This will be instanciated by the explicit template instantiation 
definition.
+  virtual void to_be_exported();
+
+  // This will be instantiated by the VTable definition, regardless of
+  // `exclude_from_explicit_instantiation`.
+  // The dllexport attribute won't be inherited.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION virtual void to_be_instantiated();
+
+  // This too, but will be exported by the member attribute.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) virtual void 
to_be_exported_explicitly();
+};
+
+template  void E::to_be_exported() {}
+template  void E::to_be_instantiated() {}
+template  void E::to_be_exported_explicitly() {}
+
+// MSC: $"?to_be_exported@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_exported@?$E@H@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_exported@?$E@I@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_explicitly@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?not_to_be_exported@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_iff_no_explicit_instantiation@?$D@H@@QEAAXXZ" = 
comdat any
+// MSC: $"?to_be_exported_iff_no_explicit_instantiation@?$D@I@@QEAAXXZ" = 
comdat any
+// MSC: $"?to_be_instantiated@?$E@H@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_explicitly@?$E@H@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_instantiated@?$E@I@@UEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_explicitly@?$E@I@@UEAAXXZ" = comdat any
+// GNU: $_ZN1CIiE14to_be_exportedEv = comdat any
+// GNU: $_ZN1EIiE14to_be_exportedEv = comdat any
+// GNU: $_ZN1EIjE14to_be_exportedEv = comdat any
+// GNU: $_ZN1CIiE25to_be_exported_explicitlyEv = comdat any
+// GNU: $_ZN1CIiE18not_to_be_exportedEv = comdat any
+// GNU: $_ZN1DIiE44to_be_exported_iff_no_explicit_instantiationEv = comdat any
+// GNU: $_ZN1DIjE44to_be_exported_iff_no_explicit_instantiationEv = comdat any
+// GNU: $_ZN1EIiE18to_be_instantiatedEv = comdat any
+// GNU: $_ZN1EIiE25to_be_exported_explicitlyEv = comdat any
+// GNU: $_ZN1EIjE18to_be_instantiatedEv = comdat any
+// GNU: $_ZN1EIjE25to_be_exported_explicitlyEv = comdat any
+
+// MSC: @0 = private unnamed_addr constant {{.*}}, comdat($"??_7?$E@H@@6B@")
+// MSC: @1 = private unnamed_addr constant {{.*}}, comdat($"??_7?$E@I@@6B@")
+// MSC: @"??_7?$E@H@@6B@" = dllexport unnamed_addr
+// MSC: @"??_7?$E@I@@6B@" = unnamed_addr
+// GNU: @_ZTV1EIiE = weak_odr dso_local dllexport unnamed_addr constant 
{{.*}}, comdat
+// GNU: @_ZTV1EIjE = weak_odr dso_local unnamed_addr constant {{.*}}, comdat
+
+// MSC: define weak_odr dso_local dllexport{{.*}} ptr 
@"??4?$C@H@@QEAAAEAU0@AEBU0@@Z"
+// MSC: define weak_odr 

[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2026-01-21 Thread Hans Wennborg via cfe-commits


@@ -0,0 +1,181 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-cygwin-emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+
+// Test that __declspec(dllexport) doesn't instantiate entities marked with
+// the exclude_from_explicit_instantiation attribute unless marked as 
dllexport explicitly.
+
+// Silence --implicit-check-not=dllexport.
+// MSC: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// MSC: source_filename = {{.*}}exclude_from_dllexport.cpp
+// GNU: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// GNU: source_filename = {{.*}}exclude_from_dllexport.cpp
+
+#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION 
__attribute__((exclude_from_explicit_instantiation))
+
+template 
+struct C {
+  // This will be instantiated explicitly as an exported function because it
+  // inherits dllexport from the class instantiation.
+  void to_be_exported();
+
+  // This will be instantiated implicitly as an exported function because it is
+  // marked as dllexport explicitly.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) void 
to_be_exported_explicitly();
+
+  // This will be instantiated implicitly but won't be exported.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_exported();
+
+  // This won't be instantiated.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_instantiated();
+};
+
+template  void C::to_be_exported() {}
+template  void C::to_be_exported_explicitly() {}
+template  void C::not_to_be_exported() {}
+template  void C::not_to_be_instantiated() {}
+
+// Attach the attribute to class template declaration instead of instantiation 
declaration.
+template 
+struct __declspec(dllexport) D {
+  // This will be exported if and only if no explicit instantiations are 
provided.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void 
to_be_exported_iff_no_explicit_instantiation();
+};
+
+template  void D::to_be_exported_iff_no_explicit_instantiation() {}

zmodem wrote:

Same as above, can it be defined inline instead?

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2026-01-21 Thread Hans Wennborg via cfe-commits


@@ -0,0 +1,181 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-cygwin-emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport

zmodem wrote:

I don't see any difference in terms of dllexport between the MSC and GNU checks 
in the test, so maybe just use the MSC ones to make it simpler?

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2026-01-21 Thread Hans Wennborg via cfe-commits


@@ -0,0 +1,171 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-cygwin-emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+
+// Test that __declspec(dllexport) doesn't instantiate entities marked with
+// the exclude_from_explicit_instantiation attribute unless marked as 
dllexport explicitly.
+
+// MSC: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// MSC: source_filename = {{.*}}exclude_from_dllexport.cpp
+// GNU: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// GNU: source_filename = {{.*}}exclude_from_dllexport.cpp

zmodem wrote:

I still think the test might be more readable if we used explicit checks and 
check-nots for everything.

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2026-01-21 Thread Hans Wennborg via cfe-commits


@@ -0,0 +1,181 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-cygwin-emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+
+// Test that __declspec(dllexport) doesn't instantiate entities marked with
+// the exclude_from_explicit_instantiation attribute unless marked as 
dllexport explicitly.
+
+// Silence --implicit-check-not=dllexport.
+// MSC: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// MSC: source_filename = {{.*}}exclude_from_dllexport.cpp
+// GNU: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// GNU: source_filename = {{.*}}exclude_from_dllexport.cpp
+
+#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION 
__attribute__((exclude_from_explicit_instantiation))

zmodem wrote:

(nit: Since you're using a macro to get a shorter name anyway, I'd consider 
making it even shorter, like `EXCLUDE_ATTR`)

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2026-01-21 Thread Tomohiro Kashiwada via cfe-commits


@@ -19109,7 +19119,17 @@ bool Sema::DefineUsedVTables() {
 }
   }
 
-  if (IsExplicitInstantiationDeclaration)
+  if (IsExplicitInstantiationDeclaration &&
+  llvm::none_of(Class->decls(), [](Decl *decl) {
+// If the class has a virtual member function declared with
+// `__attribute__((exclude_from_explicit_instantiation))`, the
+// explicit instantiation declaration shouldn't suppress emitting
+// the vtable to ensure that the excluded member function is
+// accessible through the vtable.
+auto *Method = dyn_cast(decl);
+return Method && Method->isVirtual() &&
+   Method->hasAttr();
+  }))

kikairoya wrote:

I think I understand now -- I was thinking only about explicit instantiation 
_declarations_, but I should also consider the interaction with explicit 
instantiation _definitions_.
Thank you for your detailed and patient guidance.

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2026-01-21 Thread Tomohiro Kashiwada via cfe-commits

https://github.com/kikairoya updated 
https://github.com/llvm/llvm-project/pull/168171

>From 3234c2685a86561a3df695f6a8e4b6c55c1a7f5c Mon Sep 17 00:00:00 2001
From: kikairoya 
Date: Sat, 15 Nov 2025 11:25:23 +0900
Subject: [PATCH 01/16] pretest

---
 ...t_instantiation.exclude_from_dllexport.cpp | 64 +++
 ...t_instantiation.exclude_from_dllimport.cpp | 50 +++
 2 files changed, 114 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 0..6b1bd83f6d69b
--- /dev/null
+++ 
b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-cygwin-emit-llvm -o - %s | 
FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_
+
+// Test that __declspec(dllexport) doesn't instantiate entities marked with
+// the exclude_from_explicit_instantiation attribute unless marked as 
dllexport explicitly.
+
+#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION 
__attribute__((exclude_from_explicit_instantiation))
+
+template 
+struct C {
+  // This will be instantiated explicitly as an exported function because it
+  // inherits dllexport from the class instantiation.
+  void to_be_exported() noexcept;
+
+  // This will be instantiated implicitly as an exported function because it is
+  // marked as dllexport explicitly.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) void 
to_be_exported_explicitly() noexcept;
+
+  // This will be instantiated implicitly as an exported function 
unintentionally.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_exported() noexcept;
+
+  // This won't be instantiated.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_instantiated() noexcept;
+};
+
+template  void C::to_be_exported() noexcept {}
+template  void C::to_be_exported_explicitly() noexcept {}
+template  void C::not_to_be_exported() noexcept {}
+template  void C::not_to_be_instantiated() noexcept {}
+
+// MSC: $"?to_be_exported@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_explicitly@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?not_to_be_exported@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?not_to_be_instantiated@?$C@H@@QEAAXXZ" = comdat any
+// GNU: $_ZN1CIiE14to_be_exportedEv = comdat any
+// GNU: $_ZN1CIiE25to_be_exported_explicitlyEv = comdat any
+// GNU: $_ZN1CIiE18not_to_be_exportedEv = comdat any
+// GNU: $_ZN1CIiE22not_to_be_instantiatedEv = comdat any
+
+// MSC: define weak_odr dso_local dllexport{{.*}} void 
@"?to_be_exported@?$C@H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport{{.*}} void 
@_ZN1CIiE14to_be_exportedEv
+template struct __declspec(dllexport) C;
+
+void use() {
+  C c;
+
+  // MSC: call void @"?to_be_exported_explicitly@?$C@H@@QEAAXXZ"
+  // GNU: call void @_ZN1CIiE25to_be_exported_explicitlyEv
+  c.to_be_exported_explicitly(); // implicitly instantiated here
+
+  // MSC: call void @"?not_to_be_exported@?$C@H@@QEAAXXZ"
+  // GNU: call void @_ZN1CIiE18not_to_be_exportedEv
+  c.not_to_be_exported(); // implicitly instantiated here
+};
+
+// MSC: define weak_odr dso_local dllexport{{.*}} void 
@"?to_be_exported_explicitly@?$C@H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport{{.*}} void 
@_ZN1CIiE25to_be_exported_explicitlyEv
+
+// MSC: define weak_odr dso_local dllexport void 
@"?not_to_be_exported@?$C@H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport void 
@_ZN1CIiE18not_to_be_exportedEv
+
+// MSC: define weak_odr dso_local dllexport void 
@"?not_to_be_instantiated@?$C@H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport void 
@_ZN1CIiE22not_to_be_instantiatedEv
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 0..adc420f37bbc6
--- /dev/null
+++ 
b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-cygwin

[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2026-01-20 Thread Tomohiro Kashiwada via cfe-commits


@@ -19109,7 +19119,17 @@ bool Sema::DefineUsedVTables() {
 }
   }
 
-  if (IsExplicitInstantiationDeclaration)
+  if (IsExplicitInstantiationDeclaration &&
+  llvm::none_of(Class->decls(), [](Decl *decl) {
+// If the class has a virtual member function declared with
+// `__attribute__((exclude_from_explicit_instantiation))`, the
+// explicit instantiation declaration shouldn't suppress emitting
+// the vtable to ensure that the excluded member function is
+// accessible through the vtable.
+auto *Method = dyn_cast(decl);
+return Method && Method->isVirtual() &&
+   Method->hasAttr();
+  }))

kikairoya wrote:

> > Are there any cases to emit vtables, other than excluded constructors?
> 
> I'm not sure. I think they're emitted when used, which is typically by the 
> constructor, but maybe there could be other cases.

I found the case. A virtual inheritance triggers to emit sub-tables.
https://godbolt.org/z/GqWKbYYjK

In that case, I feel odd if adding the attribute to `normal_fn` affects the 
vtable generator routine, even if the result is not changed. The assumption 
includes non-virtual functions looks too strong for me.

As this attribute is an extension, so I'd prefer to minimize the areas affected 
by the attribute.

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2026-01-19 Thread Hans Wennborg via cfe-commits


@@ -19109,7 +19119,17 @@ bool Sema::DefineUsedVTables() {
 }
   }
 
-  if (IsExplicitInstantiationDeclaration)
+  if (IsExplicitInstantiationDeclaration &&
+  llvm::none_of(Class->decls(), [](Decl *decl) {
+// If the class has a virtual member function declared with
+// `__attribute__((exclude_from_explicit_instantiation))`, the
+// explicit instantiation declaration shouldn't suppress emitting
+// the vtable to ensure that the excluded member function is
+// accessible through the vtable.
+auto *Method = dyn_cast(decl);
+return Method && Method->isVirtual() &&
+   Method->hasAttr();
+  }))

zmodem wrote:

> Are there any cases to emit vtables, other than excluded constructors?

I'm not sure. I think they're emitted when used, which is typically by the 
constructor, but maybe there could be other cases.

> In other words, if control reaches here (`if 
> (IsExplicitInstantiationDeclaration`) block), can we assume that some of 
> constructors are excluded?

I don't think so. Why would we be able to assume that?

>From what I understand, all that we know at this point is that 1) there's a 
>use of some class's vtable, 2) that class is an explicit instantiation decl.

The previous code assumes the explicit instantiation decl means *no* methods 
are emitted here, but will be emitted elsewhere (with the explicit 
instantiation definition).

With the addition of ExcludeFromExplicitInstantiationAttr, that assumption no 
longer holds true.

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2026-01-19 Thread Hans Wennborg via cfe-commits

https://github.com/zmodem commented:

Sorry, this got lost in the email pile over the holidays.

I'm still confused about the change to `Sema::DefineUsedVTables`. I'd rather we 
just check whether *any* method has `ExcludeFromExplicitInstantiationAttr`.

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2026-01-19 Thread Hans Wennborg via cfe-commits

https://github.com/zmodem edited 
https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2026-01-16 Thread Tomohiro Kashiwada via cfe-commits

kikairoya wrote:

Gentle ping.

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-12-25 Thread Tomohiro Kashiwada via cfe-commits

https://github.com/kikairoya updated 
https://github.com/llvm/llvm-project/pull/168171

>From 3234c2685a86561a3df695f6a8e4b6c55c1a7f5c Mon Sep 17 00:00:00 2001
From: kikairoya 
Date: Sat, 15 Nov 2025 11:25:23 +0900
Subject: [PATCH 01/14] pretest

---
 ...t_instantiation.exclude_from_dllexport.cpp | 64 +++
 ...t_instantiation.exclude_from_dllimport.cpp | 50 +++
 2 files changed, 114 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 0..6b1bd83f6d69b
--- /dev/null
+++ 
b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-cygwin-emit-llvm -o - %s | 
FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_
+
+// Test that __declspec(dllexport) doesn't instantiate entities marked with
+// the exclude_from_explicit_instantiation attribute unless marked as 
dllexport explicitly.
+
+#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION 
__attribute__((exclude_from_explicit_instantiation))
+
+template 
+struct C {
+  // This will be instantiated explicitly as an exported function because it
+  // inherits dllexport from the class instantiation.
+  void to_be_exported() noexcept;
+
+  // This will be instantiated implicitly as an exported function because it is
+  // marked as dllexport explicitly.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) void 
to_be_exported_explicitly() noexcept;
+
+  // This will be instantiated implicitly as an exported function 
unintentionally.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_exported() noexcept;
+
+  // This won't be instantiated.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_instantiated() noexcept;
+};
+
+template  void C::to_be_exported() noexcept {}
+template  void C::to_be_exported_explicitly() noexcept {}
+template  void C::not_to_be_exported() noexcept {}
+template  void C::not_to_be_instantiated() noexcept {}
+
+// MSC: $"?to_be_exported@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_explicitly@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?not_to_be_exported@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?not_to_be_instantiated@?$C@H@@QEAAXXZ" = comdat any
+// GNU: $_ZN1CIiE14to_be_exportedEv = comdat any
+// GNU: $_ZN1CIiE25to_be_exported_explicitlyEv = comdat any
+// GNU: $_ZN1CIiE18not_to_be_exportedEv = comdat any
+// GNU: $_ZN1CIiE22not_to_be_instantiatedEv = comdat any
+
+// MSC: define weak_odr dso_local dllexport{{.*}} void 
@"?to_be_exported@?$C@H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport{{.*}} void 
@_ZN1CIiE14to_be_exportedEv
+template struct __declspec(dllexport) C;
+
+void use() {
+  C c;
+
+  // MSC: call void @"?to_be_exported_explicitly@?$C@H@@QEAAXXZ"
+  // GNU: call void @_ZN1CIiE25to_be_exported_explicitlyEv
+  c.to_be_exported_explicitly(); // implicitly instantiated here
+
+  // MSC: call void @"?not_to_be_exported@?$C@H@@QEAAXXZ"
+  // GNU: call void @_ZN1CIiE18not_to_be_exportedEv
+  c.not_to_be_exported(); // implicitly instantiated here
+};
+
+// MSC: define weak_odr dso_local dllexport{{.*}} void 
@"?to_be_exported_explicitly@?$C@H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport{{.*}} void 
@_ZN1CIiE25to_be_exported_explicitlyEv
+
+// MSC: define weak_odr dso_local dllexport void 
@"?not_to_be_exported@?$C@H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport void 
@_ZN1CIiE18not_to_be_exportedEv
+
+// MSC: define weak_odr dso_local dllexport void 
@"?not_to_be_instantiated@?$C@H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport void 
@_ZN1CIiE22not_to_be_instantiatedEv
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 0..adc420f37bbc6
--- /dev/null
+++ 
b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-cygwin

[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-12-17 Thread Tomohiro Kashiwada via cfe-commits


@@ -19109,7 +19119,17 @@ bool Sema::DefineUsedVTables() {
 }
   }
 
-  if (IsExplicitInstantiationDeclaration)
+  if (IsExplicitInstantiationDeclaration &&
+  llvm::none_of(Class->decls(), [](Decl *decl) {
+// If the class has a virtual member function declared with
+// `__attribute__((exclude_from_explicit_instantiation))`, the
+// explicit instantiation declaration shouldn't suppress emitting
+// the vtable to ensure that the excluded member function is
+// accessible through the vtable.
+auto *Method = dyn_cast(decl);
+return Method && Method->isVirtual() &&
+   Method->hasAttr();
+  }))

kikairoya wrote:

Are there any cases to emit vtables, other than excluded constructors?
In other words, if control reaches here (` if 
(IsExplicitInstantiationDeclaration)` block), can we assume that some of 
constructors are excluded?

- If so, `IsExplicitInstantiationDeclaration && 
!HasExcludeFromExplicitInstantiationAttr` is always `false`; therefore, `if 
(!KeyFunc)` block can be removed.
- Otherwise, the template might not have an excluded constructor; then, 
non-virtual non-ctor members are unrelated to the vtable, therefore, 
`isVirtual` shouldn't be omitted.

Am I missing something else?

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-12-15 Thread Hans Wennborg via cfe-commits


@@ -19109,7 +19119,17 @@ bool Sema::DefineUsedVTables() {
 }
   }
 
-  if (IsExplicitInstantiationDeclaration)
+  if (IsExplicitInstantiationDeclaration &&
+  llvm::none_of(Class->decls(), [](Decl *decl) {
+// If the class has a virtual member function declared with
+// `__attribute__((exclude_from_explicit_instantiation))`, the
+// explicit instantiation declaration shouldn't suppress emitting
+// the vtable to ensure that the excluded member function is
+// accessible through the vtable.
+auto *Method = dyn_cast(decl);
+return Method && Method->isVirtual() &&
+   Method->hasAttr();
+  }))

zmodem wrote:

> Why are non-virtual functions allowed to affect vtables?

When there's no key function, emitting a constructor will trigger emitting the 
vtable, because the constructor needs to set the vptr to point to it.

That's why the reasoning above about "vtable will live with the explicit 
instantiation" won't hold if the constructor is excluded.

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-12-15 Thread Tomohiro Kashiwada via cfe-commits


@@ -19109,7 +19119,17 @@ bool Sema::DefineUsedVTables() {
 }
   }
 
-  if (IsExplicitInstantiationDeclaration)
+  if (IsExplicitInstantiationDeclaration &&
+  llvm::none_of(Class->decls(), [](Decl *decl) {
+// If the class has a virtual member function declared with
+// `__attribute__((exclude_from_explicit_instantiation))`, the
+// explicit instantiation declaration shouldn't suppress emitting
+// the vtable to ensure that the excluded member function is
+// accessible through the vtable.
+auto *Method = dyn_cast(decl);
+return Method && Method->isVirtual() &&
+   Method->hasAttr();
+  }))

kikairoya wrote:

> "vtable will live with the explicit instantiation" doesn't necessarily hold 
> if some methods are excluded from explicit instantiation.

I'm sorry, but I still don't understand. Why are non-virtual functions allowed 
to affect vtables? Is it just an optimization?

In the testcase, the implicitly instantiation of the excluded constructor 
triggers emitting the vtable. If there is no other way to run this block, the 
whole `if (!KeyFunc)` block could be omitted. Otherwise, that means this block 
may run even if no constructors are excluded, so I think that any non-virtual 
members that are not instantiated shouldn't affect code generation.

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-12-15 Thread Hans Wennborg via cfe-commits


@@ -19109,7 +19119,17 @@ bool Sema::DefineUsedVTables() {
 }
   }
 
-  if (IsExplicitInstantiationDeclaration)
+  if (IsExplicitInstantiationDeclaration &&
+  llvm::none_of(Class->decls(), [](Decl *decl) {
+// If the class has a virtual member function declared with
+// `__attribute__((exclude_from_explicit_instantiation))`, the
+// explicit instantiation declaration shouldn't suppress emitting
+// the vtable to ensure that the excluded member function is
+// accessible through the vtable.
+auto *Method = dyn_cast(decl);
+return Method && Method->isVirtual() &&
+   Method->hasAttr();
+  }))

zmodem wrote:

> I don't understand why non-virtual functions matter here.

A constructor method may trigger emitting the vtable. The larger point is that 
the reasoning on lines 19095-190198 about the "vtable will live with the 
explicit instantiation" doesn't necessarily hold if some methods are excluded 
from explicit instantiation.

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-12-13 Thread Tomohiro Kashiwada via cfe-commits


@@ -19109,7 +19119,17 @@ bool Sema::DefineUsedVTables() {
 }
   }
 
-  if (IsExplicitInstantiationDeclaration)
+  if (IsExplicitInstantiationDeclaration &&
+  llvm::none_of(Class->decls(), [](Decl *decl) {
+// If the class has a virtual member function declared with
+// `__attribute__((exclude_from_explicit_instantiation))`, the
+// explicit instantiation declaration shouldn't suppress emitting
+// the vtable to ensure that the excluded member function is
+// accessible through the vtable.
+auto *Method = dyn_cast(decl);
+return Method && Method->isVirtual() &&
+   Method->hasAttr();
+  }))

kikairoya wrote:

> As a style issue, I think it would be easier to read if we put this in a 
> variable

Sure.

> Also, I'm not sure that it matters whether the method with the attribute is 
> virtual or not. I think it would be enough to check that _any_ method has the 
> attribute -- because then the motivation about "suppress the vtable; it will 
> live with the explicit instantiation definition" may not hold.

I don't understand why non-virtual functions matter here. If no virtual methods 
are excluded, then no special handling is needed to enforce emitting the 
definition. The vtable itself is emitted by another procedure anyway (I still 
can't find the procedure, though).

> I wonder if we could break this out into a separate PR as well, since it 
> seems somewhat separate from the other issue.

No, this should be a part of the PR because this is the cause of reverting 
#65961.

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-12-10 Thread Hans Wennborg via cfe-commits


@@ -19109,7 +19119,17 @@ bool Sema::DefineUsedVTables() {
 }
   }
 
-  if (IsExplicitInstantiationDeclaration)
+  if (IsExplicitInstantiationDeclaration &&
+  llvm::none_of(Class->decls(), [](Decl *decl) {
+// If the class has a virtual member function declared with
+// `__attribute__((exclude_from_explicit_instantiation))`, the
+// explicit instantiation declaration shouldn't suppress emitting
+// the vtable to ensure that the excluded member function is
+// accessible through the vtable.
+auto *Method = dyn_cast(decl);
+return Method && Method->isVirtual() &&
+   Method->hasAttr();
+  }))

zmodem wrote:

I wonder if we could break this out into a separate PR as well, since it seems 
somewhat separate from the other issue.

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-12-10 Thread Hans Wennborg via cfe-commits


@@ -0,0 +1,171 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-cygwin-emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+
+// Test that __declspec(dllexport) doesn't instantiate entities marked with
+// the exclude_from_explicit_instantiation attribute unless marked as 
dllexport explicitly.
+
+// MSC: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// MSC: source_filename = {{.*}}exclude_from_dllexport.cpp
+// GNU: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// GNU: source_filename = {{.*}}exclude_from_dllexport.cpp

zmodem wrote:

I think the `--implicit'check-not`'s are a little bit confusing here. I think 
the test may be easier to read with explicit checks, and then you could drop 
these lines.

If not, I think we need some comments explaining the `check-not`'s.

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-12-10 Thread Hans Wennborg via cfe-commits


@@ -19109,7 +19119,17 @@ bool Sema::DefineUsedVTables() {
 }
   }
 
-  if (IsExplicitInstantiationDeclaration)
+  if (IsExplicitInstantiationDeclaration &&
+  llvm::none_of(Class->decls(), [](Decl *decl) {
+// If the class has a virtual member function declared with
+// `__attribute__((exclude_from_explicit_instantiation))`, the
+// explicit instantiation declaration shouldn't suppress emitting
+// the vtable to ensure that the excluded member function is
+// accessible through the vtable.
+auto *Method = dyn_cast(decl);
+return Method && Method->isVirtual() &&
+   Method->hasAttr();
+  }))

zmodem wrote:

As a style issue, I think it would be easier to read if we put this in a 
variable, like:

```
bool HasExcludeFromExplicitInstantiation = llvm::any_of(... 
hasAttr() ...
```

Also, I'm not sure that it matters whether the method with the attribute is 
virtual or not. I think it would be enough to check that *any* method has the 
attribute -- because then the motivation about "suppress the vtable; it will 
live with the explicit instantiation definition" may not hold.

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-12-10 Thread Tomohiro Kashiwada via cfe-commits


@@ -19108,8 +19118,23 @@ bool Sema::DefineUsedVTables() {
 }
   }
 
-  if (IsExplicitInstantiationDeclaration)
+  if (IsExplicitInstantiationDeclaration) {
 DefineVTable = false;
+
+// Ensure the instance of a virtual member function which is declared
+// with `__attribute__((exclude_from_explicit_instantiation))` is
+// accessible from the VTable.
+for (Decl *decl : Class->decls()) {
+  auto *Method = dyn_cast(decl);
+  if (!Method || !Method->isVirtual())
+continue;
+
+  if (Method->hasAttr()) {
+MarkFunctionReferenced(Loc, Method);
+DefinedAnything = true;
+  }
+}

kikairoya wrote:

I've rewritten here without changing behavior.

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-12-10 Thread Tomohiro Kashiwada via cfe-commits

https://github.com/kikairoya updated 
https://github.com/llvm/llvm-project/pull/168171

>From 3234c2685a86561a3df695f6a8e4b6c55c1a7f5c Mon Sep 17 00:00:00 2001
From: kikairoya 
Date: Sat, 15 Nov 2025 11:25:23 +0900
Subject: [PATCH 01/12] pretest

---
 ...t_instantiation.exclude_from_dllexport.cpp | 64 +++
 ...t_instantiation.exclude_from_dllimport.cpp | 50 +++
 2 files changed, 114 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 0..6b1bd83f6d69b
--- /dev/null
+++ 
b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-cygwin-emit-llvm -o - %s | 
FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_
+
+// Test that __declspec(dllexport) doesn't instantiate entities marked with
+// the exclude_from_explicit_instantiation attribute unless marked as 
dllexport explicitly.
+
+#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION 
__attribute__((exclude_from_explicit_instantiation))
+
+template 
+struct C {
+  // This will be instantiated explicitly as an exported function because it
+  // inherits dllexport from the class instantiation.
+  void to_be_exported() noexcept;
+
+  // This will be instantiated implicitly as an exported function because it is
+  // marked as dllexport explicitly.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) void 
to_be_exported_explicitly() noexcept;
+
+  // This will be instantiated implicitly as an exported function 
unintentionally.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_exported() noexcept;
+
+  // This won't be instantiated.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_instantiated() noexcept;
+};
+
+template  void C::to_be_exported() noexcept {}
+template  void C::to_be_exported_explicitly() noexcept {}
+template  void C::not_to_be_exported() noexcept {}
+template  void C::not_to_be_instantiated() noexcept {}
+
+// MSC: $"?to_be_exported@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_explicitly@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?not_to_be_exported@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?not_to_be_instantiated@?$C@H@@QEAAXXZ" = comdat any
+// GNU: $_ZN1CIiE14to_be_exportedEv = comdat any
+// GNU: $_ZN1CIiE25to_be_exported_explicitlyEv = comdat any
+// GNU: $_ZN1CIiE18not_to_be_exportedEv = comdat any
+// GNU: $_ZN1CIiE22not_to_be_instantiatedEv = comdat any
+
+// MSC: define weak_odr dso_local dllexport{{.*}} void 
@"?to_be_exported@?$C@H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport{{.*}} void 
@_ZN1CIiE14to_be_exportedEv
+template struct __declspec(dllexport) C;
+
+void use() {
+  C c;
+
+  // MSC: call void @"?to_be_exported_explicitly@?$C@H@@QEAAXXZ"
+  // GNU: call void @_ZN1CIiE25to_be_exported_explicitlyEv
+  c.to_be_exported_explicitly(); // implicitly instantiated here
+
+  // MSC: call void @"?not_to_be_exported@?$C@H@@QEAAXXZ"
+  // GNU: call void @_ZN1CIiE18not_to_be_exportedEv
+  c.not_to_be_exported(); // implicitly instantiated here
+};
+
+// MSC: define weak_odr dso_local dllexport{{.*}} void 
@"?to_be_exported_explicitly@?$C@H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport{{.*}} void 
@_ZN1CIiE25to_be_exported_explicitlyEv
+
+// MSC: define weak_odr dso_local dllexport void 
@"?not_to_be_exported@?$C@H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport void 
@_ZN1CIiE18not_to_be_exportedEv
+
+// MSC: define weak_odr dso_local dllexport void 
@"?not_to_be_instantiated@?$C@H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport void 
@_ZN1CIiE22not_to_be_instantiatedEv
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 0..adc420f37bbc6
--- /dev/null
+++ 
b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-cygwin

[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-12-10 Thread Tomohiro Kashiwada via cfe-commits

https://github.com/kikairoya updated 
https://github.com/llvm/llvm-project/pull/168171

>From 3234c2685a86561a3df695f6a8e4b6c55c1a7f5c Mon Sep 17 00:00:00 2001
From: kikairoya 
Date: Sat, 15 Nov 2025 11:25:23 +0900
Subject: [PATCH 1/9] pretest

---
 ...t_instantiation.exclude_from_dllexport.cpp | 64 +++
 ...t_instantiation.exclude_from_dllimport.cpp | 50 +++
 2 files changed, 114 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 0..6b1bd83f6d69b
--- /dev/null
+++ 
b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-cygwin-emit-llvm -o - %s | 
FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_
+
+// Test that __declspec(dllexport) doesn't instantiate entities marked with
+// the exclude_from_explicit_instantiation attribute unless marked as 
dllexport explicitly.
+
+#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION 
__attribute__((exclude_from_explicit_instantiation))
+
+template 
+struct C {
+  // This will be instantiated explicitly as an exported function because it
+  // inherits dllexport from the class instantiation.
+  void to_be_exported() noexcept;
+
+  // This will be instantiated implicitly as an exported function because it is
+  // marked as dllexport explicitly.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) void 
to_be_exported_explicitly() noexcept;
+
+  // This will be instantiated implicitly as an exported function 
unintentionally.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_exported() noexcept;
+
+  // This won't be instantiated.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_instantiated() noexcept;
+};
+
+template  void C::to_be_exported() noexcept {}
+template  void C::to_be_exported_explicitly() noexcept {}
+template  void C::not_to_be_exported() noexcept {}
+template  void C::not_to_be_instantiated() noexcept {}
+
+// MSC: $"?to_be_exported@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_explicitly@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?not_to_be_exported@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?not_to_be_instantiated@?$C@H@@QEAAXXZ" = comdat any
+// GNU: $_ZN1CIiE14to_be_exportedEv = comdat any
+// GNU: $_ZN1CIiE25to_be_exported_explicitlyEv = comdat any
+// GNU: $_ZN1CIiE18not_to_be_exportedEv = comdat any
+// GNU: $_ZN1CIiE22not_to_be_instantiatedEv = comdat any
+
+// MSC: define weak_odr dso_local dllexport{{.*}} void 
@"?to_be_exported@?$C@H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport{{.*}} void 
@_ZN1CIiE14to_be_exportedEv
+template struct __declspec(dllexport) C;
+
+void use() {
+  C c;
+
+  // MSC: call void @"?to_be_exported_explicitly@?$C@H@@QEAAXXZ"
+  // GNU: call void @_ZN1CIiE25to_be_exported_explicitlyEv
+  c.to_be_exported_explicitly(); // implicitly instantiated here
+
+  // MSC: call void @"?not_to_be_exported@?$C@H@@QEAAXXZ"
+  // GNU: call void @_ZN1CIiE18not_to_be_exportedEv
+  c.not_to_be_exported(); // implicitly instantiated here
+};
+
+// MSC: define weak_odr dso_local dllexport{{.*}} void 
@"?to_be_exported_explicitly@?$C@H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport{{.*}} void 
@_ZN1CIiE25to_be_exported_explicitlyEv
+
+// MSC: define weak_odr dso_local dllexport void 
@"?not_to_be_exported@?$C@H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport void 
@_ZN1CIiE18not_to_be_exportedEv
+
+// MSC: define weak_odr dso_local dllexport void 
@"?not_to_be_instantiated@?$C@H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport void 
@_ZN1CIiE22not_to_be_instantiatedEv
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 0..adc420f37bbc6
--- /dev/null
+++ 
b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-cygwin  

[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-12-09 Thread Tomohiro Kashiwada via cfe-commits


@@ -19108,8 +19118,23 @@ bool Sema::DefineUsedVTables() {
 }
   }
 
-  if (IsExplicitInstantiationDeclaration)
+  if (IsExplicitInstantiationDeclaration) {
 DefineVTable = false;
+
+// Ensure the instance of a virtual member function which is declared
+// with `__attribute__((exclude_from_explicit_instantiation))` is
+// accessible from the VTable.
+for (Decl *decl : Class->decls()) {
+  auto *Method = dyn_cast(decl);
+  if (!Method || !Method->isVirtual())
+continue;
+
+  if (Method->hasAttr()) {
+MarkFunctionReferenced(Loc, Method);
+DefinedAnything = true;
+  }
+}

kikairoya wrote:

I wasn't sure if `Consumer.HandleVTable(Class);` below should be called in this 
case; that was not called previously. However, since the VTable is actually 
emitted, it might need to be called.

Surprisingly, setting `DefineVTable = true` regardless 
`IsExplicitInstantiationDeclaration` doesn't break any tests. 
The current construction was introduced in 88d292ccb86c108, but the commit 
doesn't mention MSVC ABI.
How do I check "correct" behavior?

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-12-09 Thread Tomohiro Kashiwada via cfe-commits


@@ -0,0 +1,171 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-cygwin-emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+
+// Test that __declspec(dllexport) doesn't instantiate entities marked with
+// the exclude_from_explicit_instantiation attribute unless marked as 
dllexport explicitly.
+
+// MSC: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// MSC: source_filename = {{.*}}exclude_from_dllexport.cpp
+// GNU: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// GNU: source_filename = {{.*}}exclude_from_dllexport.cpp
+
+#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION 
__attribute__((exclude_from_explicit_instantiation))
+
+template 
+struct C {
+  // This will be instantiated explicitly as an exported function because it
+  // inherits dllexport from the class instantiation.
+  void to_be_exported() noexcept;

kikairoya wrote:

I thought a test I referenced did that but I can't remember. I'll remove them.

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-12-09 Thread Tomohiro Kashiwada via cfe-commits


@@ -0,0 +1,171 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-cygwin-emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+
+// Test that __declspec(dllexport) doesn't instantiate entities marked with
+// the exclude_from_explicit_instantiation attribute unless marked as 
dllexport explicitly.
+
+// MSC: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// MSC: source_filename = {{.*}}exclude_from_dllexport.cpp
+// GNU: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// GNU: source_filename = {{.*}}exclude_from_dllexport.cpp

kikairoya wrote:

It's just to silence `--implicit-check=dllexport`.

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-12-08 Thread Hans Wennborg via cfe-commits


@@ -0,0 +1,171 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-cygwin-emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+
+// Test that __declspec(dllexport) doesn't instantiate entities marked with
+// the exclude_from_explicit_instantiation attribute unless marked as 
dllexport explicitly.
+
+// MSC: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// MSC: source_filename = {{.*}}exclude_from_dllexport.cpp
+// GNU: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// GNU: source_filename = {{.*}}exclude_from_dllexport.cpp
+
+#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION 
__attribute__((exclude_from_explicit_instantiation))
+
+template 
+struct C {
+  // This will be instantiated explicitly as an exported function because it
+  // inherits dllexport from the class instantiation.
+  void to_be_exported() noexcept;

zmodem wrote:

Why is there `noexcept` everywhere?

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-12-08 Thread Hans Wennborg via cfe-commits


@@ -19108,8 +19118,23 @@ bool Sema::DefineUsedVTables() {
 }
   }
 
-  if (IsExplicitInstantiationDeclaration)
+  if (IsExplicitInstantiationDeclaration) {
 DefineVTable = false;
+
+// Ensure the instance of a virtual member function which is declared
+// with `__attribute__((exclude_from_explicit_instantiation))` is
+// accessible from the VTable.
+for (Decl *decl : Class->decls()) {
+  auto *Method = dyn_cast(decl);
+  if (!Method || !Method->isVirtual())
+continue;
+
+  if (Method->hasAttr()) {
+MarkFunctionReferenced(Loc, Method);
+DefinedAnything = true;
+  }
+}

zmodem wrote:

Hmm. I guess I'm confused by the contradiction of setting "DefineVTable = 
false" and then "ensure ... is accessible from the vtable".

The problem seems to be that some parts of the code tries to suppress vtable 
emission, while a different part emits it.

Would it work if we don't do the `DefineVTable = false` part, i.e. just changed 
the the `if (IsExplicitInstantiationDeclaration)` to something like `if 
(IsExplicitInstantiationDeclaration && 
!HasExcludeFromExplicitInstantiationAttr)`?


https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-12-08 Thread Hans Wennborg via cfe-commits


@@ -0,0 +1,171 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+// RUN: %clang_cc1 -triple x86_64-cygwin-emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllexport
+
+// Test that __declspec(dllexport) doesn't instantiate entities marked with
+// the exclude_from_explicit_instantiation attribute unless marked as 
dllexport explicitly.
+
+// MSC: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// MSC: source_filename = {{.*}}exclude_from_dllexport.cpp
+// GNU: ModuleID = {{.*}}exclude_from_dllexport.cpp
+// GNU: source_filename = {{.*}}exclude_from_dllexport.cpp

zmodem wrote:

These checks seem redundant. (Same in the other file.)

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-12-05 Thread Tomohiro Kashiwada via cfe-commits

kikairoya wrote:

The issues are addressed.
AArch64 failure seems irrelevant.

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-12-05 Thread Tomohiro Kashiwada via cfe-commits

https://github.com/kikairoya ready_for_review 
https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-12-05 Thread Tomohiro Kashiwada via cfe-commits

https://github.com/kikairoya updated 
https://github.com/llvm/llvm-project/pull/168171

>From 3234c2685a86561a3df695f6a8e4b6c55c1a7f5c Mon Sep 17 00:00:00 2001
From: kikairoya 
Date: Sat, 15 Nov 2025 11:25:23 +0900
Subject: [PATCH 1/9] pretest

---
 ...t_instantiation.exclude_from_dllexport.cpp | 64 +++
 ...t_instantiation.exclude_from_dllimport.cpp | 50 +++
 2 files changed, 114 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 0..6b1bd83f6d69b
--- /dev/null
+++ 
b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-cygwin-emit-llvm -o - %s | 
FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_
+
+// Test that __declspec(dllexport) doesn't instantiate entities marked with
+// the exclude_from_explicit_instantiation attribute unless marked as 
dllexport explicitly.
+
+#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION 
__attribute__((exclude_from_explicit_instantiation))
+
+template 
+struct C {
+  // This will be instantiated explicitly as an exported function because it
+  // inherits dllexport from the class instantiation.
+  void to_be_exported() noexcept;
+
+  // This will be instantiated implicitly as an exported function because it is
+  // marked as dllexport explicitly.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) void 
to_be_exported_explicitly() noexcept;
+
+  // This will be instantiated implicitly as an exported function 
unintentionally.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_exported() noexcept;
+
+  // This won't be instantiated.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_instantiated() noexcept;
+};
+
+template  void C::to_be_exported() noexcept {}
+template  void C::to_be_exported_explicitly() noexcept {}
+template  void C::not_to_be_exported() noexcept {}
+template  void C::not_to_be_instantiated() noexcept {}
+
+// MSC: $"?to_be_exported@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_explicitly@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?not_to_be_exported@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?not_to_be_instantiated@?$C@H@@QEAAXXZ" = comdat any
+// GNU: $_ZN1CIiE14to_be_exportedEv = comdat any
+// GNU: $_ZN1CIiE25to_be_exported_explicitlyEv = comdat any
+// GNU: $_ZN1CIiE18not_to_be_exportedEv = comdat any
+// GNU: $_ZN1CIiE22not_to_be_instantiatedEv = comdat any
+
+// MSC: define weak_odr dso_local dllexport{{.*}} void 
@"?to_be_exported@?$C@H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport{{.*}} void 
@_ZN1CIiE14to_be_exportedEv
+template struct __declspec(dllexport) C;
+
+void use() {
+  C c;
+
+  // MSC: call void @"?to_be_exported_explicitly@?$C@H@@QEAAXXZ"
+  // GNU: call void @_ZN1CIiE25to_be_exported_explicitlyEv
+  c.to_be_exported_explicitly(); // implicitly instantiated here
+
+  // MSC: call void @"?not_to_be_exported@?$C@H@@QEAAXXZ"
+  // GNU: call void @_ZN1CIiE18not_to_be_exportedEv
+  c.not_to_be_exported(); // implicitly instantiated here
+};
+
+// MSC: define weak_odr dso_local dllexport{{.*}} void 
@"?to_be_exported_explicitly@?$C@H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport{{.*}} void 
@_ZN1CIiE25to_be_exported_explicitlyEv
+
+// MSC: define weak_odr dso_local dllexport void 
@"?not_to_be_exported@?$C@H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport void 
@_ZN1CIiE18not_to_be_exportedEv
+
+// MSC: define weak_odr dso_local dllexport void 
@"?not_to_be_instantiated@?$C@H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport void 
@_ZN1CIiE22not_to_be_instantiatedEv
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 0..adc420f37bbc6
--- /dev/null
+++ 
b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-cygwin  

[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-12-05 Thread Tomohiro Kashiwada via cfe-commits

https://github.com/kikairoya edited 
https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-12-05 Thread Tomohiro Kashiwada via cfe-commits

https://github.com/kikairoya updated 
https://github.com/llvm/llvm-project/pull/168171

>From 3234c2685a86561a3df695f6a8e4b6c55c1a7f5c Mon Sep 17 00:00:00 2001
From: kikairoya 
Date: Sat, 15 Nov 2025 11:25:23 +0900
Subject: [PATCH 1/9] pretest

---
 ...t_instantiation.exclude_from_dllexport.cpp | 64 +++
 ...t_instantiation.exclude_from_dllimport.cpp | 50 +++
 2 files changed, 114 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 0..6b1bd83f6d69b
--- /dev/null
+++ 
b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-cygwin-emit-llvm -o - %s | 
FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_
+
+// Test that __declspec(dllexport) doesn't instantiate entities marked with
+// the exclude_from_explicit_instantiation attribute unless marked as 
dllexport explicitly.
+
+#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION 
__attribute__((exclude_from_explicit_instantiation))
+
+template 
+struct C {
+  // This will be instantiated explicitly as an exported function because it
+  // inherits dllexport from the class instantiation.
+  void to_be_exported() noexcept;
+
+  // This will be instantiated implicitly as an exported function because it is
+  // marked as dllexport explicitly.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) void 
to_be_exported_explicitly() noexcept;
+
+  // This will be instantiated implicitly as an exported function 
unintentionally.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_exported() noexcept;
+
+  // This won't be instantiated.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_instantiated() noexcept;
+};
+
+template  void C::to_be_exported() noexcept {}
+template  void C::to_be_exported_explicitly() noexcept {}
+template  void C::not_to_be_exported() noexcept {}
+template  void C::not_to_be_instantiated() noexcept {}
+
+// MSC: $"?to_be_exported@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_explicitly@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?not_to_be_exported@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?not_to_be_instantiated@?$C@H@@QEAAXXZ" = comdat any
+// GNU: $_ZN1CIiE14to_be_exportedEv = comdat any
+// GNU: $_ZN1CIiE25to_be_exported_explicitlyEv = comdat any
+// GNU: $_ZN1CIiE18not_to_be_exportedEv = comdat any
+// GNU: $_ZN1CIiE22not_to_be_instantiatedEv = comdat any
+
+// MSC: define weak_odr dso_local dllexport{{.*}} void 
@"?to_be_exported@?$C@H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport{{.*}} void 
@_ZN1CIiE14to_be_exportedEv
+template struct __declspec(dllexport) C;
+
+void use() {
+  C c;
+
+  // MSC: call void @"?to_be_exported_explicitly@?$C@H@@QEAAXXZ"
+  // GNU: call void @_ZN1CIiE25to_be_exported_explicitlyEv
+  c.to_be_exported_explicitly(); // implicitly instantiated here
+
+  // MSC: call void @"?not_to_be_exported@?$C@H@@QEAAXXZ"
+  // GNU: call void @_ZN1CIiE18not_to_be_exportedEv
+  c.not_to_be_exported(); // implicitly instantiated here
+};
+
+// MSC: define weak_odr dso_local dllexport{{.*}} void 
@"?to_be_exported_explicitly@?$C@H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport{{.*}} void 
@_ZN1CIiE25to_be_exported_explicitlyEv
+
+// MSC: define weak_odr dso_local dllexport void 
@"?not_to_be_exported@?$C@H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport void 
@_ZN1CIiE18not_to_be_exportedEv
+
+// MSC: define weak_odr dso_local dllexport void 
@"?not_to_be_instantiated@?$C@H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport void 
@_ZN1CIiE22not_to_be_instantiatedEv
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 0..adc420f37bbc6
--- /dev/null
+++ 
b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-cygwin  

[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-12-05 Thread Tomohiro Kashiwada via cfe-commits

https://github.com/kikairoya updated 
https://github.com/llvm/llvm-project/pull/168171

>From 3234c2685a86561a3df695f6a8e4b6c55c1a7f5c Mon Sep 17 00:00:00 2001
From: kikairoya 
Date: Sat, 15 Nov 2025 11:25:23 +0900
Subject: [PATCH 1/6] pretest

---
 ...t_instantiation.exclude_from_dllexport.cpp | 64 +++
 ...t_instantiation.exclude_from_dllimport.cpp | 50 +++
 2 files changed, 114 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 0..6b1bd83f6d69b
--- /dev/null
+++ 
b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-cygwin-emit-llvm -o - %s | 
FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_
+
+// Test that __declspec(dllexport) doesn't instantiate entities marked with
+// the exclude_from_explicit_instantiation attribute unless marked as 
dllexport explicitly.
+
+#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION 
__attribute__((exclude_from_explicit_instantiation))
+
+template 
+struct C {
+  // This will be instantiated explicitly as an exported function because it
+  // inherits dllexport from the class instantiation.
+  void to_be_exported() noexcept;
+
+  // This will be instantiated implicitly as an exported function because it is
+  // marked as dllexport explicitly.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) void 
to_be_exported_explicitly() noexcept;
+
+  // This will be instantiated implicitly as an exported function 
unintentionally.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_exported() noexcept;
+
+  // This won't be instantiated.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_instantiated() noexcept;
+};
+
+template  void C::to_be_exported() noexcept {}
+template  void C::to_be_exported_explicitly() noexcept {}
+template  void C::not_to_be_exported() noexcept {}
+template  void C::not_to_be_instantiated() noexcept {}
+
+// MSC: $"?to_be_exported@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_explicitly@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?not_to_be_exported@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?not_to_be_instantiated@?$C@H@@QEAAXXZ" = comdat any
+// GNU: $_ZN1CIiE14to_be_exportedEv = comdat any
+// GNU: $_ZN1CIiE25to_be_exported_explicitlyEv = comdat any
+// GNU: $_ZN1CIiE18not_to_be_exportedEv = comdat any
+// GNU: $_ZN1CIiE22not_to_be_instantiatedEv = comdat any
+
+// MSC: define weak_odr dso_local dllexport{{.*}} void 
@"?to_be_exported@?$C@H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport{{.*}} void 
@_ZN1CIiE14to_be_exportedEv
+template struct __declspec(dllexport) C;
+
+void use() {
+  C c;
+
+  // MSC: call void @"?to_be_exported_explicitly@?$C@H@@QEAAXXZ"
+  // GNU: call void @_ZN1CIiE25to_be_exported_explicitlyEv
+  c.to_be_exported_explicitly(); // implicitly instantiated here
+
+  // MSC: call void @"?not_to_be_exported@?$C@H@@QEAAXXZ"
+  // GNU: call void @_ZN1CIiE18not_to_be_exportedEv
+  c.not_to_be_exported(); // implicitly instantiated here
+};
+
+// MSC: define weak_odr dso_local dllexport{{.*}} void 
@"?to_be_exported_explicitly@?$C@H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport{{.*}} void 
@_ZN1CIiE25to_be_exported_explicitlyEv
+
+// MSC: define weak_odr dso_local dllexport void 
@"?not_to_be_exported@?$C@H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport void 
@_ZN1CIiE18not_to_be_exportedEv
+
+// MSC: define weak_odr dso_local dllexport void 
@"?not_to_be_instantiated@?$C@H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport void 
@_ZN1CIiE22not_to_be_instantiatedEv
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 0..adc420f37bbc6
--- /dev/null
+++ 
b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-cygwin  

[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-12-01 Thread Tomohiro Kashiwada via cfe-commits


@@ -0,0 +1,169 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_ 
--implicit-check-not=dllimport
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllimport
+// RUN: %clang_cc1 -triple x86_64-cygwin-emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllimport
+
+// Test that __declspec(dllimport) doesn't instantiate entities marked with
+// the exclude_from_explicit_instantiation attribute unless marked as 
dllimport explicitly.
+
+// MSC: ModuleID = {{.*}}exclude_from_dllimport.cpp
+// MSC: source_filename = {{.*}}exclude_from_dllimport.cpp
+// GNU: ModuleID = {{.*}}exclude_from_dllimport.cpp
+// GNU: source_filename = {{.*}}exclude_from_dllimport.cpp
+
+#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION 
__attribute__((exclude_from_explicit_instantiation))
+
+template 
+struct C {
+  // This will be instantiated explicitly as an imported function because it
+  // inherits dllimport from the class instantiation.
+  void to_be_imported() noexcept;
+
+  // This will be instantiated implicitly as an imported function because it is
+  // marked as dllimport explicitly.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllimport) void 
to_be_imported_explicitly() noexcept;
+
+  // This will be instantiated implicitly but won't be imported.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_imported() noexcept;
+
+  // This won't be instantiated.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_instantiated() noexcept;
+};
+
+template  void C::to_be_imported() noexcept {}
+template  void C::not_to_be_imported() noexcept {}
+template  void C::not_to_be_instantiated() noexcept {}
+
+// Attach the attribute to class template declaration instead of instantiation 
declaration.
+template 
+struct __declspec(dllimport) D {
+  // This will be imported by the class-level attribute.
+  void to_be_imported() noexcept;
+
+  // This also should be imported by the class-level attribute but currently 
not.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void also_to_be_imported() noexcept;
+};
+
+template  void D::to_be_imported() noexcept {}
+template  void D::also_to_be_imported() noexcept {}
+
+// Interaction with VTables.
+template 
+struct E {
+  // For the MSVC ABI: this constructor causes implicit instantiation of
+  // the VTable, which should trigger instantiating all virtual member
+  // functions regardless `exclude_from_explicit_instantiation` but currently 
not.
+  // For the Itanium ABI: Emitting the VTable is suppressed by implicit
+  // instantiation declaration so virtual member functions won't be 
instantiated.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION explicit E(int);
+
+  // This constructor doesn't trigger the instantiation of the VTable.
+  // In this case, declaration of virtual member functions are absent too.
+  explicit E(long);
+
+  // The body of this shouldn't be emitted since instantiation is suppressed
+  // by the explicit instantiation declaration.
+  virtual void to_be_imported() noexcept;
+
+  // The body of this should be emitted if the VTable is instantiated, even if
+  // the instantiation of this class template is declared with dllimport.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION virtual void to_be_instantiated() 
noexcept;
+
+  // The body of this shouldn't be emitted since that comes from an external 
DLL.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllimport) virtual void 
to_be_imported_explicitly() noexcept;
+
+};
+
+template  E::E(int) {}
+template  E::E(long) {}
+template  void E::to_be_imported() noexcept {}
+template  void E::to_be_instantiated() noexcept {}
+
+// MSC: $"?not_to_be_imported@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?also_to_be_imported@?$D@H@@QEAAXXZ" = comdat any
+// GNU: $_ZN1CIiE18not_to_be_importedEv = comdat any
+// GNU: $_ZN1DIiE19also_to_be_importedEv = comdat any
+// GNU: @_ZTV1EIiE = external dllimport unnamed_addr
+// GNU: @_ZTV1EIjE = external unnamed_addr
+
+// MSC: @0 = private unnamed_addr constant {{.*}}, comdat($"??_S?$E@H@@6B@")
+// MSC: @1 = private unnamed_addr constant {{.*}}, comdat($"??_7?$E@I@@6B@")
+// MSC: @"??_S?$E@H@@6B@" =
+// MSC: @"??_7?$E@I@@6B@" =
+
+extern template struct __declspec(dllimport) C;
+
+extern template struct D;
+
+extern template struct __declspec(dllimport) E;  // $E@H, 1EIiE
+extern template struct E;   // $E@I, 1EIjE
+extern template struct __declspec(dllimport) E; // $E@J, 1EIlE
+extern template struct E;  // $E@K, 1EImE
+
+void use() {
+  C c;
+
+  // MSC: call void @"?to_be_imported@?$C@H@@QEAAXXZ"
+  // GNU: call void @_ZN1CIiE14to_be_importedEv
+  c.to_be_imported();
+
+  // MSC: call void @"?to_be_imported_explicitly@?$C@H@@QEAAXXZ"
+  // GNU: call vo

[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-12-01 Thread Tomohiro Kashiwada via cfe-commits

https://github.com/kikairoya commented:

I've added tests related to #40363 and #66909 .
Is it worth submitting these test-only patches first, to assert the current 
behavior?

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-12-01 Thread Tomohiro Kashiwada via cfe-commits


@@ -0,0 +1,169 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_ 
--implicit-check-not=dllimport
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllimport
+// RUN: %clang_cc1 -triple x86_64-cygwin-emit-llvm -o - %s | \
+// RUN: FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_ 
--implicit-check-not=dllimport
+
+// Test that __declspec(dllimport) doesn't instantiate entities marked with
+// the exclude_from_explicit_instantiation attribute unless marked as 
dllimport explicitly.
+
+// MSC: ModuleID = {{.*}}exclude_from_dllimport.cpp
+// MSC: source_filename = {{.*}}exclude_from_dllimport.cpp
+// GNU: ModuleID = {{.*}}exclude_from_dllimport.cpp
+// GNU: source_filename = {{.*}}exclude_from_dllimport.cpp
+
+#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION 
__attribute__((exclude_from_explicit_instantiation))
+
+template 
+struct C {
+  // This will be instantiated explicitly as an imported function because it
+  // inherits dllimport from the class instantiation.
+  void to_be_imported() noexcept;
+
+  // This will be instantiated implicitly as an imported function because it is
+  // marked as dllimport explicitly.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllimport) void 
to_be_imported_explicitly() noexcept;
+
+  // This will be instantiated implicitly but won't be imported.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_imported() noexcept;
+
+  // This won't be instantiated.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_instantiated() noexcept;
+};
+
+template  void C::to_be_imported() noexcept {}
+template  void C::not_to_be_imported() noexcept {}
+template  void C::not_to_be_instantiated() noexcept {}
+
+// Attach the attribute to class template declaration instead of instantiation 
declaration.
+template 
+struct __declspec(dllimport) D {
+  // This will be imported by the class-level attribute.
+  void to_be_imported() noexcept;
+
+  // This also should be imported by the class-level attribute but currently 
not.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void also_to_be_imported() noexcept;
+};
+
+template  void D::to_be_imported() noexcept {}
+template  void D::also_to_be_imported() noexcept {}
+
+// Interaction with VTables.
+template 
+struct E {
+  // For the MSVC ABI: this constructor causes implicit instantiation of
+  // the VTable, which should trigger instantiating all virtual member
+  // functions regardless `exclude_from_explicit_instantiation` but currently 
not.
+  // For the Itanium ABI: Emitting the VTable is suppressed by implicit
+  // instantiation declaration so virtual member functions won't be 
instantiated.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION explicit E(int);
+
+  // This constructor doesn't trigger the instantiation of the VTable.
+  // In this case, declaration of virtual member functions are absent too.
+  explicit E(long);
+
+  // The body of this shouldn't be emitted since instantiation is suppressed
+  // by the explicit instantiation declaration.
+  virtual void to_be_imported() noexcept;
+
+  // The body of this should be emitted if the VTable is instantiated, even if
+  // the instantiation of this class template is declared with dllimport.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION virtual void to_be_instantiated() 
noexcept;
+
+  // The body of this shouldn't be emitted since that comes from an external 
DLL.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllimport) virtual void 
to_be_imported_explicitly() noexcept;
+
+};
+
+template  E::E(int) {}
+template  E::E(long) {}
+template  void E::to_be_imported() noexcept {}
+template  void E::to_be_instantiated() noexcept {}
+
+// MSC: $"?not_to_be_imported@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?also_to_be_imported@?$D@H@@QEAAXXZ" = comdat any
+// GNU: $_ZN1CIiE18not_to_be_importedEv = comdat any
+// GNU: $_ZN1DIiE19also_to_be_importedEv = comdat any
+// GNU: @_ZTV1EIiE = external dllimport unnamed_addr
+// GNU: @_ZTV1EIjE = external unnamed_addr
+
+// MSC: @0 = private unnamed_addr constant {{.*}}, comdat($"??_S?$E@H@@6B@")
+// MSC: @1 = private unnamed_addr constant {{.*}}, comdat($"??_7?$E@I@@6B@")
+// MSC: @"??_S?$E@H@@6B@" =
+// MSC: @"??_7?$E@I@@6B@" =
+
+extern template struct __declspec(dllimport) C;
+
+extern template struct D;
+
+extern template struct __declspec(dllimport) E;  // $E@H, 1EIiE
+extern template struct E;   // $E@I, 1EIjE
+extern template struct __declspec(dllimport) E; // $E@J, 1EIlE
+extern template struct E;  // $E@K, 1EImE
+
+void use() {
+  C c;
+
+  // MSC: call void @"?to_be_imported@?$C@H@@QEAAXXZ"
+  // GNU: call void @_ZN1CIiE14to_be_importedEv
+  c.to_be_imported();
+
+  // MSC: call void @"?to_be_imported_explicitly@?$C@H@@QEAAXXZ"
+  // GNU: call vo

[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-12-01 Thread Tomohiro Kashiwada via cfe-commits

https://github.com/kikairoya edited 
https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-12-01 Thread Tomohiro Kashiwada via cfe-commits

https://github.com/kikairoya updated 
https://github.com/llvm/llvm-project/pull/168171

>From 3234c2685a86561a3df695f6a8e4b6c55c1a7f5c Mon Sep 17 00:00:00 2001
From: kikairoya 
Date: Sat, 15 Nov 2025 11:25:23 +0900
Subject: [PATCH 1/6] pretest

---
 ...t_instantiation.exclude_from_dllexport.cpp | 64 +++
 ...t_instantiation.exclude_from_dllimport.cpp | 50 +++
 2 files changed, 114 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 0..6b1bd83f6d69b
--- /dev/null
+++ 
b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllexport.cpp
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-cygwin-emit-llvm -o - %s | 
FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_
+
+// Test that __declspec(dllexport) doesn't instantiate entities marked with
+// the exclude_from_explicit_instantiation attribute unless marked as 
dllexport explicitly.
+
+#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION 
__attribute__((exclude_from_explicit_instantiation))
+
+template 
+struct C {
+  // This will be instantiated explicitly as an exported function because it
+  // inherits dllexport from the class instantiation.
+  void to_be_exported() noexcept;
+
+  // This will be instantiated implicitly as an exported function because it is
+  // marked as dllexport explicitly.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION __declspec(dllexport) void 
to_be_exported_explicitly() noexcept;
+
+  // This will be instantiated implicitly as an exported function 
unintentionally.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_exported() noexcept;
+
+  // This won't be instantiated.
+  EXCLUDE_FROM_EXPLICIT_INSTANTIATION void not_to_be_instantiated() noexcept;
+};
+
+template  void C::to_be_exported() noexcept {}
+template  void C::to_be_exported_explicitly() noexcept {}
+template  void C::not_to_be_exported() noexcept {}
+template  void C::not_to_be_instantiated() noexcept {}
+
+// MSC: $"?to_be_exported@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?to_be_exported_explicitly@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?not_to_be_exported@?$C@H@@QEAAXXZ" = comdat any
+// MSC: $"?not_to_be_instantiated@?$C@H@@QEAAXXZ" = comdat any
+// GNU: $_ZN1CIiE14to_be_exportedEv = comdat any
+// GNU: $_ZN1CIiE25to_be_exported_explicitlyEv = comdat any
+// GNU: $_ZN1CIiE18not_to_be_exportedEv = comdat any
+// GNU: $_ZN1CIiE22not_to_be_instantiatedEv = comdat any
+
+// MSC: define weak_odr dso_local dllexport{{.*}} void 
@"?to_be_exported@?$C@H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport{{.*}} void 
@_ZN1CIiE14to_be_exportedEv
+template struct __declspec(dllexport) C;
+
+void use() {
+  C c;
+
+  // MSC: call void @"?to_be_exported_explicitly@?$C@H@@QEAAXXZ"
+  // GNU: call void @_ZN1CIiE25to_be_exported_explicitlyEv
+  c.to_be_exported_explicitly(); // implicitly instantiated here
+
+  // MSC: call void @"?not_to_be_exported@?$C@H@@QEAAXXZ"
+  // GNU: call void @_ZN1CIiE18not_to_be_exportedEv
+  c.not_to_be_exported(); // implicitly instantiated here
+};
+
+// MSC: define weak_odr dso_local dllexport{{.*}} void 
@"?to_be_exported_explicitly@?$C@H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport{{.*}} void 
@_ZN1CIiE25to_be_exported_explicitlyEv
+
+// MSC: define weak_odr dso_local dllexport void 
@"?not_to_be_exported@?$C@H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport void 
@_ZN1CIiE18not_to_be_exportedEv
+
+// MSC: define weak_odr dso_local dllexport void 
@"?not_to_be_instantiated@?$C@H@@QEAAXXZ"
+// GNU: define weak_odr dso_local dllexport void 
@_ZN1CIiE22not_to_be_instantiatedEv
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 0..adc420f37bbc6
--- /dev/null
+++ 
b/clang/test/CodeGenCXX/attr-exclude_from_explicit_instantiation.exclude_from_dllimport.cpp
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -triple x86_64-win32 -fms-extensions -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=MSC --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-mingw -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=GNU --implicit-check-not=to_be_
+// RUN: %clang_cc1 -triple x86_64-cygwin  

[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-12-01 Thread Hans Wennborg via cfe-commits

zmodem wrote:

> If I remember correctly, there are a number of preexisting references to the 
> problem that `exclude_from_explicit_instantiation` doesn't do what it would 
> need to do on Windows; I think such references may exist in libcxx (in the 
> code tree maybe?) and/or as other issues here on github. It would be a nice 
> extra if we could find some of those references, to get more stakeholders 
> aware of this change here (and possibly know which references to update).

I think the main one is https://github.com/llvm/llvm-project/issues/40363 
maybe. It would be good to check how this interacts with the problem described 
there.

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-11-29 Thread Tomohiro Kashiwada via cfe-commits

https://github.com/kikairoya converted_to_draft 
https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-11-29 Thread Tomohiro Kashiwada via cfe-commits

kikairoya wrote:

> If I remember correctly, there are a number of preexisting references to the 
> problem that `exclude_from_explicit_instantiation` doesn't do what it would 
> need to do on Windows; I think such references may exist in libcxx (in the 
> code tree maybe?) and/or as other issues here on github. It would be a nice 
> extra if we could find some of those references, to get more stakeholders 
> aware of this change here (and possibly know which references to update).

Ugh, I missed #66909. I need to add more fixes to address it.

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-11-29 Thread Tomohiro Kashiwada via cfe-commits

kikairoya wrote:

> That's great! Does this, together with #168170, address the overall problem 
> in #135910, or are there many other issues remaining in order to fix that 
> (other than reverting my old clang change)?

Neither of this nor #168170 is directly related to #135910 itself.
These are prerequisites for libc++'s ABI checking 
https://github.com/llvm/llvm-project/issues/135910#issuecomment-2901310436 , 
and another patch and checking functionality itself are still required to 
upstream.

For #135910 , I already have a "functional" local patch (with exporting nested 
classes), but I feel that I should try to find more edge cases.

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-11-28 Thread Martin Storsjö via cfe-commits

mstorsjo wrote:

Thanks!

If I remember correctly, there are a number of preexisting references to the 
problem that `exclude_from_explicit_instantiation` doesn't do what it would 
need to do on Windows; I think such references may exist in libcxx and/or as 
other issues here on github. It would be a nice extra if we could find some of 
those references, to get more stakeholders aware of this change here (and 
possibly know which references to update).

I'm not very familiar with the code here so I'm not sure if I can do an 
authoritative review - but it practically looks reasonable. Looping in @zmodem 
who either can do a more confident review, or find more reviewers.

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Apply exclude_from_explicit_instantiation to dllimport/dllexport (PR #168171)

2025-11-28 Thread Martin Storsjö via cfe-commits

mstorsjo wrote:

> @mstorsjo This fixes [#135910 
> (comment)](https://github.com/llvm/llvm-project/issues/135910#issuecomment-2907742933)

That's great! Does this, together with 
https://github.com/llvm/llvm-project/pull/168170, address the overall problem 
in #135910, or are there many other issues remaining in order to fix that 
(other than reverting my old clang change)?

https://github.com/llvm/llvm-project/pull/168171
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits