https://github.com/aganea created
https://github.com/llvm/llvm-project/pull/171628
Consider the following:
```
struct A {
__declspec(dllimport) __forceinline
static const int* foo() {
static constexpr int var = 42;
static constexpr const int* p = &var;
static_assert(*p == 42, "");
return p;
}
};
const int* (*pfoo)() = &A::foo;
int main() {
return pfoo() == A::foo();
}
```
With clang-cl, this generates an error:
```
>clang-cl /c C:\src\git\test\test.cpp
C:\src\git\test\test.cpp(5,37): error: constexpr variable 'p' must be
initialized by a constant expression
5 | static constexpr const int* p = &var;
| ^ ~~~~
C:\src\git\test\test.cpp(6,23): error: static assertion expression is not an
integral constant expression
6 | static_assert(*p == 42, "");
| ^~~~~~~~
C:\src\git\test\test.cpp(6,24): note: initializer of 'p' is not a constant
expression
6 | static_assert(*p == 42, "");
| ^
C:\src\git\test\test.cpp(5,37): note: declared here
5 | static constexpr const int* p = &var;
| ^
2 errors generated.
```
The problem here is that the static variable 'var' inherits the dllimport
attribute, and the const-init evaluation for 'p' is rejected because of the
dllimport attribute. MSVC cl is fine with the snipped above.
I think it's fine to accept the exemple above since the body of the function
will be discarded anyway; and the inlined version of the function will contain
a reference to the imported function-static symbol, like MSVC does:
```
> cl.exe /c test.cpp /Ox
...
> dumpbin /disasm test.obj
Microsoft (R) COFF/PE Dumper Version 14.44.35222.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file test.obj
File Type: COFF OBJECT
main:
0000000000000000: 48 83 EC 28 sub rsp,28h
0000000000000004: FF 15 00 00 00 00 call qword ptr
[?pfoo@@3P6APEBHXZEA]
000000000000000A: 48 8B 0D 00 00 00 mov rcx,qword ptr
[__imp_?p@?1??foo@A@@SAPEBHXZ@4QEBHEB]
00
0000000000000011: 33 D2 xor edx,edx
0000000000000013: 48 3B 01 cmp rax,qword ptr [rcx]
0000000000000016: 0F 94 C2 sete dl
0000000000000019: 8B C2 mov eax,edx
000000000000001B: 48 83 C4 28 add rsp,28h
000000000000001F: C3 ret
??__Epfoo@@YAXXZ (void __cdecl `dynamic initializer for 'pfoo''(void)):
0000000000000000: 48 8B 05 00 00 00 mov rax,qword ptr
[__imp_?foo@A@@SAPEBHXZ]
00
0000000000000007: 48 89 05 00 00 00 mov qword ptr
[?pfoo@@3P6APEBHXZEA],rax
00
000000000000000E: C3 ret
> clang-cl..exe /c test.cpp /Ox
> dumpbin /disasm test.obj
Microsoft (R) COFF/PE Dumper Version 14.44.35222.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file test.obj
File Type: COFF OBJECT
main:
0000000000000000: 48 83 EC 28 sub rsp,28h
0000000000000004: FF 15 00 00 00 00 call qword ptr
[?pfoo@@3P6APEBHXZEA]
000000000000000A: 31 C9 xor ecx,ecx
000000000000000C: 48 3B 05 00 00 00 cmp rax,qword ptr
[__imp_?var@?1??foo@A@@SAPEBHXZ@4HB]
00
0000000000000013: 0F 94 C1 sete cl
0000000000000016: 89 C8 mov eax,ecx
0000000000000018: 48 83 C4 28 add rsp,28h
000000000000001C: C3 ret
000000000000001D: 0F 1F 00 nop dword ptr [rax]
_GLOBAL__sub_I_test.cpp:
0000000000000020: 48 8B 05 00 00 00 mov rax,qword ptr
[__imp_?foo@A@@SAPEBHXZ]
00
0000000000000027: 48 89 05 00 00 00 mov qword ptr
[?pfoo@@3P6APEBHXZEA],rax
00
000000000000002E: C3 ret
```
>From 29817263e2e11c468089d742fd39179e78d4ca1a Mon Sep 17 00:00:00 2001
From: Alexandre Ganea <[email protected]>
Date: Tue, 9 Dec 2025 19:36:08 -0500
Subject: [PATCH 1/2] [SemaCXX] Fix static constexpr in dllimport function
---
clang/lib/AST/ExprConstant.cpp | 7 +++++--
clang/test/SemaCXX/dllimport.cpp | 22 ++++++++++++++++++++++
2 files changed, 27 insertions(+), 2 deletions(-)
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index d81496ffd74e0..e5ca6912ed566 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -2407,8 +2407,11 @@ static bool CheckLValueConstantExpression(EvalInfo
&Info, SourceLocation Loc,
return false;
// A dllimport variable never acts like a constant, unless we're
- // evaluating a value for use only in name mangling.
- if (!isForManglingOnly(Kind) && Var->hasAttr<DLLImportAttr>())
+ // evaluating a value for use only in name mangling, and unless we're a
+ // static local. For the latter case, we'd still need to evaluate the
+ // constant expression in case we're inside a (inlined) function.
+ if (!isForManglingOnly(Kind) && Var->hasAttr<DLLImportAttr>() &&
+ !Var->isStaticLocal())
// FIXME: Diagnostic!
return false;
diff --git a/clang/test/SemaCXX/dllimport.cpp b/clang/test/SemaCXX/dllimport.cpp
index b7a1a62b8725b..dafb12fab6888 100644
--- a/clang/test/SemaCXX/dllimport.cpp
+++ b/clang/test/SemaCXX/dllimport.cpp
@@ -1526,6 +1526,28 @@ template <typename T> struct __declspec(dllimport)
PartiallySpecializedClassTemp
template <typename T> struct ExpliciallySpecializedClassTemplate {};
template <> struct __declspec(dllimport)
ExpliciallySpecializedClassTemplate<int> { void f() {} };
+// Function-local static constexpr in dllimport function (or class).
+struct DLLImportFuncWithConstexprStatic {
+ __declspec(dllimport) static const int *func() {
+ // expected-warning@-1{{'dllimport' attribute ignored on inline function}}
+ static constexpr int value = 42;
+ static constexpr const int *p = &value;
+ static_assert(*p == 42, "");
+ return p;
+ }
+ __declspec(dllimport) __forceinline static const int *funcForceInline() {
+ // expected-warning@-1{{'dllimport' attribute ignored on inline function}}
+ static constexpr int value = 42;
+ static constexpr const int *p = &value;
+ static_assert(*p == 42, "");
+ return p;
+ }
+};
+const int* (*pFunc)() = &DLLImportFuncWithConstexprStatic::func;
+const int* (*pFuncForceInline)() =
&DLLImportFuncWithConstexprStatic::funcForceInline;
+bool UsedDLLImportFuncWithConstexprStatic() {
+ return pFunc() == DLLImportFuncWithConstexprStatic::func() &&
pFuncForceInline() == DLLImportFuncWithConstexprStatic::funcForceInline();
+}
//===----------------------------------------------------------------------===//
// Classes with template base classes
>From 17a28e40e670961fefc303603602687667b3a53e Mon Sep 17 00:00:00 2001
From: Alexandre Ganea <[email protected]>
Date: Wed, 10 Dec 2025 09:30:05 -0500
Subject: [PATCH 2/2] Fix tests
---
clang/test/SemaCXX/dllimport.cpp | 28 ++++++++++++++++++++--------
1 file changed, 20 insertions(+), 8 deletions(-)
diff --git a/clang/test/SemaCXX/dllimport.cpp b/clang/test/SemaCXX/dllimport.cpp
index dafb12fab6888..eaf217c8e2d3b 100644
--- a/clang/test/SemaCXX/dllimport.cpp
+++ b/clang/test/SemaCXX/dllimport.cpp
@@ -1528,26 +1528,38 @@ template <> struct __declspec(dllimport)
ExpliciallySpecializedClassTemplate<int
// Function-local static constexpr in dllimport function (or class).
struct DLLImportFuncWithConstexprStatic {
+#if defined(GNU)
+// expected-warning@+2{{'dllimport' attribute ignored on inline function}}
+#endif
__declspec(dllimport) static const int *func() {
- // expected-warning@-1{{'dllimport' attribute ignored on inline function}}
static constexpr int value = 42;
static constexpr const int *p = &value;
static_assert(*p == 42, "");
return p;
}
- __declspec(dllimport) __forceinline static const int *funcForceInline() {
- // expected-warning@-1{{'dllimport' attribute ignored on inline function}}
+};
+const int* (*pFunc)() = &DLLImportFuncWithConstexprStatic::func;
+bool UsedDLLImportFuncWithConstexprStatic() {
+ return pFunc() == DLLImportFuncWithConstexprStatic::func();
+}
+
+#if !defined(PS)
+struct DLLImportInlineFuncWithConstexprStatic {
+#if defined(GNU)
+ // expected-warning@+2{{'dllimport' attribute ignored on inline function}}
+#endif
+ __declspec(dllimport) __forceinline static const int* funcForceInline() {
static constexpr int value = 42;
- static constexpr const int *p = &value;
+ static constexpr const int* p = &value;
static_assert(*p == 42, "");
return p;
}
};
-const int* (*pFunc)() = &DLLImportFuncWithConstexprStatic::func;
-const int* (*pFuncForceInline)() =
&DLLImportFuncWithConstexprStatic::funcForceInline;
-bool UsedDLLImportFuncWithConstexprStatic() {
- return pFunc() == DLLImportFuncWithConstexprStatic::func() &&
pFuncForceInline() == DLLImportFuncWithConstexprStatic::funcForceInline();
+const int* (*pFuncForceInline)() =
&DLLImportInlineFuncWithConstexprStatic::funcForceInline;
+bool UsedDLLImportInlineFuncWithConstexprStatic() {
+ return pFuncForceInline() ==
DLLImportInlineFuncWithConstexprStatic::funcForceInline();
}
+#endif // !PS
//===----------------------------------------------------------------------===//
// Classes with template base classes
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits