-
Notifications
You must be signed in to change notification settings - Fork 14.7k
Description
Here's a rather obscure issue that works with header files but not with modules. Take the following code (complete set of files attached):
// a.ccm
module;
export module M;
// Declare and export a template class
export template <typename T> struct S {
S();
};
// Say that S<int> is instantiated somewhere else
extern template struct S<int>;
// a.cc
module;
module M : impl;
import M;
// Implement the constructor
template <typename T>
S<T>::S() {}
// Do the instantiation of S<int> promised in a.ccm
template struct S<int>;
// b.cc
module;
export module b;
import M;
int main() {
S<int> s;
}
The important part for this bug report is the extern template struct S<int>;
declaration in a.ccm
. It tells the compiler that some other translation unit provides an explicit instantiation of the template, which here we do in a.cc
: template struct S<int>;
. These sorts of declarations are optimizations in a header-based system: They tell compilers not to bother with implicit instantiations of certain templates because an explicit specialization is provided elsewhere. These optimizations are useful if, for example, the body of the template class had a bunch of long implementations of member functions.
Yet, something is going wrong with modules. When compiling these files, I get the following error message:
/usr/bin/ld: CMakeFiles/test.dir/b.cc.o: in function `main':
b.pcm:(.text+0xd): undefined reference to `S@M<int>::S()'
In other words, the existence of the extern template
declaration in a.ccm
resulted in the compiler not doing the explicit instantiation in a.cc
at all, even though the code explicitly says to do so. This is clearly a bug. Removing the extern template
line in a.ccm
makes the linker error go away, but that's of course not the right solution :-)
Compiler version: 20.1.7. Complete test case: bug.tar.gz
@ChuanqiXu9 FYI
(This PR describes the issue referenced in dealii/dealii#18500. It is part of dealii/dealii#18071)