================
@@ -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 <class T>
+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 <class T> void C<T>::to_be_imported() noexcept {}
+template <class T> void C<T>::not_to_be_imported() noexcept {}
+template <class T> void C<T>::not_to_be_instantiated() noexcept {}
+
+// Attach the attribute to class template declaration instead of instantiation
declaration.
+template <class T>
+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 <class T> void D<T>::to_be_imported() noexcept {}
+template <class T> void D<T>::also_to_be_imported() noexcept {}
+
+// Interaction with VTables.
+template <class T>
+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 <class T> E<T>::E(int) {}
+template <class T> E<T>::E(long) {}
+template <class T> void E<T>::to_be_imported() noexcept {}
+template <class T> void E<T>::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<int>;
+
+extern template struct D<int>;
+
+extern template struct __declspec(dllimport) E<int>; // $E@H, 1EIiE
+extern template struct E<unsigned>; // $E@I, 1EIjE
+extern template struct __declspec(dllimport) E<long int>; // $E@J, 1EIlE
+extern template struct E<unsigned long int>; // $E@K, 1EImE
+
+void use() {
+ C<int> 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 void @_ZN1CIiE25to_be_imported_explicitlyEv
+ c.to_be_imported_explicitly(); // implicitly instantiated here
+
+ // MSC: call void @"?not_to_be_imported@?$C@H@@QEAAXXZ"
+ // GNU: call void @_ZN1CIiE18not_to_be_importedEv
+ c.not_to_be_imported(); // implicitly instantiated here
+
+ D<int> d;
+
+ // MSC: call void @"?to_be_imported@?$D@H@@QEAAXXZ"
+ // GNU: call void @_ZN1DIiE14to_be_importedEv
+ d.to_be_imported(); // implicitly instantiated here
+
+ // MSC: call void @"?also_to_be_imported@?$D@H@@QEAAXXZ"
+ // GNU: call void @_ZN1DIiE19also_to_be_importedEv
+ d.also_to_be_imported(); // implicitly instantiated here
+
+ E<int> ei{1};
+
+ E<unsigned> ej{1};
+
+ E<long int> el{1L};
+
+ E<unsigned long int> eu{1L};
+}
+
+// MSC: declare dllimport void @"?to_be_imported@?$C@H@@QEAAXXZ"
+// GNU: declare dllimport void @_ZN1CIiE14to_be_importedEv
+
+// MSC: declare dllimport void @"?to_be_imported_explicitly@?$C@H@@QEAAXXZ"
+// GNU: declare dllimport void @_ZN1CIiE25to_be_imported_explicitlyEv
+
+// MSC: define linkonce_odr dso_local void
@"?not_to_be_imported@?$C@H@@QEAAXXZ"
+// GNU: define linkonce_odr dso_local void @_ZN1CIiE18not_to_be_importedEv
+
+// MSC: declare dllimport void @"?to_be_imported@?$D@H@@QEAAXXZ"
+// GNU: declare dllimport void @_ZN1DIiE14to_be_importedEv
+
+// MSC: define linkonce_odr dso_local void
@"?also_to_be_imported@?$D@H@@QEAAXXZ"
+// GNU: define linkonce_odr dso_local void @_ZN1DIiE19also_to_be_importedEv
----------------
kikairoya wrote:
#40363 claims this member shouldn't be dllimport-ed but I'd oppose to that.
Since dllimport is attached to the class template rather than the explicit
instantiation, exclude_from_explicit_instantiation shouldn't block the
inheritance of dllimport. (The current patch unintentionally aligns with that
though).
https://github.com/llvm/llvm-project/pull/168171
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits