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:
parent
50f071d999
commit
6324c52bba
5 changed files with 119 additions and 10 deletions
|
@ -3189,6 +3189,7 @@ write_expression (tree expr)
|
||||||
{
|
{
|
||||||
vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (expr);
|
vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (expr);
|
||||||
unsigned last_nonzero = UINT_MAX, i;
|
unsigned last_nonzero = UINT_MAX, i;
|
||||||
|
constructor_elt *ce;
|
||||||
tree val;
|
tree val;
|
||||||
|
|
||||||
if (!nontriv)
|
if (!nontriv)
|
||||||
|
@ -3197,12 +3198,18 @@ write_expression (tree expr)
|
||||||
last_nonzero = i;
|
last_nonzero = i;
|
||||||
|
|
||||||
if (nontriv || last_nonzero != UINT_MAX)
|
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)
|
if (i > last_nonzero)
|
||||||
break;
|
break;
|
||||||
/* FIXME handle RANGE_EXPR */
|
/* 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
|
else
|
||||||
|
|
|
@ -4534,13 +4534,6 @@ structural_type_p (tree t, bool explain)
|
||||||
structural types or (possibly multi-dimensional) array thereof. */
|
structural types or (possibly multi-dimensional) array thereof. */
|
||||||
if (!CLASS_TYPE_P (t))
|
if (!CLASS_TYPE_P (t))
|
||||||
return false;
|
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 (!literal_type_p (t))
|
||||||
{
|
{
|
||||||
if (explain)
|
if (explain)
|
||||||
|
|
25
gcc/testsuite/g++.dg/cpp2a/nontype-class-union1.C
Normal file
25
gcc/testsuite/g++.dg/cpp2a/nontype-class-union1.C
Normal 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)>) { }
|
|
@ -1809,13 +1809,16 @@ const struct demangle_operator_info cplus_demangle_operators[] =
|
||||||
{ "cm", NL (","), 2 },
|
{ "cm", NL (","), 2 },
|
||||||
{ "co", NL ("~"), 1 },
|
{ "co", NL ("~"), 1 },
|
||||||
{ "dV", NL ("/="), 2 },
|
{ "dV", NL ("/="), 2 },
|
||||||
|
{ "dX", NL ("[...]="), 3 }, /* [expr...expr] = expr */
|
||||||
{ "da", NL ("delete[] "), 1 },
|
{ "da", NL ("delete[] "), 1 },
|
||||||
{ "dc", NL ("dynamic_cast"), 2 },
|
{ "dc", NL ("dynamic_cast"), 2 },
|
||||||
{ "de", NL ("*"), 1 },
|
{ "de", NL ("*"), 1 },
|
||||||
|
{ "di", NL ("="), 2 }, /* .name = expr */
|
||||||
{ "dl", NL ("delete "), 1 },
|
{ "dl", NL ("delete "), 1 },
|
||||||
{ "ds", NL (".*"), 2 },
|
{ "ds", NL (".*"), 2 },
|
||||||
{ "dt", NL ("."), 2 },
|
{ "dt", NL ("."), 2 },
|
||||||
{ "dv", NL ("/"), 2 },
|
{ "dv", NL ("/"), 2 },
|
||||||
|
{ "dx", NL ("]="), 2 }, /* [expr] = expr */
|
||||||
{ "eO", NL ("^="), 2 },
|
{ "eO", NL ("^="), 2 },
|
||||||
{ "eo", NL ("^"), 2 },
|
{ "eo", NL ("^"), 2 },
|
||||||
{ "eq", 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>
|
||||||
::= sr <type> <unqualified-name> <template-args>
|
::= sr <type> <unqualified-name> <template-args>
|
||||||
::= <expr-primary>
|
::= <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 *
|
static inline struct demangle_component *
|
||||||
|
@ -3453,6 +3462,8 @@ d_expression_1 (struct d_info *di)
|
||||||
else if (code[0] == 'f')
|
else if (code[0] == 'f')
|
||||||
/* fold-expression. */
|
/* fold-expression. */
|
||||||
left = d_operator_name (di);
|
left = d_operator_name (di);
|
||||||
|
else if (!strcmp (code, "di"))
|
||||||
|
left = d_unqualified_name (di);
|
||||||
else
|
else
|
||||||
left = d_expression_1 (di);
|
left = d_expression_1 (di);
|
||||||
if (!strcmp (code, "cl"))
|
if (!strcmp (code, "cl"))
|
||||||
|
@ -3480,7 +3491,8 @@ d_expression_1 (struct d_info *di)
|
||||||
|
|
||||||
if (code == NULL)
|
if (code == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
else if (!strcmp (code, "qu"))
|
else if (!strcmp (code, "qu")
|
||||||
|
|| !strcmp (code, "dX"))
|
||||||
{
|
{
|
||||||
/* ?: expression. */
|
/* ?: expression. */
|
||||||
first = d_expression_1 (di);
|
first = d_expression_1 (di);
|
||||||
|
@ -4675,6 +4687,64 @@ d_maybe_print_fold_expression (struct d_print_info *dpi, int options,
|
||||||
return 1;
|
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. */
|
/* Subroutine to handle components. */
|
||||||
|
|
||||||
static void
|
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))
|
if (d_maybe_print_fold_expression (dpi, options, dc))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (d_maybe_print_designated_init (dpi, options, dc))
|
||||||
|
return;
|
||||||
|
|
||||||
/* We wrap an expression which uses the greater-than operator in
|
/* We wrap an expression which uses the greater-than operator in
|
||||||
an extra layer of parens so that it does not get confused
|
an extra layer of parens so that it does not get confused
|
||||||
with the '>' which ends the template parameters. */
|
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))
|
if (d_maybe_print_fold_expression (dpi, options, dc))
|
||||||
return;
|
return;
|
||||||
|
if (d_maybe_print_designated_init (dpi, options, dc))
|
||||||
|
return;
|
||||||
{
|
{
|
||||||
struct demangle_component *op = d_left (dc);
|
struct demangle_component *op = d_left (dc);
|
||||||
struct demangle_component *first = d_left (d_right (dc));
|
struct demangle_component *first = d_left (d_right (dc));
|
||||||
|
|
|
@ -1456,3 +1456,12 @@ coro1::empty::operator co_await() const
|
||||||
|
|
||||||
_ZNK3FoossERKS_
|
_ZNK3FoossERKS_
|
||||||
Foo::operator<=>(Foo const&) const
|
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)}>)
|
||||||
|
|
Loading…
Add table
Reference in a new issue