Patchwork C++ PATCH for c++/52377 (NSDMI and unions)

login
register
mail settings
Submitter Jason Merrill
Date May 30, 2013, 7:19 p.m.
Message ID <51A7A64E.9020601@redhat.com>
Download mbox | patch
Permalink /patch/247677/
State New
Headers show

Comments

Jason Merrill - May 30, 2013, 7:19 p.m.
sort_mem_initializers was skipping over all fields without a 
mem-initializer, even ones with an NSDMI.

Tested x86_64-pc-linux-gnu, applying to trunk.
Rainer Orth - May 31, 2013, 11:13 a.m.
Jason Merrill <jason@redhat.com> writes:

> sort_mem_initializers was skipping over all fields without a
> mem-initializer, even ones with an NSDMI.

One of the testcases doesn't compile on Solaris 10/x86:

output is:
/vol/gcc/src/hg/trunk/local/gcc/testsuite/g++.dg/cpp0x/nsdmi-union2.C:4:7: error: multiple fields in union 'A' initialized
/vol/gcc/src/hg/trunk/local/gcc/testsuite/g++.dg/cpp0x/nsdmi-union2.C: In constructor 'constexpr A::A()':
/vol/gcc/src/hg/trunk/local/gcc/testsuite/g++.dg/cpp0x/nsdmi-union2.C:4:7: error: initializations for multiple members of 'A'
/vol/gcc/src/hg/trunk/local/gcc/testsuite/g++.dg/cpp0x/nsdmi-union2.C: At global scope:
/vol/gcc/src/hg/trunk/local/gcc/testsuite/g++.dg/cpp0x/nsdmi-union2.C:10:3: note: synthesized method 'constexpr A::A()' first required here 
/vol/gcc/src/hg/trunk/local/gcc/testsuite/g++.dg/cpp0x/nsdmi-union2.C: In constructor 'B::B()':
/vol/gcc/src/hg/trunk/local/gcc/testsuite/g++.dg/cpp0x/nsdmi-union2.C:10:3: note: synthesized method 'constexpr A::A()' first required here 
/vol/gcc/src/hg/trunk/local/gcc/testsuite/g++.dg/cpp0x/nsdmi-union2.C: In constructor 'B::B()':
/vol/gcc/src/hg/trunk/local/gcc/testsuite/g++.dg/cpp0x/nsdmi-union2.C:15:3: error: initializations for multiple members of 'B'

and produces a warning:

WARNING: g++.dg/cpp0x/nsdmi-union2.C -std=c++11 compilation failed to produce executable

Is this really intended to be a run test?

Also, both testcases are missing from gcc/testsuite/ChangeLog.

	Rainer
Jason Merrill - May 31, 2013, 1:41 p.m.
On 05/31/2013 07:13 AM, Rainer Orth wrote:
> Is this really intended to be a run test?

Oops, no, thanks.

> Also, both testcases are missing from gcc/testsuite/ChangeLog.

I prefer not to mess with logging testcase changes.

http://gcc.gnu.org/codingconventions.html#ChangeLogs

Jason
Rainer Orth - June 7, 2013, 12:42 p.m.
Jason Merrill <jason@redhat.com> writes:

> On 05/31/2013 07:13 AM, Rainer Orth wrote:
>> Also, both testcases are missing from gcc/testsuite/ChangeLog.
>
> I prefer not to mess with logging testcase changes.
>
> http://gcc.gnu.org/codingconventions.html#ChangeLogs

I hadn't seen this before.  I think this policy is highly unfortunate:
unreliable entries are worse than none at all.

	Rainer

Patch

commit 25b01320a7aefae42d9e14f3807247ca8f88ae40
Author: Jason Merrill <jason@redhat.com>
Date:   Sat May 25 17:28:15 2013 -0400

    	PR c++/52377
    	* class.c (common_enclosing_class): New.
    	* cp-tree.h: Declare it.
    	* init.c (sort_mem_initializers): Don't splice out a union member
    	with an NSDMI.

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 90b31bf..64918c6 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -9261,4 +9261,30 @@  publicly_uniquely_derived_p (tree parent, tree type)
   return base && base != error_mark_node;
 }
 
+/* CTX1 and CTX2 are declaration contexts.  Return the innermost common
+   class between them, if any.  */
+
+tree
+common_enclosing_class (tree ctx1, tree ctx2)
+{
+  if (!TYPE_P (ctx1) || !TYPE_P (ctx2))
+    return NULL_TREE;
+  gcc_assert (ctx1 == TYPE_MAIN_VARIANT (ctx1)
+	      && ctx2 == TYPE_MAIN_VARIANT (ctx2));
+  if (ctx1 == ctx2)
+    return ctx1;
+  for (tree t = ctx1; TYPE_P (t); t = TYPE_CONTEXT (t))
+    TYPE_MARKED_P (t) = true;
+  tree found = NULL_TREE;
+  for (tree t = ctx2; TYPE_P (t); t = TYPE_CONTEXT (t))
+    if (TYPE_MARKED_P (t))
+      {
+	found = t;
+	break;
+      }
+  for (tree t = ctx1; TYPE_P (t); t = TYPE_CONTEXT (t))
+    TYPE_MARKED_P (t) = false;
+  return found;
+}
+
 #include "gt-cp-class.h"
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 1f85ca7..aebc440 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5112,6 +5112,7 @@  extern void deduce_noexcept_on_destructor       (tree);
 extern void insert_late_enum_def_into_classtype_sorted_fields (tree, tree);
 extern bool uniquely_derived_from_p             (tree, tree);
 extern bool publicly_uniquely_derived_p         (tree, tree);
