This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[C++ PATCH] [PR/9154] New parser regression on ">>" vs "> >"
- From: "Giovanni Bajo" <giovannibajo at libero dot it>
- To: <gcc-patches at gcc dot gnu dot org>
- Cc: "Mark Mitchell" <mark at codesourcery dot com>
- Date: Fri, 5 Dec 2003 01:53:08 +0100
- Subject: [C++ PATCH] [PR/9154] New parser regression on ">>" vs "> >"
Hello,
this is basically take 3 of:
http://gcc.gnu.org/ml/gcc-patches/2003-06/msg02677.html
Given this testcase:
template <class T>
class A {};
A<A<int>> blah;
A<int>> blah2;
mainline emits this:
error5.C:12: error: template argument 1 is invalid
error5.C:12: error: template argument 1 is invalid
error5.C:12: error: expected unqualified-id
error5.C:12: error: expected `,' or `;'
error5.C:13: error: template argument 1 is invalid
error5.C:13: error: expected unqualified-id
error5.C:13: error: expected `,' or `;'
With my patch, we emit:
error5.C:12: error: `>>' should be `> >' within a nested template argument
list
error5.C:13: error: spurious `>>', use `>' to terminate a template argument
list
The attached testcase incorporate several situations where ">>" is used
correctly within a template argument list. Notice that the patch makes the
parser eat the template-id correctly, so there aren't subsequent errors.
This patch has been tested on i686-pc-linux-gnu (rebuild v3 & libjava,
check-c++) with no new regressions. OK for mainline?
Giovanni Bajo
2003-12-05 Giovanni Bajo <giovannibajo@gcc.gnu.org>
* 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-05 Giovanni Bajo <giovannibajo@gcc.gnu.org>
* g++.dg/template/error5.C: New test.
Index: parser.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parser.c,v
retrieving revision 1.123
diff -c -p -r1.123 parser.c
*** parser.c 1 Dec 2003 05:58:22 -0000 1.123
--- parser.c 1 Dec 2003 16:14:55 -0000
*************** cp_parser_template_argument (cp_parser*
*** 7936,7941 ****
--- 7936,7942 ----
tree argument;
bool template_p;
bool address_p;
+ bool maybe_type_id = false;
cp_token *token;
cp_id_kind idk;
tree qualifying_class;
*************** cp_parser_template_argument (cp_parser*
*** 7952,7964 ****
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;
/* We're still not sure what the argument will be. */
cp_parser_parse_tentatively (parser);
/* Try a template. */
--- 7953,7987 ----
Therefore, we try a type-id first. */
cp_parser_parse_tentatively (parser);
argument = cp_parser_type_id (parser);
! /* 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. */
*************** cp_parser_template_argument (cp_parser*
*** 8073,8084 ****
cp_parser_error (parser, "invalid non-type template argument");
return error_mark_node;
}
! /* The argument must be a constant-expression. */
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);
}
/* Parse an explicit-instantiation.
--- 8096,8122 ----
cp_parser_error (parser, "invalid non-type template argument");
return error_mark_node;
}
! /* 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);
! 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.
*************** cp_parser_enclosed_template_argument_lis
*** 14009,14016 ****
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, "`>'");
/* The `>' token might be a greater-than operator again now. */
parser->greater_than_is_operator_p
= saved_greater_than_is_operator_p;
--- 14047,14077 ----
arguments = NULL_TREE;
else
arguments = cp_parser_template_argument_list (parser);
! /* 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;
*************** cp_parser_next_token_starts_class_defini
*** 14451,14457 ****
}
/* Returns TRUE iff the next token is the "," or ">" ending a
! template-argument. */
static bool
cp_parser_next_token_ends_template_argument_p (cp_parser *parser)
--- 14512,14520 ----
}
/* Returns TRUE iff the next token is the "," or ">" ending a
! 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)
*************** cp_parser_next_token_ends_template_argum
*** 14459,14465 ****
cp_token *token;
token = cp_lexer_peek_token (parser->lexer);
! return (token->type == CPP_COMMA || token->type == CPP_GREATER);
}
/* Returns the kind of tag indicated by TOKEN, if it is a class-key,
--- 14522,14529 ----
cp_token *token;
token = cp_lexer_peek_token (parser->lexer);
! return (token->type == CPP_COMMA || token->type == CPP_GREATER
! || token->type == CPP_LSHIFT);
}
/* Returns the kind of tag indicated by TOKEN, if it is a class-key,
// { dg-do compile }
// Origin: <tilps at hotmail dot com>
// c++/9154: poor error message for ">>" vs "> >" in template argument list
/*
* Test that the error message is issued properly
*/
template <class T>
class A {};
A<A<int>> blah; // { dg-error "should be `> >' within" }
A<int>> blah2; // { dg-error "spurious `>>'" }
/*
* Test that a few valid constructs containing a ">>" token in a
* template argument list are handled correctly.
*/
template <int N>
void B(void) {}
int Btest()
{
B<256 >> 4>();
}
template <int N = 123>>4>
struct C {};
template <int> struct D {};
template <typename> struct E {};
E<D< 1>>2 > > E1;
const int x = 0;
E<D< 1>>x > > E2;
template <int> struct F {
typedef int I;
};
template <typename T = F< 1>>2 >::I>
struct G {};
/*
* In this special case, a valid type-id (H() is a function type) is followed
* by '>>', but the argument should still be parsed as an expression, which
* will then be rejected as non-constant expression.
*/
struct H
{
int operator >>(int);
};
template <int V> struct L {};
L<H() >> 5> l; // { dg-error "" "non-constant" }