* [PATCH 1/2] c++: make strip_typedefs generalize strip_typedefs_expr
@ 2023-04-20 13:56 Patrick Palka
2023-04-20 13:56 ` [PATCH 2/2] c++: use TREE_VEC for trailing args of variadic built-in traits Patrick Palka
2023-04-20 16:58 ` [PATCH 1/2] c++: make strip_typedefs generalize strip_typedefs_expr Jason Merrill
0 siblings, 2 replies; 4+ messages in thread
From: Patrick Palka @ 2023-04-20 13:56 UTC (permalink / raw)
To: gcc-patches; +Cc: jason, Patrick Palka
If we have a TREE_VEC of types that we want to strip of typedefs, we
unintuitively need to call strip_typedefs_expr instead of strip_typedefs
since only strip_typedefs_expr handles TREE_VEC, and it also dispatches
to strip_typedefs when given a type. But this seems backwards: arguably
strip_typedefs_expr should be the more specialized function, which
strip_typedefs dispatches to (and thus generalizes).
This patch makes strip_typedefs generalize strip_typedefs_expr, which
allows for some simplifications.
gcc/cp/ChangeLog:
* tree.cc (strip_typedefs): Move TREE_LIST handling to
strip_typedefs_expr. Dispatch to strip_typedefs_expr
for a non-type 't'.
<case TYPENAME_TYPE>: Remove manual dispatching to
strip_typedefs_expr.
<case TRAIT_TYPE>: Likewise.
(strip_typedefs_expr): Replaces calls to strip_typedefs_expr
with strip_typedefs throughout. Don't dispatch to strip_typedefs
for a type 't'.
<case TREE_LIST>: Replace this with the better version from
strip_typedefs.
---
gcc/cp/tree.cc | 83 +++++++++++++++-----------------------------------
1 file changed, 24 insertions(+), 59 deletions(-)
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 2c22fac17ee..f0fb78fe69d 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -1562,7 +1562,8 @@ apply_identity_attributes (tree result, tree attribs, bool *remove_attributes)
/* Builds a qualified variant of T that is either not a typedef variant
(the default behavior) or not a typedef variant of a user-facing type
- (if FLAGS contains STF_USER_FACING).
+ (if FLAGS contains STF_USER_FACING). If T is not a type, then this
+ just calls strip_typedefs_expr.
E.g. consider the following declarations:
typedef const int ConstInt;
@@ -1596,25 +1597,8 @@ strip_typedefs (tree t, bool *remove_attributes /* = NULL */,
if (!t || t == error_mark_node)
return t;
- if (TREE_CODE (t) == TREE_LIST)
- {
- bool changed = false;
- releasing_vec vec;
- tree r = t;
- for (; t; t = TREE_CHAIN (t))
- {
- gcc_assert (!TREE_PURPOSE (t));
- tree elt = strip_typedefs (TREE_VALUE (t), remove_attributes, flags);
- if (elt != TREE_VALUE (t))
- changed = true;
- vec_safe_push (vec, elt);
- }
- if (changed)
- r = build_tree_list_vec (vec);
- return r;
- }
-
- gcc_assert (TYPE_P (t));
+ if (!TYPE_P (t))
+ return strip_typedefs_expr (t, remove_attributes, flags);
if (t == TYPE_CANONICAL (t))
return t;
@@ -1747,12 +1731,7 @@ strip_typedefs (tree t, bool *remove_attributes /* = NULL */,
for (int i = 0; i < TREE_VEC_LENGTH (args); ++i)
{
tree arg = TREE_VEC_ELT (args, i);
- tree strip_arg;
- if (TYPE_P (arg))
- strip_arg = strip_typedefs (arg, remove_attributes, flags);
- else
- strip_arg = strip_typedefs_expr (arg, remove_attributes,
- flags);
+ tree strip_arg = strip_typedefs (arg, remove_attributes, flags);
TREE_VEC_ELT (new_args, i) = strip_arg;
if (strip_arg != arg)
changed = true;
@@ -1792,11 +1771,8 @@ strip_typedefs (tree t, bool *remove_attributes /* = NULL */,
break;
case TRAIT_TYPE:
{
- tree type1 = TRAIT_TYPE_TYPE1 (t);
- if (TYPE_P (type1))
- type1 = strip_typedefs (type1, remove_attributes, flags);
- else
- type1 = strip_typedefs_expr (type1, remove_attributes, flags);
+ tree type1 = strip_typedefs (TRAIT_TYPE_TYPE1 (t),
+ remove_attributes, flags);
tree type2 = strip_typedefs (TRAIT_TYPE_TYPE2 (t),
remove_attributes, flags);
if (type1 == TRAIT_TYPE_TYPE1 (t) && type2 == TRAIT_TYPE_TYPE2 (t))
@@ -1883,7 +1859,8 @@ strip_typedefs (tree t, bool *remove_attributes /* = NULL */,
return cp_build_qualified_type (result, cp_type_quals (t));
}
-/* Like strip_typedefs above, but works on expressions, so that in
+/* Like strip_typedefs above, but works on expressions (and other non-types
+ such as TREE_VEC), so that in
template<class T> struct A
{
@@ -1908,11 +1885,6 @@ strip_typedefs_expr (tree t, bool *remove_attributes, unsigned int flags)
if (DECL_P (t) || CONSTANT_CLASS_P (t))
return t;
- /* Some expressions have type operands, so let's handle types here rather
- than check TYPE_P in multiple places below. */
- if (TYPE_P (t))
- return strip_typedefs (t, remove_attributes, flags);
-
code = TREE_CODE (t);
switch (code)
{
@@ -1940,26 +1912,19 @@ strip_typedefs_expr (tree t, bool *remove_attributes, unsigned int flags)
case TREE_LIST:
{
- releasing_vec vec;
bool changed = false;
- tree it;
- for (it = t; it; it = TREE_CHAIN (it))
+ releasing_vec vec;
+ r = t;
+ for (; t; t = TREE_CHAIN (t))
{
- tree val = strip_typedefs_expr (TREE_VALUE (it),
- remove_attributes, flags);
- vec_safe_push (vec, val);
- if (val != TREE_VALUE (it))
+ gcc_assert (!TREE_PURPOSE (t));
+ tree elt = strip_typedefs (TREE_VALUE (t), remove_attributes, flags);
+ if (elt != TREE_VALUE (t))
changed = true;
- gcc_assert (TREE_PURPOSE (it) == NULL_TREE);
+ vec_safe_push (vec, elt);
}
if (changed)
- {
- r = NULL_TREE;
- FOR_EACH_VEC_ELT_REVERSE (*vec, i, it)
- r = tree_cons (NULL_TREE, it, r);
- }
- else
- r = t;
+ r = build_tree_list_vec (vec);
return r;
}
@@ -1971,8 +1936,8 @@ strip_typedefs_expr (tree t, bool *remove_attributes, unsigned int flags)
vec_safe_reserve (vec, n);
for (i = 0; i < n; ++i)
{
- tree op = strip_typedefs_expr (TREE_VEC_ELT (t, i),
- remove_attributes, flags);
+ tree op = strip_typedefs (TREE_VEC_ELT (t, i),
+ remove_attributes, flags);
vec->quick_push (op);
if (op != TREE_VEC_ELT (t, i))
changed = true;
@@ -2000,15 +1965,15 @@ strip_typedefs_expr (tree t, bool *remove_attributes, unsigned int flags)
for (i = 0; i < n; ++i)
{
constructor_elt *e = &(*vec)[i];
- tree op = strip_typedefs_expr (e->value, remove_attributes, flags);
+ tree op = strip_typedefs (e->value, remove_attributes, flags);
if (op != e->value)
{
changed = true;
e->value = op;
}
gcc_checking_assert
- (e->index == strip_typedefs_expr (e->index, remove_attributes,
- flags));
+ (e->index == strip_typedefs (e->index, remove_attributes,
+ flags));
}
if (!changed && type == TREE_TYPE (t))
@@ -2057,8 +2022,8 @@ strip_typedefs_expr (tree t, bool *remove_attributes, unsigned int flags)
default:
for (i = 0; i < n; ++i)
- ops[i] = strip_typedefs_expr (TREE_OPERAND (t, i),
- remove_attributes, flags);
+ ops[i] = strip_typedefs (TREE_OPERAND (t, i),
+ remove_attributes, flags);
break;
}
--
2.40.0.352.g667fcf4e15
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 2/2] c++: use TREE_VEC for trailing args of variadic built-in traits
2023-04-20 13:56 [PATCH 1/2] c++: make strip_typedefs generalize strip_typedefs_expr Patrick Palka
@ 2023-04-20 13:56 ` Patrick Palka
2023-04-20 17:03 ` Jason Merrill
2023-04-20 16:58 ` [PATCH 1/2] c++: make strip_typedefs generalize strip_typedefs_expr Jason Merrill
1 sibling, 1 reply; 4+ messages in thread
From: Patrick Palka @ 2023-04-20 13:56 UTC (permalink / raw)
To: gcc-patches; +Cc: jason, Patrick Palka
This patch makes us use a TREE_VEC instead of TREE_LIST to represent the
trailing arguments of a variadic built-in trait. These built-ins are
typically passed a simple pack expansion as the second argument, e.g.
__is_constructible(T, Ts...)
so the main benefit of this representation change means that expanding
such an argument list at substitution time is now basically free, since
argument packs are also TREE_VECs and tsubst_template_args makes sure
we reuse this TREE_VEC when expanding such pack expansions. Previously,
we would perform the expansion via tsubst_tree_list which converts the
expanded pack expansion into a TREE_LIST.
Note, after this patch an empty set of trailing arguments is now
represented as an empty TREE_VEC instead of NULL_TREE, so
TRAIT_TYPE/EXPR_TYPE2 should be empty only for unary traits now.
(This patch slightly depends on "c++: make strip_typedefs generalize
strip_typedefs_expr". Without it, strip_typedefs <case TRAIT_TYPE>
would need to conditionally dispatch to strip_typedefs_expr for
non-TYPE_P TRAIT_TYPE_TYPE2 since it could now be a TREE_VEC which
only strip_typedefs_expr handles.)
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?
gcc/cp/ChangeLog:
* constraint.cc (diagnose_trait_expr): Convert a TREE_VEC
of arguments into a TREE_LIST for sake of pretty printing.
* cxx-pretty-print.cc (pp_cxx_trait): Handle TREE_VEC
instead of TREE_LIST of variadic trait arguments.
* method.cc (constructible_expr): Likewise.
(is_xible_helper): Likewise.
* parser.cc (cp_parser_trait): Represent variadic trait
arguments as a TREE_VEC instead of TREE_LIST.
* pt.cc (value_dependent_expression_p): Handle TREE_VEC
instead of TREE_LIST of variadic trait arguments.
* semantics.cc (finish_type_pack_element): Likewise.
(check_trait_type): Likewise.
---
gcc/cp/constraint.cc | 10 ++++++++++
gcc/cp/cxx-pretty-print.cc | 6 +++---
gcc/cp/method.cc | 17 +++++++++--------
gcc/cp/parser.cc | 10 ++++++----
gcc/cp/pt.cc | 9 ++++-----
gcc/cp/semantics.cc | 15 +++++++++------
6 files changed, 41 insertions(+), 26 deletions(-)
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 273d15ab097..dfead28e8c7 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3675,6 +3675,16 @@ diagnose_trait_expr (tree expr, tree args)
tree t1 = TRAIT_EXPR_TYPE1 (expr);
tree t2 = TRAIT_EXPR_TYPE2 (expr);
+ if (t2 && TREE_CODE (t2) == TREE_VEC)
+ {
+ /* Convert the TREE_VEC of arguments into a TREE_LIST, since the
+ pretty printer cannot directly print a TREE_VEC but it can a
+ TREE_LIST via the E format specifier. */
+ tree list = NULL_TREE;
+ for (tree t : tree_vec_range (t2))
+ list = tree_cons (NULL_TREE, t, list);
+ t2 = nreverse (list);
+ }
switch (TRAIT_EXPR_KIND (expr))
{
case CPTK_HAS_NOTHROW_ASSIGN:
diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc
index c33919873f1..4cda27f2b30 100644
--- a/gcc/cp/cxx-pretty-print.cc
+++ b/gcc/cp/cxx-pretty-print.cc
@@ -2640,16 +2640,16 @@ pp_cxx_trait (cxx_pretty_printer *pp, tree t)
}
if (type2)
{
- if (TREE_CODE (type2) != TREE_LIST)
+ if (TREE_CODE (type2) != TREE_VEC)
{
pp_cxx_separate_with (pp, ',');
pp->type_id (type2);
}
else
- for (tree arg = type2; arg; arg = TREE_CHAIN (arg))
+ for (tree arg : tree_vec_range (type2))
{
pp_cxx_separate_with (pp, ',');
- pp->type_id (TREE_VALUE (arg));
+ pp->type_id (arg);
}
}
if (kind == CPTK_TYPE_PACK_ELEMENT)
diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
index 225ec456143..00eae56eb5b 100644
--- a/gcc/cp/method.cc
+++ b/gcc/cp/method.cc
@@ -2075,8 +2075,9 @@ constructible_expr (tree to, tree from)
if (!TYPE_REF_P (to))
to = cp_build_reference_type (to, /*rval*/false);
tree ob = build_stub_object (to);
- for (; from; from = TREE_CHAIN (from))
- vec_safe_push (args, build_stub_object (TREE_VALUE (from)));
+ vec_alloc (args, TREE_VEC_LENGTH (from));
+ for (tree arg : tree_vec_range (from))
+ args->quick_push (build_stub_object (arg));
expr = build_special_member_call (ob, complete_ctor_identifier, &args,
ctype, LOOKUP_NORMAL, tf_none);
if (expr == error_mark_node)
@@ -2096,9 +2097,9 @@ constructible_expr (tree to, tree from)
}
else
{
- if (from == NULL_TREE)
+ const int len = TREE_VEC_LENGTH (from);
+ if (len == 0)
return build_value_init (strip_array_types (to), tf_none);
- const int len = list_length (from);
if (len > 1)
{
if (cxx_dialect < cxx20)
@@ -2112,9 +2113,9 @@ constructible_expr (tree to, tree from)
should be true. */
vec<constructor_elt, va_gc> *v;
vec_alloc (v, len);
- for (tree t = from; t; t = TREE_CHAIN (t))
+ for (tree arg : tree_vec_range (from))
{
- tree stub = build_stub_object (TREE_VALUE (t));
+ tree stub = build_stub_object (arg);
constructor_elt elt = { NULL_TREE, stub };
v->quick_push (elt);
}
@@ -2123,7 +2124,7 @@ constructible_expr (tree to, tree from)
CONSTRUCTOR_IS_PAREN_INIT (from) = true;
}
else
- from = build_stub_object (TREE_VALUE (from));
+ from = build_stub_object (TREE_VEC_ELT (from, 0));
expr = perform_direct_initialization_if_possible (to, from,
/*cast*/false,
tf_none);
@@ -2160,7 +2161,7 @@ is_xible_helper (enum tree_code code, tree to, tree from, bool trivial)
tree expr;
if (code == MODIFY_EXPR)
expr = assignable_expr (to, from);
- else if (trivial && from && TREE_CHAIN (from)
+ else if (trivial && TREE_VEC_LENGTH (from) > 1
&& cxx_dialect < cxx20)
return error_mark_node; // only 0- and 1-argument ctors can be trivial
// before C++20 aggregate paren init
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index ee1497b7071..7ecf97b937b 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -11003,9 +11003,8 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
"is not a type");
return error_mark_node;
}
- type2 = tree_cons (NULL_TREE, elt, type2);
}
- type2 = nreverse (type2);
+ type2 = rest;
}
else if (binary)
{
@@ -11021,6 +11020,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
}
else if (variadic)
{
+ auto_vec<tree, 4> rest;
while (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
{
cp_lexer_consume_token (parser->lexer);
@@ -11032,9 +11032,11 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
}
if (elt == error_mark_node)
return error_mark_node;
- type2 = tree_cons (NULL_TREE, elt, type2);
+ rest.safe_push (elt);
}
- type2 = nreverse (type2);
+ type2 = make_tree_vec (rest.length ());
+ for (int i = 0; i < TREE_VEC_LENGTH (type2); ++i)
+ TREE_VEC_ELT (type2, i) = rest[i];
}
location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location;
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index f65f2d58b28..d393c99ba9e 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -28065,19 +28065,18 @@ value_dependent_expression_p (tree expression)
case TRAIT_EXPR:
{
- tree type2 = TRAIT_EXPR_TYPE2 (expression);
-
if (dependent_type_p (TRAIT_EXPR_TYPE1 (expression)))
return true;
+ tree type2 = TRAIT_EXPR_TYPE2 (expression);
if (!type2)
return false;
- if (TREE_CODE (type2) != TREE_LIST)
+ if (TREE_CODE (type2) != TREE_VEC)
return dependent_type_p (type2);
- for (; type2; type2 = TREE_CHAIN (type2))
- if (dependent_type_p (TREE_VALUE (type2)))
+ for (tree arg : tree_vec_range (type2))
+ if (dependent_type_p (arg))
return true;
return false;
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index a4f30fdac11..9ba316ab3be 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -4490,14 +4490,13 @@ finish_type_pack_element (tree idx, tree types, tsubst_flags_t complain)
error ("%<__type_pack_element%> index is negative");
return error_mark_node;
}
- tree result = chain_index (val, types);
- if (!result)
+ if (val >= TREE_VEC_LENGTH (types))
{
if (complain & tf_error)
error ("%<__type_pack_element%> index is out of range");
return error_mark_node;
}
- return TREE_VALUE (result);
+ return TREE_VEC_ELT (types, val);
}
/* Implement the __direct_bases keyword: Return the direct base classes
@@ -12121,9 +12120,13 @@ check_trait_type (tree type, int kind = 1)
if (type == NULL_TREE)
return true;
- if (TREE_CODE (type) == TREE_LIST)
- return (check_trait_type (TREE_VALUE (type))
- && check_trait_type (TREE_CHAIN (type)));
+ if (TREE_CODE (type) == TREE_VEC)
+ {
+ for (tree arg : tree_vec_range (type))
+ if (!check_trait_type (arg, kind))
+ return false;
+ return true;
+ }
if (kind == 1 && TREE_CODE (type) == ARRAY_TYPE && !TYPE_DOMAIN (type))
return true; // Array of unknown bound. Don't care about completeness.
--
2.40.0.352.g667fcf4e15
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH 1/2] c++: make strip_typedefs generalize strip_typedefs_expr
2023-04-20 13:56 [PATCH 1/2] c++: make strip_typedefs generalize strip_typedefs_expr Patrick Palka
2023-04-20 13:56 ` [PATCH 2/2] c++: use TREE_VEC for trailing args of variadic built-in traits Patrick Palka
@ 2023-04-20 16:58 ` Jason Merrill
1 sibling, 0 replies; 4+ messages in thread
From: Jason Merrill @ 2023-04-20 16:58 UTC (permalink / raw)
To: Patrick Palka, gcc-patches
On 4/20/23 09:56, Patrick Palka wrote:
> If we have a TREE_VEC of types that we want to strip of typedefs, we
> unintuitively need to call strip_typedefs_expr instead of strip_typedefs
> since only strip_typedefs_expr handles TREE_VEC, and it also dispatches
> to strip_typedefs when given a type. But this seems backwards: arguably
> strip_typedefs_expr should be the more specialized function, which
> strip_typedefs dispatches to (and thus generalizes).
>
> This patch makes strip_typedefs generalize strip_typedefs_expr, which
> allows for some simplifications.
OK.
> gcc/cp/ChangeLog:
>
> * tree.cc (strip_typedefs): Move TREE_LIST handling to
> strip_typedefs_expr. Dispatch to strip_typedefs_expr
> for a non-type 't'.
> <case TYPENAME_TYPE>: Remove manual dispatching to
> strip_typedefs_expr.
> <case TRAIT_TYPE>: Likewise.
> (strip_typedefs_expr): Replaces calls to strip_typedefs_expr
> with strip_typedefs throughout. Don't dispatch to strip_typedefs
> for a type 't'.
> <case TREE_LIST>: Replace this with the better version from
> strip_typedefs.
> ---
> gcc/cp/tree.cc | 83 +++++++++++++++-----------------------------------
> 1 file changed, 24 insertions(+), 59 deletions(-)
>
> diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
> index 2c22fac17ee..f0fb78fe69d 100644
> --- a/gcc/cp/tree.cc
> +++ b/gcc/cp/tree.cc
> @@ -1562,7 +1562,8 @@ apply_identity_attributes (tree result, tree attribs, bool *remove_attributes)
>
> /* Builds a qualified variant of T that is either not a typedef variant
> (the default behavior) or not a typedef variant of a user-facing type
> - (if FLAGS contains STF_USER_FACING).
> + (if FLAGS contains STF_USER_FACING). If T is not a type, then this
> + just calls strip_typedefs_expr.
>
> E.g. consider the following declarations:
> typedef const int ConstInt;
> @@ -1596,25 +1597,8 @@ strip_typedefs (tree t, bool *remove_attributes /* = NULL */,
> if (!t || t == error_mark_node)
> return t;
>
> - if (TREE_CODE (t) == TREE_LIST)
> - {
> - bool changed = false;
> - releasing_vec vec;
> - tree r = t;
> - for (; t; t = TREE_CHAIN (t))
> - {
> - gcc_assert (!TREE_PURPOSE (t));
> - tree elt = strip_typedefs (TREE_VALUE (t), remove_attributes, flags);
> - if (elt != TREE_VALUE (t))
> - changed = true;
> - vec_safe_push (vec, elt);
> - }
> - if (changed)
> - r = build_tree_list_vec (vec);
> - return r;
> - }
> -
> - gcc_assert (TYPE_P (t));
> + if (!TYPE_P (t))
> + return strip_typedefs_expr (t, remove_attributes, flags);
>
> if (t == TYPE_CANONICAL (t))
> return t;
> @@ -1747,12 +1731,7 @@ strip_typedefs (tree t, bool *remove_attributes /* = NULL */,
> for (int i = 0; i < TREE_VEC_LENGTH (args); ++i)
> {
> tree arg = TREE_VEC_ELT (args, i);
> - tree strip_arg;
> - if (TYPE_P (arg))
> - strip_arg = strip_typedefs (arg, remove_attributes, flags);
> - else
> - strip_arg = strip_typedefs_expr (arg, remove_attributes,
> - flags);
> + tree strip_arg = strip_typedefs (arg, remove_attributes, flags);
> TREE_VEC_ELT (new_args, i) = strip_arg;
> if (strip_arg != arg)
> changed = true;
> @@ -1792,11 +1771,8 @@ strip_typedefs (tree t, bool *remove_attributes /* = NULL */,
> break;
> case TRAIT_TYPE:
> {
> - tree type1 = TRAIT_TYPE_TYPE1 (t);
> - if (TYPE_P (type1))
> - type1 = strip_typedefs (type1, remove_attributes, flags);
> - else
> - type1 = strip_typedefs_expr (type1, remove_attributes, flags);
> + tree type1 = strip_typedefs (TRAIT_TYPE_TYPE1 (t),
> + remove_attributes, flags);
> tree type2 = strip_typedefs (TRAIT_TYPE_TYPE2 (t),
> remove_attributes, flags);
> if (type1 == TRAIT_TYPE_TYPE1 (t) && type2 == TRAIT_TYPE_TYPE2 (t))
> @@ -1883,7 +1859,8 @@ strip_typedefs (tree t, bool *remove_attributes /* = NULL */,
> return cp_build_qualified_type (result, cp_type_quals (t));
> }
>
> -/* Like strip_typedefs above, but works on expressions, so that in
> +/* Like strip_typedefs above, but works on expressions (and other non-types
> + such as TREE_VEC), so that in
>
> template<class T> struct A
> {
> @@ -1908,11 +1885,6 @@ strip_typedefs_expr (tree t, bool *remove_attributes, unsigned int flags)
> if (DECL_P (t) || CONSTANT_CLASS_P (t))
> return t;
>
> - /* Some expressions have type operands, so let's handle types here rather
> - than check TYPE_P in multiple places below. */
> - if (TYPE_P (t))
> - return strip_typedefs (t, remove_attributes, flags);
> -
> code = TREE_CODE (t);
> switch (code)
> {
> @@ -1940,26 +1912,19 @@ strip_typedefs_expr (tree t, bool *remove_attributes, unsigned int flags)
>
> case TREE_LIST:
> {
> - releasing_vec vec;
> bool changed = false;
> - tree it;
> - for (it = t; it; it = TREE_CHAIN (it))
> + releasing_vec vec;
> + r = t;
> + for (; t; t = TREE_CHAIN (t))
> {
> - tree val = strip_typedefs_expr (TREE_VALUE (it),
> - remove_attributes, flags);
> - vec_safe_push (vec, val);
> - if (val != TREE_VALUE (it))
> + gcc_assert (!TREE_PURPOSE (t));
> + tree elt = strip_typedefs (TREE_VALUE (t), remove_attributes, flags);
> + if (elt != TREE_VALUE (t))
> changed = true;
> - gcc_assert (TREE_PURPOSE (it) == NULL_TREE);
> + vec_safe_push (vec, elt);
> }
> if (changed)
> - {
> - r = NULL_TREE;
> - FOR_EACH_VEC_ELT_REVERSE (*vec, i, it)
> - r = tree_cons (NULL_TREE, it, r);
> - }
> - else
> - r = t;
> + r = build_tree_list_vec (vec);
> return r;
> }
>
> @@ -1971,8 +1936,8 @@ strip_typedefs_expr (tree t, bool *remove_attributes, unsigned int flags)
> vec_safe_reserve (vec, n);
> for (i = 0; i < n; ++i)
> {
> - tree op = strip_typedefs_expr (TREE_VEC_ELT (t, i),
> - remove_attributes, flags);
> + tree op = strip_typedefs (TREE_VEC_ELT (t, i),
> + remove_attributes, flags);
> vec->quick_push (op);
> if (op != TREE_VEC_ELT (t, i))
> changed = true;
> @@ -2000,15 +1965,15 @@ strip_typedefs_expr (tree t, bool *remove_attributes, unsigned int flags)
> for (i = 0; i < n; ++i)
> {
> constructor_elt *e = &(*vec)[i];
> - tree op = strip_typedefs_expr (e->value, remove_attributes, flags);
> + tree op = strip_typedefs (e->value, remove_attributes, flags);
> if (op != e->value)
> {
> changed = true;
> e->value = op;
> }
> gcc_checking_assert
> - (e->index == strip_typedefs_expr (e->index, remove_attributes,
> - flags));
> + (e->index == strip_typedefs (e->index, remove_attributes,
> + flags));
> }
>
> if (!changed && type == TREE_TYPE (t))
> @@ -2057,8 +2022,8 @@ strip_typedefs_expr (tree t, bool *remove_attributes, unsigned int flags)
>
> default:
> for (i = 0; i < n; ++i)
> - ops[i] = strip_typedefs_expr (TREE_OPERAND (t, i),
> - remove_attributes, flags);
> + ops[i] = strip_typedefs (TREE_OPERAND (t, i),
> + remove_attributes, flags);
> break;
> }
>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH 2/2] c++: use TREE_VEC for trailing args of variadic built-in traits
2023-04-20 13:56 ` [PATCH 2/2] c++: use TREE_VEC for trailing args of variadic built-in traits Patrick Palka
@ 2023-04-20 17:03 ` Jason Merrill
0 siblings, 0 replies; 4+ messages in thread
From: Jason Merrill @ 2023-04-20 17:03 UTC (permalink / raw)
To: Patrick Palka, gcc-patches
On 4/20/23 09:56, Patrick Palka wrote:
> This patch makes us use a TREE_VEC instead of TREE_LIST to represent the
> trailing arguments of a variadic built-in trait. These built-ins are
> typically passed a simple pack expansion as the second argument, e.g.
>
> __is_constructible(T, Ts...)
>
> so the main benefit of this representation change means that expanding
> such an argument list at substitution time is now basically free, since
> argument packs are also TREE_VECs and tsubst_template_args makes sure
> we reuse this TREE_VEC when expanding such pack expansions. Previously,
> we would perform the expansion via tsubst_tree_list which converts the
> expanded pack expansion into a TREE_LIST.
>
> Note, after this patch an empty set of trailing arguments is now
> represented as an empty TREE_VEC instead of NULL_TREE, so
> TRAIT_TYPE/EXPR_TYPE2 should be empty only for unary traits now.
>
> (This patch slightly depends on "c++: make strip_typedefs generalize
> strip_typedefs_expr". Without it, strip_typedefs <case TRAIT_TYPE>
> would need to conditionally dispatch to strip_typedefs_expr for
> non-TYPE_P TRAIT_TYPE_TYPE2 since it could now be a TREE_VEC which
> only strip_typedefs_expr handles.)
>
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk?
OK.
> gcc/cp/ChangeLog:
>
> * constraint.cc (diagnose_trait_expr): Convert a TREE_VEC
> of arguments into a TREE_LIST for sake of pretty printing.
> * cxx-pretty-print.cc (pp_cxx_trait): Handle TREE_VEC
> instead of TREE_LIST of variadic trait arguments.
> * method.cc (constructible_expr): Likewise.
> (is_xible_helper): Likewise.
> * parser.cc (cp_parser_trait): Represent variadic trait
> arguments as a TREE_VEC instead of TREE_LIST.
> * pt.cc (value_dependent_expression_p): Handle TREE_VEC
> instead of TREE_LIST of variadic trait arguments.
> * semantics.cc (finish_type_pack_element): Likewise.
> (check_trait_type): Likewise.
> ---
> gcc/cp/constraint.cc | 10 ++++++++++
> gcc/cp/cxx-pretty-print.cc | 6 +++---
> gcc/cp/method.cc | 17 +++++++++--------
> gcc/cp/parser.cc | 10 ++++++----
> gcc/cp/pt.cc | 9 ++++-----
> gcc/cp/semantics.cc | 15 +++++++++------
> 6 files changed, 41 insertions(+), 26 deletions(-)
>
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index 273d15ab097..dfead28e8c7 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -3675,6 +3675,16 @@ diagnose_trait_expr (tree expr, tree args)
>
> tree t1 = TRAIT_EXPR_TYPE1 (expr);
> tree t2 = TRAIT_EXPR_TYPE2 (expr);
> + if (t2 && TREE_CODE (t2) == TREE_VEC)
> + {
> + /* Convert the TREE_VEC of arguments into a TREE_LIST, since the
> + pretty printer cannot directly print a TREE_VEC but it can a
> + TREE_LIST via the E format specifier. */
> + tree list = NULL_TREE;
> + for (tree t : tree_vec_range (t2))
> + list = tree_cons (NULL_TREE, t, list);
> + t2 = nreverse (list);
> + }
> switch (TRAIT_EXPR_KIND (expr))
> {
> case CPTK_HAS_NOTHROW_ASSIGN:
> diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc
> index c33919873f1..4cda27f2b30 100644
> --- a/gcc/cp/cxx-pretty-print.cc
> +++ b/gcc/cp/cxx-pretty-print.cc
> @@ -2640,16 +2640,16 @@ pp_cxx_trait (cxx_pretty_printer *pp, tree t)
> }
> if (type2)
> {
> - if (TREE_CODE (type2) != TREE_LIST)
> + if (TREE_CODE (type2) != TREE_VEC)
> {
> pp_cxx_separate_with (pp, ',');
> pp->type_id (type2);
> }
> else
> - for (tree arg = type2; arg; arg = TREE_CHAIN (arg))
> + for (tree arg : tree_vec_range (type2))
> {
> pp_cxx_separate_with (pp, ',');
> - pp->type_id (TREE_VALUE (arg));
> + pp->type_id (arg);
> }
> }
> if (kind == CPTK_TYPE_PACK_ELEMENT)
> diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
> index 225ec456143..00eae56eb5b 100644
> --- a/gcc/cp/method.cc
> +++ b/gcc/cp/method.cc
> @@ -2075,8 +2075,9 @@ constructible_expr (tree to, tree from)
> if (!TYPE_REF_P (to))
> to = cp_build_reference_type (to, /*rval*/false);
> tree ob = build_stub_object (to);
> - for (; from; from = TREE_CHAIN (from))
> - vec_safe_push (args, build_stub_object (TREE_VALUE (from)));
> + vec_alloc (args, TREE_VEC_LENGTH (from));
> + for (tree arg : tree_vec_range (from))
> + args->quick_push (build_stub_object (arg));
> expr = build_special_member_call (ob, complete_ctor_identifier, &args,
> ctype, LOOKUP_NORMAL, tf_none);
> if (expr == error_mark_node)
> @@ -2096,9 +2097,9 @@ constructible_expr (tree to, tree from)
> }
> else
> {
> - if (from == NULL_TREE)
> + const int len = TREE_VEC_LENGTH (from);
> + if (len == 0)
> return build_value_init (strip_array_types (to), tf_none);
> - const int len = list_length (from);
> if (len > 1)
> {
> if (cxx_dialect < cxx20)
> @@ -2112,9 +2113,9 @@ constructible_expr (tree to, tree from)
> should be true. */
> vec<constructor_elt, va_gc> *v;
> vec_alloc (v, len);
> - for (tree t = from; t; t = TREE_CHAIN (t))
> + for (tree arg : tree_vec_range (from))
> {
> - tree stub = build_stub_object (TREE_VALUE (t));
> + tree stub = build_stub_object (arg);
> constructor_elt elt = { NULL_TREE, stub };
> v->quick_push (elt);
> }
> @@ -2123,7 +2124,7 @@ constructible_expr (tree to, tree from)
> CONSTRUCTOR_IS_PAREN_INIT (from) = true;
> }
> else
> - from = build_stub_object (TREE_VALUE (from));
> + from = build_stub_object (TREE_VEC_ELT (from, 0));
> expr = perform_direct_initialization_if_possible (to, from,
> /*cast*/false,
> tf_none);
> @@ -2160,7 +2161,7 @@ is_xible_helper (enum tree_code code, tree to, tree from, bool trivial)
> tree expr;
> if (code == MODIFY_EXPR)
> expr = assignable_expr (to, from);
> - else if (trivial && from && TREE_CHAIN (from)
> + else if (trivial && TREE_VEC_LENGTH (from) > 1
> && cxx_dialect < cxx20)
> return error_mark_node; // only 0- and 1-argument ctors can be trivial
> // before C++20 aggregate paren init
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index ee1497b7071..7ecf97b937b 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -11003,9 +11003,8 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> "is not a type");
> return error_mark_node;
> }
> - type2 = tree_cons (NULL_TREE, elt, type2);
> }
> - type2 = nreverse (type2);
> + type2 = rest;
> }
> else if (binary)
> {
> @@ -11021,6 +11020,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> }
> else if (variadic)
> {
> + auto_vec<tree, 4> rest;
> while (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
> {
> cp_lexer_consume_token (parser->lexer);
> @@ -11032,9 +11032,11 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> }
> if (elt == error_mark_node)
> return error_mark_node;
> - type2 = tree_cons (NULL_TREE, elt, type2);
> + rest.safe_push (elt);
> }
> - type2 = nreverse (type2);
> + type2 = make_tree_vec (rest.length ());
> + for (int i = 0; i < TREE_VEC_LENGTH (type2); ++i)
> + TREE_VEC_ELT (type2, i) = rest[i];
> }
>
> location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location;
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index f65f2d58b28..d393c99ba9e 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -28065,19 +28065,18 @@ value_dependent_expression_p (tree expression)
>
> case TRAIT_EXPR:
> {
> - tree type2 = TRAIT_EXPR_TYPE2 (expression);
> -
> if (dependent_type_p (TRAIT_EXPR_TYPE1 (expression)))
> return true;
>
> + tree type2 = TRAIT_EXPR_TYPE2 (expression);
> if (!type2)
> return false;
>
> - if (TREE_CODE (type2) != TREE_LIST)
> + if (TREE_CODE (type2) != TREE_VEC)
> return dependent_type_p (type2);
>
> - for (; type2; type2 = TREE_CHAIN (type2))
> - if (dependent_type_p (TREE_VALUE (type2)))
> + for (tree arg : tree_vec_range (type2))
> + if (dependent_type_p (arg))
> return true;
>
> return false;
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index a4f30fdac11..9ba316ab3be 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -4490,14 +4490,13 @@ finish_type_pack_element (tree idx, tree types, tsubst_flags_t complain)
> error ("%<__type_pack_element%> index is negative");
> return error_mark_node;
> }
> - tree result = chain_index (val, types);
> - if (!result)
> + if (val >= TREE_VEC_LENGTH (types))
> {
> if (complain & tf_error)
> error ("%<__type_pack_element%> index is out of range");
> return error_mark_node;
> }
> - return TREE_VALUE (result);
> + return TREE_VEC_ELT (types, val);
> }
>
> /* Implement the __direct_bases keyword: Return the direct base classes
> @@ -12121,9 +12120,13 @@ check_trait_type (tree type, int kind = 1)
> if (type == NULL_TREE)
> return true;
>
> - if (TREE_CODE (type) == TREE_LIST)
> - return (check_trait_type (TREE_VALUE (type))
> - && check_trait_type (TREE_CHAIN (type)));
> + if (TREE_CODE (type) == TREE_VEC)
> + {
> + for (tree arg : tree_vec_range (type))
> + if (!check_trait_type (arg, kind))
> + return false;
> + return true;
> + }
>
> if (kind == 1 && TREE_CODE (type) == ARRAY_TYPE && !TYPE_DOMAIN (type))
> return true; // Array of unknown bound. Don't care about completeness.
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2023-04-20 17:03 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-04-20 13:56 [PATCH 1/2] c++: make strip_typedefs generalize strip_typedefs_expr Patrick Palka
2023-04-20 13:56 ` [PATCH 2/2] c++: use TREE_VEC for trailing args of variadic built-in traits Patrick Palka
2023-04-20 17:03 ` Jason Merrill
2023-04-20 16:58 ` [PATCH 1/2] c++: make strip_typedefs generalize strip_typedefs_expr Jason Merrill
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).