diff mbox series

[pushed] c++: Support non-type template parms of union type.

Message ID 20200710123824.2669-1-jason@redhat.com
State New
Headers show
Series [pushed] c++: Support non-type template parms of union type. | expand

Commit Message

Jason Merrill July 10, 2020, 12:38 p.m. UTC
Another thing newly allowed by P1907R1.  The ABI group has discussed
representing unions with designated initializers, and has separately
specified how to represent designators; this patch implements both.

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

gcc/cp/ChangeLog:

	* tree.c (structural_type_p): Allow unions.
	* mangle.c (write_expression): Express unions with a designator.

libiberty/ChangeLog:

	* cp-demangle.c (cplus_demangle_operators): Add di, dx, dX.
	(d_expression_1): Handle di and dX.
	(is_designated_init, d_maybe_print_designated_init): New.
	(d_print_comp_inner): Use d_maybe_print_designated_init.
	* testsuite/demangle-expected: Add designator tests.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp2a/nontype-class-union1.C: New test.
---
 gcc/cp/mangle.c                               | 11 ++-
 gcc/cp/tree.c                                 |  7 --
 .../g++.dg/cpp2a/nontype-class-union1.C       | 25 ++++++
 libiberty/cp-demangle.c                       | 77 ++++++++++++++++++-
 libiberty/testsuite/demangle-expected         |  9 +++
 5 files changed, 119 insertions(+), 10 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class-union1.C


base-commit: e47dfca5aa473e77fdff95d631dc39de87a41eec
diff mbox series

Patch

diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index 090fb529a98..ab2d8ecf2f2 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -3189,6 +3189,7 @@  write_expression (tree expr)
 	    {
 	      vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (expr);
 	      unsigned last_nonzero = UINT_MAX, i;
+	      constructor_elt *ce;
 	      tree val;
 
 	      if (!nontriv)
@@ -3197,12 +3198,18 @@  write_expression (tree expr)
 		    last_nonzero = i;
 
 	      if (nontriv || last_nonzero != UINT_MAX)
-		FOR_EACH_CONSTRUCTOR_VALUE (elts, i, val)
+		for (HOST_WIDE_INT i = 0; vec_safe_iterate (elts, i, &ce); ++i)
 		  {
 		    if (i > last_nonzero)
 		      break;
 		    /* FIXME handle RANGE_EXPR */
-		    write_expression (val);
+		    if (TREE_CODE (etype) == UNION_TYPE)
+		      {
+			/* Express the active member as a designator.  */
+			write_string ("di");
+			write_unqualified_name (ce->index);
+		      }
+		    write_expression (ce->value);
 		  }
 	    }
 	  else
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 9effd27f587..1fcba55313a 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -4534,13 +4534,6 @@  structural_type_p (tree t, bool explain)
        structural types or (possibly multi-dimensional) array thereof.  */
   if (!CLASS_TYPE_P (t))
     return false;
