Created attachment 30378 [details] Minimal test case I don't claim to fully understand all the intricies of C++11, but the following smells fishy to me. I am using a combination of features: 1. The = default syntax to restore implicit constructors/assignments that were otherwise hidden (e.g. default constructor when there are no user-defined constructors), in a templated class. 2. "extern template" in the header to suppress instantiation of a specific instance, with an explicit instantiation in one translation unit. In some cases (I assume depending on compiler eliding) this causes a link-time error for the defaulted constructor. I have attached a minimal test case. I don't know whether there is supposed to be a symbol or whether the compiler is supposed to inline the default implementation, but currently there is a mismatch. System information: Ubuntu 12.04 with gcc version 4.8.1 (Ubuntu 4.8.1-2ubuntu1~12.04) Output (there's a more detailed log in the attachment with -v -save-temps): g++-4.8 -std=c++11 -c defaulted.cpp g++-4.8 -std=c++11 -c impl.cpp g++-4.8 -std=c++11 -o defaulted defaulted.o impl.o defaulted.o: In function `main': defaulted.cpp:(.text+0x10): undefined reference to `A<int>::A()' collect2: error: ld returned 1 exit status make: *** [defaulted] Error 1
The explicit instantiation declaration suppresses the definition of A<int>::A() in defaulted.o, but the explicit instantiation definition doesn't cause that symbol to be emitted in impl.o, so when that constructor is not inlined there is no definition. As a single file: template<typename T> struct A { T x; A() = default; A(const A &other) = delete; }; extern template class A<int>; int main() { A<int> a; } This compiles with clang but not G++ because Clang doesn't create a reference to A<int>::A() from main(), so it doesn't matter that the explicit instantiation is not defined in the program.
(In reply to Jonathan Wakely from comment #1) > The explicit instantiation declaration suppresses the definition of > A<int>::A() in defaulted.o, but the explicit instantiation definition > doesn't cause that symbol to be emitted in impl.o, so when that constructor > is not inlined there is no definition. That's more or less what I figured was happening. Can you clarify whether you think this a GCC bug or just me misunderstanding the language? Thanks.
It's a bug
*** Bug 58078 has been marked as a duplicate of this bug. ***
*** Bug 76521 has been marked as a duplicate of this bug. ***
*** Bug 51629 has been marked as a duplicate of this bug. ***
Related to (and maybe a dup of) PR 60796 Also https://llvm.org/bugs/show_bug.cgi?id=22763
*** Bug 60796 has been marked as a duplicate of this bug. ***
Author: jason Date: Fri Aug 26 15:10:51 2016 New Revision: 239782 URL: https://gcc.gnu.org/viewcvs?rev=239782&root=gcc&view=rev Log: PR c++/57728 - explicit instantiation and defaulted functions * pt.c (do_type_instantiation): Don't mess with non-user-provided member functions. Added: trunk/gcc/testsuite/g++.dg/cpp0x/explicit11.C trunk/gcc/testsuite/g++.dg/cpp0x/explicit12.C Modified: trunk/gcc/cp/ChangeLog trunk/gcc/cp/class.c trunk/gcc/cp/pt.c
For aarch64 and arm, the new test g++.dg/cpp0x/explicit12.C shows as UNRESOLVED and the log complain about output files not existing. The test has { dg-do link .. } and { dg-final { scan-assembler-not .. } } but dg-do link doesn't seem to preserve the assembler files. Was the test intended to have a { dg-options "-save-temps" } set? Matthew
Author: jason Date: Thu Sep 1 01:55:47 2016 New Revision: 239913 URL: https://gcc.gnu.org/viewcvs?rev=239913&root=gcc&view=rev Log: PR c++/57728 - adjust testcase * g++.dg/cpp0x/explicit12.C: Add -save-temps. Modified: trunk/gcc/testsuite/g++.dg/cpp0x/explicit12.C
Author: jason Date: Tue Dec 6 18:51:37 2016 New Revision: 243311 URL: https://gcc.gnu.org/viewcvs?rev=243311&root=gcc&view=rev Log: PR c++/57728 - explicit instantiation and defaulted functions * pt.c (do_type_instantiation): Don't mess with non-user-provided member functions. Added: branches/gcc-6-branch/gcc/testsuite/g++.dg/cpp0x/explicit12.C Modified: branches/gcc-6-branch/gcc/cp/ChangeLog branches/gcc-6-branch/gcc/cp/class.c branches/gcc-6-branch/gcc/cp/pt.c
This bug saw its last activity nearly a year ago, with patches from Jason applied, but the issue does not seem to be fixed in its entirety (using gcc 7.2). Specifically, this translation unit: template<class T> struct C { C() = default; void f() { } int i = 5; }; template class C<int>; causes C<int>::f() to be defined, but the defaulted constructor of C<int> is not defined. (Replacing "= default" with "{}" causes definition of the C<int> constructor.) $ nm -C x.o 0000000000000000 W C<int>::f() The current behavior is obviously not what we want if we choose to use explicit instantiations.
*** Bug 67632 has been marked as a duplicate of this bug. ***
Jens, see the discussion in https://bugs.llvm.org/show_bug.cgi?id=22763 Jason, should this be closed as FIXED for 6.3 and up? I believe what Jens observes is the intended behaviour of GCC and Clang now.
Yes.