DR 325
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 2 Jan 2012 17:53:16 +0000 (17:53 +0000)
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 2 Jan 2012 17:53:16 +0000 (17:53 +0000)
PR c++/51666
* parser.c (cp_parser_cache_defarg): Split out...
(cp_parser_parameter_declaration): ...from here.
(cp_parser_save_nsdmi): Use it.
(cp_parser_cache_group): Remove CPP_COMMA support.

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

gcc/cp/ChangeLog
gcc/cp/parser.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/nsdmi-defer5.C [new file with mode: 0644]

index 23f3ae0..7668a7b 100644 (file)
@@ -1,3 +1,12 @@
+2012-01-02  Jason Merrill  <jason@redhat.com>
+
+       DR 325
+       PR c++/51666
+       * parser.c (cp_parser_cache_defarg): Split out...
+       (cp_parser_parameter_declaration): ...from here.
+       (cp_parser_save_nsdmi): Use it.
+       (cp_parser_cache_group): Remove CPP_COMMA support.
+
 2012-01-02  Dodji Seketeli  <dodji@redhat.com>
 
        PR c++/51462
index 0f5bb8e..7e6915c 100644 (file)
@@ -2249,6 +2249,8 @@ static void cp_parser_pre_parsed_nested_name_specifier
   (cp_parser *);
 static bool cp_parser_cache_group
   (cp_parser *, enum cpp_ttype, unsigned);
+static tree cp_parser_cache_defarg
+  (cp_parser *parser, bool nsdmi);
 static void cp_parser_parse_tentatively
   (cp_parser *);
 static void cp_parser_commit_to_tentative_parse
