re PR c++/15946 (Unhelpful error message when "typename" is omitted)
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. From-SVN: r153978
This commit is contained in:
parent
3c3905fc17
commit
e1faa105c1
@ -1,5 +1,17 @@
|
||||
2009-11-06 Jason Merrill <jason@redhat.com>
|
||||
|
||||
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.
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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 %<typename%> 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<T>::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 %<typename%> 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 <class T> void S<T>::R<T>::f (); */
|
||||
if (parser->num_template_parameter_lists < num_templates)
|
||||
{
|
||||
if (declarator)
|
||||
if (declarator && !current_function_decl)
|
||||
error_at (location, "specializing member %<%T::%E%> "
|
||||
"requires %<template<>%> 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;
|
||||
|
@ -1,5 +1,9 @@
|
||||
2009-11-06 Jason Merrill <jason@redhat.com>
|
||||
|
||||
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.
|
||||
|
||||
|
17
gcc/testsuite/g++.dg/parse/error36.C
Normal file
17
gcc/testsuite/g++.dg/parse/error36.C
Normal file
@ -0,0 +1,17 @@
|
||||
// Test for helpful error message about missing typename.
|
||||
|
||||
template <class T> struct A { typedef T foo; typedef T bar; };
|
||||
template <class T>
|
||||
void f(T t)
|
||||
{
|
||||
typedef A<T>::foo type; // { dg-error "typename" }
|
||||
A<T>::bar b; // { dg-error "typename" }
|
||||
} // { dg-error "expected ';'" "" { target *-*-* } 8 }
|
||||
|
||||
template <class T> struct B
|
||||
{
|
||||
void f()
|
||||
{
|
||||
A<T>::baz z; // { dg-error "typename" }
|
||||
} // { dg-error "expected ';'" "" { target *-*-* } 15 }
|
||||
};
|
@ -2,4 +2,4 @@
|
||||
|
||||
template<typename> struct A;
|
||||
|
||||
template<typename T> void foo (A<&T::template i>); // { dg-error "T::template i|mismatch|& T::i" }
|
||||
template<typename T> void foo (A<&T::template i>); // { dg-error "T:: ?template i|mismatch|& T::i" }
|
||||
|
@ -13,5 +13,5 @@ public:
|
||||
template<class T>
|
||||
void f()
|
||||
{
|
||||
Vector<T>::iterator i = 0; // { dg-error "expected" } missing typename
|
||||
}
|
||||
Vector<T>::iterator i = 0; // { dg-error "typename" } missing typename
|
||||
} // { dg-error "expected" "" { target *-*-* } 16 }
|
||||
|
Loading…
x
Reference in New Issue
Block a user