Commit abd5730b by Jason Merrill Committed by Jason Merrill

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
parent 42a06e46
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> 2009-11-20 Simon Martin <simartin@users.sourceforge.net>
PR c++/38646 PR c++/38646
......
...@@ -568,10 +568,11 @@ dump_aggr_type (tree t, int flags) ...@@ -568,10 +568,11 @@ dump_aggr_type (tree t, int flags)
{ {
typdef = !DECL_ARTIFICIAL (name); typdef = !DECL_ARTIFICIAL (name);
if (typdef if ((typdef
&& ((flags & TFF_CHASE_TYPEDEF) && ((flags & TFF_CHASE_TYPEDEF)
|| (!flag_pretty_templates && DECL_LANG_SPECIFIC (name) || (!flag_pretty_templates && DECL_LANG_SPECIFIC (name)
&& DECL_TEMPLATE_INFO (name)))) && DECL_TEMPLATE_INFO (name))))
|| DECL_SELF_REFERENCE_P (name))
{ {
t = TYPE_MAIN_VARIANT (t); t = TYPE_MAIN_VARIANT (t);
name = TYPE_NAME (t); name = TYPE_NAME (t);
......
...@@ -2400,6 +2400,12 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, ...@@ -2400,6 +2400,12 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser,
if (TREE_CODE (parser->scope) == NAMESPACE_DECL) if (TREE_CODE (parser->scope) == NAMESPACE_DECL)
error_at (location, "%qE in namespace %qE does not name a type", error_at (location, "%qE in namespace %qE does not name a type",
id, parser->scope); 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) else if (TYPE_P (parser->scope)
&& dependent_scope_p (parser->scope)) && dependent_scope_p (parser->scope))
error_at (location, "need %<typename%> before %<%T::%E%> because " error_at (location, "need %<typename%> before %<%T::%E%> because "
...@@ -3890,7 +3896,7 @@ cp_parser_unqualified_id (cp_parser* parser, ...@@ -3890,7 +3896,7 @@ cp_parser_unqualified_id (cp_parser* parser,
if (scope if (scope
&& token->type == CPP_NAME && token->type == CPP_NAME
&& (cp_lexer_peek_nth_token (parser->lexer, 2)->type && (cp_lexer_peek_nth_token (parser->lexer, 2)->type
== CPP_OPEN_PAREN) != CPP_LESS)
&& constructor_name_p (token->u.value, scope)) && constructor_name_p (token->u.value, scope))
{ {
cp_lexer_consume_token (parser->lexer); cp_lexer_consume_token (parser->lexer);
...@@ -3898,7 +3904,11 @@ cp_parser_unqualified_id (cp_parser* parser, ...@@ -3898,7 +3904,11 @@ cp_parser_unqualified_id (cp_parser* parser,
} }
/* If there was an explicit qualification (S::~T), first look /* 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; done = false;
type_decl = NULL_TREE; type_decl = NULL_TREE;
if (scope) if (scope)
...@@ -3907,7 +3917,7 @@ cp_parser_unqualified_id (cp_parser* parser, ...@@ -3907,7 +3917,7 @@ cp_parser_unqualified_id (cp_parser* parser,
type_decl = cp_parser_class_name (parser, type_decl = cp_parser_class_name (parser,
/*typename_keyword_p=*/false, /*typename_keyword_p=*/false,
/*template_keyword_p=*/false, /*template_keyword_p=*/false,
none_type, class_type,
/*check_dependency=*/false, /*check_dependency=*/false,
/*class_head_p=*/false, /*class_head_p=*/false,
declarator_p); declarator_p);
...@@ -3925,7 +3935,7 @@ cp_parser_unqualified_id (cp_parser* parser, ...@@ -3925,7 +3935,7 @@ cp_parser_unqualified_id (cp_parser* parser,
= cp_parser_class_name (parser, = cp_parser_class_name (parser,
/*typename_keyword_p=*/false, /*typename_keyword_p=*/false,
/*template_keyword_p=*/false, /*template_keyword_p=*/false,
none_type, class_type,
/*check_dependency=*/false, /*check_dependency=*/false,
/*class_head_p=*/false, /*class_head_p=*/false,
declarator_p); declarator_p);
...@@ -3943,7 +3953,7 @@ cp_parser_unqualified_id (cp_parser* parser, ...@@ -3943,7 +3953,7 @@ cp_parser_unqualified_id (cp_parser* parser,
= cp_parser_class_name (parser, = cp_parser_class_name (parser,
/*typename_keyword_p=*/false, /*typename_keyword_p=*/false,
/*template_keyword_p=*/false, /*template_keyword_p=*/false,
none_type, class_type,
/*check_dependency=*/false, /*check_dependency=*/false,
/*class_head_p=*/false, /*class_head_p=*/false,
declarator_p); declarator_p);
...@@ -3962,7 +3972,7 @@ cp_parser_unqualified_id (cp_parser* parser, ...@@ -3962,7 +3972,7 @@ cp_parser_unqualified_id (cp_parser* parser,
= cp_parser_class_name (parser, = cp_parser_class_name (parser,
/*typename_keyword_p=*/false, /*typename_keyword_p=*/false,
/*template_keyword_p=*/false, /*template_keyword_p=*/false,
none_type, class_type,
/*check_dependency=*/false, /*check_dependency=*/false,
/*class_head_p=*/false, /*class_head_p=*/false,
declarator_p); declarator_p);
...@@ -14275,6 +14285,10 @@ cp_parser_direct_declarator (cp_parser* parser, ...@@ -14275,6 +14285,10 @@ cp_parser_direct_declarator (cp_parser* parser,
unqualified_name = constructor_name (class_type); unqualified_name = constructor_name (class_type);
sfk = sfk_constructor; 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) if (ctor_dtor_or_conv_p && sfk != sfk_none)
*ctor_dtor_or_conv_p = -1; *ctor_dtor_or_conv_p = -1;
...@@ -17969,6 +17983,26 @@ cp_parser_lookup_name (cp_parser *parser, tree name, ...@@ -17969,6 +17983,26 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
lookup_member, we must enter the scope here. */ lookup_member, we must enter the scope here. */
if (dependent_p) if (dependent_p)
pushed_scope = push_scope (parser->scope); 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 /* If the PARSER->SCOPE is a template specialization, it
may be instantiated during name lookup. In that case, may be instantiated during name lookup. In that case,
errors may be issued. Even if we rollback the current errors may be issued. Even if we rollback the current
...@@ -18320,8 +18354,7 @@ static bool ...@@ -18320,8 +18354,7 @@ static bool
cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p) cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
{ {
bool constructor_p; bool constructor_p;
tree type_decl = NULL_TREE; tree nested_name_specifier;
bool nested_name_p;
cp_token *next_token; cp_token *next_token;
/* The common case is that this is not a constructor declarator, so /* 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) ...@@ -18347,34 +18380,48 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
cp_parser_global_scope_opt (parser, cp_parser_global_scope_opt (parser,
/*current_scope_valid_p=*/false); /*current_scope_valid_p=*/false);
/* Look for the nested-name-specifier. */ /* Look for the nested-name-specifier. */
nested_name_p nested_name_specifier
= (cp_parser_nested_name_specifier_opt (parser, = (cp_parser_nested_name_specifier_opt (parser,
/*typename_keyword_p=*/false, /*typename_keyword_p=*/false,
/*check_dependency_p=*/false, /*check_dependency_p=*/false,
/*type_p=*/false, /*type_p=*/false,
/*is_declaration=*/false) /*is_declaration=*/false));
!= NULL_TREE);
/* Outside of a class-specifier, there must be a /* Outside of a class-specifier, there must be a
nested-name-specifier. */ nested-name-specifier. */
if (!nested_name_p && if (!nested_name_specifier &&
(!at_class_scope_p () || !TYPE_BEING_DEFINED (current_class_type) (!at_class_scope_p () || !TYPE_BEING_DEFINED (current_class_type)
|| friend_p)) || friend_p))
constructor_p = false; 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, /* If we still think that this might be a constructor-declarator,
look for a class-name. */ look for a class-name. */
if (constructor_p) else if (constructor_p)
{ {
/* If we have: /* If we have:
template <typename T> struct S { S(); }; template <typename T> struct S {
template <typename T> S<T>::S (); S();
};
we must recognize that the nested `S' names a class.
Similarly, for:
template <typename T> S<T>::S<T> (); we must recognize that the nested `S' names a class. */
tree type_decl;
we must recognize that the nested `S' names a template. */
type_decl = cp_parser_class_name (parser, type_decl = cp_parser_class_name (parser,
/*typename_keyword_p=*/false, /*typename_keyword_p=*/false,
/*template_keyword_p=*/false, /*template_keyword_p=*/false,
...@@ -18384,22 +18431,23 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p) ...@@ -18384,22 +18431,23 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
/*is_declaration=*/false); /*is_declaration=*/false);
/* If there was no class-name, then this is not a constructor. */ /* If there was no class-name, then this is not a constructor. */
constructor_p = !cp_parser_error_occurred (parser); constructor_p = !cp_parser_error_occurred (parser);
}
/* If we're still considering a constructor, we have to see a `(', /* If we're still considering a constructor, we have to see a `(',
to begin the parameter-declaration-clause, followed by either a to begin the parameter-declaration-clause, followed by either a
`)', an `...', or a decl-specifier. We need to check for a `)', an `...', or a decl-specifier. We need to check for a
type-specifier to avoid being fooled into thinking that: 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 is a constructor. (It is actually a function named `f' that
takes one parameter (of type `int') and returns a value of type takes one parameter (of type `int') and returns a value of type
`S::S'. */ `S'. */
if (constructor_p if (constructor_p
&& cp_parser_require (parser, CPP_OPEN_PAREN, "%<(%>")) && !cp_parser_require (parser, CPP_OPEN_PAREN, "%<(%>"))
{ constructor_p = false;
if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN)
if (constructor_p
&& cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN)
&& cp_lexer_next_token_is_not (parser->lexer, CPP_ELLIPSIS) && cp_lexer_next_token_is_not (parser->lexer, CPP_ELLIPSIS)
/* A parameter declaration begins with a decl-specifier, /* A parameter declaration begins with a decl-specifier,
which is either the "attribute" keyword, a storage class which is either the "attribute" keyword, a storage class
...@@ -18454,8 +18502,7 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p) ...@@ -18454,8 +18502,7 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
constructor_p = !cp_parser_error_occurred (parser); constructor_p = !cp_parser_error_occurred (parser);
} }
} }
else
constructor_p = false;
/* We did not really want to consume any tokens. */ /* We did not really want to consume any tokens. */
cp_parser_abort_tentative_parse (parser); cp_parser_abort_tentative_parse (parser);
......
...@@ -2429,6 +2429,14 @@ finish_class_member_access_expr (tree object, tree name, bool template_p, ...@@ -2429,6 +2429,14 @@ finish_class_member_access_expr (tree object, tree name, bool template_p,
gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE
|| TREE_CODE (name) == BIT_NOT_EXPR); || 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. */ /* Find the base of OBJECT_TYPE corresponding to SCOPE. */
access_path = lookup_base (object_type, scope, ba_check, NULL); access_path = lookup_base (object_type, scope, ba_check, NULL);
if (access_path == error_mark_node) if (access_path == error_mark_node)
......
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> 2009-11-21 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/42078 PR tree-optimization/42078
......
...@@ -9,4 +9,4 @@ struct A ...@@ -9,4 +9,4 @@ struct A
template<int> struct A {}; // { dg-error "same name" } 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" }
...@@ -11,7 +11,7 @@ A::A() { } ...@@ -11,7 +11,7 @@ A::A() { }
B::B() { } B::B() { }
B::A ba; 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 { ...@@ -26,6 +26,6 @@ template <class T> struct A {
template <class T2> A(T2); template <class T2> A(T2);
static A x; 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" }
} }
// PR c++/9050, DR 147, 318
struct Y
{
template <typename T> Y (T);
template <typename T> void foo (T);
};
template <> Y::Y<int> (int) { }
// { dg-do run }
// PRMS Id: 6604 // 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; int c;
...@@ -12,6 +12,8 @@ struct A { ...@@ -12,6 +12,8 @@ struct A {
int main () int main ()
{ {
A::A(); A a;
a.A::A(); // { dg-error "" }
A::A(); // { dg-error "" }
return c; return c;
} }
...@@ -10,4 +10,4 @@ struct A { ...@@ -10,4 +10,4 @@ struct A {
template <class T> template <class T>
A<T>::A<T>() // { dg-error "invalid use of constructor|qualified name" } A<T>::A<T>() // { dg-error "invalid use of constructor|qualified name" }
{ {
} } // { dg-error "end of input" }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment