mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-25 16:50:49 +08:00
re PR c++/9154 (poor error message for ">>" vs. "> >" for nested template args)
PR c++/9154 * parser.c (cp_parser_template_argument): A type-id followed by '>>' is just an user typo, and should be accepted as last resort if any other parsing fails. (cp_parser_enclosed_template_argument_list): If the argument list is parsed correctly, but the next token is '>>', emit a diagnostic. (cp_parser_next_token_ends_template_argument): Accept '>>' as delimiter of template argument, it will be later detected as a typo. From-SVN: r74776
This commit is contained in:
parent
a21f130e82
commit
4d5297fad4
@ -1,3 +1,14 @@
|
||||
2003-12-18 Giovanni Bajo <giovannibajo@gcc.gnu.org>
|
||||
|
||||
PR c++/9154
|
||||
* parser.c (cp_parser_template_argument): A type-id followed by '>>'
|
||||
is just an user typo, and should be accepted as last resort if any
|
||||
other parsing fails.
|
||||
(cp_parser_enclosed_template_argument_list): If the argument list is
|
||||
parsed correctly, but the next token is '>>', emit a diagnostic.
|
||||
(cp_parser_next_token_ends_template_argument): Accept '>>' as
|
||||
delimiter of template argument, it will be later detected as a typo.
|
||||
|
||||
2003-12-17 Kelley Cook <kcook@gcc.gnu.org>
|
||||
|
||||
* Make-lang.in: Replace cp/g++.1 with $(docobjdir)/g++.1.
|
||||
@ -44,7 +55,7 @@
|
||||
2003-12-16 Giovanni Bajo <giovannibajo@gcc.gnu.org>
|
||||
|
||||
PR c++/2294
|
||||
* name-lookup.c (push_overloaded_decl): always construct an OVERLOAD
|
||||
* name-lookup.c (push_overloaded_decl): always construct an OVERLOAD
|
||||
if the declaration comes from an using declaration.
|
||||
|
||||
2003-12-16 Giovanni Bajo <giovannibajo@gcc.gnu.org>
|
||||
|
@ -8101,6 +8101,7 @@ cp_parser_template_argument (cp_parser* parser)
|
||||
tree argument;
|
||||
bool template_p;
|
||||
bool address_p;
|
||||
bool maybe_type_id = false;
|
||||
cp_token *token;
|
||||
cp_id_kind idk;
|
||||
tree qualifying_class;
|
||||
@ -8117,13 +8118,35 @@ cp_parser_template_argument (cp_parser* parser)
|
||||
Therefore, we try a type-id first. */
|
||||
cp_parser_parse_tentatively (parser);
|
||||
argument = cp_parser_type_id (parser);
|
||||
/* If the next token isn't a `,' or a `>', then this argument wasn't
|
||||
really finished. */
|
||||
if (!cp_parser_next_token_ends_template_argument_p (parser))
|
||||
cp_parser_error (parser, "expected template-argument");
|
||||
/* If that worked, we're done. */
|
||||
if (cp_parser_parse_definitely (parser))
|
||||
return argument;
|
||||
/* If there was no error parsing the type-id but the next token is a '>>',
|
||||
we probably found a typo for '> >'. But there are type-id which are
|
||||
also valid expressions. For instance:
|
||||
|
||||
struct X { int operator >> (int); };
|
||||
template <int V> struct Foo {};
|
||||
Foo<X () >> 5> r;
|
||||
|
||||
Here 'X()' is a valid type-id of a function type, but the user just
|
||||
wanted to write the expression "X() >> 5". Thus, we remember that we
|
||||
found a valid type-id, but we still try to parse the argument as an
|
||||
expression to see what happens. */
|
||||
if (!cp_parser_error_occurred (parser)
|
||||
&& cp_lexer_next_token_is (parser->lexer, CPP_RSHIFT))
|
||||
{
|
||||
maybe_type_id = true;
|
||||
cp_parser_abort_tentative_parse (parser);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If the next token isn't a `,' or a `>', then this argument wasn't
|
||||
really finished. This means that the argument is not a valid
|
||||
type-id. */
|
||||
if (!cp_parser_next_token_ends_template_argument_p (parser))
|
||||
cp_parser_error (parser, "expected template-argument");
|
||||
/* If that worked, we're done. */
|
||||
if (cp_parser_parse_definitely (parser))
|
||||
return argument;
|
||||
}
|
||||
/* We're still not sure what the argument will be. */
|
||||
cp_parser_parse_tentatively (parser);
|
||||
/* Try a template. */
|
||||
@ -8238,12 +8261,27 @@ cp_parser_template_argument (cp_parser* parser)
|
||||
cp_parser_error (parser, "invalid non-type template argument");
|
||||
return error_mark_node;
|
||||
}
|
||||
/* The argument must be a constant-expression. */
|
||||
/* If the argument wasn't successfully parsed as a type-id followed
|
||||
by '>>', the argument can only be a constant expression now.
|
||||
Otherwise, we try parsing the constant-expression tentatively,
|
||||
because the argument could really be a type-id. */
|
||||
if (maybe_type_id)
|
||||
cp_parser_parse_tentatively (parser);
|
||||
argument = cp_parser_constant_expression (parser,
|
||||
/*allow_non_constant_p=*/false,
|
||||
/*non_constant_p=*/NULL);
|
||||
/* If it's non-dependent, simplify it. */
|
||||
return cp_parser_fold_non_dependent_expr (argument);
|
||||
argument = cp_parser_fold_non_dependent_expr (argument);
|
||||
if (!maybe_type_id)
|
||||
return argument;
|
||||
if (!cp_parser_next_token_ends_template_argument_p (parser))
|
||||
cp_parser_error (parser, "expected template-argument");
|
||||
if (cp_parser_parse_definitely (parser))
|
||||
return argument;
|
||||
/* We did our best to parse the argument as a non type-id, but that
|
||||
was the only alternative that matched (albeit with a '>' after
|
||||
it). We can assume it's just a typo from the user, and a
|
||||
diagnostic will then be issued. */
|
||||
return cp_parser_type_id (parser);
|
||||
}
|
||||
|
||||
/* Parse an explicit-instantiation.
|
||||
@ -14177,8 +14215,31 @@ cp_parser_enclosed_template_argument_list (cp_parser* parser)
|
||||
arguments = NULL_TREE;
|
||||
else
|
||||
arguments = cp_parser_template_argument_list (parser);
|
||||
/* Look for the `>' that ends the template-argument-list. */
|
||||
cp_parser_require (parser, CPP_GREATER, "`>'");
|
||||
/* Look for the `>' that ends the template-argument-list. If we find
|
||||
a '>>' instead, it's probably just a typo. */
|
||||
if (cp_lexer_next_token_is (parser->lexer, CPP_RSHIFT))
|
||||
{
|
||||
if (!saved_greater_than_is_operator_p)
|
||||
{
|
||||
/* If we're in a nested template argument list, the '>>' has to be
|
||||
a typo for '> >'. We emit the error message, but we continue
|
||||
parsing and we push a '>' as next token, so that the argument
|
||||
list will be parsed correctly.. */
|
||||
cp_token* token;
|
||||
error ("`>>' should be `> >' within a nested template argument list");
|
||||
token = cp_lexer_peek_token (parser->lexer);
|
||||
token->type = CPP_GREATER;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If this is not a nested template argument list, the '>>' is
|
||||
a typo for '>'. Emit an error message and continue. */
|
||||
error ("spurious `>>', use `>' to terminate a template argument list");
|
||||
cp_lexer_consume_token (parser->lexer);
|
||||
}
|
||||
}
|
||||
else
|
||||
cp_parser_require (parser, CPP_GREATER, "`>'");
|
||||
/* The `>' token might be a greater-than operator again now. */
|
||||
parser->greater_than_is_operator_p
|
||||
= saved_greater_than_is_operator_p;
|
||||
@ -14618,7 +14679,9 @@ cp_parser_next_token_starts_class_definition_p (cp_parser *parser)
|
||||
}
|
||||
|
||||
/* Returns TRUE iff the next token is the "," or ">" ending a
|
||||
template-argument. */
|
||||
template-argument. ">>" is also accepted (after the full
|
||||
argument was parsed) because it's probably a typo for "> >",
|
||||
and there is a specific diagnostic for this. */
|
||||
|
||||
static bool
|
||||
cp_parser_next_token_ends_template_argument_p (cp_parser *parser)
|
||||
@ -14626,7 +14689,8 @@ cp_parser_next_token_ends_template_argument_p (cp_parser *parser)
|
||||
cp_token *token;
|
||||
|
||||
token = cp_lexer_peek_token (parser->lexer);
|
||||
return (token->type == CPP_COMMA || token->type == CPP_GREATER);
|
||||
return (token->type == CPP_COMMA || token->type == CPP_GREATER
|
||||
|| token->type == CPP_RSHIFT);
|
||||
}
|
||||
|
||||
/* Returns the kind of tag indicated by TOKEN, if it is a class-key,
|
||||
|
Loading…
x
Reference in New Issue
Block a user