[clang][ExprConstant] Fix error on static constexpr symbol in dllimport function (#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.
```
MSVC cl.exe does not generate such error with the same snippet.
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.
I think it's fine to accept the example 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
```
Thanks to @jfmarquis for crafting a reproducer.