OSDN Git Service

2007-03-28 Douglas Gregor <doug.gregor@gmail.com>
authordgregor <dgregor@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 28 Mar 2007 14:14:33 +0000 (14:14 +0000)
committerdgregor <dgregor@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 28 Mar 2007 14:14:33 +0000 (14:14 +0000)
* 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 <doug.gregor@gmail.com>

* g++.dg/cpp0x/bracket1.C: New.
* g++.dg/cpp0x/bracket2.C: New.
* g++.dg/cpp0x/bracket3.C: New.
* g++.dg/cpp0x/bracket4.C: New.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@123302 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/cp/ChangeLog
gcc/cp/parser.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/bracket1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/bracket2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/bracket3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/bracket4.C [new file with mode: 0644]

index 2a63629..a2a0f6e 100644 (file)
@@ -1,3 +1,21 @@
+2007-03-28 Douglas Gregor <doug.gregor@gmail.com>
+
+       * 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  <doug.gregor@gmail.com>
 
        * decl.c (redeclaration_error_message): Complain when redeclaring
index da573cb..dcd73f0 100644 (file)
@@ -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 <token> 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
index b59cc0a..2b66dad 100644 (file)
@@ -1,3 +1,10 @@
+2007-03-28 Douglas Gregor <doug.gregor@gmail.com>
+
+       * 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  <doug.gregor@gmail.com>
 
        * 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 (file)
index 0000000..cffb921
--- /dev/null
@@ -0,0 +1,16 @@
+// { dg-do "compile" }
+// { dg-options "-std=gnu++0x" }
+
+template<typename T>
+struct list {};
+
+template<typename T>
+struct vector { 
+  operator T() const;
+};
+
+void f()
+{
+  vector<vector<int>> v;
+  const vector<int> vi = static_cast<vector<int>>(v);
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/bracket2.C b/gcc/testsuite/g++.dg/cpp0x/bracket2.C
new file mode 100644 (file)
index 0000000..ccd466d
--- /dev/null
@@ -0,0 +1,11 @@
+// { dg-do "compile" }
+// { dg-options "-std=gnu++0x" }
+
+template<int i> class X { /* ... */ };
+X< 1>2 > x1;    // // { dg-error "numeric constant" }
+X<(1>2)> x2;    // Okay.
+
+template<class T> class Y { /* ... */ };
+Y<X<1>> x3;     // Okay, same as "Y<X<1> > x3;".
+Y<X<6>>1>> x4;  // { dg-error "numeric constant" }
+Y<X<(6>>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 (file)
index 0000000..eb1ef02
--- /dev/null
@@ -0,0 +1,5 @@
+// { dg-options "-std=c++98 -Wc++0x-compat" }
+
+template<int N> 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 (file)
index 0000000..2ac5ff3
--- /dev/null
@@ -0,0 +1,27 @@
+// { dg-do "compile" }
+// { dg-options "-std=c++0x" }
+
+template<typename T>
+struct vector { 
+};
+
+struct X {
+  template<typename T>
+  struct tmpl { 
+    operator T() const;
+  };
+};
+
+template<typename T>
+void g()
+{
+  T::template tmpl<vector<int>>() + 2;
+}
+
+template<typename T>
+void operator+(vector<T>, int);
+
+void f()
+{
+  vector<vector<int>>() + 2;
+}