+extern tree common_enclosing_class		(tree, tree);
 
 /* in cvt.c */
 extern tree convert_to_reference		(tree, tree, int, int, tree,
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 671c774..4edd150 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -914,13 +914,12 @@  sort_mem_initializers (tree t, tree mem_inits)
      Here we also splice out uninitialized union members.  */
   if (uses_unions_p)
     {
-      tree last_field = NULL_TREE;
+      tree *last_p = NULL;
       tree *p;
       for (p = &sorted_inits; *p; )
 	{
 	  tree field;
 	  tree ctx;
-	  int done;
 
 	  init = *p;
 
@@ -940,22 +939,25 @@  sort_mem_initializers (tree t, tree mem_inits)
 	  for (ctx = DECL_CONTEXT (field);
 	       !same_type_p (ctx, t);
 	       ctx = TYPE_CONTEXT (ctx))
-	    if (TREE_CODE (ctx) == UNION_TYPE)
+	    if (TREE_CODE (ctx) == UNION_TYPE
+		|| !ANON_AGGR_TYPE_P (ctx))
 	      break;
 	  /* If this field is not a member of a union, skip it.  */
 	  if (TREE_CODE (ctx) != UNION_TYPE)
 	    goto next;
 
-	  /* If this union member has no explicit initializer, splice
-	     it out.  */
-	  if (!TREE_VALUE (init))
+	  /* If this union member has no explicit initializer and no NSDMI,
+	     splice it out.  */
+	  if (TREE_VALUE (init) || DECL_INITIAL (field))
+	    /* OK.  */;
+	  else
 	    goto splice;
 
 	  /* It's only an error if we have two initializers for the same
 	     union type.  */
-	  if (!last_field)
+	  if (!last_p)
 	    {
-	      last_field = field;
+	      last_p = p;
 	      goto next;
 	    }
 
@@ -967,41 +969,23 @@  sort_mem_initializers (tree t, tree mem_inits)
 	       union { struct { int i; int j; }; };
 
 	     initializing both `i' and `j' makes sense.  */
-	  ctx = DECL_CONTEXT (field);
-	  done = 0;
-	  do
+	  ctx = common_enclosing_class (DECL_CONTEXT (field),
+					DECL_CONTEXT (TREE_PURPOSE (*last_p)));
+
+	  if (ctx && TREE_CODE (ctx) == UNION_TYPE)
 	    {
-	      tree last_ctx;
-
-	      last_ctx = DECL_CONTEXT (last_field);
-	      while (1)
-		{
-		  if (same_type_p (last_ctx, ctx))
-		    {
-		      if (TREE_CODE (ctx) == UNION_TYPE)
-			error_at (DECL_SOURCE_LOCATION (current_function_decl),
-				  "initializations for multiple members of %qT",
-				  last_ctx);
-		      done = 1;
-		      break;
-		    }
-
-		  if (same_type_p (last_ctx, t))
-		    break;
-
-		  last_ctx = TYPE_CONTEXT (last_ctx);
-		}
-
-	      /* If we've reached the outermost class, then we're
-		 done.  */
-	      if (same_type_p (ctx, t))
-		break;
-
-	      ctx = TYPE_CONTEXT (ctx);
+	      /* A mem-initializer hides an NSDMI.  */
+	      if (TREE_VALUE (init) && !TREE_VALUE (*last_p))
+		*last_p = TREE_CHAIN (*last_p);
+	      else if (TREE_VALUE (*last_p) && !TREE_VALUE (init))
+		goto splice;
+	      else
+		error_at (DECL_SOURCE_LOCATION (current_function_decl),
+			  "initializations for multiple members of %qT",
+			  ctx);
 	    }
-	  while (!done);
 
-	  last_field = field;
+	  last_p = p;
 
 	next:
 	  p = &TREE_CHAIN (*p);
diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi-union1.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi-union1.C
new file mode 100644
index 0000000..11bdd88
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi-union1.C
@@ -0,0 +1,25 @@ 
+// PR c++/52377
+// { dg-do run { target c++11 } }
+
+union Test
+{
+  int a{4};
+};
+
+union B
+{
+  int i = 42;
+  double d;
+  B() = default;
+  B(double d): d(d) { }
+};
+
+int main()
+{
+  Test t;
+  B b;
+  B b2(4.2);
+
+  if (t.a != 4 || b.i != 42 || b2.d != 4.2)
+    __builtin_abort();
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi-union2.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi-union2.C
new file mode 100644
index 0000000..b45fe83
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi-union2.C
@@ -0,0 +1,18 @@ 
+// PR c++/52377
+// { dg-do run { target c++11 } }
+
+union A				// { dg-error "multiple" }
+{
+  int i = 4;
+  int j = 2;
+};
+
+A a;
+
+union B
+{
+  int i,j;
+  B(): i(1), j(2) {}		// { dg-error "multiple" }
+};
+
+B b;