Bug 57728 - Explicit template instantiation with defaulted method causes missing symbol
Summary: Explicit template instantiation with defaulted method causes missing symbol
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.8.1
: P3 normal
Target Milestone: 6.3
Assignee: Not yet assigned to anyone
URL:
Keywords: wrong-code
: 51629 58078 60796 67632 76521 (view as bug list)
Depends on:
Blocks:
 
Reported: 2013-06-26 14:42 UTC by Bruce Merry
Modified: 2018-04-06 17:20 UTC (History)
5 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2013-06-26 00:00:00


Attachments
Minimal test case (3.02 KB, application/zip)
2013-06-26 14:42 UTC, Bruce Merry
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Bruce Merry 2013-06-26 14:42:58 UTC
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
Comment 1 Jonathan Wakely 2013-06-26 15:42:38 UTC
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.
Comment 2 Bruce Merry 2013-06-26 15:46:23 UTC
(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.
Comment 3 Jonathan Wakely 2013-06-26 15:49:52 UTC
It's a bug
Comment 4 Paolo Carlini 2013-08-04 12:03:21 UTC
*** Bug 58078 has been marked as a duplicate of this bug. ***
Comment 5 Jonathan Wakely 2016-08-15 11:09:33 UTC
*** Bug 76521 has been marked as a duplicate of this bug. ***
Comment 6 Jonathan Wakely 2016-08-15 11:12:09 UTC
*** Bug 51629 has been marked as a duplicate of this bug. ***
Comment 7 Jonathan Wakely 2016-08-15 11:14:08 UTC
Related to (and maybe a dup of) PR 60796

Also https://llvm.org/bugs/show_bug.cgi?id=22763
Comment 8 Jason Merrill 2016-08-26 13:37:16 UTC
*** Bug 60796 has been marked as a duplicate of this bug. ***
Comment 9 Jason Merrill 2016-08-26 15:11:22 UTC
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
Comment 10 mwahab 2016-08-30 12:07:10 UTC
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
Comment 11 Jason Merrill 2016-09-01 01:56:21 UTC
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
Comment 12 Jason Merrill 2016-12-06 18:52:09 UTC
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
Comment 13 Jens Maurer 2017-11-02 19:40:44 UTC
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.
Comment 14 Jonathan Wakely 2018-04-04 21:11:12 UTC
*** Bug 67632 has been marked as a duplicate of this bug. ***
Comment 15 Jonathan Wakely 2018-04-04 21:17:55 UTC
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.
Comment 16 Jason Merrill 2018-04-06 17:20:58 UTC
Yes.