[clang] [Clang] Export inline move constructors in dllexport-ed template instantiations on non-MSVC targets (PR #168170)
Tomohiro Kashiwada via cfe-commits
cfe-commits at lists.llvm.org
Thu Nov 27 03:51:39 PST 2025
https://github.com/kikairoya updated https://github.com/llvm/llvm-project/pull/168170
>From cef60afe8f60893e8991c95c615bbb8c03834394 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Sat, 15 Nov 2025 11:19:05 +0900
Subject: [PATCH 1/6] pretest
---
clang/test/CodeGenCXX/dllexport.cpp | 1 +
clang/test/CodeGenCXX/mingw-template-dllexport.cpp | 2 ++
2 files changed, 3 insertions(+)
diff --git a/clang/test/CodeGenCXX/dllexport.cpp b/clang/test/CodeGenCXX/dllexport.cpp
index ef9d8131c511c..0c8ddc2803c89 100644
--- a/clang/test/CodeGenCXX/dllexport.cpp
+++ b/clang/test/CodeGenCXX/dllexport.cpp
@@ -1133,3 +1133,4 @@ class __declspec(dllexport) ACE_Service_Object : public ACE_Shared_Object {};
// MSVC2015-DAG: define weak_odr dso_local dllexport {{.+}}ACE_Service_Object@@Q{{.+}}@$$Q
// The declarations should not be exported.
// MSVC2013-NOT: define weak_odr dso_local dllexport {{.+}}ACE_Service_Object@@Q{{.+}}@$$Q
+// PS-NOT: define weak_odr dllexport void @_ZN18ACE_Service_ObjectC1EOS_
diff --git a/clang/test/CodeGenCXX/mingw-template-dllexport.cpp b/clang/test/CodeGenCXX/mingw-template-dllexport.cpp
index de112d6da53db..1e2759fbb5cc7 100644
--- a/clang/test/CodeGenCXX/mingw-template-dllexport.cpp
+++ b/clang/test/CodeGenCXX/mingw-template-dllexport.cpp
@@ -10,11 +10,13 @@
template <class T>
class c {
+ c(c &&) noexcept {}
void f() {}
};
template class __declspec(dllexport) c<int>;
+// CHECK-NOT: define {{.*}} dllexport {{.*}} @_ZN1cIiEC1EOS0_
// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIiE1fEv
extern template class __declspec(dllexport) c<char>;
>From 5dd04f3a507caf64fec85af028deb052b2c80a7a Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Sat, 15 Nov 2025 11:19:06 +0900
Subject: [PATCH 2/6] [Clang] Export inline move constructors in dllexport-ed
template instantiations on non-MSVC targets
Previously, even when MSVC compatibility was not requested, inline move constructors in dllexport-ed templates were not exported, which was seemingly unintended.
On non-MSVC targets (MinGW, Cygwin, and PS), such move constructors should be exported consistently with copy constructors and with the behavior of modern MSVC.
---
clang/lib/Sema/SemaDeclCXX.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index aa36a79142e52..5f741166d0e29 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -6627,6 +6627,7 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) {
auto *Ctor = dyn_cast<CXXConstructorDecl>(MD);
if ((MD->isMoveAssignmentOperator() ||
(Ctor && Ctor->isMoveConstructor())) &&
+ getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2010) &&
!getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2015))
continue;
>From 0291a3477865d23734de369fe06d291393cf7a64 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Sat, 15 Nov 2025 11:19:06 +0900
Subject: [PATCH 3/6] update test
---
clang/test/CodeGenCXX/dllexport.cpp | 2 +-
clang/test/CodeGenCXX/mingw-template-dllexport.cpp | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/test/CodeGenCXX/dllexport.cpp b/clang/test/CodeGenCXX/dllexport.cpp
index 0c8ddc2803c89..a34a87c5b9f21 100644
--- a/clang/test/CodeGenCXX/dllexport.cpp
+++ b/clang/test/CodeGenCXX/dllexport.cpp
@@ -1131,6 +1131,6 @@ class __declspec(dllexport) ACE_Shared_Object {
class __declspec(dllexport) ACE_Service_Object : public ACE_Shared_Object {};
// Implicit move constructor declaration.
// MSVC2015-DAG: define weak_odr dso_local dllexport {{.+}}ACE_Service_Object@@Q{{.+}}@$$Q
+// PS-DAG: define weak_odr dllexport void @_ZN18ACE_Service_ObjectC1EOS_
// The declarations should not be exported.
// MSVC2013-NOT: define weak_odr dso_local dllexport {{.+}}ACE_Service_Object@@Q{{.+}}@$$Q
-// PS-NOT: define weak_odr dllexport void @_ZN18ACE_Service_ObjectC1EOS_
diff --git a/clang/test/CodeGenCXX/mingw-template-dllexport.cpp b/clang/test/CodeGenCXX/mingw-template-dllexport.cpp
index 1e2759fbb5cc7..15969d2415cca 100644
--- a/clang/test/CodeGenCXX/mingw-template-dllexport.cpp
+++ b/clang/test/CodeGenCXX/mingw-template-dllexport.cpp
@@ -16,7 +16,7 @@ class c {
template class __declspec(dllexport) c<int>;
-// CHECK-NOT: define {{.*}} dllexport {{.*}} @_ZN1cIiEC1EOS0_
+// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIiEC1EOS0_
// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIiE1fEv
extern template class __declspec(dllexport) c<char>;
>From 69c45af53cc6d3c29f9b528079c51fa35ccaab8b Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Thu, 27 Nov 2025 20:19:05 +0900
Subject: [PATCH 4/6] test/CodeGenCXX/dllimport.cpp: use correct signature for
copy assignment operator
---
clang/test/CodeGenCXX/dllimport.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/clang/test/CodeGenCXX/dllimport.cpp b/clang/test/CodeGenCXX/dllimport.cpp
index 363f97a8d58ee..16c51be472a83 100644
--- a/clang/test/CodeGenCXX/dllimport.cpp
+++ b/clang/test/CodeGenCXX/dllimport.cpp
@@ -35,7 +35,7 @@ struct ExplicitSpec_NotImported {};
#define USEMEMFUNC(class, func) void (class::*UNIQ(use)())() { return &class::func; }
#define USESTATICMEMFUNC(class, func) void (*UNIQ(use)())() { return &class::func; }
#define USECLASS(class) void UNIQ(USE)() { class x; }
-#define USECOPYASSIGN(class) class& (class::*UNIQ(use)())(class&) { return &class::operator=; }
+#define USECOPYASSIGN(class) class& (class::*UNIQ(use)())(const class&) { return &class::operator=; }
#define USEMOVEASSIGN(class) class& (class::*UNIQ(use)())(class&&) { return &class::operator=; }
//===----------------------------------------------------------------------===//
@@ -649,11 +649,11 @@ struct __declspec(dllimport) T {
static int b;
// MO1-DAG: @"?b at T@@2HA" = external dllimport global i32
- T& operator=(T&) = default;
- // MO1-DAG: define available_externally dllimport x86_thiscallcc nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) ptr @"??4T@@QAEAAU0 at AAU0@@Z"
+ T& operator=(const T&) = default;
+ // MO1-DAG: define available_externally dllimport x86_thiscallcc nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) ptr @"??4T@@QAEAAU0 at ABU0@@Z"
T& operator=(T&&) = default;
- // Note: Don't mark inline move operators dllimport because current MSVC versions don't export them.
+ // Note: Don't mark inline move operators dllimport because MSVC versions before 2015 don't export them.
// M18-DAG: define linkonce_odr dso_local x86_thiscallcc nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) ptr @"??4T@@QAEAAU0@$$QAU0@@Z"
// M19-DAG: define available_externally dllimport x86_thiscallcc nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) ptr @"??4T@@QAEAAU0@$$QAU0@@Z"
};
>From 9bc8f58f6fdb32608930b39ad52575e9179b7573 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Thu, 27 Nov 2025 20:20:23 +0900
Subject: [PATCH 5/6] add dllimport tests
---
clang/test/CodeGenCXX/dllimport.cpp | 2 ++
.../test/CodeGenCXX/mingw-template-dllexport.cpp | 15 +++++++++++++++
2 files changed, 17 insertions(+)
diff --git a/clang/test/CodeGenCXX/dllimport.cpp b/clang/test/CodeGenCXX/dllimport.cpp
index 16c51be472a83..ed1c72c5185d3 100644
--- a/clang/test/CodeGenCXX/dllimport.cpp
+++ b/clang/test/CodeGenCXX/dllimport.cpp
@@ -651,11 +651,13 @@ struct __declspec(dllimport) T {
T& operator=(const T&) = default;
// MO1-DAG: define available_externally dllimport x86_thiscallcc nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) ptr @"??4T@@QAEAAU0 at ABU0@@Z"
+ // PS-DAG: declare dllimport nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) ptr @_ZN1TaSERKS_
T& operator=(T&&) = default;
// Note: Don't mark inline move operators dllimport because MSVC versions before 2015 don't export them.
// M18-DAG: define linkonce_odr dso_local x86_thiscallcc nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) ptr @"??4T@@QAEAAU0@$$QAU0@@Z"
// M19-DAG: define available_externally dllimport x86_thiscallcc nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) ptr @"??4T@@QAEAAU0@$$QAU0@@Z"
+ // PS-DAG: declare dllimport nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) ptr @_ZN1TaSEOS_
};
USEMEMFUNC(T, a)
USESTATICMEMFUNC(T, StaticMethod)
diff --git a/clang/test/CodeGenCXX/mingw-template-dllexport.cpp b/clang/test/CodeGenCXX/mingw-template-dllexport.cpp
index 15969d2415cca..9f116c46853b6 100644
--- a/clang/test/CodeGenCXX/mingw-template-dllexport.cpp
+++ b/clang/test/CodeGenCXX/mingw-template-dllexport.cpp
@@ -10,12 +10,15 @@
template <class T>
class c {
+public:
+ c(const c &) {}
c(c &&) noexcept {}
void f() {}
};
template class __declspec(dllexport) c<int>;
+// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIiEC1ERKS0_
// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIiEC1EOS0_
// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIiE1fEv
@@ -29,6 +32,18 @@ template class __declspec(dllexport) c<double>;
// CHECK-NOT: define {{.*}} dllexport {{.*}} @_ZN1cIdE1fEv
+extern template class __declspec(dllimport) c<short>;
+
+// CHECK: declare dllimport {{.*}} @_ZN1cIsEC1ERKS0_
+// CHECK: declare dllimport {{.*}} @_ZN1cIsEC1EOS0_
+// CHECK: declare dllimport {{.*}} @_ZN1cIsE1fEv
+
+void use_ctors(c<short> &&x) {
+ c<short> y{x};
+ c<short> z{static_cast<c<short> &&>(x)};
+ z.f();
+}
+
template <class T>
struct outer {
void f();
>From 17966e5a21421b9eea5168efa2fbe8ef75a16c3f Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Thu, 27 Nov 2025 19:28:00 +0900
Subject: [PATCH 6/6] add `isCompatibleWithMSVC(void)` and use it
---
clang/include/clang/Basic/LangOptions.h | 2 ++
clang/lib/Sema/SemaDeclCXX.cpp | 2 +-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index 8aa89d8c8c807..14a6c55c3f8f7 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -623,6 +623,8 @@ class LangOptions : public LangOptionsBase {
!ObjCSubscriptingLegacyRuntime;
}
+ bool isCompatibleWithMSVC() const { return MSCompatibilityVersion > 0; }
+
bool isCompatibleWithMSVC(MSVCMajorVersion MajorVersion) const {
return MSCompatibilityVersion >= MajorVersion * 100000U;
}
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 5f741166d0e29..f7b71cbb1bb20 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -6627,7 +6627,7 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) {
auto *Ctor = dyn_cast<CXXConstructorDecl>(MD);
if ((MD->isMoveAssignmentOperator() ||
(Ctor && Ctor->isMoveConstructor())) &&
- getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2010) &&
+ getLangOpts().isCompatibleWithMSVC() &&
!getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2015))
continue;
More information about the cfe-commits
mailing list