Microsoft allows the support of ‘constexpr’ with ‘declspec(dllimport) starting
from VS2017 15.u update 4. See Constexpr doesn't support declspec(dllimport)
in VS2017 15.8 - Visual Studio Feedback.
Let’s consider this example.
lib.cpp:
declspec(dllexport) int val=12;
declspec(dllexport)
int next(int n)
{
return n + 1;
}
app1.cpp:
#include <iostream>
extern int __declspec(dllimport) next(int n);
int main () {
extern int __declspec(dllimport) val; constexpr int& val_ref = val; int i = next(val_ref); std::cout << "i: " << i << std::endl; return i;
}
Compiling this will give the expected output.
$ cl /LD lib.cpp
$ cl /EHsc app1.cpp /link lib.lib
$ ./app1.exe
i: 13
The Intel compiler has the same behavior than MSVC.
Clang compiles this test case with this error:
error: constexpr variable 'val_ref' must be initialized by a constant
expression constexpr int& val_ref = val; ^ ~~~
1 error generated.
I think this should be fixed. This patch is doing that.
Now let’s look now at this example (dllimport at TU scope level):
app2.cpp:
#include <iostream>
extern int declspec(dllimport) next(int n);
extern int declspec(dllimport) val;
constexpr int& val_ref = val;
int main () {
int i = next(val_ref); std::cout << "i: " << i << std::endl; return i;
}
Compiling this will result into an unresolved symbol:
$ cl /EHsc app2.cpp /link lib.lib
app2.obj : error LNK2001: unresolved external symbol "int val" (?val@@3HA)
app2.exe : fatal error LNK1120: 1 unresolved externals
ICL and clang generate the same error.
These are the symols generated for all 3 compilers:
ICL:
003 00000000 UNDEF notype External | imp_?next@@YAHH@Z (declspec(dllimport) int cdecl next(int))
004 00000000 UNDEF notype External | imp_?val@@3HA (declspec(dllimport) int val)
00C 00000000 SECT4 notype External | ?val_ref@@3AEAHEA (int & val_ref)
00D 00000000 UNDEF notype External | ?val@@3HA (int val)
MSVC:
00A 00000000 UNDEF notype External | imp_?next@@YAHH@Z (declspec(dllimport) int cdecl next(int))
015 00000000 SECT6 notype Static | ?val_ref@@3AEAHEA (int & val_ref)
The symbols generated by ICL seem to be what's expected. MSVC should be generating an "__imp_?val" symbol.
Clang with the change in this patch is generating the expected symbols:
010 00000000 UNDEF notype External | imp_?val@@3HA (declspec(dllimport) int val)
011 00000000 UNDEF notype External | imp_?next@@YAHH@Z (declspec(dllimport) int __cdecl next(int))
012 00000000 SECT5 notype External | ?val_ref@@3AEAHEA (int & val_ref)
013 00000000 UNDEF notype External | ?val@@3HA (int val)
Fixes issue https://github.com/llvm/llvm-project/issues/53182
Differential Revision: https://reviews.llvm.org/D137107
I don't really like the copy-pasted bits here.