public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [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).