Patchwork C++ PATCH to implement C++11 non-static data member initializers

login
register
mail settings
Submitter Jason Merrill
Date Sept. 25, 2011, 2:24 a.m.
Message ID <4E7E90CC.7070804@redhat.com>
Download mbox | patch
Permalink /patch/116264/
State New
Headers show

Comments

Jason Merrill - Sept. 25, 2011, 2:24 a.m.
This patch implements C++11 non-static data member initializers (NSDMI), 
as proposed in 
http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2756.htm and 
specified by the C++11 standard.

For ease of reading, the changes are broken into four patches:

1) Implementation of non-static data member initializers with immediate 
parsing.  This patch was somewhat smaller than it might have been 
because there was still some code left from when G++ experimented with 
non-static data member initializers back in the early '90s, though I 
needed to fix a typo at one point.

2) Implementation of deferred parsing of NSDMI.  As with member function 
bodies and default arguments, names used in an NSDMI can be declared 
later in the class body, so we need to wait and parse them at the end of 
the class.

3) Implementation of deferred instantiation of NSDMI.  This is not 
specified by the standard, but seems natural given the other 
similarities between NSDMI and default arguments.

4) Implementation of core issue 1351 for NSDMI: discussion of this issue 
at the Bloomington meeting led to general agreement that an NSDMI that 
can throw should cause an implicitly-declared default constructor to be 
declared noexcept(false).  This patch is currently broken because it 
conflicts with deferred parsing (#2 above); we can't tell whether the 
NSDMI throws until we parse it, but we can't parse it until we've 
completed the class, and declaring the default constructor is part of 
completing the class.  So I've marked the test as XFAIL pending 
committee direction on this point.

Tested x86_64-pc-linux-gnu, applying to trunk.

Patch

commit 3f2eec8c217136c06a1c24af4ded96a6cde5a4df
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Sep 16 11:11:02 2011 -0400

    	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.
    	* call.c (convert_like_real) [ck_user]: Don't complain about
    	using an explicit constructor for direct-initialization.
    	* class.c (check_field_decl): Fix ancient typo.
    	(check_field_decls): NSDMIs make the default ctor non-trivial.
    	* decl.c (cp_finish_decl): Record NSDMI.
    	(grokdeclarator): Allow NSDMI.
    	* decl2.c (grokfield): Allow NSDMI.  Correct LOOKUP flags.
    	* init.c (perform_member_init): Use NSDMI.
    	* method.c (walk_field_subobs): Check for NSDMI.
    	* parser.c (cp_parser_member_declaration): Parse { } init.
    	* semantics.c (register_constexpr_fundef): Don't talk about
    	a return statement in a constexpr constructor.
    	(cxx_eval_call_expression): Check DECL_INITIAL instead of
    	DECL_SAVED_TREE.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 8c99f7a..6a7dfd3 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -5648,6 +5648,9 @@  convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
 	/* When converting from an init list we consider explicit
 	   constructors, but actually trying to call one is an error.  */
 	if (DECL_NONCONVERTING_P (convfn) && DECL_CONSTRUCTOR_P (convfn)
+	    /* Unless this is for direct-list-initialization.  */
+	    && !(BRACE_ENCLOSED_INITIALIZER_P (expr)
+		 && CONSTRUCTOR_IS_DIRECT_INIT (expr))
 	    /* Unless we're calling it for value-initialization from an
 	       empty list, since that is handled separately in 8.5.4.  */
 	    && cand->num_convs > 0)
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index acfe3f2..a7d8218 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -2958,7 +2958,7 @@  check_field_decl (tree field,
     {
       /* `build_class_init_list' does not recognize
 	 non-FIELD_DECLs.  */
-      if (TREE_CODE (t) == UNION_TYPE && any_default_members != 0)
+      if (TREE_CODE (t) == UNION_TYPE && *any_default_members != 0)
 	error ("multiple fields in union %qT initialized", t);
       *any_default_members = 1;
     }
@@ -3256,6 +3256,14 @@  check_field_decls (tree t, tree *access_decls,
 		 "  but does not override %<operator=(const %T&)%>", t);
     }
 
+  /* Non-static data member initializers make the default constructor
+     non-trivial.  */
+  if (any_default_members)
+    {
+      TYPE_NEEDS_CONSTRUCTING (t) = true;
+      TYPE_HAS_COMPLEX_DFLT (t) = true;
+    }
+
   /* If any of the fields couldn't be packed, unset TYPE_PACKED.  */
   if (cant_pack)
     TYPE_PACKED (t) = 0;
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index f2c9211..2f93bba 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -394,7 +394,9 @@  typedef enum cpp0x_warn_str
   /* inline namespaces */
   CPP0X_INLINE_NAMESPACES,
   /* override controls, override/final */
-  CPP0X_OVERRIDE_CONTROLS
+  CPP0X_OVERRIDE_CONTROLS,
+  /* non-static data member initializers */
+  CPP0X_NSDMI
 } cpp0x_warn_str;
   
 /* The various kinds of operation used by composite_pointer_type. */
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 495d8a0..661cc5e 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -6075,6 +6075,10 @@  cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
       return;
     }
 
