]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Handle deferred parsing of NSDMIs.
authorJason Merrill <jason@redhat.com>
Sun, 25 Sep 2011 02:26:01 +0000 (22:26 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Sun, 25 Sep 2011 02:26:01 +0000 (22:26 -0400)
* parser.h (cp_unparsed_functions_entry): Add nsdmis field.
* parser.c (unparsed_nsdmis, cp_parser_save_nsdmi): New.
(cp_parser_late_parse_one_default_arg): Split out from
cp_parser_late_parsing_default_args.
(cp_parser_late_parsing_nsdmi): New.
(push_unparsed_function_queues): Set it.
(cp_parser_parameter_declaration): Save the '=' token.
(cp_parser_template_parameter): Likewise.
(cp_parser_default_argument): Call cp_parser_initializer
rather than cp_parser_initializer_clause.
(cp_parser_class_specifier_1): Parse unparsed_nsdmis.
(cp_parser_member_declaration): Handle nsdmis.
* decl2.c (grokfield): Handle DEFAULT_ARG for a function.

From-SVN: r179156

gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/parser.c
gcc/cp/parser.h
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/nsdmi-defer1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/nsdmi-defer2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/other/pr39060.C
gcc/testsuite/g++.dg/parse/crash56.C

index 7881e1fef5e4b1622c85b82961b635a78ffa7f40..f1496b63d8950de24496571992d8ba90ed5112d8 100644 (file)
@@ -1,5 +1,20 @@
 2011-09-24  Jason Merrill  <jason@redhat.com>
 
+       Handle deferred parsing of NSDMIs.
+       * parser.h (cp_unparsed_functions_entry): Add nsdmis field.
+       * parser.c (unparsed_nsdmis, cp_parser_save_nsdmi): New.
+       (cp_parser_late_parse_one_default_arg): Split out from
+       cp_parser_late_parsing_default_args.
+       (cp_parser_late_parsing_nsdmi): New.
+       (push_unparsed_function_queues): Set it.
+       (cp_parser_parameter_declaration): Save the '=' token.
+       (cp_parser_template_parameter): Likewise.
+       (cp_parser_default_argument): Call cp_parser_initializer
+       rather than cp_parser_initializer_clause.
+       (cp_parser_class_specifier_1): Parse unparsed_nsdmis.
+       (cp_parser_member_declaration): Handle nsdmis.
+       * decl2.c (grokfield): Handle DEFAULT_ARG for a function.
+
        Implement C++11 non-static data member initializers.
        * cp-tree.h (enum cpp_warn_str): Add CPP0X_NSDMI.
        * error.c (maybe_warn_cpp0x): Handle it.
index 661cc5ea113e984c9bc40ae56a63636fdabb4012..45bf6a121a39d242752401a5ec5c1485f69b6963 100644 (file)
@@ -6077,7 +6077,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
 
   /* Just store non-static data member initializers for later.  */
   if (init && TREE_CODE (decl) == FIELD_DECL)
-    DECL_INITIAL (decl) = digest_init_flags (TREE_TYPE (decl), init, flags);
+    DECL_INITIAL (decl) = init;
 
   /* Take care of TYPE_DECLs up front.  */
   if (TREE_CODE (decl) == TYPE_DECL)
index 1e06280b26c74389a62ba8d9c63b0a806a9ea8c1..6e5f7cc7d7519f03bb032d6f8487ed0580e6a73b 100644 (file)
@@ -902,6 +902,8 @@ grokfield (const cp_declarator *declarator,
                  DECL_DECLARED_INLINE_P (value) = 1;
                }
            }
+         else if (TREE_CODE (init) == DEFAULT_ARG)
+           error ("invalid initializer for member function %qD", value);
          else if (TREE_CODE (TREE_TYPE (value)) == METHOD_TYPE)
            {
              if (integer_zerop (init))
index bd46af38cb00085c2d8c3e5acb9de7fa039b04d2..2dbe86613c4b9e80d570b8e94bc8897cb8d31a74 100644 (file)
@@ -1486,6 +1486,8 @@ cp_parser_context_new (cp_parser_context* next)
   VEC_last (cp_unparsed_functions_entry, parser->unparsed_queues)->funs_with_default_args
 #define unparsed_funs_with_definitions \
   VEC_last (cp_unparsed_functions_entry, parser->unparsed_queues)->funs_with_definitions
+#define unparsed_nsdmis \
+  VEC_last (cp_unparsed_functions_entry, parser->unparsed_queues)->nsdmis
 
 static void
 push_unparsed_function_queues (cp_parser *parser)
@@ -1494,6 +1496,7 @@ push_unparsed_function_queues (cp_parser *parser)
                 parser->unparsed_queues, NULL);
   unparsed_funs_with_default_args = NULL;
   unparsed_funs_with_definitions = make_tree_vector ();