@@ -17267,159 +17269,18 @@ cp_parser_parameter_declaration (cp_parser *parser,
   /* If the next token is `=', then process a default argument.  */
   if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
     {
+      token = cp_lexer_peek_token (parser->lexer);
       /* If we are defining a class, then the tokens that make up the
         default argument must be saved and processed later.  */
       if (!template_parm_p && at_class_scope_p ()
          && TYPE_BEING_DEFINED (current_class_type)
          && !LAMBDA_TYPE_P (current_class_type))
-       {
-         unsigned depth = 0;
-         int maybe_template_id = 0;
-         cp_token *first_token;
-         cp_token *token;
-
-         /* Add tokens until we have processed the entire default
-            argument.  We add the range [first_token, token).  */
-         first_token = cp_lexer_peek_token (parser->lexer);
-         while (true)
-           {
-             bool done = false;
-
-             /* Peek at the next token.  */
-             token = cp_lexer_peek_token (parser->lexer);
-             /* What we do depends on what token we have.  */
-             switch (token->type)
-               {
-                 /* In valid code, a default argument must be
-                    immediately followed by a `,' `)', or `...'.  */
-               case CPP_COMMA:
-                 if (depth == 0 && maybe_template_id)
-                   {
-                     /* If we've seen a '<', we might be in a
-                        template-argument-list.  Until Core issue 325 is
-                        resolved, we don't know how this situation ought
-                        to be handled, so try to DTRT.  We check whether
-                        what comes after the comma is a valid parameter
-                        declaration list.  If it is, then the comma ends
-                        the default argument; otherwise the default
-                        argument continues.  */
-                     bool error = false;
-                     tree t;
-
-                     /* Set ITALP so cp_parser_parameter_declaration_list
-                        doesn't decide to commit to this parse.  */
-                     bool saved_italp = parser->in_template_argument_list_p;
-                     parser->in_template_argument_list_p = true;
-
-                     cp_parser_parse_tentatively (parser);
-                     cp_lexer_consume_token (parser->lexer);
-                     begin_scope (sk_function_parms, NULL_TREE);
-                     cp_parser_parameter_declaration_list (parser, &error);
-                     for (t = current_binding_level->names; t; t = DECL_CHAIN (t))
-                       pop_binding (DECL_NAME (t), t);
-                     leave_scope ();
-                     if (!cp_parser_error_occurred (parser) && !error)
-                       done = true;
-                     cp_parser_abort_tentative_parse (parser);
-
-                     parser->in_template_argument_list_p = saved_italp;
-                     break;
-                   }
-               case CPP_CLOSE_PAREN:
-               case CPP_ELLIPSIS:
-                 /* If we run into a non-nested `;', `}', or `]',
-                    then the code is invalid -- but the default
-                    argument is certainly over.  */
-               case CPP_SEMICOLON:
-               case CPP_CLOSE_BRACE:
-               case CPP_CLOSE_SQUARE:
-                 if (depth == 0)
-                   done = true;
-                 /* Update DEPTH, if necessary.  */
-                 else if (token->type == CPP_CLOSE_PAREN
-                          || token->type == CPP_CLOSE_BRACE
-                          || token->type == CPP_CLOSE_SQUARE)
-                   --depth;
-                 break;
-
-               case CPP_OPEN_PAREN:
-               case CPP_OPEN_SQUARE:
-               case CPP_OPEN_BRACE:
-                 ++depth;
-                 break;
-
-               case CPP_LESS:
-                 if (depth == 0)
-                   /* This might be the comparison operator, or it might
-                      start a template argument list.  */
-                   ++maybe_template_id;
-                 break;
-
-                case CPP_RSHIFT:
-                  if (cxx_dialect == cxx98)
-                    break;
-                  /* Fall through for C++0x, which treats the `>>'
-                     operator like two `>' tokens in certain
-                     cases.  */
-
-               case CPP_GREATER:
-                 if (depth == 0)
-                   {
-                     /* This might be an operator, or it might close a
-                        template argument list.  But if a previous '<'
-                        started a template argument list, this will have
-                        closed it, so we can't be in one anymore.  */
-                     maybe_template_id -= 1 + (token->type == CPP_RSHIFT);
-                     if (maybe_template_id < 0)
-                       maybe_template_id = 0;
-                   }
-                 break;
-
-                 /* If we run out of tokens, issue an error message.  */
-               case CPP_EOF:
-               case CPP_PRAGMA_EOL:
-                 error_at (token->location, "file ends in default argument");
-                 done = true;
-                 break;
-
-               case CPP_NAME:
-               case CPP_SCOPE:
-                 /* In these cases, we should look for template-ids.
-                    For example, if the default argument is
-                    `X<int, double>()', we need to do name lookup to
-                    figure out whether or not `X' is a template; if
-                    so, the `,' does not end the default argument.
-
-                    That is not yet done.  */
-                 break;
-
-               default:
-                 break;
-               }
-
-             /* If we've reached the end, stop.  */
-             if (done)
-               break;
-
-             /* Add the token to the token block.  */
-             token = cp_lexer_consume_token (parser->lexer);
-           }
-
-         /* Create a DEFAULT_ARG to represent the unparsed default
-            argument.  */
-         default_argument = make_node (DEFAULT_ARG);
-         DEFARG_TOKENS (default_argument)
-           = cp_token_cache_new (first_token, token);
-         DEFARG_INSTANTIATIONS (default_argument) = NULL;
-       }
+       default_argument = cp_parser_cache_defarg (parser, /*nsdmi=*/false);
       /* Outside of a class definition, we can just parse the
         assignment-expression.  */
       else
-       {
-         token = cp_lexer_peek_token (parser->lexer);
-         default_argument 
-           = cp_parser_default_argument (parser, template_parm_p);
-       }
+       default_argument
+         = cp_parser_default_argument (parser, template_parm_p);
 
       if (!parser->default_arg_ok_p)
        {
@@ -21630,25 +21491,9 @@ cp_parser_save_member_function_body (cp_parser* parser,
 static tree
 cp_parser_save_nsdmi (cp_parser* parser)
 {
-  /* Save away the tokens that make up the body of the
-     function.  */
-  cp_token *first = parser->lexer->next_token;
-  cp_token *last;
-  tree node;
-
-  /* Save tokens until the next comma or semicolon.  */
-  cp_parser_cache_group (parser, CPP_COMMA, /*depth=*/0);
-
-  last = parser->lexer->next_token;
-
-  node = make_node (DEFAULT_ARG);
-  DEFARG_TOKENS (node) = cp_token_cache_new (first, last);
-  DEFARG_INSTANTIATIONS (node) = NULL;
-
-  return node;
+  return cp_parser_cache_defarg (parser, /*nsdmi=*/true);
 }
 
-
 /* Parse a template-argument-list, as well as the trailing ">" (but
    not the opening "<").  See cp_parser_template_argument_list for the
    return value.  */
@@ -22758,12 +22603,6 @@ cp_parser_cache_group (cp_parser *parser,
           kind of syntax error.  */
        return true;
 
-      /* If we're caching something finished by a comma (or semicolon),
-        such as an NSDMI, don't consume the comma.  */
-      if (end == CPP_COMMA
-         && (token->type == CPP_SEMICOLON || token->type == CPP_COMMA))
-       return false;
-
       /* Consume the token.  */
       cp_lexer_consume_token (parser->lexer);
       /* See if it starts a new group.  */
@@ -22789,6 +22628,178 @@ cp_parser_cache_group (cp_parser *parser,
     }
 }
 
+/* Like above, for caching a default argument or NSDMI.  Both of these are
+   terminated by a non-nested comma, but it can be unclear whether or not a
+   comma is nested in a template argument list unless we do more parsing.
+   In order to handle this ambiguity, when we encounter a ',' after a '<'
+   we try to parse what follows as a parameter-declaration-list (in the
+   case of a default argument) or a member-declarator (in the case of an
+   NSDMI).  If that succeeds, then we stop caching.  */
+
+static tree
+cp_parser_cache_defarg (cp_parser *parser, bool nsdmi)
+{
+  unsigned depth = 0;
+  int maybe_template_id = 0;
+  cp_token *first_token;
+  cp_token *token;
+  tree default_argument;
+
+  /* Add tokens until we have processed the entire default
+     argument.  We add the range [first_token, token).  */
+  first_token = cp_lexer_peek_token (parser->lexer);
+  if (first_token->type == CPP_OPEN_BRACE)
+    {
+      /* For list-initialization, this is straightforward.  */
+      cp_parser_cache_group (parser, CPP_CLOSE_BRACE, /*depth=*/0);
+      token = cp_lexer_peek_token (parser->lexer);
+    }
+  else while (true)
+    {
+      bool done = false;
+
+      /* Peek at the next token.  */
+      token = cp_lexer_peek_token (parser->lexer);
+      /* What we do depends on what token we have.  */
+      switch (token->type)
+       {
+         /* In valid code, a default argument must be
+            immediately followed by a `,' `)', or `...'.  */
+       case CPP_COMMA:
+         if (depth == 0 && maybe_template_id)
+           {
+             /* If we've seen a '<', we might be in a
+                template-argument-list.  Until Core issue 325 is
+                resolved, we don't know how this situation ought
+                to be handled, so try to DTRT.  We check whether
+                what comes after the comma is a valid parameter
+                declaration list.  If it is, then the comma ends
+                the default argument; otherwise the default
+                argument continues.  */
+             bool error = false;
+             tree t;
+
+             /* Set ITALP so cp_parser_parameter_declaration_list
+                doesn't decide to commit to this parse.  */
+             bool saved_italp = parser->in_template_argument_list_p;
+             parser->in_template_argument_list_p = true;
+
+             cp_parser_parse_tentatively (parser);
+             cp_lexer_consume_token (parser->lexer);
+
+             if (nsdmi)
+               {
+                 int ctor_dtor_or_conv_p;
+                 cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
+                                       &ctor_dtor_or_conv_p,
+                                       /*parenthesized_p=*/NULL,
+                                       /*member_p=*/true);
+               }
+             else
+               {
+                 begin_scope (sk_function_parms, NULL_TREE);
+                 cp_parser_parameter_declaration_list (parser, &error);
+                 for (t = current_binding_level->names; t; t = DECL_CHAIN (t))
+                   pop_binding (DECL_NAME (t), t);
+                 leave_scope ();
+               }
+             if (!cp_parser_error_occurred (parser) && !error)
+               done = true;
+             cp_parser_abort_tentative_parse (parser);
+
+             parser->in_template_argument_list_p = saved_italp;
+             break;
+           }
+       case CPP_CLOSE_PAREN:
+       case CPP_ELLIPSIS:
+         /* If we run into a non-nested `;', `}', or `]',
+            then the code is invalid -- but the default
+            argument is certainly over.  */
+       case CPP_SEMICOLON:
+       case CPP_CLOSE_BRACE:
+       case CPP_CLOSE_SQUARE:
+         if (depth == 0)
+           done = true;
+         /* Update DEPTH, if necessary.  */
+         else if (token->type == CPP_CLOSE_PAREN
+                  || token->type == CPP_CLOSE_BRACE
+                  || token->type == CPP_CLOSE_SQUARE)
+           --depth;
+         break;
+
+       case CPP_OPEN_PAREN:
+       case CPP_OPEN_SQUARE:
+       case CPP_OPEN_BRACE:
+         ++depth;
+         break;
+
+       case CPP_LESS:
+         if (depth == 0)
+           /* This might be the comparison operator, or it might
+              start a template argument list.  */
+           ++maybe_template_id;
+         break;
+
+       case CPP_RSHIFT:
+         if (cxx_dialect == cxx98)
+           break;
+         /* Fall through for C++0x, which treats the `>>'
+            operator like two `>' tokens in certain
+            cases.  */
+
+       case CPP_GREATER:
+         if (depth == 0)
+           {
+             /* This might be an operator, or it might close a
+                template argument list.  But if a previous '<'
+                started a template argument list, this will have
+                closed it, so we can't be in one anymore.  */
+             maybe_template_id -= 1 + (token->type == CPP_RSHIFT);
+             if (maybe_template_id < 0)
+               maybe_template_id = 0;
+           }
+         break;
+
+         /* If we run out of tokens, issue an error message.  */
+       case CPP_EOF:
+       case CPP_PRAGMA_EOL:
+         error_at (token->location, "file ends in default argument");
+         done = true;
+         break;
+
+       case CPP_NAME:
+       case CPP_SCOPE:
+         /* In these cases, we should look for template-ids.
+            For example, if the default argument is
+            `X<int, double>()', we need to do name lookup to
+            figure out whether or not `X' is a template; if
+            so, the `,' does not end the default argument.
+
+            That is not yet done.  */
+         break;
+
+       default:
+         break;
+       }
+
+      /* If we've reached the end, stop.  */
+      if (done)
+       break;
+
+      /* Add the token to the token block.  */
+      token = cp_lexer_consume_token (parser->lexer);
+    }
+
+  /* Create a DEFAULT_ARG to represent the unparsed default
+     argument.  */
+  default_argument = make_node (DEFAULT_ARG);
+  DEFARG_TOKENS (default_argument)
+    = cp_token_cache_new (first_token, token);
+  DEFARG_INSTANTIATIONS (default_argument) = NULL;
+
+  return default_argument;
+}
+
 /* Begin parsing tentatively.  We always save tokens while parsing
    tentatively so that if the tentative parsing fails we can restore the
    tokens.  */
index ad865db..e1e0dfe 100644 (file)
@@ -1,3 +1,8 @@
+2012-01-02  Jason Merrill  <jason@redhat.com>
+
+       PR c++/51666
+       * g++.dg/cpp0x/nsdmi-defer5.C: New.
+
 2012-01-02  Dodji Seketeli  <dodji@redhat.com>
 
        PR c++/51462
diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi-defer5.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi-defer5.C
new file mode 100644 (file)
index 0000000..85abfbf
--- /dev/null
@@ -0,0 +1,20 @@
+// PR c++/51666 (DR 325)
+// { dg-options -std=c++0x }
+
+template<typename T, typename U>
+struct tuple
+{
+  tuple(T, U) { }
+};
+
+struct Y
+{
+  tuple<int, int> tt = tuple<int, int>{1, 2};
+};
+
+struct A
+{
+  int i = 0;
+  int j = i < 42, k;           // OK, declares j and k
+  int l = i < 42, 24;          // { dg-error "" }
+};