diff mbox

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

Message ID 4E7FF818.1080408@redhat.com
State New
Headers show

Commit Message

Jason Merrill Sept. 26, 2011, 3:57 a.m. UTC
Ville pointed out that my earlier patch failed to support 'this' in 
NSDMIs.  So this patch implements that.

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

Patch

commit 3c4ebe4dc7470d3d8cf2261f87df2f7a97bc0ce9
Author: Jason Merrill <jason@redhat.com>
Date:   Sun Sep 25 23:29:23 2011 -0400

    	* parser.c (inject_this_parameter): Split out from
    	cp_parser_late_return_type_opt.
    	(cp_parser_class_specifier_1): Use it for NSDMIs.
    	* tree.c (bot_replace): Replace NSDMI 'this' with real 'this'.

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 2dbe866..9600aa9 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -15690,6 +15690,31 @@  cp_parser_virt_specifier_seq_opt (cp_parser* parser)
   return virt_specifiers;
 }
 
+/* Used by handling of trailing-return-types and NSDMI, in which 'this'
+   is in scope even though it isn't real.  */
+
+static void
+inject_this_parameter (tree ctype, cp_cv_quals quals)
+{
+  tree this_parm;
+
+  if (current_class_ptr)
+    {
+      /* We don't clear this between NSDMIs.  Is it already what we want?  */
+      tree type = TREE_TYPE (TREE_TYPE (current_class_ptr));
+      if (same_type_ignoring_top_level_qualifiers_p (ctype, type)
+	  && cp_type_quals (type) == quals)
+	return;
+    }
+
+  this_parm = build_this_parm (ctype, quals);
+  /* Clear this first to avoid shortcut in cp_build_indirect_ref.  */
+  current_class_ptr = NULL_TREE;
+  current_class_ref
+    = cp_build_indirect_ref (this_parm, RO_NULL, tf_warning_or_error);
+  current_class_ptr = this_parm;
+}
+
 /* Parse a late-specified return type, if any.  This is not a separate
    non-terminal, but part of a function declarator, which looks like
 
@@ -15718,12 +15743,8 @@  cp_parser_late_return_type_opt (cp_parser* parser, cp_cv_quals quals)
   if (quals >= 0)
     {
       /* DR 1207: 'this' is in scope in the trailing return type.  */
-      tree this_parm = build_this_parm (current_class_type, quals);
       gcc_assert (current_class_ptr == NULL_TREE);
-      current_class_ref
-	= cp_build_indirect_ref (this_parm, RO_NULL, tf_warning_or_error);
-      /* Set this second to avoid shortcut in cp_build_indirect_ref.  */
-      current_class_ptr = this_parm;
+      inject_this_parameter (current_class_type, quals);
     }
 
   type = cp_parser_trailing_type_id (parser);
@@ -17274,6 +17295,7 @@  cp_parser_class_specifier_1 (cp_parser* parser)
       tree pushed_scope = NULL_TREE;
       unsigned ix;
       cp_default_arg_entry *e;
+      tree save_ccp, save_ccr;
 
       /* In a first pass, parse default arguments to the functions.
 	 Then, in a second pass, parse the bodies of the functions.
@@ -17307,6 +17329,8 @@  cp_parser_class_specifier_1 (cp_parser* parser)
 	}
       VEC_truncate (cp_default_arg_entry, unparsed_funs_with_default_args, 0);
       /* Now parse any NSDMIs.  */
+      save_ccp = current_class_ptr;
+      save_ccr = current_class_ref;
       FOR_EACH_VEC_ELT (tree, unparsed_nsdmis, ix, decl)
 	{
 	  if (class_type != DECL_CONTEXT (decl))
@@ -17316,9 +17340,12 @@  cp_parser_class_specifier_1 (cp_parser* parser)
 	      class_type = DECL_CONTEXT (decl);
 	      pushed_scope = push_scope (class_type);
 	    }
+	  inject_this_parameter (class_type, TYPE_UNQUALIFIED);
 	  cp_parser_late_parsing_nsdmi (parser, decl);
 	}
       VEC_truncate (tree, unparsed_nsdmis, 0);
+      current_class_ptr = save_ccp;
+      current_class_ref = save_ccr;
       if (pushed_scope)
 	pop_scope (pushed_scope);
       /* Now parse the body of the functions.  */
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index a9e1a26..f23b888 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -1926,6 +1926,13 @@  bot_replace (tree* t,
       if (n)
 	*t = (tree) n->value;
     }
+  else if (TREE_CODE (*t) == PARM_DECL
+	   && DECL_NAME (*t) == this_identifier)
+    {
+      /* In an NSDMI we need to replace the 'this' parameter we used for
+	 parsing with the real one for this function.  */
+      *t = current_class_ptr;
+    }
 
   return NULL_TREE;
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi-defer4.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi-defer4.C
new file mode 100644
index 0000000..68c8380
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi-defer4.C
@@ -0,0 +1,17 @@ 
+// { dg-options -std=c++0x }
+
+struct A
+{
+  int i = 42;
+  int j = f();
+  int k = this->f();
+  int f() { return i++; }
+};
+
+A a;
+
+int main()
+{
+  if (a.j != 42 || a.k != 43 || a.i != 44)
+    __builtin_abort();
+}