+  unparsed_nsdmis = NULL;
 }
 
 static void
@@ -1936,12 +1939,18 @@ static tree cp_parser_functional_cast
   (cp_parser *, tree);
 static tree cp_parser_save_member_function_body
   (cp_parser *, cp_decl_specifier_seq *, cp_declarator *, tree);
+static tree cp_parser_save_nsdmi
+  (cp_parser *);
 static tree cp_parser_enclosed_template_argument_list
   (cp_parser *);
 static void cp_parser_save_default_args
   (cp_parser *, tree);
 static void cp_parser_late_parsing_for_member
   (cp_parser *, tree);
+static tree cp_parser_late_parse_one_default_arg
+  (cp_parser *, tree, tree, tree);
+static void cp_parser_late_parsing_nsdmi
+  (cp_parser *, tree);
 static void cp_parser_late_parsing_default_args
   (cp_parser *, tree);
 static tree cp_parser_sizeof_operand
@@ -11343,9 +11352,7 @@ cp_parser_template_parameter (cp_parser* parser, bool *is_non_type,
         user may try to do so, so we'll parse them and give an
         appropriate diagnostic here.  */
 
-      /* Consume the `='.  */
       cp_token *start_token = cp_lexer_peek_token (parser->lexer);
-      cp_lexer_consume_token (parser->lexer);
       
       /* Find the name of the parameter pack.  */     
       id_declarator = parameter_declarator->declarator;
@@ -16323,9 +16330,6 @@ 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))
     {
-      /* Consume the `='.  */
-      cp_lexer_consume_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 ()
@@ -16535,7 +16539,7 @@ cp_parser_default_argument (cp_parser *parser, bool template_parm_p)
   tree default_argument = NULL_TREE;
   bool saved_greater_than_is_operator_p;
   bool saved_local_variables_forbidden_p;
-  bool non_constant_p;
+  bool non_constant_p, is_direct_init;
 
   /* Make sure that PARSER->GREATER_THAN_IS_OPERATOR_P is
      set correctly.  */
@@ -16549,7 +16553,7 @@ cp_parser_default_argument (cp_parser *parser, bool template_parm_p)
   if (template_parm_p)
     push_deferring_access_checks (dk_no_deferred);
   default_argument
-    = cp_parser_initializer_clause (parser, &non_constant_p);
+    = cp_parser_initializer (parser, &is_direct_init, &non_constant_p);
   if (BRACE_ENCLOSED_INITIALIZER_P (default_argument))
     maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS);
   if (template_parm_p)
@@ -17265,7 +17269,7 @@ cp_parser_class_specifier_1 (cp_parser* parser)
      there is no need to delay the parsing of `A::B::f'.  */
   if (--parser->num_classes_being_defined == 0)
     {
-      tree fn;
+      tree decl;
       tree class_type = NULL_TREE;
       tree pushed_scope = NULL_TREE;
       unsigned ix;
@@ -17284,7 +17288,7 @@ cp_parser_class_specifier_1 (cp_parser* parser)
       FOR_EACH_VEC_ELT (cp_default_arg_entry, unparsed_funs_with_default_args,
                        ix, e)
        {
-         fn = e->decl;
+         decl = e->decl;
          /* If there are default arguments that have not yet been processed,
             take care of them now.  */
          if (class_type != e->class_type)
@@ -17295,18 +17299,31 @@ cp_parser_class_specifier_1 (cp_parser* parser)
              pushed_scope = push_scope (class_type);
            }
          /* Make sure that any template parameters are in scope.  */
-         maybe_begin_member_template_processing (fn);
+         maybe_begin_member_template_processing (decl);
          /* Parse the default argument expressions.  */
-         cp_parser_late_parsing_default_args (parser, fn);
+         cp_parser_late_parsing_default_args (parser, decl);
          /* Remove any template parameters from the symbol table.  */
          maybe_end_member_template_processing ();
        }
+      VEC_truncate (cp_default_arg_entry, unparsed_funs_with_default_args, 0);
+      /* Now parse any NSDMIs.  */
+      FOR_EACH_VEC_ELT (tree, unparsed_nsdmis, ix, decl)
+       {
+         if (class_type != DECL_CONTEXT (decl))
+           {
+             if (pushed_scope)
+               pop_scope (pushed_scope);
+             class_type = DECL_CONTEXT (decl);
+             pushed_scope = push_scope (class_type);
+           }
+         cp_parser_late_parsing_nsdmi (parser, decl);
+       }
+      VEC_truncate (tree, unparsed_nsdmis, 0);
       if (pushed_scope)
        pop_scope (pushed_scope);
-      VEC_truncate (cp_default_arg_entry, unparsed_funs_with_default_args, 0);
       /* Now parse the body of the functions.  */
-      FOR_EACH_VEC_ELT (tree, unparsed_funs_with_definitions, ix, fn)
-       cp_parser_late_parsing_for_member (parser, fn);
+      FOR_EACH_VEC_ELT (tree, unparsed_funs_with_definitions, ix, decl)
+       cp_parser_late_parsing_for_member (parser, decl);
       VEC_truncate (tree, unparsed_funs_with_definitions, 0);
     }
 
@@ -18185,8 +18202,14 @@ cp_parser_member_declaration (cp_parser* parser)
                     constant-initializer.  When we call `grokfield', it will
                     perform more stringent semantics checks.  */
                  initializer_token_start = cp_lexer_peek_token (parser->lexer);