+  /* 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);
+
   /* Take care of TYPE_DECLs up front.  */
   if (TREE_CODE (decl) == TYPE_DECL)
     {
@@ -10087,36 +10091,6 @@  grokdeclarator (const cp_declarator *declarator,
 
 	if (decl == NULL_TREE)
 	  {
-	    if (initialized)
-	      {
-		if (!staticp)
-		  {
-		    /* An attempt is being made to initialize a non-static
-		       member.  But, from [class.mem]:
-
-		       4 A member-declarator can contain a
-		       constant-initializer only if it declares a static
-		       member (_class.static_) of integral or enumeration
-		       type, see _class.static.data_.
-
-		       This used to be relatively common practice, but
-		       the rest of the compiler does not correctly
-		       handle the initialization unless the member is
-		       static so we make it static below.  */
-		    if (cxx_dialect >= cxx0x)
-		      {
-			sorry ("non-static data member initializers");
-		      }
-		    else
-		      {
-			permerror (input_location, "ISO C++ forbids initialization of member %qD",
-				   unqualified_id);
-			permerror (input_location, "making %qD static", unqualified_id);
-			staticp = 1;
-		      }
-		  }
-	      }
-
 	    if (staticp)
 	      {
 		/* C++ allows static class members.  All other work
@@ -10157,6 +10131,11 @@  grokdeclarator (const cp_declarator *declarator,
 		    DECL_MUTABLE_P (decl) = 1;
 		    storage_class = sc_none;
 		  }
+
+		if (initialized)
+		  /* An attempt is being made to initialize a non-static
+		     member.  This is new in C++11.  */
+		  maybe_warn_cpp0x (CPP0X_NSDMI);
 	      }
 
 	    bad_specifiers (decl, BSP_FIELD, virtualp,
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 68e9b9b..1e06280 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -795,7 +795,7 @@  grokfield (const cp_declarator *declarator,
 {
   tree value;
   const char *asmspec = 0;
-  int flags = LOOKUP_ONLYCONVERTING;
+  int flags;
   tree name;
 
   if (init
@@ -919,9 +919,10 @@  grokfield (const cp_declarator *declarator,
 		     value);
 	    }
 	}
-      else if (pedantic && TREE_CODE (value) != VAR_DECL)
-	/* Already complained in grokdeclarator.  */
-	init = NULL_TREE;
+      else if (TREE_CODE (value) == FIELD_DECL)
+	/* C++11 NSDMI, keep going.  */;
+      else if (TREE_CODE (value) != VAR_DECL)
+	gcc_unreachable ();
       else if (!processing_template_decl)
 	{
 	  if (TREE_CODE (init) == CONSTRUCTOR)
@@ -955,6 +956,12 @@  grokfield (const cp_declarator *declarator,
   if (attrlist)
     cplus_decl_attributes (&value, attrlist, 0);
 
+  if (init && BRACE_ENCLOSED_INITIALIZER_P (init)
+      && CONSTRUCTOR_IS_DIRECT_INIT (init))
+    flags = LOOKUP_NORMAL;
+  else
+    flags = LOOKUP_IMPLICIT;
+
   switch (TREE_CODE (value))
     {
     case VAR_DECL:
@@ -969,7 +976,6 @@  grokfield (const cp_declarator *declarator,
 	init = error_mark_node;
       cp_finish_decl (value, init, /*init_const_expr_p=*/false,
 		      NULL_TREE, flags);
-      DECL_INITIAL (value) = init;
       DECL_IN_AGGR_P (value) = 1;
       return value;
 
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 598ddf1..392f304 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -3236,6 +3236,11 @@  maybe_warn_cpp0x (cpp0x_warn_str str)
 		 "override controls (override/final) "
 		 "only available with -std=c++0x or -std=gnu++0x");
         break;
+      case CPP0X_NSDMI:
+	pedwarn (input_location, 0,
+		 "non-static data member initializers "
+		 "only available with -std=c++0x or -std=gnu++0x");
+        break;
       default:
 	gcc_unreachable();
       }
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index ac3221e..f5904d5 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -493,6 +493,11 @@  perform_member_init (tree member, tree init)
   tree decl;
   tree type = TREE_TYPE (member);
 
+  /* Use the non-static data member initializer if there was no
+     mem-initializer for this field.  */
+  if (init == NULL_TREE)
+    init = break_out_target_exprs (DECL_INITIAL (member));
+
   /* Effective C++ rule 12 requires that all data members be
      initialized.  */
   if (warn_ecpp && init == NULL_TREE && TREE_CODE (type) != ARRAY_TYPE)
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 88bb2a9..734c23b 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -1036,10 +1036,20 @@  walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
 	  if (bad && deleted_p)
 	    *deleted_p = true;
 
+	  if (DECL_INITIAL (field))
+	    {
+	      if (msg && DECL_INITIAL (field) == error_mark_node)
+		inform (0, "initializer for %q+#D is invalid", field);
+	      if (trivial_p)
+		*trivial_p = false;
+
+	      /* Don't do the normal processing.  */
+	      continue;
+	    }
+
 	  /* For an implicitly-defined default constructor to be constexpr,
-	     every member must have a user-provided default constructor.  */
-	  /* FIXME will need adjustment for non-static data member
-	     initializers.  */
+	     every member must have a user-provided default constructor or
+	     an explicit initializer.  */
 	  if (constexpr_p && !CLASS_TYPE_P (mem_type))
 	    {
 	      *constexpr_p = false;
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 2283312..bd46af3 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -18202,6 +18202,12 @@  cp_parser_member_declaration (cp_parser* parser)
 		    /* Parse the initializer.  */
 		    initializer = cp_parser_constant_initializer (parser);
 		}
+	      else if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)
+		       && !function_declarator_p (declarator))
+		{
+		  bool x;
+		  initializer = cp_parser_initializer (parser, &x, &x);
+		}
 	      /* Otherwise, there is no initializer.  */
 	      else
 		initializer = NULL_TREE;
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 0662b29..19ecbee 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -5826,8 +5826,8 @@  register_constexpr_fundef (tree fun, tree body)
   body = massage_constexpr_body (fun, body);
   if (body == NULL_TREE || body == error_mark_node)
     {
-      error ("body of constexpr function %qD not a return-statement", fun);
-      DECL_DECLARED_CONSTEXPR_P (fun) = false;
+      if (!DECL_CONSTRUCTOR_P (fun))
+	error ("body of constexpr function %qD not a return-statement", fun);
       return NULL;
     }
 
@@ -6245,7 +6245,7 @@  cxx_eval_call_expression (const constexpr_call *old_call, tree t,
         {
 	  if (!allow_non_constant)
 	    {
-	      if (DECL_SAVED_TREE (fun))
+	      if (DECL_INITIAL (fun))
 		{
 		  /* The definition of fun was somehow unsuitable.  */
 		  error_at (loc, "%qD called in a constant expression", fun);
diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi1.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi1.C
new file mode 100644
index 0000000..f6381d0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi1.C
@@ -0,0 +1,53 @@ 
+// { dg-do run }
+// { dg-options -std=c++0x }
+
+struct A
+{
+  int i = 42;
+};
+
+struct B
+{
+  int i = 42;
+  B() { }
+  B(int i): i(i) { }
+};
+
+template <class T, T t>
+struct C
+{
+  T m = t;
+};
+
+template <class T, T t>
+struct D
+{
+  T m = t;
+  D() { }
+  D(T m):m(m) { }
+};
+
+int main()
+{
+  A a1;
+  if (a1.i != 42) return 1;
+  A a2 = { 24 };
+  if (a2.i != 24) return 2;
+  A a3[1];
+  if (a3[0].i != 42) return 3;
+
+  B b1;
+  if (b1.i != 42) return 3;
+  B b2 (24);
+  if (b2.i != 24) return 4;
+
+  C<int,3> c1;
+  if (c1.m != 3) return 5;
+  C<int,3> c2 { 5 };
+  if (c2.m != 5) return 6;
+
+  D<int,3> d1;
+  if (d1.m != 3) return 7;
+  D<int,3> d2 (5) ;
+  if (d2.m != 5) return 8;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi2.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi2.C
new file mode 100644
index 0000000..9636bed
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi2.C
@@ -0,0 +1,21 @@ 
+// { dg-options -std=c++0x }
+
+struct A
+{
+  int i;
+  constexpr A(int i): i(i) {}
+};
+
+struct B
+{
+  A a1 = 1;
+  A a2 { 2 };
+  A a3 = { 3 };
+};
+
+#define SA(X) static_assert(X,#X)
+
+constexpr B b;
+SA(b.a1.i == 1);
+SA(b.a2.i == 2);
+SA(b.a3.i == 3);
diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi3.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi3.C
new file mode 100644
index 0000000..73b2bc2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi3.C
@@ -0,0 +1,18 @@ 
+// { dg-options -std=c++0x }
+
+struct A
+{
+  int i;
+  explicit constexpr A(int i): i(i) {}
+};
+
+struct B
+{
+  A a1 = 1;			// { dg-error "" }
+  A a2 { 2 };
+  A a3 = { 3 };			// { dg-error "" }
+};
+
+constexpr B b;			// { dg-error "B::B" }
+
+// { dg-message "a1. is invalid" "" { target *-*-* } 11 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi4.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi4.C
new file mode 100644
index 0000000..db365cb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi4.C
@@ -0,0 +1,24 @@ 
+// { dg-do run }
+// { dg-options -std=c++0x }
+
+int c;
+
+struct A
+{
+  A() { }
+  A(const A&) { }
+};
+
+A f() { ++c; return A(); }
+
+struct B
+{
+  A a = f();
+};
+
+int main()
+{
+  B b1, b2;
+  if (c != 2)
+    __builtin_abort();
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.other/init4.C b/gcc/testsuite/g++.old-deja/g++.other/init4.C
index 92562ef..f8246d6 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/init4.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/init4.C
@@ -1,4 +1,4 @@ 
-// { dg-options -std=c++98 }
+// { dg-options "-std=c++98 -pedantic-errors" }
 // { dg-do assemble  }
 
 class error {

commit 09c44f25bcee3c4f77ba9070522c676d15314576
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Sep 23 14:21:31 2011 -0400

    	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.

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 661cc5e..45bf6a1 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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)
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 1e06280..6e5f7cc 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -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))
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index bd46af3..2dbe866 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -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 ();
diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h
index 33582fb..e08c0b4 100644
--- a/gcc/cp/parser.h
+++ b/gcc/cp/parser.h
@@ -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);
diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi-defer1.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi-defer1.C
new file mode 100644
index 0000000..b3d9b93
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi-defer1.C
@@ -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
index 0000000..1951262
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi-defer2.C
@@ -0,0 +1,9 @@ 
+// { dg-options -std=c++0x }
+
+struct A
+{
+  int i = f();
+  static int f(int i = 42) { return i; }
+};
+
+A a;
diff --git a/gcc/testsuite/g++.dg/other/pr39060.C b/gcc/testsuite/g++.dg/other/pr39060.C
index a625aea..e149410 100644
--- a/gcc/testsuite/g++.dg/other/pr39060.C
+++ b/gcc/testsuite/g++.dg/other/pr39060.C
@@ -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" }
diff --git a/gcc/testsuite/g++.dg/parse/crash56.C b/gcc/testsuite/g++.dg/parse/crash56.C
index 9a370cb..2b823ae 100644
--- a/gcc/testsuite/g++.dg/parse/crash56.C
+++ b/gcc/testsuite/g++.dg/parse/crash56.C
@@ -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" } */
 };

commit 10bd74fa7bd2671d9a48aa728691b27b4e2565fa
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Sep 23 12:59:45 2011 -0400

    	* init.c (perform_member_init): Instantiate NSDMI here.
    	* pt.c (tsubst_decl) [FIELD_DECL]: Not here.

diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index f5904d5..f246286 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -496,7 +496,17 @@  perform_member_init (tree member, tree init)
   /* Use the non-static data member initializer if there was no
      mem-initializer for this field.  */
   if (init == NULL_TREE)
-    init = break_out_target_exprs (DECL_INITIAL (member));
+    {
+      if (CLASSTYPE_TEMPLATE_INSTANTIATION (DECL_CONTEXT (member)))
+	/* Do deferred instantiation of the NSDMI.  */
+	init = (tsubst_copy_and_build
+		(DECL_INITIAL (member),
+		 CLASSTYPE_TI_ARGS (DECL_CONTEXT (member)),
+		 tf_warning_or_error, member, /*function_p=*/false,
+		 /*integral_constant_expression_p=*/false));
+      else
+	init = break_out_target_exprs (DECL_INITIAL (member));
+    }
 
   /* Effective C++ rule 12 requires that all data members be
      initialized.  */
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index af5ca5c..ebadebf 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -10264,11 +10264,14 @@  tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 	TREE_TYPE (r) = type;
 	cp_apply_type_quals_to_decl (cp_type_quals (type), r);
 
-	/* DECL_INITIAL gives the number of bits in a bit-field.  */
-	DECL_INITIAL (r)
-	  = tsubst_expr (DECL_INITIAL (t), args,
-			 complain, in_decl,
-			 /*integral_constant_expression_p=*/true);
+	if (DECL_C_BIT_FIELD (r))
+	  /* For bit-fields, DECL_INITIAL gives the number of bits.  For
+	     non-bit-fields DECL_INITIAL is a non-static data member
+	     initializer, which gets deferred instantiation.  */
+	  DECL_INITIAL (r)
+	    = tsubst_expr (DECL_INITIAL (t), args,
+			   complain, in_decl,
+			   /*integral_constant_expression_p=*/true);
 	/* We don't have to set DECL_CONTEXT here; it is set by
 	   finish_member_declaration.  */
 	DECL_CHAIN (r) = NULL_TREE;
diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi-defer3.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi-defer3.C
new file mode 100644
index 0000000..2777fb5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi-defer3.C
@@ -0,0 +1,19 @@ 
+// Do NSDMI get deferred instantiation?
+// { dg-options -std=c++0x }
+
+template <class T>
+struct A
+{
+  T t = T(42);
+  constexpr A() { }
+  A(T t): t(t) { }
+};
+
+struct B { };
+
+#define SA(X) static_assert(X,#X)
+
+constexpr A<int> a1;
+SA(a1.t == 42);
+
+A<B> a2 {B()};

commit 6c3a4b9feac862caadd988fab4b54907dfae9ccc
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Sep 15 17:21:34 2011 -0400

    	* except.c (expr_noexcept_p): Split out from finish_noexcept_expr.
    	* cp-tree.h: Declare it.
    	* method.c (walk_field_subobs): Use it.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 2f93bba..0f7deb6 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5047,6 +5047,7 @@  extern tree build_throw				(tree);
 extern int nothrow_libfn_p			(const_tree);
 extern void check_handlers			(tree);
 extern tree finish_noexcept_expr		(tree, tsubst_flags_t);
+extern bool expr_noexcept_p			(tree, tsubst_flags_t);
 extern void perform_deferred_noexcept_checks	(void);
 extern bool nothrow_spec_p			(const_tree);
 extern bool type_noexcept_p			(const_tree);
diff --git a/gcc/cp/except.c b/gcc/cp/except.c
index bfc520d..ceec858 100644
--- a/gcc/cp/except.c
+++ b/gcc/cp/except.c
@@ -1125,14 +1125,27 @@  perform_deferred_noexcept_checks (void)
 tree
 finish_noexcept_expr (tree expr, tsubst_flags_t complain)
 {
-  tree fn;
-
   if (expr == error_mark_node)
     return error_mark_node;
 
   if (processing_template_decl)
     return build_min (NOEXCEPT_EXPR, boolean_type_node, expr);
 
+  return (expr_noexcept_p (expr, complain)
+	  ? boolean_true_node : boolean_false_node);
+}
+
+/* Returns whether EXPR is noexcept, possibly warning if allowed by
+   COMPLAIN.  */
+
+bool
+expr_noexcept_p (tree expr, tsubst_flags_t complain)
+{
+  tree fn;
+
+  if (expr == error_mark_node)
+    return false;
+
   fn = cp_walk_tree_without_duplicates (&expr, check_noexcept_r, 0);
   if (fn)
     {
@@ -1151,10 +1164,10 @@  finish_noexcept_expr (tree expr, tsubst_flags_t complain)
 	  else
 	    maybe_noexcept_warning (fn);
 	}
-      return boolean_false_node;
+      return false;
     }
   else
-    return boolean_true_node;
+    return true;
 }
 
 /* Return true iff SPEC is throw() or noexcept(true).  */
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 734c23b..1316dfb 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -1042,6 +1042,12 @@  walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
 		inform (0, "initializer for %q+#D is invalid", field);
 	      if (trivial_p)
 		*trivial_p = false;
+	      /* Core 1351: If the field has an NSDMI that could throw, the
+		 default constructor is noexcept(false).  FIXME this is
+	         broken by deferred parsing and 1360 saying we can't
+		 lazily declare a non-trivial default constructor.  */
+	      if (spec_p && !expr_noexcept_p (DECL_INITIAL (field), complain))
+		*spec_p = noexcept_false_spec;
 
 	      /* Don't do the normal processing.  */
 	      continue;
diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi-eh1.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi-eh1.C
new file mode 100644
index 0000000..09c92d2f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi-eh1.C
@@ -0,0 +1,18 @@ 
+// Core issue 1351
+// { dg-do run { xfail *-*-* } }
+// { dg-options -std=c++0x }
+
+bool fail;
+struct A
+{
+  int i = fail ? throw "noooooooo" : 42;
+};
+
+int main()
+{
+  A a1;
+  if (a1.i != 42) return 1;
+  fail = true;
+  try { A a2; }
+  catch (...) { }
+}