diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 2a636294a68..a2a0f6ef90c 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,21 @@ +2007-03-28 Douglas Gregor + + * parser.c (struct cp_parser): Update comment for + greater_than_is_operator_p. + (cp_parser_primary_expression): In C++0x mode, a cast operator can + be terminated with a `>>' token when !GREATER_THAN_IS_OPERATOR_P. + (TOKEN_PRECEDENCE): In C++0x mode, `>>' is treated like `>' when + !GREATER_THAN_IS_OPERATOR_P. + (cp_parser_binary_expression): When -Wc++0x-compat, warn about + `>>' operators that will become two `>' tokens in C++0x. + (cp_parser_parameter_declaration): Treat `>>' like `>' in C++0x + mode, allowing it to terminate default arguments. + (cp_parser_enclosed_template_argument_list): In C++0x mode, treat + `>>' like two consecutive `>' tokens. + (cp_parser_skip_to_end_of_template_parameter_list): Ditto. + (cp_parser_next_token_ends_template_argument_p): In C++0x, `>>' + ends a template argument. + 2007-03-28 Douglas Gregor * decl.c (redeclaration_error_message): Complain when redeclaring diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index da573cb91f7..dcd73f06ab5 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1400,7 +1400,9 @@ typedef struct cp_parser GTY(()) /* TRUE if the `>' token should be interpreted as the greater-than operator. FALSE if it is the end of a template-id or - template-parameter-list. */ + template-parameter-list. In C++0x mode, this flag also applies to + `>>' tokens, which are viewed as two consecutive `>' tokens when + this flag is FALSE. */ bool greater_than_is_operator_p; /* TRUE if default arguments are allowed within a parameter list @@ -3027,6 +3029,11 @@ cp_parser_primary_expression (cp_parser *parser, && next_token->type != CPP_CLOSE_SQUARE /* The closing ">" in a template-argument-list. */ && (next_token->type != CPP_GREATER + || parser->greater_than_is_operator_p) + /* C++0x only: A ">>" treated like two ">" tokens, + in a template-argument-list. */ + && (next_token->type != CPP_RSHIFT + || !flag_cpp0x || parser->greater_than_is_operator_p)) cast_p = false; } @@ -5792,10 +5799,12 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p) The binops_by_token map is used to get the tree codes for each type. binary-expressions are associated according to a precedence table. */ -#define TOKEN_PRECEDENCE(token) \ - ((token->type == CPP_GREATER && !parser->greater_than_is_operator_p) \ - ? PREC_NOT_OPERATOR \ - : binops_by_token[token->type].prec) +#define TOKEN_PRECEDENCE(token) \ +(((token->type == CPP_GREATER \ + || (flag_cpp0x && token->type == CPP_RSHIFT)) \ + && !parser->greater_than_is_operator_p) \ + ? PREC_NOT_OPERATOR \ + : binops_by_token[token->type].prec) static tree cp_parser_binary_expression (cp_parser* parser, bool cast_p) @@ -5817,6 +5826,17 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p) /* Get an operator token. */ token = cp_lexer_peek_token (parser->lexer); + if (warn_cxx0x_compat + && token->type == CPP_RSHIFT + && !parser->greater_than_is_operator_p) + { + warning (OPT_Wc__0x_compat, + "%H%<>>%> operator will be treated as two right angle brackets in C++0x", + &token->location); + warning (OPT_Wc__0x_compat, + "suggest parentheses around %<>>%> expression"); + } + new_prec = TOKEN_PRECEDENCE (token); /* Popping an entry off the stack means we completed a subexpression: @@ -13015,6 +13035,13 @@ cp_parser_parameter_declaration (cp_parser *parser, ++depth; break; + case CPP_RSHIFT: + if (!flag_cpp0x) + break; + /* Fall through for C++0x, which treats the `>>' + operator like two `>' tokens in certain + cases. */ + case CPP_GREATER: /* If we see a non-nested `>', and `>' is not an operator, then it marks the end of the default @@ -16536,7 +16563,8 @@ cp_parser_enclosed_template_argument_list (cp_parser* parser) saved_skip_evaluation = skip_evaluation; skip_evaluation = false; /* Parse the template-argument-list itself. */ - if (cp_lexer_next_token_is (parser->lexer, CPP_GREATER)) + if (cp_lexer_next_token_is (parser->lexer, CPP_GREATER) + || cp_lexer_next_token_is (parser->lexer, CPP_RSHIFT)) arguments = NULL_TREE; else arguments = cp_parser_template_argument_list (parser); @@ -16544,7 +16572,28 @@ cp_parser_enclosed_template_argument_list (cp_parser* parser) 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 (flag_cpp0x) + { + /* In C++0x, a `>>' in a template argument list or cast + expression is considered to be two separate `>' + tokens. So, change the current token to a `>', but don't + consume it: it will be consumed later when the outer + template argument list (or cast expression) is parsed. + Note that this replacement of `>' for `>>' is necessary + even if we are parsing tentatively: in the tentative + case, after calling + cp_parser_enclosed_template_argument_list we will always + throw away all of the template arguments and the first + closing `>', either because the template argument list + was erroneous or because we are replacing those tokens + with a CPP_TEMPLATE_ID token. The second `>' (which will + not have been thrown away) is needed either to close an + outer template argument list or to complete a new-style + cast. */ + cp_token *token = cp_lexer_peek_token (parser->lexer); + token->type = CPP_GREATER; + } + else 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 @@ -16557,8 +16606,6 @@ cp_parser_enclosed_template_argument_list (cp_parser* parser) "within a nested template argument list", &token->location); - /* ??? Proper recovery should terminate two levels of - template argument list here. */ token->type = CPP_GREATER; } else @@ -17054,6 +17101,23 @@ cp_parser_skip_to_end_of_template_parameter_list (cp_parser* parser) ++level; break; + case CPP_RSHIFT: + if (!flag_cpp0x) + /* C++0x views the `>>' operator as two `>' tokens, but + C++98 does not. */ + break; + else if (!nesting_depth && level-- == 0) + { + /* We've hit a `>>' where the first `>' closes the + template argument list, and the second `>' is + spurious. Just consume the `>>' and stop; we've + already produced at least one error. */ + cp_lexer_consume_token (parser->lexer); + return; + } + /* Fall through for C++0x, so we handle the second `>' in + the `>>'. */ + case CPP_GREATER: if (!nesting_depth && level-- == 0) { @@ -17148,8 +17212,8 @@ cp_parser_next_token_starts_class_definition_p (cp_parser *parser) return (token->type == CPP_OPEN_BRACE || token->type == CPP_COLON); } -/* Returns TRUE iff the next token is the "," or ">" ending a - template-argument. */ +/* Returns TRUE iff the next token is the "," or ">" (or `>>', in + C++0x) ending a template-argument. */ static bool cp_parser_next_token_ends_template_argument_p (cp_parser *parser) @@ -17159,7 +17223,8 @@ cp_parser_next_token_ends_template_argument_p (cp_parser *parser) token = cp_lexer_peek_token (parser->lexer); return (token->type == CPP_COMMA || token->type == CPP_GREATER - || token->type == CPP_ELLIPSIS); + || token->type == CPP_ELLIPSIS + || (flag_cpp0x && token->type == CPP_RSHIFT)); } /* Returns TRUE iff the n-th token is a "<", or the n-th is a "[" and the diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index b59cc0a009b..2b66dad9c03 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2007-03-28 Douglas Gregor + + * g++.dg/cpp0x/bracket1.C: New. + * g++.dg/cpp0x/bracket2.C: New. + * g++.dg/cpp0x/bracket3.C: New. + * g++.dg/cpp0x/bracket4.C: New. + 2007-03-28 Douglas Gregor * g++.dg/cpp0x/temp_default1.C: New. diff --git a/gcc/testsuite/g++.dg/cpp0x/bracket1.C b/gcc/testsuite/g++.dg/cpp0x/bracket1.C new file mode 100644 index 00000000000..cffb921edcf --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/bracket1.C @@ -0,0 +1,16 @@ +// { dg-do "compile" } +// { dg-options "-std=gnu++0x" } + +template +struct list {}; + +template +struct vector { + operator T() const; +}; + +void f() +{ + vector> v; + const vector vi = static_cast>(v); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/bracket2.C b/gcc/testsuite/g++.dg/cpp0x/bracket2.C new file mode 100644 index 00000000000..ccd466da26f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/bracket2.C @@ -0,0 +1,11 @@ +// { dg-do "compile" } +// { dg-options "-std=gnu++0x" } + +template class X { /* ... */ }; +X< 1>2 > x1; // // { dg-error "numeric constant" } +X<(1>2)> x2; // Okay. + +template class Y { /* ... */ }; +Y> x3; // Okay, same as "Y > x3;". +Y>1>> x4; // { dg-error "numeric constant" } +Y>1)>> x5; // Okay diff --git a/gcc/testsuite/g++.dg/cpp0x/bracket3.C b/gcc/testsuite/g++.dg/cpp0x/bracket3.C new file mode 100644 index 00000000000..eb1ef02297d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/bracket3.C @@ -0,0 +1,5 @@ +// { dg-options "-std=c++98 -Wc++0x-compat" } + +template struct X {}; + +X<1 >> 2> x; // { dg-warning "will be treated as|suggest parentheses" } diff --git a/gcc/testsuite/g++.dg/cpp0x/bracket4.C b/gcc/testsuite/g++.dg/cpp0x/bracket4.C new file mode 100644 index 00000000000..2ac5ff3d734 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/bracket4.C @@ -0,0 +1,27 @@ +// { dg-do "compile" } +// { dg-options "-std=c++0x" } + +template +struct vector { +}; + +struct X { + template + struct tmpl { + operator T() const; + }; +}; + +template +void g() +{ + T::template tmpl>() + 2; +} + +template +void operator+(vector, int); + +void f() +{ + vector>() + 2; +}