Bug 9050 - [DR 147] Can't explicitly specialize C++ constructor templates
Summary: [DR 147] Can't explicitly specialize C++ constructor templates
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 3.2.1
: P3 normal
Target Milestone: 4.5.0
Assignee: Jason Merrill
URL:
Keywords: monitored, rejects-valid
: 10832 (view as bug list)
Depends on:
Blocks: 5023 10832 26988
  Show dependency treegraph
 
Reported: 2002-12-23 19:06 UTC by martin
Modified: 2014-02-16 13:16 UTC (History)
11 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail: 3.4.3, 4.1.2, 4.3.0, 4.4.0
Last reconfirmed: 2009-11-20 05:17:23


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description martin 2002-12-23 19:06:01 UTC
C++ function templates can be explicitly instantiated.
Constructors can be function templates.
So the following should compile 
(and indeed does with icc and Comeau C++)

struct Y
{
  template <typename T> Y (T);
  template <typename T> void foo (T);
};

template <> void Y::foo      (bool) { }
template <> void Y::foo<int> (int)  { }

template <>      Y::Y        (bool) { }
template <>      Y::Y<int>   (int)  { }


Explicit instantiation of Y::foo, 
but not Y::Y, is permitted.

g++ gives these errors:

(not only is g++ wrong to give an error,
but the error message below contains the nonsensical
"no member function `._0' declared")

constructor-explicit-instantiation-bug.cc:11: `Y' is not a template
constructor-explicit-instantiation-bug.cc:11: ISO C++ forbids declaration of `
   type name' with no type
