[C++ PATCH] [PR/9154] New parser regression on ">>" vs "> >"

Giovanni Bajo giovannibajo@libero.it
Wed Dec 17 23:19:00 GMT 2003


Giovanni Bajo wrote:

> [...]
> !   return (token->type == CPP_COMMA || token->type == CPP_GREATER);
> --- 14522,14529 ----
> !   return (token->type == CPP_COMMA || token->type == CPP_GREATER
> !         || token->type == CPP_LSHIFT);

Mark spotted a typo here, where CPP_LSHIFT actually had to be CPP_RSHIFT. I
fixed it and retested the whole patch on i686-pc-linux-gnu (no new
regressions). I also updated the testcase to include a case that were affected
by the typo.

OK for mainline?

Giovanni Bajo



2003-12-17  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-17  Giovanni Bajo  <giovannibajo@gcc.gnu.org>

        * g++.dg/template/error10.C: New test.


Index: parser.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parser.c,v
retrieving revision 1.135
diff -c -3 -p -r1.135 parser.c
*** parser.c    16 Dec 2003 16:09:13 -0000      1.135
--- parser.c    17 Dec 2003 21:52:07 -0000
*************** cp_parser_template_argument (cp_parser*
*** 8096,8101 ****
--- 8096,8102 ----
    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*
*** 8112,8124 ****
       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.  */
--- 8113,8147 ----
       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*
*** 8233,8244 ****
        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.
--- 8256,8282 ----
        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
*** 14162,14169 ****
      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;
--- 14200,14230 ----
      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
*** 14603,14609 ****
  }

  /* 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)
--- 14664,14672 ----
  }

  /* 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
*** 14611,14617 ****
    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,
--- 14674,14681 ----
    cp_token *token;

    token = cp_lexer_peek_token (parser->lexer);
!   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,




// { 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" }


/*
 * This case used to not emit the nice error message because of a typo
 *  in the code.
 */
template <void (*)(void)>
struct K {};

void KFunc(void);

A<K<&KFunc>> k1;  // { dg-error "should be `> >' within" }
K<&KFunc>> k2; // { dg-error "spurious `>>'" }





More information about the Gcc-patches mailing list