diff mbox series

[d/92309] Committed fix for assignment to anonymous union member corrupts sibling members in struct

Message ID 20200316233136.9926-1-ibuclaw@gdcproject.org
State New
Headers show
Series [d/92309] Committed fix for assignment to anonymous union member corrupts sibling members in struct | expand

Commit Message

Li, Pan2 via Gcc-patches March 16, 2020, 11:31 p.m. UTC
Hi,

This patch fixes a logic bug in the adjustment of nested fields in
anonymous aggregates in the D front-end, closing PR d/92309.

Bootstrapped and tested on x86_64-linux-gnu, and committed to trunk.

Regards
Iain.

---
gcc/d/ChangeLog:

	PR d/92309
	* types.cc (fixup_anonymous_offset): Don't set DECL_FIELD_OFFSET on
	anonymous fields.

gcc/testsuite/ChangeLog:

	PR d/92309
	* gdc.dg/pr92309.d: New test.

---
 gcc/d/types.cc                 | 10 +++++++---
 gcc/testsuite/gdc.dg/pr92309.d | 25 +++++++++++++++++++++++++
 2 files changed, 32 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/gdc.dg/pr92309.d
diff mbox series

Patch

diff --git a/gcc/d/types.cc b/gcc/d/types.cc
index 736f128422c..866da965b40 100644
--- a/gcc/d/types.cc
+++ b/gcc/d/types.cc
@@ -234,16 +234,20 @@  insert_aggregate_field (tree type, tree field, size_t offset)
 static void
 fixup_anonymous_offset (tree fields, tree offset)
 {
+  /* No adjustment in field offset required.  */
+  if (integer_zerop (offset))
+    return;
+
   while (fields != NULL_TREE)
     {
-      /* Traverse all nested anonymous aggregates to update their offset.
-	 Set the anonymous decl offset to its first member.  */
+      /* Traverse all nested anonymous aggregates to update the offset of their
+	 fields.  Note that the anonymous field itself is not adjusted, as it
+	 already has an offset relative to its outer aggregate.  */
       tree ftype = TREE_TYPE (fields);
       if (TYPE_NAME (ftype) && IDENTIFIER_ANON_P (TYPE_IDENTIFIER (ftype)))
 	{
 	  tree vfields = TYPE_FIELDS (ftype);
 	  fixup_anonymous_offset (vfields, offset);
-	  DECL_FIELD_OFFSET (fields) = DECL_FIELD_OFFSET (vfields);
 	}
       else
 	{
diff --git a/gcc/testsuite/gdc.dg/pr92309.d b/gcc/testsuite/gdc.dg/pr92309.d
new file mode 100644
index 00000000000..01ebc40d336
--- /dev/null
+++ b/gcc/testsuite/gdc.dg/pr92309.d
@@ -0,0 +1,25 @@ 
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92309
+// { dg-do run { target hw } }
+// { dg-skip-if "needs gcc/config.d" { ! d_runtime } }
+
+union U
+{
+    struct
+    {
+        size_t a;
+        size_t b;
+        union
+        {
+            size_t c;
+            size_t d;
+        }
+    }
+}
+
+void main()
+{
+    U u;
+    assert(u.a == 0);
+    u.d = 1;
+    assert(u.a == 0);
+}