constructor-explicit-instantiation-bug.cc:11: abstract declarator `int 
   (Y::)(int)' used as declaration
constructor-explicit-instantiation-bug.cc:11: no member function `._0' declared 
   in `Y'
constructor-explicit-instantiation-bug.cc:11: syntax error before `{' token

Release:
g++ 3.2.1

Environment:
Linux x86

How-To-Repeat:
Compile the provided fragment with "g++ -c"
Comment 1 Kriang Lerdsuwanakij 2002-12-25 00:00:37 UTC
State-Changed-From-To: open->analyzed
State-Changed-Why: Confirmed.
Comment 2 Andrew Pinski 2003-05-25 16:24:07 UTC
it still happens in the mainline (20030525) but it produces different error message:
[omni:~/src/gccPRs] pinskia% g++ pr9050.cc
pr9050.cc:11: error: expected unqualified-id
Comment 3 Volker Reichelt 2003-08-05 15:12:08 UTC
This seems to be related to PR 10832.
Comment 4 Volker Reichelt 2004-01-06 13:07:12 UTC
The error message on mainline now is:

bug.cc:11: error: `Y' is not a template
bug.cc:11: error: expected unqualified-id before "int"
bug.cc:11: error: expected `)' before "int"
bug.cc:11: error: expected `;' before "int"
Comment 5 Andrew Pinski 2004-06-05 18:13:32 UTC
*** Bug 10832 has been marked as a duplicate of this bug. ***
Comment 6 Chris Bowlby 2004-07-22 17:05:13 UTC
Hi All, 

 I've been working on a project for the last month or so and have ran into this 
bug under G++ 2.95.4. The code I have is different from the code above and is 
as follows:

test.hxx

template <class T> class Test {
 private:
  T *handle_object;

 public:

  Test(T * = NULL);
  Test(const Test<T> &);

  ~Test();

  bool operator==(const Test<T> &) const;
};

class MyTest;
typedef Test<MyTest> MyTestHandle;

Test.cxx:

template <class T> Test<T>::Test(T* th) {
 this->handle_object = th;

 if (this->handle_object != NULL) {
  this->handle_object->counter++;
 }
}

template <class T> Test<T>::Test(const Test<T> &source) {
 this->handle_object = source.handle_object;

 if (this->handle_object != NULL) {
  this->handle_object->counter++;
 }
}

template <class T> Test<T>::~Test() {
 if (this->handle_object != NULL && this->handle_object->counter != 0) {
  this->handle_object->counter--;
 }

 if (this->handle_object != NULL && this->handle_object->counter == 0) {
  delete this->handle_object;
  this->handle_object = NULL;
 }
}

template <class T> bool Test<T>::operator==(const Test<T> &source) const {
 return (this->handle_object == source->handle_object);
}

When I left it in this format I got this error:

test/libtest.a(MyBigTest.o): In function `MyBigTest::add(Test<MyTest> const &)':
/usr/local/include/stlport/stl/_construct.h:237: undefined reference to 
`Test<MyTest>::Test(Test<MyTest> const &)'
test/libtest.a(MyBigTest.o): In function `MyBigTest::remove(Test<MyTest> &)':
/usr/local/include/stlport/stl/_list.h:122: undefined reference to 
`Test<MyTest>::operator==(Test<MyTest> const &) const'
test/libtest.a(MyBigTest.o): In function `MyBigTest::remove(Test<MyTest> &)':
/usr/local/include/stlport/stl/_construct.h:360: undefined reference to 
`Test<MyTest>::~Test(void)'
test/libtest.a(MyBigTest.o): In function `_STL::allocator<Test<MyTest> 
>::~allocator(void)':
/usr/local/include/stlport/stl/_alloc.h
(.gnu.linkonce.t.clear__Q24_STLt10_List_base2Zt14Test1Z6MyTestZQ24_STLt9allocato
r1Zt14Test1Z6MyTest+0x26): undefined reference to `Test<MyTest>::~Test(void)'
*** Error code 1

Research showed that I needed to instantiate my template using:

template void Test<MyTest>();

 in the Test.cpp file so that it can create an instance in the libtest.a file, 
so that when I compile that into my app it would link properly. However, I now 
run into a compiler error (rather then a linking error) like this:

Test.cxx:52: `Test<MyTest>' specified as declarator-id
Test.cxx:52: two or more data types in declaration of `Test<MyTest>'
Test.cxx:52: non-template used as template
Test.cxx:52: confused by earlier errors, bailing out
*** Error code 1

 Which I believe is related to the issue above. I'm building under FreeBSD 4.10-
STABLE. Does anyone have a fix for this yet? or did I do something wrong?
Comment 7 Wolfgang Bangerth 2004-07-22 18:36:35 UTC
The problem in comment #6 has nothing to do with the rest of the 
PR. The syntax to explicitly instantiate the class is just completely 
bogus. It should read 
  template class Test<MyTest>; 
but there are more bugs (specificly: MyTest is only forward declared). 
 
The original problem of this PR persists as of now. 
 
W. 
Comment 8 Vlad Sharanhovich 2008-02-11 22:19:50 UTC
This bug is present in gcc 3.4.3. Was ever fixed or forgotten forever?
Comment 9 Manuel López-Ibáñez 2008-02-11 23:43:25 UTC
(In reply to comment #8)
> This bug is present in gcc 3.4.3. Was ever fixed or forgotten forever?

manuel@gcc12:~$ ~/132202/build/gcc/cc1plus --version
GNU C++ (GCC) version 4.3.0 20080209 (experimental) [trunk revision 132202] (x86_64-unknown-linux-gnu)
        compiled by GNU C version 4.3.0 20080209 (experimental) [trunk revision 132202], GMP version 4.2.2, MPFR version 2.3.0.
GGC heuristics: --param ggc-min-expand=30 --param ggc-min-heapsize=4096

manuel@gcc12:~$ ~/132202/build/gcc/cc1plus src/pr9050.C
 void Y::foo(T) [with T = bool] void Y::foo(T) [with T = int] Y::Y(T) [with T = bool] Y::Y(T) [with T = bool] Y::Y(T) [with T = bool]
src/pr9050.C: At global scope:
src/pr9050.C:11: error: ‘Y’ is not a template
src/pr9050.C:11: error: expected unqualified-id before ‘int’
src/pr9050.C:11: error: expected `)' before ‘int’