-                 if (function_declarator_p (declarator))
+                 if (function_declarator_p (declarator)
+                     || (decl_specifiers.type
+                         && TREE_CODE (decl_specifiers.type) == TYPE_DECL
+                         && (TREE_CODE (TREE_TYPE (decl_specifiers.type))
+                             == FUNCTION_TYPE)))
                    initializer = cp_parser_pure_specifier (parser);
+                 else if (decl_specifiers.storage_class != sc_static)
+                   initializer = cp_parser_save_nsdmi (parser);
                  else if (cxx_dialect >= cxx0x)
                    {
                      bool nonconst;
@@ -18206,7 +18229,10 @@ cp_parser_member_declaration (cp_parser* parser)
                       && !function_declarator_p (declarator))
                {
                  bool x;
-                 initializer = cp_parser_initializer (parser, &x, &x);
+                 if (decl_specifiers.storage_class != sc_static)
+                   initializer = cp_parser_save_nsdmi (parser);
+                 else
+                   initializer = cp_parser_initializer (parser, &x, &x);
                }
              /* Otherwise, there is no initializer.  */
              else
@@ -18292,6 +18318,11 @@ cp_parser_member_declaration (cp_parser* parser)
 
              if (TREE_CODE (decl) == FUNCTION_DECL)
                cp_parser_save_default_args (parser, decl);
+             else if (TREE_CODE (decl) == FIELD_DECL
+                      && !DECL_C_BIT_FIELD (decl)
+                      && DECL_INITIAL (decl))
+               /* Add DECL to the queue of NSDMI to be parsed later.  */
+               VEC_safe_push (tree, gc, unparsed_nsdmis, decl);
            }
 
          if (assume_semicolon)
@@ -20539,6 +20570,30 @@ cp_parser_save_member_function_body (cp_parser* parser,
   return fn;
 }
 
+/* Save the tokens that make up the in-class initializer for a non-static
+   data member.  Returns a DEFAULT_ARG.  */
+
+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;
+
+  cp_parser_cache_group (parser, CPP_CLOSE_PAREN, /*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;
+}
+
+
 /* Parse a template-argument-list, as well as the trailing ">" (but
    not the opening ">").  See cp_parser_template_argument_list for the
    return value.  */
@@ -20744,6 +20799,83 @@ cp_parser_save_default_args (cp_parser* parser, tree decl)
       }
 }
 
