diff mbox series

[pushed] c++: [[no_unique_address]] fixes. [PR96105]

Message ID 20200710123554.8039-1-jason@redhat.com
State New
Headers show
Series [pushed] c++: [[no_unique_address]] fixes. [PR96105] | expand

Commit Message

Jason Merrill July 10, 2020, 12:35 p.m. UTC
We were wrongly checking is_empty_class on the result of strip_array_types
rather than the actual field type.  We weren't considering the alignment of
the data member.  We needed to handle unions the same way as
layout_nonempty_base_or_field.

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

gcc/cp/ChangeLog:

	PR c++/96105
	PR c++/96052
	PR c++/95976
	* class.c (check_field_decls): An array of empty classes is not an
	empty data member.
	(layout_empty_base_or_field): Handle explicit alignment.
	Fix union handling.

gcc/testsuite/ChangeLog:

	PR c++/96105
	PR c++/96052
	PR c++/95976
	* g++.dg/cpp2a/no_unique_address4.C: New test.
	* g++.dg/cpp2a/no_unique_address5.C: New test.
	* g++.dg/cpp2a/no_unique_address6.C: New test.
---
 gcc/cp/class.c                                | 27 ++++++++++++++-----
 .../g++.dg/cpp2a/no_unique_address4.C         | 22 +++++++++++++++
 .../g++.dg/cpp2a/no_unique_address5.C         | 25 +++++++++++++++++
 .../g++.dg/cpp2a/no_unique_address6.C         | 25 +++++++++++++++++
 4 files changed, 92 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/no_unique_address4.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/no_unique_address5.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/no_unique_address6.C


base-commit: ea82325afeccf3604f393916832eaadcbe1225bd
diff mbox series

Patch

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 7b5f1669d04..14380c7a08c 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -3718,7 +3718,8 @@  check_field_decls (tree t, tree *access_decls,
 	/* We don't treat zero-width bitfields as making a class
 	   non-empty.  */
 	;
-      else if (field_poverlapping_p (field) && is_empty_class (type))
+      else if (field_poverlapping_p (field)
+	       && is_empty_class (TREE_TYPE (field)))
 	/* Empty data members also don't make a class non-empty.  */
 	CLASSTYPE_CONTAINS_EMPTY_CLASS_P (t) = 1;
       else
@@ -4385,15 +4386,20 @@  layout_empty_base_or_field (record_layout_info rli, tree binfo_or_decl,
 
   /* This routine should only be used for empty classes.  */
   gcc_assert (is_empty_class (type));
-  alignment = size_int (CLASSTYPE_ALIGN_UNIT (type));
+
+  if (decl && DECL_USER_ALIGN (decl))
+    alignment = size_int (DECL_ALIGN_UNIT (decl));
+  else
+    alignment = size_int (CLASSTYPE_ALIGN_UNIT (type));
 
   /* This is an empty base class.  We first try to put it at offset
      zero.  */
   tree offset = size_zero_node;
-  if (layout_conflict_p (type,
-			 offset,
-			 offsets,
-			 /*vbases_p=*/0))
+  if (TREE_CODE (rli->t) != UNION_TYPE
+      && layout_conflict_p (type,
+			    offset,
+			    offsets,
+			    /*vbases_p=*/0))
     {
       /* That didn't work.  Now, we move forward from the next
 	 available spot in the class.  */
@@ -4413,7 +4419,14 @@  layout_empty_base_or_field (record_layout_info rli, tree binfo_or_decl,
 	}
     }
 
-  if (CLASSTYPE_USER_ALIGN (type))
+  if (decl && DECL_USER_ALIGN (decl))
+    {
+      rli->record_align = MAX (rli->record_align, DECL_ALIGN (decl));
+      if (warn_packed)
+	rli->unpacked_align = MAX (rli->unpacked_align, DECL_ALIGN (decl));
+      TYPE_USER_ALIGN (rli->t) = 1;
+    }
+  else if (CLASSTYPE_USER_ALIGN (type))
     {
       rli->record_align = MAX (rli->record_align, CLASSTYPE_ALIGN (type));
       if (warn_packed)
diff --git a/gcc/testsuite/g++.dg/cpp2a/no_unique_address4.C b/gcc/testsuite/g++.dg/cpp2a/no_unique_address4.C
new file mode 100644
index 00000000000..2fe44e37163
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/no_unique_address4.C
@@ -0,0 +1,22 @@ 
+// PR c++/96105
+// { dg-do compile { target c++20 } }
+
+struct Empty {};
+
+struct A {
+  Empty emp [[no_unique_address]][3];
+};
+
+struct B : A {
+  float f;
+};
+
+struct C {
+  Empty emp [[no_unique_address]][3];
+  float f;
+};
+
+extern char szc[sizeof(C)];
+extern char szc[sizeof(float) * 2];  // GCC likes this
+extern char szb[sizeof(B)];
+extern char szb[sizeof(float) * 2];  // GCC does not like this
diff --git a/gcc/testsuite/g++.dg/cpp2a/no_unique_address5.C b/gcc/testsuite/g++.dg/cpp2a/no_unique_address5.C
new file mode 100644
index 00000000000..5fca35dbd81
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/no_unique_address5.C
@@ -0,0 +1,25 @@ 
+// PR c++/96052
+// { dg-do compile { target c++20 } }
+
+struct Q {
+  struct {
+  } emp alignas(8) [[no_unique_address]];
+  char x;
+};
+struct QQ {
+  char x;
+  Q q;
+};
+
+struct Z {
+  char x alignas(8) [[no_unique_address]];
+};
+struct ZZ {
+  char x;
+  Z z;
+};
+
+extern char qx[sizeof(QQ)];
+extern char qx[16];
+extern char qz[sizeof(ZZ)];
+extern char qz[16];
diff --git a/gcc/testsuite/g++.dg/cpp2a/no_unique_address6.C b/gcc/testsuite/g++.dg/cpp2a/no_unique_address6.C
new file mode 100644
index 00000000000..427db4439dd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/no_unique_address6.C
@@ -0,0 +1,25 @@ 
+// PR c++/95976
+// { dg-do compile { target c++20 } }
+
+struct empty {};
+
+union no_attribute_t
+{
+  empty _0;
+  empty _1;
+};
+
+union with_attribute_t
+{
+  [[no_unique_address]] empty _0;
+  [[no_unique_address]] empty _1;
+};
+
+constexpr no_attribute_t no_attribute{};
+constexpr with_attribute_t with_attribute{};
+
+// This succeeds
+static_assert( &no_attribute._0 == &no_attribute._1 );
+
+// This fails
+static_assert( &with_attribute._0 == &with_attribute._1 );