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

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.

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.
This commit is contained in:
Jason Merrill 2020-07-04 05:45:01 -04:00
parent 50f071d999
commit 6324c52bba
5 changed files with 119 additions and 10 deletions

View File

@ -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

View File

@ -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)

View File

@ -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)>) { }

View File

@ -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));

View File

@ -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)}>)