+/* DEFAULT_ARG contains the saved tokens for the initializer of DECL,
+   which is either a FIELD_DECL or PARM_DECL.  Parse it and return
+   the result.  For a PARM_DECL, PARMTYPE is the corresponding type
+   from the parameter-type-list.  */
+
+static tree
+cp_parser_late_parse_one_default_arg (cp_parser *parser, tree decl,
+                                     tree default_arg, tree parmtype)
+{
+  cp_token_cache *tokens;
+  tree parsed_arg;
+  bool dummy;
+
+  /* Push the saved tokens for the default argument onto the parser's
+     lexer stack.  */
+  tokens = DEFARG_TOKENS (default_arg);
+  cp_parser_push_lexer_for_tokens (parser, tokens);
+
+  start_lambda_scope (decl);
+
+  /* Parse the default argument.  */
+  parsed_arg = cp_parser_initializer (parser, &dummy, &dummy);
+  if (BRACE_ENCLOSED_INITIALIZER_P (parsed_arg))
+    maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS);
+
+  finish_lambda_scope ();
+
+  if (!processing_template_decl)
+    {
+      /* In a non-template class, check conversions now.  In a template,
+        we'll wait and instantiate these as needed.  */
+      if (TREE_CODE (decl) == PARM_DECL)
+       parsed_arg = check_default_argument (parmtype, parsed_arg);
+      else
+       {
+         int flags = LOOKUP_IMPLICIT;
+         if (BRACE_ENCLOSED_INITIALIZER_P (parsed_arg)
+             && CONSTRUCTOR_IS_DIRECT_INIT (parsed_arg))
+           flags = LOOKUP_NORMAL;
+         parsed_arg = digest_init_flags (TREE_TYPE (decl), parsed_arg, flags);
+       }
+    }
+
+  /* If the token stream has not been completely used up, then
+     there was extra junk after the end of the default
+     argument.  */
+  if (!cp_lexer_next_token_is (parser->lexer, CPP_EOF))
+    {
+      if (TREE_CODE (decl) == PARM_DECL)
+       cp_parser_error (parser, "expected %<,%>");
+      else
+       cp_parser_error (parser, "expected %<;%>");
+    }
+
+  /* Revert to the main lexer.  */
+  cp_parser_pop_lexer (parser);
+
+  return parsed_arg;
+}
+
+/* FIELD is a non-static data member with an initializer which we saved for
+   later; parse it now.  */
+
+static void
+cp_parser_late_parsing_nsdmi (cp_parser *parser, tree field)
+{
+  tree def;
+
+  push_unparsed_function_queues (parser);
+  def = cp_parser_late_parse_one_default_arg (parser, field,
+                                             DECL_INITIAL (field),
+                                             NULL_TREE);
+  pop_unparsed_function_queues (parser);
+
+  DECL_INITIAL (field) = def;
+}
+
 /* FN is a FUNCTION_DECL which may contains a parameter with an
    unparsed DEFAULT_ARG.  Parse the default args now.  This function
    assumes that the current scope is the scope in which the default
@@ -20753,7 +20885,6 @@ static void
 cp_parser_late_parsing_default_args (cp_parser *parser, tree fn)
 {
   bool saved_local_variables_forbidden_p;
-  bool non_constant_p;
   tree parm, parmdecl;
 
   /* While we're parsing the default args, we might (due to the
@@ -20775,7 +20906,6 @@ cp_parser_late_parsing_default_args (cp_parser *parser, tree fn)
        parm = TREE_CHAIN (parm),
         parmdecl = DECL_CHAIN (parmdecl))
     {
-      cp_token_cache *tokens;
       tree default_arg = TREE_PURPOSE (parm);
       tree parsed_arg;
       VEC(tree,gc) *insts;
@@ -20790,25 +20920,14 @@ cp_parser_late_parsing_default_args (cp_parser *parser, tree fn)
           already declared with default arguments.  */
        continue;
 
-       /* Push the saved tokens for the default argument onto the parser's
-         lexer stack.  */
-      tokens = DEFARG_TOKENS (default_arg);
-      cp_parser_push_lexer_for_tokens (parser, tokens);
-
-      start_lambda_scope (parmdecl);
-
-      /* Parse the assignment-expression.  */
-      parsed_arg = cp_parser_initializer_clause (parser, &non_constant_p);
+      parsed_arg
+       = cp_parser_late_parse_one_default_arg (parser, parmdecl,
+                                               default_arg,
+                                               TREE_VALUE (parm));
       if (parsed_arg == error_mark_node)
        {
-         cp_parser_pop_lexer (parser);
          continue;
        }
-      if (BRACE_ENCLOSED_INITIALIZER_P (parsed_arg))
-       maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS);
-
-      if (!processing_template_decl)
-       parsed_arg = check_default_argument (TREE_VALUE (parm), parsed_arg);
 
       TREE_PURPOSE (parm) = parsed_arg;
 
@@ -20816,17 +20935,6 @@ cp_parser_late_parsing_default_args (cp_parser *parser, tree fn)
       for (insts = DEFARG_INSTANTIATIONS (default_arg), ix = 0;
           VEC_iterate (tree, insts, ix, copy); ix++)
        TREE_PURPOSE (copy) = parsed_arg;
-
-      finish_lambda_scope ();
-
-      /* If the token stream has not been completely used up, then
-        there was extra junk after the end of the default
-        argument.  */
-      if (!cp_lexer_next_token_is (parser->lexer, CPP_EOF))
-       cp_parser_error (parser, "expected %<,%>");
-
-      /* Revert to the main lexer.  */
-      cp_parser_pop_lexer (parser);
     }
 
   pop_defarg_context ();
