From abd5730b2df531b752b1447e05f1c947f5ecdeb2 Mon Sep 17 00:00:00 2001
From: Jason Merrill <jason@redhat.com>
Date: Sat, 21 Nov 2009 01:33:56 -0500
Subject: [PATCH] PR c++/9050, DR 147, DR 318

	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.

From-SVN: r154403
---
 gcc/cp/ChangeLog                              |  18 +++
 gcc/cp/error.c                                |   9 +-
 gcc/cp/parser.c                               | 119 ++++++++++++------
 gcc/cp/typeck.c                               |   8 ++
 gcc/testsuite/ChangeLog                       |   9 ++
 gcc/testsuite/g++.dg/lookup/name-clash4.C     |   2 +-
 gcc/testsuite/g++.dg/tc1/dr147.C              |   4 +-
 gcc/testsuite/g++.dg/template/ctor9.C         |   9 ++
 .../g++.old-deja/g++.jason/temporary5.C       |   8 +-
 gcc/testsuite/g++.old-deja/g++.pt/ctor2.C     |   2 +-
 10 files changed, 141 insertions(+), 47 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/ctor9.C

diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 520262e21fe0..b9f1cbebbfbd 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,21 @@
+2009-11-20  Jason Merrill  <jason@redhat.com>
+
+	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.
+
 2009-11-20  Simon Martin  <simartin@users.sourceforge.net>
 
 	PR c++/38646
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index a424299627e5..e0e5ae52ceb7 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -568,10 +568,11 @@ dump_aggr_type (tree t, int flags)
     {
       typdef = !DECL_ARTIFICIAL (name);
 
-      if (typdef
-	  && ((flags & TFF_CHASE_TYPEDEF)
-	      || (!flag_pretty_templates && DECL_LANG_SPECIFIC (name)
-		  && DECL_TEMPLATE_INFO (name))))
+      if ((typdef
+	   && ((flags & TFF_CHASE_TYPEDEF)
+	       || (!flag_pretty_templates && DECL_LANG_SPECIFIC (name)
+		   && DECL_TEMPLATE_INFO (name))))
+	  || DECL_SELF_REFERENCE_P (name))
 	{
 	  t = TYPE_MAIN_VARIANT (t);
 	  name = TYPE_NAME (t);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 284d16700339..c7560a872b4e 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -2400,6 +2400,12 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser,
       if (TREE_CODE (parser->scope) == NAMESPACE_DECL)
 	error_at (location, "%qE in namespace %qE does not name a type",
 		  id, parser->scope);
+      else if (CLASS_TYPE_P (parser->scope)
+	       && constructor_name_p (id, parser->scope)
+	       && cp_lexer_next_token_is (parser->lexer, CPP_LESS))
+	/* A<T>::A<T>() */
+	error_at (location, "invalid use of constructor %<%T::%E%> as "
+		  "template", parser->scope, id);
       else if (TYPE_P (parser->scope)
 	       && dependent_scope_p (parser->scope))
 	error_at (location, "need %<typename%> before %<%T::%E%> because "
@@ -3890,7 +3896,7 @@ cp_parser_unqualified_id (cp_parser* parser,
 	if (scope
 	    && token->type == CPP_NAME
 	    && (cp_lexer_peek_nth_token (parser->lexer, 2)->type
-		== CPP_OPEN_PAREN)
+		!= CPP_LESS)
 	    && constructor_name_p (token->u.value, scope))
 	  {
 	    cp_lexer_consume_token (parser->lexer);
@@ -3898,7 +3904,11 @@ cp_parser_unqualified_id (cp_parser* parser,
 	  }
 
 	/* If there was an explicit qualification (S::~T), first look
-	   in the scope given by the qualification (i.e., S).  */
+	   in the scope given by the qualification (i.e., S).
+
+	   Note: in the calls to cp_parser_class_name below we pretend that
+	   the lookup had an explicit 'class' tag so that lookup finds the
+	   injected-class-name rather than the constructor.  */
 	done = false;
 	type_decl = NULL_TREE;
 	if (scope)
@@ -3907,7 +3917,7 @@ cp_parser_unqualified_id (cp_parser* parser,
 	    type_decl = cp_parser_class_name (parser,
 					      /*typename_keyword_p=*/false,
 					      /*template_keyword_p=*/false,
-					      none_type,
+					      class_type,
 					      /*check_dependency=*/false,
 					      /*class_head_p=*/false,
 					      declarator_p);
@@ -3925,7 +3935,7 @@ cp_parser_unqualified_id (cp_parser* parser,
 	      = cp_parser_class_name (parser,
 				      /*typename_keyword_p=*/false,
 				      /*template_keyword_p=*/false,
-				      none_type,
+				      class_type,
 				      /*check_dependency=*/false,
 				      /*class_head_p=*/false,
 				      declarator_p);
@@ -3943,7 +3953,7 @@ cp_parser_unqualified_id (cp_parser* parser,
 	      = cp_parser_class_name (parser,
 				      /*typename_keyword_p=*/false,
 				      /*template_keyword_p=*/false,
-				      none_type,
+				      class_type,
 				      /*check_dependency=*/false,
 				      /*class_head_p=*/false,
 				      declarator_p);
@@ -3962,7 +3972,7 @@ cp_parser_unqualified_id (cp_parser* parser,
 	      = cp_parser_class_name (parser,
 				      /*typename_keyword_p=*/false,
 				      /*template_keyword_p=*/false,
-				      none_type,
+				      class_type,
 				      /*check_dependency=*/false,
 				      /*class_head_p=*/false,
 				      declarator_p);
@@ -14275,6 +14285,10 @@ cp_parser_direct_declarator (cp_parser* parser,
 			unqualified_name = constructor_name (class_type);
 			sfk = sfk_constructor;
 		      }
+		    else if (is_overloaded_fn (unqualified_name)
+			     && DECL_CONSTRUCTOR_P (get_first_fn
+						    (unqualified_name)))
+		      sfk = sfk_constructor;
 
 		    if (ctor_dtor_or_conv_p && sfk != sfk_none)
 		      *ctor_dtor_or_conv_p = -1;
@@ -17969,6 +17983,26 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
 	     lookup_member, we must enter the scope here.  */
 	  if (dependent_p)
 	    pushed_scope = push_scope (parser->scope);
+
+	  /* 3.4.3.1: In a lookup in which the constructor is an acceptable
+	     lookup result and the nested-name-specifier nominates a class C:
+	       * if the name specified after the nested-name-specifier, when
+	       looked up in C, is the injected-class-name of C (Clause 9), or
+	       * if the name specified after the nested-name-specifier is the
+	       same as the identifier or the simple-template-id's template-
+	       name in the last component of the nested-name-specifier,
+	     the name is instead considered to name the constructor of
+	     class C. [ Note: for example, the constructor is not an
+	     acceptable lookup result in an elaborated-type-specifier so
+	     the constructor would not be used in place of the
+	     injected-class-name. --end note ] Such a constructor name
+	     shall be used only in the declarator-id of a declaration that
+	     names a constructor or in a using-declaration.  */
+	  if (tag_type == none_type
+	      && CLASS_TYPE_P (parser->scope)
+	      && constructor_name_p (name, parser->scope))
+	    name = ctor_identifier;
+
 	  /* If the PARSER->SCOPE is a template specialization, it
 	     may be instantiated during name lookup.  In that case,
 	     errors may be issued.  Even if we rollback the current
@@ -18320,8 +18354,7 @@ static bool
 cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
 {
   bool constructor_p;
-  tree type_decl = NULL_TREE;
-  bool nested_name_p;
+  tree nested_name_specifier;
   cp_token *next_token;
 
   /* The common case is that this is not a constructor declarator, so
@@ -18347,34 +18380,48 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
   cp_parser_global_scope_opt (parser,
 			      /*current_scope_valid_p=*/false);
   /* Look for the nested-name-specifier.  */
-  nested_name_p
+  nested_name_specifier
     = (cp_parser_nested_name_specifier_opt (parser,
 					    /*typename_keyword_p=*/false,
 					    /*check_dependency_p=*/false,
 					    /*type_p=*/false,
-					    /*is_declaration=*/false)
-       != NULL_TREE);
+					    /*is_declaration=*/false));
   /* Outside of a class-specifier, there must be a
      nested-name-specifier.  */
-  if (!nested_name_p &&
+  if (!nested_name_specifier &&
       (!at_class_scope_p () || !TYPE_BEING_DEFINED (current_class_type)
        || friend_p))
     constructor_p = false;
+  else if (nested_name_specifier == error_mark_node)
+    constructor_p = false;
+
+  /* If we have a class scope, this is easy; DR 147 says that S::S always
+     names the constructor, and no other qualified name could.  */
+  if (constructor_p && nested_name_specifier
+      && TYPE_P (nested_name_specifier))
+    {
+      tree id = cp_parser_unqualified_id (parser,
+					  /*template_keyword_p=*/false,
+					  /*check_dependency_p=*/false,
+					  /*declarator_p=*/true,
+					  /*optional_p=*/false);
+      if (is_overloaded_fn (id))
+	id = DECL_NAME (get_first_fn (id));
+      if (!constructor_name_p (id, nested_name_specifier))
+	constructor_p = false;
+    }
   /* If we still think that this might be a constructor-declarator,
      look for a class-name.  */
-  if (constructor_p)
+  else if (constructor_p)
     {
       /* If we have:
 
-	   template <typename T> struct S { S(); };
-	   template <typename T> S<T>::S ();
-
-	 we must recognize that the nested `S' names a class.
-	 Similarly, for:
+	   template <typename T> struct S {
+	     S();
+	   };
 
-	   template <typename T> S<T>::S<T> ();
-
-	 we must recognize that the nested `S' names a template.  */
+	 we must recognize that the nested `S' names a class.  */
+      tree type_decl;
       type_decl = cp_parser_class_name (parser,
 					/*typename_keyword_p=*/false,
 					/*template_keyword_p=*/false,
@@ -18384,22 +18431,23 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
 					/*is_declaration=*/false);
       /* If there was no class-name, then this is not a constructor.  */
       constructor_p = !cp_parser_error_occurred (parser);
-    }
 
-  /* If we're still considering a constructor, we have to see a `(',
-     to begin the parameter-declaration-clause, followed by either a
-     `)', an `...', or a decl-specifier.  We need to check for a
-     type-specifier to avoid being fooled into thinking that:
+      /* If we're still considering a constructor, we have to see a `(',
+	 to begin the parameter-declaration-clause, followed by either a
+	 `)', an `...', or a decl-specifier.  We need to check for a
+	 type-specifier to avoid being fooled into thinking that:
 
-       S::S (f) (int);
+	   S (f) (int);
 
-     is a constructor.  (It is actually a function named `f' that
-     takes one parameter (of type `int') and returns a value of type
-     `S::S'.  */
-  if (constructor_p
-      && cp_parser_require (parser, CPP_OPEN_PAREN, "%<(%>"))
-    {
-      if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN)
+	 is a constructor.  (It is actually a function named `f' that
+	 takes one parameter (of type `int') and returns a value of type
+	 `S'.  */
+      if (constructor_p
+	  && !cp_parser_require (parser, CPP_OPEN_PAREN, "%<(%>"))
+	constructor_p = false;
+
+      if (constructor_p
+	  && cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN)
 	  && cp_lexer_next_token_is_not (parser->lexer, CPP_ELLIPSIS)
 	  /* A parameter declaration begins with a decl-specifier,
 	     which is either the "attribute" keyword, a storage class
@@ -18454,8 +18502,7 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
 	  constructor_p = !cp_parser_error_occurred (parser);
 	}
     }
-  else
-    constructor_p = false;
+
   /* We did not really want to consume any tokens.  */
   cp_parser_abort_tentative_parse (parser);
 
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 8685530a4ddd..307825f65160 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -2429,6 +2429,14 @@ finish_class_member_access_expr (tree object, tree name, bool template_p,
 	  gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE
 		      || TREE_CODE (name) == BIT_NOT_EXPR);
 
+	  if (constructor_name_p (name, scope))
+	    {
+	      if (complain & tf_error)
+		error ("cannot call constructor %<%T::%D%> directly",
+		       scope, name);
+	      return error_mark_node;
+	    }
+
 	  /* Find the base of OBJECT_TYPE corresponding to SCOPE.  */
 	  access_path = lookup_base (object_type, scope, ba_check, NULL);
 	  if (access_path == error_mark_node)
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index bb722a77ac3d..0c067501f1a4 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,12 @@
+2009-11-20  Jason Merrill  <jason@redhat.com>
+
+	PR c++/9050, DR 147, DR 318
+	* g++.dg/template/ctor9.C: New.
+	* g++.dg/tc1/dr147.C: Remove xfails.
+	* g++.dg/lookup/name-clash4.C: Adjust.
+	* g++.old-deja/g++.jason/temporary5.C: Adjust.
+	* g++.old-deja/g++.pt/ctor2.C: Adjust.
+
 2009-11-21  Jakub Jelinek  <jakub@redhat.com>
 
 	PR tree-optimization/42078
diff --git a/gcc/testsuite/g++.dg/lookup/name-clash4.C b/gcc/testsuite/g++.dg/lookup/name-clash4.C
index d4ff55133935..d6c6d97bbc13 100644
--- a/gcc/testsuite/g++.dg/lookup/name-clash4.C
+++ b/gcc/testsuite/g++.dg/lookup/name-clash4.C
@@ -9,4 +9,4 @@ struct A
     template<int> struct A {};	// { dg-error "same name" }
 };
 
-A::A<0> a;			// { dg-error "not a template" }
+A::A<0> a;	// { dg-error "not a template|invalid use of constructor" }
diff --git a/gcc/testsuite/g++.dg/tc1/dr147.C b/gcc/testsuite/g++.dg/tc1/dr147.C
index 26ac6a60eccc..9c90d982f5f6 100644
--- a/gcc/testsuite/g++.dg/tc1/dr147.C
+++ b/gcc/testsuite/g++.dg/tc1/dr147.C
@@ -11,7 +11,7 @@ A::A() { }
 B::B() { }
 
 B::A ba;
-A::A a; // { dg-error "" "the injected-class-name can never be found through qualified lookup" { xfail *-*-* } }
+A::A a; // { dg-error "" "the injected-class-name can never be found through qualified lookup" }
 
 }
 
@@ -26,6 +26,6 @@ template <class T> struct A {
   template <class T2> A(T2);
   static A x;
 };
-template<> A<int>::A<int>(A<int>::x);  // { dg-error "" "this is an invalid declaration of the constructor" { xfail *-*-* } }
+template<> A<int>::A<int>(A<int>::x);  // { dg-error "" "this is an invalid declaration of the constructor" }
 
 }
diff --git a/gcc/testsuite/g++.dg/template/ctor9.C b/gcc/testsuite/g++.dg/template/ctor9.C
new file mode 100644
index 000000000000..819ca1c94010
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/ctor9.C
@@ -0,0 +1,9 @@
+// PR c++/9050, DR 147, 318
+
+struct Y
+{
+  template <typename T> Y (T);
+  template <typename T> void foo (T);
+};
+
+template <>      Y::Y<int>   (int)  { }
diff --git a/gcc/testsuite/g++.old-deja/g++.jason/temporary5.C b/gcc/testsuite/g++.old-deja/g++.jason/temporary5.C
index d233fa9b3ad6..eef2e200539c 100644
--- a/gcc/testsuite/g++.old-deja/g++.jason/temporary5.C
+++ b/gcc/testsuite/g++.old-deja/g++.jason/temporary5.C
@@ -1,6 +1,6 @@
-// { dg-do run  }
 // PRMS Id: 6604
-// Bug: Scoped constructor call is not properly recognized as a functional cast
+// Old bug: Scoped constructor call is not properly recognized as a functional cast
+// But after DR 147 A::A() is a constructor call, not a functional cast.
 
 int c;
 
@@ -12,6 +12,8 @@ struct A {
 
 int main ()
 {
-  A::A();
+  A a;
+  a.A::A();			// { dg-error "" }
+  A::A();			// { dg-error "" }
   return c;
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/ctor2.C b/gcc/testsuite/g++.old-deja/g++.pt/ctor2.C
index 46039ace8172..802c2a4a446e 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/ctor2.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/ctor2.C
@@ -10,4 +10,4 @@ struct A {
 template <class T>
 A<T>::A<T>()   // { dg-error "invalid use of constructor|qualified name" }
 {
-}
+} // { dg-error "end of input" }
-- 
GitLab