diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 36f7255efee..4db5aac1fbf 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,17 @@ 2009-11-06 Jason Merrill + PR c++/15946 + * parser.c (cp_parser_check_template_parameters): Don't talk about + specialization at function scope. + (cp_parser_diagnose_invalid_type_name): Handle dependent scope. + (cp_parser_parse_and_diagnose_invalid_type_name): Likewise. + (cp_parser_expression_statement): Suggest typename. + * error.c (dump_decl) [SCOPE_REF]: Print the type here. + (dump_expr) [SCOPE_REF]: Call it. + (dump_type) [UNBOUND_CLASS_TEMPLATE]: Check TFF_UNQUALIFIED_NAME. + * cxx-pretty-print.c (pp_cxx_unqualified_id): Print class template + args. + PR c++/9381 * decl2.c (build_memfn_type): Preserve attributes. (cp_reconstruct_complex_type): Likewise. diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c index 1d7f9cf2caf..4851af901f7 100644 --- a/gcc/cp/cxx-pretty-print.c +++ b/gcc/cp/cxx-pretty-print.c @@ -200,6 +200,12 @@ pp_cxx_unqualified_id (cxx_pretty_printer *pp, tree t) case TYPENAME_TYPE: case UNBOUND_CLASS_TEMPLATE: pp_cxx_unqualified_id (pp, TYPE_NAME (t)); + if (CLASS_TYPE_P (t) && CLASSTYPE_USE_TEMPLATE (t)) + { + pp_cxx_begin_template_argument_list (pp); + pp_cxx_template_argument_list (pp, CLASSTYPE_TI_ARGS (t)); + pp_cxx_end_template_argument_list (pp); + } break; case BIT_NOT_EXPR: diff --git a/gcc/cp/error.c b/gcc/cp/error.c index ce5660f4a85..f4232075119 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -466,8 +466,11 @@ dump_type (tree t, int flags) break; case UNBOUND_CLASS_TEMPLATE: - dump_type (TYPE_CONTEXT (t), flags); - pp_cxx_colon_colon (cxx_pp); + if (! (flags & TFF_UNQUALIFIED_NAME)) + { + dump_type (TYPE_CONTEXT (t), flags); + pp_cxx_colon_colon (cxx_pp); + } pp_cxx_ws_string (cxx_pp, "template"); dump_type (DECL_NAME (TYPE_NAME (t)), flags); break; @@ -947,7 +950,9 @@ dump_decl (tree t, int flags) break; case SCOPE_REF: - pp_expression (cxx_pp, t); + dump_type (TREE_OPERAND (t, 0), flags); + pp_string (cxx_pp, "::"); + dump_decl (TREE_OPERAND (t, 1), flags|TFF_UNQUALIFIED_NAME); break; case ARRAY_REF: @@ -2219,6 +2224,9 @@ dump_expr (tree t, int flags) break; case SCOPE_REF: + dump_decl (t, flags); + break; + case EXPR_PACK_EXPANSION: case TYPEID_EXPR: case MEMBER_REF: diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 1d677cb92eb..47f5f13f1d3 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -2400,6 +2400,11 @@ 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 (TYPE_P (parser->scope) + && dependent_scope_p (parser->scope)) + error_at (location, "need % before %<%T::%E%> to name " + "a type in dependent scope %qT", + parser->scope, id, parser->scope); else if (TYPE_P (parser->scope)) error_at (location, "%qE in class %qT does not name a type", id, parser->scope); @@ -2433,11 +2438,8 @@ cp_parser_parse_and_diagnose_invalid_type_name (cp_parser *parser) /*declarator_p=*/true, /*optional_p=*/false); /* After the id-expression, there should be a plain identifier, - otherwise this is not a simple variable declaration. Also, if - the scope is dependent, we cannot do much. */ + otherwise this is not a simple variable declaration. */ if (!cp_lexer_next_token_is (parser->lexer, CPP_NAME) - || (parser->scope && TYPE_P (parser->scope) - && dependent_type_p (parser->scope)) || TREE_CODE (id) == TYPE_DECL) { cp_parser_abort_tentative_parse (parser); @@ -7760,12 +7762,21 @@ static tree cp_parser_expression_statement (cp_parser* parser, tree in_statement_expr) { tree statement = NULL_TREE; + cp_token *token = cp_lexer_peek_token (parser->lexer); /* If the next token is a ';', then there is no expression statement. */ if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) statement = cp_parser_expression (parser, /*cast_p=*/false, NULL); + /* Give a helpful message for "A::type t;" */ + if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON) + && !cp_parser_uncommitted_to_tentative_parse_p (parser) + && TREE_CODE (statement) == SCOPE_REF) + error_at (token->location, "need % before %qE to name " + "a type in dependent scope %qT", + statement, TREE_OPERAND (statement, 0)); + /* Consume the final `;'. */ cp_parser_consume_semicolon_at_end_of_statement (parser); @@ -18197,11 +18208,15 @@ cp_parser_check_template_parameters (cp_parser* parser, template void S::R::f (); */ if (parser->num_template_parameter_lists < num_templates) { - if (declarator) + if (declarator && !current_function_decl) error_at (location, "specializing member %<%T::%E%> " "requires %%> syntax", declarator->u.id.qualifying_scope, declarator->u.id.unqualified_name); + else if (declarator) + error_at (location, "invalid declaration of %<%T::%E%>", + declarator->u.id.qualifying_scope, + declarator->u.id.unqualified_name); else error_at (location, "too few template-parameter-lists"); return false; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index be66e312bf1..77cf10c03cf 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,9 @@ 2009-11-06 Jason Merrill + PR c++/15946 + * g++.dg/parse/error36.C: New. + * g++.old-deja/g++.other/typename1.C: Adjust. + PR c++/9381 * g++.dg/abi/regparm1.C: New. diff --git a/gcc/testsuite/g++.dg/parse/error36.C b/gcc/testsuite/g++.dg/parse/error36.C new file mode 100644 index 00000000000..92101e9c99f --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/error36.C @@ -0,0 +1,17 @@ +// Test for helpful error message about missing typename. + +template struct A { typedef T foo; typedef T bar; }; +template +void f(T t) +{ + typedef A::foo type; // { dg-error "typename" } + A::bar b; // { dg-error "typename" } +} // { dg-error "expected ';'" "" { target *-*-* } 8 } + +template struct B +{ + void f() + { + A::baz z; // { dg-error "typename" } + } // { dg-error "expected ';'" "" { target *-*-* } 15 } +}; diff --git a/gcc/testsuite/g++.dg/template/error26.C b/gcc/testsuite/g++.dg/template/error26.C index 7545762bf34..cd8d46d1e4f 100644 --- a/gcc/testsuite/g++.dg/template/error26.C +++ b/gcc/testsuite/g++.dg/template/error26.C @@ -2,4 +2,4 @@ template struct A; -template void foo (A<&T::template i>); // { dg-error "T::template i|mismatch|& T::i" } +template void foo (A<&T::template i>); // { dg-error "T:: ?template i|mismatch|& T::i" } diff --git a/gcc/testsuite/g++.old-deja/g++.other/typename1.C b/gcc/testsuite/g++.old-deja/g++.other/typename1.C index 43d13522fe7..4bf3de39f84 100644 --- a/gcc/testsuite/g++.old-deja/g++.other/typename1.C +++ b/gcc/testsuite/g++.old-deja/g++.other/typename1.C @@ -13,5 +13,5 @@ public: template void f() { - Vector::iterator i = 0; // { dg-error "expected" } missing typename -} + Vector::iterator i = 0; // { dg-error "typename" } missing typename +} // { dg-error "expected" "" { target *-*-* } 16 }