-  if (TREE_CODE (t) == UNION_TYPE)
-    {
-      /* FIXME allow (and mangle) unions.  */
-      if (explain)
-	inform (location_of (t), "%qT is a union", t);
-      return false;
-    }
   if (!literal_type_p (t))
     {
       if (explain)
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class-union1.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class-union1.C
new file mode 100644
index 00000000000..038d46fdac8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class-union1.C
@@ -0,0 +1,25 @@ 
+// { dg-do compile { target c++20 } }
+
+template <auto N> struct A {};
+template <class,class> struct assert_same;
+template <class T> struct assert_same<T,T> {};
+
+#define TEQ(X,Y) static_assert(__is_same(A<(X)>,A<(Y)>))
+#define TNEQ(X,Y) static_assert(!__is_same(A<(X)>,A<(Y)>))
+
+union U {
+  int i; int j;
+  constexpr U(int i): i(i) {}
+  constexpr U(unsigned u): j(u) {}
+};
+
+TEQ(U(0),U(0));
+
+// Calling the other constructor initializes a different member with the same
+// value.  We need to distinguish these.
+TNEQ(U(0),U(0u));
+
+// { dg-final { scan-assembler "_Z1f1AIXtl1Udi1iLi0EEEE" } }
+void f(A<U(0)>) { }
+// { dg-final { scan-assembler "_Z1g1AIXtl1Udi1jLi0EEEE" } }
+void g(A<U(0u)>) { }
diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c
index cbfb2f937ca..b413ba2be5f 100644
--- a/libiberty/cp-demangle.c
+++ b/libiberty/cp-demangle.c
@@ -1809,13 +1809,16 @@  const struct demangle_operator_info cplus_demangle_operators[] =
   { "cm", NL (","),         2 },
   { "co", NL ("~"),         1 },
   { "dV", NL ("/="),        2 },
+  { "dX", NL ("[...]="),     3 }, /* [expr...expr] = expr */
   { "da", NL ("delete[] "), 1 },
   { "dc", NL ("dynamic_cast"), 2 },
   { "de", NL ("*"),         1 },
+  { "di", NL ("="),         2 }, /* .name = expr */
   { "dl", NL ("delete "),   1 },
   { "ds", NL (".*"),        2 },
   { "dt", NL ("."),         2 },
   { "dv", NL ("/"),         2 },
+  { "dx", NL ("]="),        2 }, /* [expr] = expr */
   { "eO", NL ("^="),        2 },
   { "eo", NL ("^"),         2 },
   { "eq", NL ("=="),        2 },
@@ -3291,6 +3294,12 @@  op_is_new_cast (struct demangle_component *op)
                 ::= sr <type> <unqualified-name>
                 ::= sr <type> <unqualified-name> <template-args>
                 ::= <expr-primary>
+
+  <braced-expression> ::= <expression>
+		      ::= di <field source-name> <braced-expression>	# .name = expr
+		      ::= dx <index expression> <braced-expression>	# [expr] = expr
+		      ::= dX <range begin expression> <range end expression> <braced-expression>
+									# [expr ... expr] = expr
 */
 
 static inline struct demangle_component *
@@ -3453,6 +3462,8 @@  d_expression_1 (struct d_info *di)
 	    else if (code[0] == 'f')
 	      /* fold-expression.  */
 	      left = d_operator_name (di);
+	    else if (!strcmp (code, "di"))
+	      left = d_unqualified_name (di);
 	    else
 	      left = d_expression_1 (di);
 	    if (!strcmp (code, "cl"))
@@ -3480,7 +3491,8 @@  d_expression_1 (struct d_info *di)
 
 	    if (code == NULL)
 	      return NULL;
-	    else if (!strcmp (code, "qu"))
+	    else if (!strcmp (code, "qu")
+		     || !strcmp (code, "dX"))
 	      {
 		/* ?: expression.  */
 		first = d_expression_1 (di);
@@ -4675,6 +4687,64 @@  d_maybe_print_fold_expression (struct d_print_info *dpi, int options,
   return 1;
 }
 
+/* True iff DC represents a C99-style designated initializer.  */
+
+static int
+is_designated_init (struct demangle_component *dc)
+{
+  if (dc->type != DEMANGLE_COMPONENT_BINARY
+      && dc->type != DEMANGLE_COMPONENT_TRINARY)
+    return 0;
+
+  struct demangle_component *op = d_left (dc);
+  const char *code = op->u.s_operator.op->code;
+  return (code[0] == 'd'
+	  && (code[1] == 'i' || code[1] == 'x' || code[1] == 'X'));
+}
+
+/* If DC represents a C99-style designated initializer, print it and return
+   true; otherwise, return false.  */
+
+static int
+d_maybe_print_designated_init (struct d_print_info *dpi, int options,
+			       struct demangle_component *dc)
+{
+  if (!is_designated_init (dc))
+    return 0;
+
+  const char *code = d_left (dc)->u.s_operator.op->code;
+
+  struct demangle_component *operands = d_right (dc);
+  struct demangle_component *op1 = d_left (operands);
+  struct demangle_component *op2 = d_right (operands);
+
+  if (code[1] == 'i')
+    d_append_char (dpi, '.');
+  else
+    d_append_char (dpi, '[');
+
+  d_print_comp (dpi, options, op1);
+  if (code[1] == 'X')
+    {
+      d_append_string (dpi, " ... ");
+      d_print_comp (dpi, options, d_left (op2));
+      op2 = d_right (op2);
+    }
+  if (code[1] != 'i')
+    d_append_char (dpi, ']');
+  if (is_designated_init (op2))
+    {
+      /* Don't put '=' or '(' between chained designators.  */
+      d_print_comp (dpi, options, op2);
+    }
+  else
+    {
+      d_append_char (dpi, '=');
+      d_print_subexpr (dpi, options, op2);
+    }
+  return 1;
+}
+
 /* Subroutine to handle components.  */
 
 static void
@@ -5491,6 +5561,9 @@  d_print_comp_inner (struct d_print_info *dpi, int options,
       if (d_maybe_print_fold_expression (dpi, options, dc))
 	return;
 
+      if (d_maybe_print_designated_init (dpi, options, dc))
+	return;
+
       /* We wrap an expression which uses the greater-than operator in
 	 an extra layer of parens so that it does not get confused
 	 with the '>' which ends the template parameters.  */
@@ -5548,6 +5621,8 @@  d_print_comp_inner (struct d_print_info *dpi, int options,
 	}
       if (d_maybe_print_fold_expression (dpi, options, dc))
 	return;
+      if (d_maybe_print_designated_init (dpi, options, dc))
+	return;
       {
 	struct demangle_component *op = d_left (dc);
 	struct demangle_component *first = d_left (d_right (dc));
diff --git a/libiberty/testsuite/demangle-expected b/libiberty/testsuite/demangle-expected
index d8e50951f84..2da27849835 100644
--- a/libiberty/testsuite/demangle-expected
+++ b/libiberty/testsuite/demangle-expected
@@ -1456,3 +1456,12 @@  coro1::empty::operator co_await() const
 
 _ZNK3FoossERKS_
 Foo::operator<=>(Foo const&) const
+
+_Z1f1AIXtl1Udi1iLi0EEEE
+f(A<U{.i=(0)}>)
+
+_Z1f1AIXtl1Xdi1adi1bdxLi3ELi1EEEE
+f(A<X{.a.b[3]=(1)}>)
+
+_Z1f1AIXtl1Xdi1adi1bdXLi3ELi4ELi1EEEE
+f(A<X{.a.b[3 ... 4]=(1)}>)