Not fixed.
Comment 10 Manuel López-Ibáñez 2008-10-26 22:01:26 UTC
It seems that the problem is cp_parser_template_id fails to parse Y<int> as a template-id because when it does a lookup it finds that Y is just a non-template class and concludes that Y<int> cannot be a template-id. This in turn makes cp_parser_class_name fail to parse Y<int>, which makes cp_parser_constructor_declarator_p return false.

No idea how this could be fixed...
Comment 11 Jason Merrill 2009-11-21 06:34:11 UTC
Subject: Bug 9050

Author: jason
Date: Sat Nov 21 06:33:56 2009
New Revision: 154403

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=154403
Log:
	PR c++/9050, DR 147, DR 318
	* parser.c (cp_parser_lookup_name): If the name matches the explicit
	class scope, we're naming the constructor.
	(cp_parser_constructor_declarator_p): Just use cp_parser_unqualified_id
	if we have a nested-name-specifier.
	(cp_parser_direct_declarator): Handle getting an overload set as a
	constructor declarator.
	(cp_parser_unqualified_id): Avoid looking up the constructor when
	naming the destructor.
	(cp_parser_diagnose_invalid_type_name): Give good
	diagnostic for improper use of constructor as template.
	* typeck.c (finish_class_member_access_expr): Give good diagnostic
	about calling constructor.

	* error.c (dump_aggr_type): Don't print A::A for injected-class-name.

Added:
    trunk/gcc/testsuite/g++.dg/template/ctor9.C
Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/error.c
    trunk/gcc/cp/parser.c
    trunk/gcc/cp/typeck.c
    trunk/gcc/testsuite/ChangeLog
    trunk/gcc/testsuite/g++.dg/lookup/name-clash4.C
    trunk/gcc/testsuite/g++.dg/tc1/dr147.C
    trunk/gcc/testsuite/g++.old-deja/g++.jason/temporary5.C
    trunk/gcc/testsuite/g++.old-deja/g++.pt/ctor2.C

Comment 12 Jason Merrill 2009-11-21 06:34:31 UTC
Fixed for 4.5.
Comment 13 Johannes Schaub 2012-04-01 14:03:40 UTC
Jason, does http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1435 not render the explicit specialization ill-formed for C++11TC1? It only allows a simple identifier, and not a template-id.
Comment 14 Johannes Schaub 2012-04-01 14:14:46 UTC
(In reply to comment #13)
> Jason, does http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1435
> not render the explicit specialization ill-formed for C++11TC1? It only allows
> a simple identifier, and not a template-id.

FWIW I don't like the resolution of that issue. For a qualified-id, the injected-class-name is an excellent way for us to know when and when not we name a constructor, and it is entirely based on name-lookup rules; I don't see the need to dictate that in clause 12. Only for an unqualified-id, we actually need the rule to know when we declare a constructor. The allowed decl-specifiers in a constructor declaration can be stated separately.
Comment 15 Jason Merrill 2012-04-02 05:41:08 UTC
(In reply to comment #14)

Good point, I've pointed out the problem with the proposed resolution.
Comment 16 Johannes Schaub 2012-04-02 07:43:23 UTC
(In reply to comment #15)
> (In reply to comment #14)
> 
> Good point, I've pointed out the problem with the proposed resolution.

Note that we currently have http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#581 open. 

Even when 12.1 would have allowed both the injected class name and it followed by template-arguments, the name lookup rules would never allow it to match the second condition because the injected class name would always have been translated to a name denoting the constructor instead of the class.

So ultimately, 12.1 allowing the injected class name followed by template arguments could only be used in an unqualified-id constructor declaration in C++03.
Comment 17 Jackie Rosen 2014-02-16 13:16:06 UTC Comment hidden (spam)