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