index 33582fbc0f189579d6c90e8e78df265d6109244a..e08c0b415a08ef2c13da4f3ec952058850575399 100644 (file)
@@ -169,6 +169,10 @@ typedef struct GTY(()) cp_unparsed_functions_entry_d {
   /* Functions with defintions that require post-processing.  Functions
      appear in this list in declaration order.  */
   VEC(tree,gc) *funs_with_definitions;
+
+  /* Non-static data members with initializers that require post-processing.
+     FIELD_DECLs appear in this list in declaration order.  */
+  VEC(tree,gc) *nsdmis;
 } cp_unparsed_functions_entry;
 
 DEF_VEC_O(cp_unparsed_functions_entry);
index 795ac70ce3b498460d4e533d422a73c094db4faa..1e516695aa6a4472c47d839867b05df94de9ef34 100644 (file)
@@ -1,5 +1,8 @@
 2011-09-24  Jason Merrill  <jason@redhat.com>
 
+       * g++.dg/cpp0x/nsdmi-defer1.C: New.
+       * g++.dg/cpp0x/nsdmi-defer2.C: New.
+
        * g++.dg/cpp0x/nsdmi1.C: New.
        * g++.dg/cpp0x/nsdmi2.C: New.
        * g++.dg/cpp0x/nsdmi3.C: New.
diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi-defer1.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi-defer1.C
new file mode 100644 (file)
index 0000000..b3d9b93
--- /dev/null
@@ -0,0 +1,14 @@
+// { dg-options -std=c++0x }
+
+#define SA(X) static_assert(X,#X)
+
+struct A
+{
+  int i = f();
+  int j { f() };
+  static constexpr int f() { return 42; }
+};
+
+constexpr A a;
+SA(a.i == 42);
+SA(a.j == 42);
diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi-defer2.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi-defer2.C
new file mode 100644 (file)
index 0000000..1951262
--- /dev/null
@@ -0,0 +1,9 @@
+// { dg-options -std=c++0x }
+
+struct A
+{
+  int i = f();
+  static int f(int i = 42) { return i; }
+};
+
+A a;
index a625aea108e4f603d9794bac7bc401786689a0e8..e1494106bb091bedd469733b888a64c86f5df100 100644 (file)
@@ -3,17 +3,17 @@
 
 struct A
 {
-  A(void* i=); // { dg-error "with|specification" }
-  A(void* i=); // { dg-error "overloaded" }
-  A(void* i=); // { dg-error "overloaded" }
+  A(void* i=); // { dg-error "with|specification|primary-expression" }
+  A(void* i=); // { dg-error "overloaded|primary-expression" }
+  A(void* i=); // { dg-error "overloaded|primary-expression" }
 
   void operator+ (void* i=);   // { dg-error "arguments" }
 
-  virtual void foo1(=);        // { dg-error "identifier" }
-  void foo2(=);                // { dg-error "identifier" }
-  void foo3(=);                // { dg-error "identifier" }
-  void foo4(=);                // { dg-error "identifier" }
-  void foo5(=);                // { dg-error "identifier" }
-};     // { dg-error "primary-expression" }
+  virtual void foo1(=);        // { dg-error "identifier|primary-expression" }
+  void foo2(=);                // { dg-error "identifier|primary-expression" }
+  void foo3(=);                // { dg-error "identifier|primary-expression" }
+  void foo4(=);                // { dg-error "identifier|primary-expression" }
+  void foo5(=);                // { dg-error "identifier|primary-expression" }
+};
 
 A::A (void* i=) {}     // { dg-error "primary-expression|argument" }
index 9a370cb5fcdee4a551082630a5428e395fd37239..2b823aed4025a5d66ff35caddb5b5d5381195267 100644 (file)
@@ -5,13 +5,13 @@
 struct A
 {
   typedef void (F)();
-  F f = []{}; /* { dg-error "invalid initializer" } */
+  F f = []{}; /* { dg-error "invalid pure" } */
 };
 
 struct B
 {
   typedef void (F)();
-  F f = 1; /* { dg-error "invalid initializer" } */
-  virtual F f2 = 2; /* { dg-error "invalid initializer" } */
-  F f3 = 3; /* { dg-error "invalid initializer" } */
+  F f = 1; /* { dg-error "invalid pure" } */
+  virtual F f2 = 2; /* { dg-error "invalid pure" } */
+  F f3 = 3; /* { dg-error "invalid pure" } */
 };