llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
27.82k stars 11.46k forks source link

DLL import/export and explicit instantiation #32336

Open zahiraam opened 7 years ago

zahiraam commented 7 years ago
Bugzilla Link 32989
Version unspecified
OS Windows NT
CC @DougGregor,@zmodem,@rnk,@zahiraam

Extended Description

ksh-3.2$ cat test.cpp
struct I;
template<typename T> struct __declspec(dllimport) X {
  void f(T *p) { p->i(); }
  void f();                 // f is now overloaded.
};
template void X<I>::f(I*);
ksh-3.2$

ksh-3.2$ which cl
c:/Program files (x86)/Microsoft Visual Studio 14.0/VC/BIN/amd64/cl.EXE

ksh-3.2$ cl -c -Zi test.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.00.24215.1 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

test.cpp

ksh-3.2$ clang -v
clang version 5.0.0 (cfe/trunk 302180)
Target: x86_64-pc-windows-msvc
Thread model: posix

ksh-3.2$ clang -c -g test.cpp
test.cpp:3:19: error: member access into incomplete type 'I'
  void f(T *p) { p->i(); }
                  ^
test.cpp:6:21: note: in instantiation of member function 'X<I>::f' requested here
template void X<I>::f(I*);
                    ^
test.cpp:1:8: note: forward declaration of 'I'
struct I;
       ^
1 error generated.
ksh-3.2$
zmodem commented 7 years ago

I think the issue is that we should treat explicit instantiations with dllimport as explicit instantiation declarations. Do we not already do that? For example, if I modify the original program like this, clang doesn't reject:

struct I; template struct X { void f(T p) { p->i(); } }; extern template void X::f(I);

I seem to remember that dllimport and dllexport have some of the effects of the 'extern' keyword.

Oh right, yes that was r270897. Sounds like we need to expand that.

I'll put this on my TODO list, but patches are also welcome :-)

rnk commented 7 years ago

I think the issue is that we should treat explicit instantiations with dllimport as explicit instantiation declarations. Do we not already do that? For example, if I modify the original program like this, clang doesn't reject:

struct I;
template<typename T> struct X {
  void f(T *p) { p->i(); }
};
extern template void X<I>::f(I*);

I seem to remember that dllimport and dllexport have some of the effects of the extern keyword.

zmodem commented 7 years ago

But can the user fix their code, or is this happening e.g. in a sytem header?

Clang doesn't promise to be bug-for-bug compatible with MSVC, and in this case I'm not sure what Clang is doing is wrong.

zahiraam commented 7 years ago

Yes this happens in user code that we don't have control over.

zmodem commented 7 years ago

Is this occurring in code that cannot be fixed?

Clang's behaviour seems reasonable here.

Is the void f(); // f is now overloaded line significant?