[3/2] c++: remove WILDCARD_DECL

Message ID 20241023203026.1680883-1-ppalka@redhat.com
State New
Headers
Series None |

Commit Message

Patrick Palka Oct. 23, 2024, 8:30 p.m. UTC
  Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
OK for trunk?

-- >8 --

This tree code was added as part of the initial Concepts TS
implementation to support type-constraints introducing any kind
of template-parameter, not just type template-parameters, e.g.

  template<int N> concept C = ...;
  template<template<class> class TT> concept D = ...;

  template<C T, D U> void f(); // T is an NTTP of type int, U is a TTP

When resolving the type-constraint we would use WILDCARD_DECL as the
dummy first argument during template argument coercion that is a valid
argument for any kind of template parameter.

But Concepts TS support has been removed, and C++20 type-constraints are
restricted to only introduce type template-parameters, and so we don't
need this catch-all WILDCARD_DECL anymore; we can instead use an auto
as the dummy first argument.

In passing introduce a helper for returning the prototype parameter
(i.e. first template parameter) of a concept and use it.  Also remove a
redundant concept_definition_p overload.

gcc/cp/ChangeLog:

	* constraint.cc (build_type_constraint): Use an auto as the
	first template argument.
	(finish_shorthand_constraint): Use concept_prototype_parameter.
	* cp-objcp-common.cc (cp_common_init_ts): Remove WILDCARD_DECL
	handling.
	* cp-tree.def (WILDCARD_DECL): Remove.
	* cp-tree.h (WILDCARD_PACK_P): Remove.
	(concept_definition_p): Remove redundant overload.
	(concept_prototype_parameter): Define.
	* error.cc (dump_decl) <case WILDCARD_DECL>: Remove.
	(dump_expr) <case WILDCARD_DECL>: Likewise.
	* parser.cc (cp_parser_placeholder_type_specifier): Check
	the prototype parameter earlier, before build_type_constraint.
	Use concept_prototype_parameter.
	* pt.cc (convert_wildcard_argument): Remove.
	(convert_template_argument): Remove WILDCARD_DECL handling.
	(coerce_template_parameter_pack): Likewise.
	(tsubst) <case TEMPLATE_TYPE_PARM>: Likewise.
	(type_dependent_expression_p): Likewise.
	(placeholder_type_constraint_dependent_p): Likewise.
---
 gcc/cp/constraint.cc      |  6 ++----
 gcc/cp/cp-objcp-common.cc |  1 -
 gcc/cp/cp-tree.def        |  6 ------
 gcc/cp/cp-tree.h          | 27 ++++++++++++++-------------
 gcc/cp/error.cc           |  5 -----
 gcc/cp/parser.cc          | 31 +++++++++++++++----------------
 gcc/cp/pt.cc              | 37 ++-----------------------------------
 7 files changed, 33 insertions(+), 80 deletions(-)
  

Comments

Patrick Palka Oct. 25, 2024, 12:28 p.m. UTC | #1
On Wed, 23 Oct 2024, Patrick Palka wrote:

> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> OK for trunk?
> 
> -- >8 --
> 
> This tree code was added as part of the initial Concepts TS
> implementation to support type-constraints introducing any kind
> of template-parameter, not just type template-parameters, e.g.
> 
>   template<int N> concept C = ...;
>   template<template<class> class TT> concept D = ...;
> 
>   template<C T, D U> void f(); // T is an NTTP of type int, U is a TTP
> 
> When resolving the type-constraint we would use WILDCARD_DECL as the
> dummy first argument during template argument coercion that is a valid
> argument for any kind of template parameter.
> 
> But Concepts TS support has been removed, and C++20 type-constraints are
> restricted to only introduce type template-parameters, and so we don't
> need this catch-all WILDCARD_DECL anymore; we can instead use an auto
> as the dummy first argument.
> 
> In passing introduce a helper for returning the prototype parameter
> (i.e. first template parameter) of a concept and use it.  Also remove a
> redundant concept_definition_p overload.
> 
> gcc/cp/ChangeLog:
> 
> 	* constraint.cc (build_type_constraint): Use an auto as the
> 	first template argument.
> 	(finish_shorthand_constraint): Use concept_prototype_parameter.
> 	* cp-objcp-common.cc (cp_common_init_ts): Remove WILDCARD_DECL
> 	handling.
> 	* cp-tree.def (WILDCARD_DECL): Remove.
> 	* cp-tree.h (WILDCARD_PACK_P): Remove.
> 	(concept_definition_p): Remove redundant overload.
> 	(concept_prototype_parameter): Define.
> 	* error.cc (dump_decl) <case WILDCARD_DECL>: Remove.
> 	(dump_expr) <case WILDCARD_DECL>: Likewise.
> 	* parser.cc (cp_parser_placeholder_type_specifier): Check
> 	the prototype parameter earlier, before build_type_constraint.
> 	Use concept_prototype_parameter.
> 	* pt.cc (convert_wildcard_argument): Remove.
> 	(convert_template_argument): Remove WILDCARD_DECL handling.
> 	(coerce_template_parameter_pack): Likewise.
> 	(tsubst) <case TEMPLATE_TYPE_PARM>: Likewise.
> 	(type_dependent_expression_p): Likewise.
> 	(placeholder_type_constraint_dependent_p): Likewise.
> ---
>  gcc/cp/constraint.cc      |  6 ++----
>  gcc/cp/cp-objcp-common.cc |  1 -
>  gcc/cp/cp-tree.def        |  6 ------
>  gcc/cp/cp-tree.h          | 27 ++++++++++++++-------------
>  gcc/cp/error.cc           |  5 -----
>  gcc/cp/parser.cc          | 31 +++++++++++++++----------------
>  gcc/cp/pt.cc              | 37 ++-----------------------------------
>  7 files changed, 33 insertions(+), 80 deletions(-)
> 
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index 9394bea8835..d6a6ac03393 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -1154,9 +1154,8 @@ build_concept_id (tree expr)
>  tree
>  build_type_constraint (tree decl, tree args, tsubst_flags_t complain)
>  {
> -  tree wildcard = build_nt (WILDCARD_DECL);
>    ++processing_template_decl;
> -  tree check = build_concept_check (decl, wildcard, args, complain);
> +  tree check = build_concept_check (decl, make_auto (), args, complain);

On second thought I think it's better simply use the prototype parameter
as its own argument here so that we don't have to allocate a new auto
for each type-constraint we build.  And it's more in the spirit with how
WILDCARD_DECL behaved.

Like so:

-- >8 --

Subject: [PATCH v2] c++: remove WILDCARD_DECL

gcc/cp/ChangeLog:

	* constraint.cc (build_type_constraint): Use the prototype
	parameter as the first template argument.
	(finish_shorthand_constraint): Use concept_prototype_parameter.
	* cp-objcp-common.cc (cp_common_init_ts): Remove WILDCARD_DECL
	handling.
	* cp-tree.def (WILDCARD_DECL): Remove.
	* cp-tree.h (WILDCARD_PACK_P): Remove.
	(concept_definition_p): Remove redundant overload.
	(concept_prototype_parameter): Define.
	* error.cc (dump_decl) <case WILDCARD_DECL>: Remove.
	(dump_expr) <case WILDCARD_DECL>: Likewise.
	* parser.cc (cp_parser_placeholder_type_specifier): Check
	the prototype parameter earlier, before build_type_constraint.
	Use concept_prototype_parameter.
	* pt.cc (convert_wildcard_argument): Remove.
	(convert_template_argument): Remove WILDCARD_DECL handling.
	(coerce_template_parameter_pack): Likewise.
	(tsubst) <case TEMPLATE_TYPE_PARM>: Likewise.
	(type_dependent_expression_p): Likewise.
	(placeholder_type_constraint_dependent_p): Likewise.
---
 gcc/cp/constraint.cc      |  7 +++----
 gcc/cp/cp-objcp-common.cc |  1 -
 gcc/cp/cp-tree.def        |  6 ------
 gcc/cp/cp-tree.h          | 27 ++++++++++++++-------------
 gcc/cp/error.cc           |  5 -----
 gcc/cp/parser.cc          | 31 +++++++++++++++----------------
 gcc/cp/pt.cc              | 37 ++-----------------------------------
 7 files changed, 34 insertions(+), 80 deletions(-)

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 9394bea8835..8b826cb240e 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -1154,9 +1154,9 @@ build_concept_id (tree expr)
 tree
 build_type_constraint (tree decl, tree args, tsubst_flags_t complain)
 {
-  tree wildcard = build_nt (WILDCARD_DECL);
+  tree proto = template_parm_to_arg (concept_prototype_parameter (decl));
   ++processing_template_decl;
-  tree check = build_concept_check (decl, wildcard, args, complain);
+  tree check = build_concept_check (decl, proto, args, complain);
   --processing_template_decl;
   return check;
 }
@@ -1203,8 +1203,7 @@ finish_shorthand_constraint (tree decl, tree constr, bool is_non_type)
     {
       tree id = PLACEHOLDER_TYPE_CONSTRAINTS (constr);
       tree tmpl = TREE_OPERAND (id, 0);
-      tree parms = DECL_INNERMOST_TEMPLATE_PARMS (tmpl);
-      proto = TREE_VALUE (TREE_VEC_ELT (parms, 0));
+      proto = concept_prototype_parameter (tmpl);
       con = DECL_TEMPLATE_RESULT (tmpl);
       args = TREE_OPERAND (id, 1);
     }
diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
index cd379514991..69eed72a5a2 100644
--- a/gcc/cp/cp-objcp-common.cc
+++ b/gcc/cp/cp-objcp-common.cc
@@ -624,7 +624,6 @@ cp_common_init_ts (void)
 
   /* New decls.  */
   MARK_TS_DECL_COMMON (TEMPLATE_DECL);
-  MARK_TS_DECL_COMMON (WILDCARD_DECL);
 
   MARK_TS_DECL_NON_COMMON (USING_DECL);
 
diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
index 18f75108c7b..53511a6d8cc 100644
--- a/gcc/cp/cp-tree.def
+++ b/gcc/cp/cp-tree.def
@@ -487,12 +487,6 @@ DEFTREECODE (OMP_DEPOBJ, "omp_depobj", tcc_statement, 2)
 /* Used to represent information associated with constrained declarations. */
 DEFTREECODE (CONSTRAINT_INFO, "constraint_info", tcc_exceptional, 0)
 
-/* A wildcard declaration is a placeholder for a template parameter
-   used to resolve constrained-type-names in concepts.  During
-   resolution, the matching argument is saved as the TREE_TYPE
-   of the wildcard.  */
-DEFTREECODE (WILDCARD_DECL, "wildcard_decl", tcc_declaration, 0)
-
 /* A requires-expr has three operands. The first operand is
    its parameter list (possibly NULL). The second is a list of
    requirements, which are denoted by the _REQ* tree codes
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 6dcf32b178e..c25dafd5981 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -438,7 +438,6 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
       TINFO_HAS_ACCESS_ERRORS (in TEMPLATE_INFO)
       SIZEOF_EXPR_TYPE_P (in SIZEOF_EXPR)
       COMPOUND_REQ_NOEXCEPT_P (in COMPOUND_REQ)
-      WILDCARD_PACK_P (in WILDCARD_DECL)
       BLOCK_OUTER_CURLY_BRACE_P (in BLOCK)
       FOLD_EXPR_MODIFY_P (*_FOLD_EXPR)
       IF_STMT_CONSTEXPR_P (IF_STMT)
@@ -4042,9 +4041,6 @@ struct GTY(()) lang_decl {
 #define PACK_EXPANSION_FORCE_EXTRA_ARGS_P(NODE) \
   TREE_LANG_FLAG_3 (PACK_EXPANSION_CHECK (NODE))
 
-/* True iff the wildcard can match a template parameter pack.  */
-#define WILDCARD_PACK_P(NODE) TREE_LANG_FLAG_0 (NODE)
-
 /* Determine if this is an argument pack.  */
 #define ARGUMENT_PACK_P(NODE)                          \
   (TREE_CODE (NODE) == TYPE_ARGUMENT_PACK              \
@@ -8879,18 +8875,10 @@ variable_template_p (tree t)
 
 /* True iff T is a concept.  */
 
-inline bool
-concept_definition_p (tree t)
-{
-  return TREE_CODE (STRIP_TEMPLATE (t)) == CONCEPT_DECL;
-}
-
-/* Same as above, but for const trees.  */
-
 inline bool
 concept_definition_p (const_tree t)
 {
-  return concept_definition_p (const_cast<tree> (t));
+  return TREE_CODE (STRIP_TEMPLATE (t)) == CONCEPT_DECL;
 }
 
 /* True if t is an expression that checks a concept.  */
@@ -8903,6 +8891,19 @@ concept_check_p (const_tree t)
   return false;
 }
 
+/* Return the prototype parameter of the concept T,
+   i.e. its first declared template parameter.  */
+
+inline tree
+concept_prototype_parameter (const_tree t)
+{
+  gcc_checking_assert (concept_definition_p (t));
+  if (TREE_CODE (t) == CONCEPT_DECL)
+    t = DECL_TI_TEMPLATE (t);
+  tree parms = DECL_INNERMOST_TEMPLATE_PARMS (t);
+  return TREE_VALUE (TREE_VEC_ELT (parms, 0));
+}
+
 /* Helpers for IMPLICIT_RVALUE_P to look through automatic dereference.  */
 
 inline bool
diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
index 65f70c595cf..c5b256f3907 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -1542,10 +1542,6 @@ dump_decl (cxx_pretty_printer *pp, tree t, int flags)
       dump_simple_decl (pp, t, TREE_TYPE (t), flags);
       break;
 
-    case WILDCARD_DECL:
-      pp_string (pp, "<wildcard>");
-      break;
-
     case TEMPLATE_ID_EXPR:
       {
 	tree name = TREE_OPERAND (t, 0);
@@ -2376,7 +2372,6 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
     case TEMPLATE_DECL:
     case NAMESPACE_DECL:
     case LABEL_DECL:
-    case WILDCARD_DECL:
     case OVERLOAD:
     case TYPE_DECL:
     case USING_DECL:
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 0bad62978dc..16e05acd7b8 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -20918,15 +20918,27 @@ cp_parser_placeholder_type_specifier (cp_parser *parser, location_t loc,
     /* A concept-name with no arguments can't be an expression.  */
     tentative = false;
 
+  tree con = STRIP_TEMPLATE (tmpl);
+  tree proto = concept_prototype_parameter (con);
   tsubst_flags_t complain = tentative ? tf_none : tf_warning_or_error;
 
+  /* A type constraint constrains a contextually determined type or type
+     parameter pack.  */
+  if (TREE_CODE (proto) != TYPE_DECL)
+    {
+      if (!tentative)
+	{
+	  auto_diagnostic_group d;
+	  error_at (loc, "%qE does not constrain a type", DECL_NAME (con));
+	  inform (DECL_SOURCE_LOCATION (con), "concept defined here");
+	}
+      return error_mark_node;
+    }
+
   /* Get the concept and prototype parameter for the constraint.  */
   tree check = build_type_constraint (tmpl, args, complain);
   if (check == error_mark_node)
     return error_mark_node;
-  tree con = STRIP_TEMPLATE (tmpl);
-  tree parms = DECL_INNERMOST_TEMPLATE_PARMS (tmpl);
-  tree proto = TREE_VALUE (TREE_VEC_ELT (parms, 0));
 
   /* As per the standard, require auto or decltype(auto).  */
   cp_token *placeholder = NULL, *close_paren = NULL;
@@ -20941,19 +20953,6 @@ cp_parser_placeholder_type_specifier (cp_parser *parser, location_t loc,
       close_paren = parens.require_close (parser);
     }
 
-  /* A type constraint constrains a contextually determined type or type
-     parameter pack.  */
-  if (TREE_CODE (proto) != TYPE_DECL)
-    {
-      if (!tentative)
-	{
-	  auto_diagnostic_group d;
-	  error_at (loc, "%qE does not constrain a type", DECL_NAME (con));
-	  inform (DECL_SOURCE_LOCATION (con), "concept defined here");
-	}
-      return error_mark_node;
-    }
-
   /* In a template parameter list, a type-parameter can be introduced
      by type-constraints alone.  */
   if (processing_template_parmlist && !placeholder)
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index ec4313090bd..9833b2bea5f 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -8539,16 +8539,6 @@ is_compatible_template_arg (tree parm, tree arg, tree args)
   return ttp_subsumes (parm_cons, arg);
 }
 
-// Convert a placeholder argument into a binding to the original
-// parameter. The original parameter is saved as the TREE_TYPE of
-// ARG.
-static inline tree
-convert_wildcard_argument (tree parm, tree arg)
-{
-  TREE_TYPE (arg) = parm;
-  return arg;
-}
-
 /* We can't fully resolve ARG given as a non-type template argument to TYPE,
    because one of them is dependent.  But we need to represent the
    conversion for the benefit of cp_tree_equal.  */
@@ -8603,10 +8593,6 @@ convert_template_argument (tree parm,
   if (parm == error_mark_node || error_operand_p (arg))
     return error_mark_node;
 
-  /* Trivially convert placeholders. */
-  if (TREE_CODE (arg) == WILDCARD_DECL)
-    return convert_wildcard_argument (parm, arg);
-
   if (arg == any_targ_node)
     return arg;
 
@@ -8988,16 +8974,6 @@ coerce_template_parameter_pack (tree parms,
 
       packed_args = make_tree_vec (TREE_VEC_LENGTH (packed_parms));
     }
-  /* Check if we have a placeholder pack, which indicates we're
-     in the context of a introduction list.  In that case we want
-     to match this pack to the single placeholder.  */
-  else if (arg_idx < nargs
-           && TREE_CODE (TREE_VEC_ELT (inner_args, arg_idx)) == WILDCARD_DECL
-           && WILDCARD_PACK_P (TREE_VEC_ELT (inner_args, arg_idx)))
-    {
-      nargs = arg_idx + 1;
-      packed_args = make_tree_vec (1);
-    }
   else
     packed_args = make_tree_vec (nargs - arg_idx);
 
@@ -16489,13 +16465,6 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	      {
 		int quals;
 
-		/* When building concept checks for the purpose of
-		   deducing placeholders, we can end up with wildcards
-		   where types are expected. Adjust this to the deduced
-		   value.  */
-		if (TREE_CODE (arg) == WILDCARD_DECL)
-		  arg = TREE_TYPE (TREE_TYPE (arg));
-
 		gcc_assert (TYPE_P (arg));
 
 		quals = cp_type_quals (arg) | cp_type_quals (t);
@@ -28559,8 +28528,7 @@ type_dependent_expression_p (tree expression)
 
   /* An unresolved name is always dependent.  */
   if (identifier_p (expression)
-      || TREE_CODE (expression) == USING_DECL
-      || TREE_CODE (expression) == WILDCARD_DECL)
+      || TREE_CODE (expression) == USING_DECL)
     return true;
 
   /* A lambda-expression in template context is dependent.  dependent_type_p is
@@ -29603,8 +29571,7 @@ placeholder_type_constraint_dependent_p (tree t)
       args = expand_template_argument_pack (args);
       first = TREE_VEC_ELT (args, 0);
     }
-  gcc_checking_assert (TREE_CODE (first) == WILDCARD_DECL
-		       || is_auto (first));
+  gcc_checking_assert (is_auto (first));
   for (int i = 1; i < TREE_VEC_LENGTH (args); ++i)
     if (dependent_template_arg_p (TREE_VEC_ELT (args, i)))
       return true;
  
Patrick Palka Nov. 5, 2024, 5:08 p.m. UTC | #2
On Fri, 25 Oct 2024, Patrick Palka wrote:

> On Wed, 23 Oct 2024, Patrick Palka wrote:
> 
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> > OK for trunk?
> > 
> > -- >8 --
> > 
> > This tree code was added as part of the initial Concepts TS
> > implementation to support type-constraints introducing any kind
> > of template-parameter, not just type template-parameters, e.g.
> > 
> >   template<int N> concept C = ...;
> >   template<template<class> class TT> concept D = ...;
> > 
> >   template<C T, D U> void f(); // T is an NTTP of type int, U is a TTP
> > 
> > When resolving the type-constraint we would use WILDCARD_DECL as the
> > dummy first argument during template argument coercion that is a valid
> > argument for any kind of template parameter.
> > 
> > But Concepts TS support has been removed, and C++20 type-constraints are
> > restricted to only introduce type template-parameters, and so we don't
> > need this catch-all WILDCARD_DECL anymore; we can instead use an auto
> > as the dummy first argument.
> > 
> > In passing introduce a helper for returning the prototype parameter
> > (i.e. first template parameter) of a concept and use it.  Also remove a
> > redundant concept_definition_p overload.
> > 
> > gcc/cp/ChangeLog:
> > 
> > 	* constraint.cc (build_type_constraint): Use an auto as the
> > 	first template argument.
> > 	(finish_shorthand_constraint): Use concept_prototype_parameter.
> > 	* cp-objcp-common.cc (cp_common_init_ts): Remove WILDCARD_DECL
> > 	handling.
> > 	* cp-tree.def (WILDCARD_DECL): Remove.
> > 	* cp-tree.h (WILDCARD_PACK_P): Remove.
> > 	(concept_definition_p): Remove redundant overload.
> > 	(concept_prototype_parameter): Define.
> > 	* error.cc (dump_decl) <case WILDCARD_DECL>: Remove.
> > 	(dump_expr) <case WILDCARD_DECL>: Likewise.
> > 	* parser.cc (cp_parser_placeholder_type_specifier): Check
> > 	the prototype parameter earlier, before build_type_constraint.
> > 	Use concept_prototype_parameter.
> > 	* pt.cc (convert_wildcard_argument): Remove.
> > 	(convert_template_argument): Remove WILDCARD_DECL handling.
> > 	(coerce_template_parameter_pack): Likewise.
> > 	(tsubst) <case TEMPLATE_TYPE_PARM>: Likewise.
> > 	(type_dependent_expression_p): Likewise.
> > 	(placeholder_type_constraint_dependent_p): Likewise.
> > ---
> >  gcc/cp/constraint.cc      |  6 ++----
> >  gcc/cp/cp-objcp-common.cc |  1 -
> >  gcc/cp/cp-tree.def        |  6 ------
> >  gcc/cp/cp-tree.h          | 27 ++++++++++++++-------------
> >  gcc/cp/error.cc           |  5 -----
> >  gcc/cp/parser.cc          | 31 +++++++++++++++----------------
> >  gcc/cp/pt.cc              | 37 ++-----------------------------------
> >  7 files changed, 33 insertions(+), 80 deletions(-)
> > 
> > diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> > index 9394bea8835..d6a6ac03393 100644
> > --- a/gcc/cp/constraint.cc
> > +++ b/gcc/cp/constraint.cc
> > @@ -1154,9 +1154,8 @@ build_concept_id (tree expr)
> >  tree
> >  build_type_constraint (tree decl, tree args, tsubst_flags_t complain)
> >  {
> > -  tree wildcard = build_nt (WILDCARD_DECL);
> >    ++processing_template_decl;
> > -  tree check = build_concept_check (decl, wildcard, args, complain);
> > +  tree check = build_concept_check (decl, make_auto (), args, complain);
> 
> On second thought I think it's better simply use the prototype parameter
> as its own argument here so that we don't have to allocate a new auto
> for each type-constraint we build.  And it's more in the spirit with how
> WILDCARD_DECL behaved.
> 
> Like so:

Ping.

> 
> -- >8 --
> 
> Subject: [PATCH v2] c++: remove WILDCARD_DECL
> 
> gcc/cp/ChangeLog:
> 
> 	* constraint.cc (build_type_constraint): Use the prototype
> 	parameter as the first template argument.
> 	(finish_shorthand_constraint): Use concept_prototype_parameter.
> 	* cp-objcp-common.cc (cp_common_init_ts): Remove WILDCARD_DECL
> 	handling.
> 	* cp-tree.def (WILDCARD_DECL): Remove.
> 	* cp-tree.h (WILDCARD_PACK_P): Remove.
> 	(concept_definition_p): Remove redundant overload.
> 	(concept_prototype_parameter): Define.
> 	* error.cc (dump_decl) <case WILDCARD_DECL>: Remove.
> 	(dump_expr) <case WILDCARD_DECL>: Likewise.
> 	* parser.cc (cp_parser_placeholder_type_specifier): Check
> 	the prototype parameter earlier, before build_type_constraint.
> 	Use concept_prototype_parameter.
> 	* pt.cc (convert_wildcard_argument): Remove.
> 	(convert_template_argument): Remove WILDCARD_DECL handling.
> 	(coerce_template_parameter_pack): Likewise.
> 	(tsubst) <case TEMPLATE_TYPE_PARM>: Likewise.
> 	(type_dependent_expression_p): Likewise.
> 	(placeholder_type_constraint_dependent_p): Likewise.
> ---
>  gcc/cp/constraint.cc      |  7 +++----
>  gcc/cp/cp-objcp-common.cc |  1 -
>  gcc/cp/cp-tree.def        |  6 ------
>  gcc/cp/cp-tree.h          | 27 ++++++++++++++-------------
>  gcc/cp/error.cc           |  5 -----
>  gcc/cp/parser.cc          | 31 +++++++++++++++----------------
>  gcc/cp/pt.cc              | 37 ++-----------------------------------
>  7 files changed, 34 insertions(+), 80 deletions(-)
> 
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index 9394bea8835..8b826cb240e 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -1154,9 +1154,9 @@ build_concept_id (tree expr)
>  tree
>  build_type_constraint (tree decl, tree args, tsubst_flags_t complain)
>  {
> -  tree wildcard = build_nt (WILDCARD_DECL);
> +  tree proto = template_parm_to_arg (concept_prototype_parameter (decl));
>    ++processing_template_decl;
> -  tree check = build_concept_check (decl, wildcard, args, complain);
> +  tree check = build_concept_check (decl, proto, args, complain);
>    --processing_template_decl;
>    return check;
>  }
> @@ -1203,8 +1203,7 @@ finish_shorthand_constraint (tree decl, tree constr, bool is_non_type)
>      {
>        tree id = PLACEHOLDER_TYPE_CONSTRAINTS (constr);
>        tree tmpl = TREE_OPERAND (id, 0);
> -      tree parms = DECL_INNERMOST_TEMPLATE_PARMS (tmpl);
> -      proto = TREE_VALUE (TREE_VEC_ELT (parms, 0));
> +      proto = concept_prototype_parameter (tmpl);
>        con = DECL_TEMPLATE_RESULT (tmpl);
>        args = TREE_OPERAND (id, 1);
>      }
> diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
> index cd379514991..69eed72a5a2 100644
> --- a/gcc/cp/cp-objcp-common.cc
> +++ b/gcc/cp/cp-objcp-common.cc
> @@ -624,7 +624,6 @@ cp_common_init_ts (void)
>  
>    /* New decls.  */
>    MARK_TS_DECL_COMMON (TEMPLATE_DECL);
> -  MARK_TS_DECL_COMMON (WILDCARD_DECL);
>  
>    MARK_TS_DECL_NON_COMMON (USING_DECL);
>  
> diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
> index 18f75108c7b..53511a6d8cc 100644
> --- a/gcc/cp/cp-tree.def
> +++ b/gcc/cp/cp-tree.def
> @@ -487,12 +487,6 @@ DEFTREECODE (OMP_DEPOBJ, "omp_depobj", tcc_statement, 2)
>  /* Used to represent information associated with constrained declarations. */
>  DEFTREECODE (CONSTRAINT_INFO, "constraint_info", tcc_exceptional, 0)
>  
> -/* A wildcard declaration is a placeholder for a template parameter
> -   used to resolve constrained-type-names in concepts.  During
> -   resolution, the matching argument is saved as the TREE_TYPE
> -   of the wildcard.  */
> -DEFTREECODE (WILDCARD_DECL, "wildcard_decl", tcc_declaration, 0)
> -
>  /* A requires-expr has three operands. The first operand is
>     its parameter list (possibly NULL). The second is a list of
>     requirements, which are denoted by the _REQ* tree codes
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 6dcf32b178e..c25dafd5981 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -438,7 +438,6 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
>        TINFO_HAS_ACCESS_ERRORS (in TEMPLATE_INFO)
>        SIZEOF_EXPR_TYPE_P (in SIZEOF_EXPR)
>        COMPOUND_REQ_NOEXCEPT_P (in COMPOUND_REQ)
> -      WILDCARD_PACK_P (in WILDCARD_DECL)
>        BLOCK_OUTER_CURLY_BRACE_P (in BLOCK)
>        FOLD_EXPR_MODIFY_P (*_FOLD_EXPR)
>        IF_STMT_CONSTEXPR_P (IF_STMT)
> @@ -4042,9 +4041,6 @@ struct GTY(()) lang_decl {
>  #define PACK_EXPANSION_FORCE_EXTRA_ARGS_P(NODE) \
>    TREE_LANG_FLAG_3 (PACK_EXPANSION_CHECK (NODE))
>  
> -/* True iff the wildcard can match a template parameter pack.  */
> -#define WILDCARD_PACK_P(NODE) TREE_LANG_FLAG_0 (NODE)
> -
>  /* Determine if this is an argument pack.  */
>  #define ARGUMENT_PACK_P(NODE)                          \
>    (TREE_CODE (NODE) == TYPE_ARGUMENT_PACK              \
> @@ -8879,18 +8875,10 @@ variable_template_p (tree t)
>  
>  /* True iff T is a concept.  */
>  
> -inline bool
> -concept_definition_p (tree t)
> -{
> -  return TREE_CODE (STRIP_TEMPLATE (t)) == CONCEPT_DECL;
> -}
> -
> -/* Same as above, but for const trees.  */
> -
>  inline bool
>  concept_definition_p (const_tree t)
>  {
> -  return concept_definition_p (const_cast<tree> (t));
> +  return TREE_CODE (STRIP_TEMPLATE (t)) == CONCEPT_DECL;
>  }
>  
>  /* True if t is an expression that checks a concept.  */
> @@ -8903,6 +8891,19 @@ concept_check_p (const_tree t)
>    return false;
>  }
>  
> +/* Return the prototype parameter of the concept T,
> +   i.e. its first declared template parameter.  */
> +
> +inline tree
> +concept_prototype_parameter (const_tree t)
> +{
> +  gcc_checking_assert (concept_definition_p (t));
> +  if (TREE_CODE (t) == CONCEPT_DECL)
> +    t = DECL_TI_TEMPLATE (t);
> +  tree parms = DECL_INNERMOST_TEMPLATE_PARMS (t);
> +  return TREE_VALUE (TREE_VEC_ELT (parms, 0));
> +}
> +
>  /* Helpers for IMPLICIT_RVALUE_P to look through automatic dereference.  */
>  
>  inline bool
> diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
> index 65f70c595cf..c5b256f3907 100644
> --- a/gcc/cp/error.cc
> +++ b/gcc/cp/error.cc
> @@ -1542,10 +1542,6 @@ dump_decl (cxx_pretty_printer *pp, tree t, int flags)
>        dump_simple_decl (pp, t, TREE_TYPE (t), flags);
>        break;
>  
> -    case WILDCARD_DECL:
> -      pp_string (pp, "<wildcard>");
> -      break;
> -
>      case TEMPLATE_ID_EXPR:
>        {
>  	tree name = TREE_OPERAND (t, 0);
> @@ -2376,7 +2372,6 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
>      case TEMPLATE_DECL:
>      case NAMESPACE_DECL:
>      case LABEL_DECL:
> -    case WILDCARD_DECL:
>      case OVERLOAD:
>      case TYPE_DECL:
>      case USING_DECL:
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index 0bad62978dc..16e05acd7b8 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -20918,15 +20918,27 @@ cp_parser_placeholder_type_specifier (cp_parser *parser, location_t loc,
>      /* A concept-name with no arguments can't be an expression.  */
>      tentative = false;
>  
> +  tree con = STRIP_TEMPLATE (tmpl);
> +  tree proto = concept_prototype_parameter (con);
>    tsubst_flags_t complain = tentative ? tf_none : tf_warning_or_error;
>  
> +  /* A type constraint constrains a contextually determined type or type
> +     parameter pack.  */
> +  if (TREE_CODE (proto) != TYPE_DECL)
> +    {
> +      if (!tentative)
> +	{
> +	  auto_diagnostic_group d;
> +	  error_at (loc, "%qE does not constrain a type", DECL_NAME (con));
> +	  inform (DECL_SOURCE_LOCATION (con), "concept defined here");
> +	}
> +      return error_mark_node;
> +    }
> +
>    /* Get the concept and prototype parameter for the constraint.  */
>    tree check = build_type_constraint (tmpl, args, complain);
>    if (check == error_mark_node)
>      return error_mark_node;
> -  tree con = STRIP_TEMPLATE (tmpl);
> -  tree parms = DECL_INNERMOST_TEMPLATE_PARMS (tmpl);
> -  tree proto = TREE_VALUE (TREE_VEC_ELT (parms, 0));
>  
>    /* As per the standard, require auto or decltype(auto).  */
>    cp_token *placeholder = NULL, *close_paren = NULL;
> @@ -20941,19 +20953,6 @@ cp_parser_placeholder_type_specifier (cp_parser *parser, location_t loc,
>        close_paren = parens.require_close (parser);
>      }
>  
> -  /* A type constraint constrains a contextually determined type or type
> -     parameter pack.  */
> -  if (TREE_CODE (proto) != TYPE_DECL)
> -    {
> -      if (!tentative)
> -	{
> -	  auto_diagnostic_group d;
> -	  error_at (loc, "%qE does not constrain a type", DECL_NAME (con));
> -	  inform (DECL_SOURCE_LOCATION (con), "concept defined here");
> -	}
> -      return error_mark_node;
> -    }
> -
>    /* In a template parameter list, a type-parameter can be introduced
>       by type-constraints alone.  */
>    if (processing_template_parmlist && !placeholder)
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index ec4313090bd..9833b2bea5f 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -8539,16 +8539,6 @@ is_compatible_template_arg (tree parm, tree arg, tree args)
>    return ttp_subsumes (parm_cons, arg);
>  }
>  
> -// Convert a placeholder argument into a binding to the original
> -// parameter. The original parameter is saved as the TREE_TYPE of
> -// ARG.
> -static inline tree
> -convert_wildcard_argument (tree parm, tree arg)
> -{
> -  TREE_TYPE (arg) = parm;
> -  return arg;
> -}
> -
>  /* We can't fully resolve ARG given as a non-type template argument to TYPE,
>     because one of them is dependent.  But we need to represent the
>     conversion for the benefit of cp_tree_equal.  */
> @@ -8603,10 +8593,6 @@ convert_template_argument (tree parm,
>    if (parm == error_mark_node || error_operand_p (arg))
>      return error_mark_node;
>  
> -  /* Trivially convert placeholders. */
> -  if (TREE_CODE (arg) == WILDCARD_DECL)
> -    return convert_wildcard_argument (parm, arg);
> -
>    if (arg == any_targ_node)
>      return arg;
>  
> @@ -8988,16 +8974,6 @@ coerce_template_parameter_pack (tree parms,
>  
>        packed_args = make_tree_vec (TREE_VEC_LENGTH (packed_parms));
>      }
> -  /* Check if we have a placeholder pack, which indicates we're
> -     in the context of a introduction list.  In that case we want
> -     to match this pack to the single placeholder.  */
> -  else if (arg_idx < nargs
> -           && TREE_CODE (TREE_VEC_ELT (inner_args, arg_idx)) == WILDCARD_DECL
> -           && WILDCARD_PACK_P (TREE_VEC_ELT (inner_args, arg_idx)))
> -    {
> -      nargs = arg_idx + 1;
> -      packed_args = make_tree_vec (1);
> -    }
>    else
>      packed_args = make_tree_vec (nargs - arg_idx);
>  
> @@ -16489,13 +16465,6 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
>  	      {
>  		int quals;
>  
> -		/* When building concept checks for the purpose of
> -		   deducing placeholders, we can end up with wildcards
> -		   where types are expected. Adjust this to the deduced
> -		   value.  */
> -		if (TREE_CODE (arg) == WILDCARD_DECL)
> -		  arg = TREE_TYPE (TREE_TYPE (arg));
> -
>  		gcc_assert (TYPE_P (arg));
>  
>  		quals = cp_type_quals (arg) | cp_type_quals (t);
> @@ -28559,8 +28528,7 @@ type_dependent_expression_p (tree expression)
>  
>    /* An unresolved name is always dependent.  */
>    if (identifier_p (expression)
> -      || TREE_CODE (expression) == USING_DECL
> -      || TREE_CODE (expression) == WILDCARD_DECL)
> +      || TREE_CODE (expression) == USING_DECL)
>      return true;
>  
>    /* A lambda-expression in template context is dependent.  dependent_type_p is
> @@ -29603,8 +29571,7 @@ placeholder_type_constraint_dependent_p (tree t)
>        args = expand_template_argument_pack (args);
>        first = TREE_VEC_ELT (args, 0);
>      }
> -  gcc_checking_assert (TREE_CODE (first) == WILDCARD_DECL
> -		       || is_auto (first));
> +  gcc_checking_assert (is_auto (first));
>    for (int i = 1; i < TREE_VEC_LENGTH (args); ++i)
>      if (dependent_template_arg_p (TREE_VEC_ELT (args, i)))
>        return true;
> -- 
> 2.47.0.118.gfd3785337b
> 
> 
> >    --processing_template_decl;
> >    return check;
> >  }
> > @@ -1203,8 +1202,7 @@ finish_shorthand_constraint (tree decl, tree constr, bool is_non_type)
> >      {
> >        tree id = PLACEHOLDER_TYPE_CONSTRAINTS (constr);
> >        tree tmpl = TREE_OPERAND (id, 0);
> > -      tree parms = DECL_INNERMOST_TEMPLATE_PARMS (tmpl);
> > -      proto = TREE_VALUE (TREE_VEC_ELT (parms, 0));
> > +      proto = concept_prototype_parameter (tmpl);
> >        con = DECL_TEMPLATE_RESULT (tmpl);
> >        args = TREE_OPERAND (id, 1);
> >      }
> > diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
> > index cd379514991..69eed72a5a2 100644
> > --- a/gcc/cp/cp-objcp-common.cc
> > +++ b/gcc/cp/cp-objcp-common.cc
> > @@ -624,7 +624,6 @@ cp_common_init_ts (void)
> >  
> >    /* New decls.  */
> >    MARK_TS_DECL_COMMON (TEMPLATE_DECL);
> > -  MARK_TS_DECL_COMMON (WILDCARD_DECL);
> >  
> >    MARK_TS_DECL_NON_COMMON (USING_DECL);
> >  
> > diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
> > index 18f75108c7b..53511a6d8cc 100644
> > --- a/gcc/cp/cp-tree.def
> > +++ b/gcc/cp/cp-tree.def
> > @@ -487,12 +487,6 @@ DEFTREECODE (OMP_DEPOBJ, "omp_depobj", tcc_statement, 2)
> >  /* Used to represent information associated with constrained declarations. */
> >  DEFTREECODE (CONSTRAINT_INFO, "constraint_info", tcc_exceptional, 0)
> >  
> > -/* A wildcard declaration is a placeholder for a template parameter
> > -   used to resolve constrained-type-names in concepts.  During
> > -   resolution, the matching argument is saved as the TREE_TYPE
> > -   of the wildcard.  */
> > -DEFTREECODE (WILDCARD_DECL, "wildcard_decl", tcc_declaration, 0)
> > -
> >  /* A requires-expr has three operands. The first operand is
> >     its parameter list (possibly NULL). The second is a list of
> >     requirements, which are denoted by the _REQ* tree codes
> > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> > index 6dcf32b178e..c25dafd5981 100644
> > --- a/gcc/cp/cp-tree.h
> > +++ b/gcc/cp/cp-tree.h
> > @@ -438,7 +438,6 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
> >        TINFO_HAS_ACCESS_ERRORS (in TEMPLATE_INFO)
> >        SIZEOF_EXPR_TYPE_P (in SIZEOF_EXPR)
> >        COMPOUND_REQ_NOEXCEPT_P (in COMPOUND_REQ)
> > -      WILDCARD_PACK_P (in WILDCARD_DECL)
> >        BLOCK_OUTER_CURLY_BRACE_P (in BLOCK)
> >        FOLD_EXPR_MODIFY_P (*_FOLD_EXPR)
> >        IF_STMT_CONSTEXPR_P (IF_STMT)
> > @@ -4042,9 +4041,6 @@ struct GTY(()) lang_decl {
> >  #define PACK_EXPANSION_FORCE_EXTRA_ARGS_P(NODE) \
> >    TREE_LANG_FLAG_3 (PACK_EXPANSION_CHECK (NODE))
> >  
> > -/* True iff the wildcard can match a template parameter pack.  */
> > -#define WILDCARD_PACK_P(NODE) TREE_LANG_FLAG_0 (NODE)
> > -
> >  /* Determine if this is an argument pack.  */
> >  #define ARGUMENT_PACK_P(NODE)                          \
> >    (TREE_CODE (NODE) == TYPE_ARGUMENT_PACK              \
> > @@ -8879,18 +8875,10 @@ variable_template_p (tree t)
> >  
> >  /* True iff T is a concept.  */
> >  
> > -inline bool
> > -concept_definition_p (tree t)
> > -{
> > -  return TREE_CODE (STRIP_TEMPLATE (t)) == CONCEPT_DECL;
> > -}
> > -
> > -/* Same as above, but for const trees.  */
> > -
> >  inline bool
> >  concept_definition_p (const_tree t)
> >  {
> > -  return concept_definition_p (const_cast<tree> (t));
> > +  return TREE_CODE (STRIP_TEMPLATE (t)) == CONCEPT_DECL;
> >  }
> >  
> >  /* True if t is an expression that checks a concept.  */
> > @@ -8903,6 +8891,19 @@ concept_check_p (const_tree t)
> >    return false;
> >  }
> >  
> > +/* Return the prototype parameter of the concept T,
> > +   i.e. its first declared template parameter.  */
> > +
> > +inline tree
> > +concept_prototype_parameter (const_tree t)
> > +{
> > +  gcc_checking_assert (concept_definition_p (t));
> > +  if (TREE_CODE (t) == CONCEPT_DECL)
> > +    t = DECL_TI_TEMPLATE (t);
> > +  tree parms = DECL_INNERMOST_TEMPLATE_PARMS (t);
> > +  return TREE_VALUE (TREE_VEC_ELT (parms, 0));
> > +}
> > +
> >  /* Helpers for IMPLICIT_RVALUE_P to look through automatic dereference.  */
> >  
> >  inline bool
> > diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
> > index 65f70c595cf..c5b256f3907 100644
> > --- a/gcc/cp/error.cc
> > +++ b/gcc/cp/error.cc
> > @@ -1542,10 +1542,6 @@ dump_decl (cxx_pretty_printer *pp, tree t, int flags)
> >        dump_simple_decl (pp, t, TREE_TYPE (t), flags);
> >        break;
> >  
> > -    case WILDCARD_DECL:
> > -      pp_string (pp, "<wildcard>");
> > -      break;
> > -
> >      case TEMPLATE_ID_EXPR:
> >        {
> >  	tree name = TREE_OPERAND (t, 0);
> > @@ -2376,7 +2372,6 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
> >      case TEMPLATE_DECL:
> >      case NAMESPACE_DECL:
> >      case LABEL_DECL:
> > -    case WILDCARD_DECL:
> >      case OVERLOAD:
> >      case TYPE_DECL:
> >      case USING_DECL:
> > diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> > index 0bad62978dc..16e05acd7b8 100644
> > --- a/gcc/cp/parser.cc
> > +++ b/gcc/cp/parser.cc
> > @@ -20918,15 +20918,27 @@ cp_parser_placeholder_type_specifier (cp_parser *parser, location_t loc,
> >      /* A concept-name with no arguments can't be an expression.  */
> >      tentative = false;
> >  
> > +  tree con = STRIP_TEMPLATE (tmpl);
> > +  tree proto = concept_prototype_parameter (con);
> >    tsubst_flags_t complain = tentative ? tf_none : tf_warning_or_error;
> >  
> > +  /* A type constraint constrains a contextually determined type or type
> > +     parameter pack.  */
> > +  if (TREE_CODE (proto) != TYPE_DECL)
> > +    {
> > +      if (!tentative)
> > +	{
> > +	  auto_diagnostic_group d;
> > +	  error_at (loc, "%qE does not constrain a type", DECL_NAME (con));
> > +	  inform (DECL_SOURCE_LOCATION (con), "concept defined here");
> > +	}
> > +      return error_mark_node;
> > +    }
> > +
> >    /* Get the concept and prototype parameter for the constraint.  */
> >    tree check = build_type_constraint (tmpl, args, complain);
> >    if (check == error_mark_node)
> >      return error_mark_node;
> > -  tree con = STRIP_TEMPLATE (tmpl);
> > -  tree parms = DECL_INNERMOST_TEMPLATE_PARMS (tmpl);
> > -  tree proto = TREE_VALUE (TREE_VEC_ELT (parms, 0));
> >  
> >    /* As per the standard, require auto or decltype(auto).  */
> >    cp_token *placeholder = NULL, *close_paren = NULL;
> > @@ -20941,19 +20953,6 @@ cp_parser_placeholder_type_specifier (cp_parser *parser, location_t loc,
> >        close_paren = parens.require_close (parser);
> >      }
> >  
> > -  /* A type constraint constrains a contextually determined type or type
> > -     parameter pack.  */
> > -  if (TREE_CODE (proto) != TYPE_DECL)
> > -    {
> > -      if (!tentative)
> > -	{
> > -	  auto_diagnostic_group d;
> > -	  error_at (loc, "%qE does not constrain a type", DECL_NAME (con));
> > -	  inform (DECL_SOURCE_LOCATION (con), "concept defined here");
> > -	}
> > -      return error_mark_node;
> > -    }
> > -
> >    /* In a template parameter list, a type-parameter can be introduced
> >       by type-constraints alone.  */
> >    if (processing_template_parmlist && !placeholder)
> > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > index ec4313090bd..9833b2bea5f 100644
> > --- a/gcc/cp/pt.cc
> > +++ b/gcc/cp/pt.cc
> > @@ -8539,16 +8539,6 @@ is_compatible_template_arg (tree parm, tree arg, tree args)
> >    return ttp_subsumes (parm_cons, arg);
> >  }
> >  
> > -// Convert a placeholder argument into a binding to the original
> > -// parameter. The original parameter is saved as the TREE_TYPE of
> > -// ARG.
> > -static inline tree
> > -convert_wildcard_argument (tree parm, tree arg)
> > -{
> > -  TREE_TYPE (arg) = parm;
> > -  return arg;
> > -}
> > -
> >  /* We can't fully resolve ARG given as a non-type template argument to TYPE,
> >     because one of them is dependent.  But we need to represent the
> >     conversion for the benefit of cp_tree_equal.  */
> > @@ -8603,10 +8593,6 @@ convert_template_argument (tree parm,
> >    if (parm == error_mark_node || error_operand_p (arg))
> >      return error_mark_node;
> >  
> > -  /* Trivially convert placeholders. */
> > -  if (TREE_CODE (arg) == WILDCARD_DECL)
> > -    return convert_wildcard_argument (parm, arg);
> > -
> >    if (arg == any_targ_node)
> >      return arg;
> >  
> > @@ -8988,16 +8974,6 @@ coerce_template_parameter_pack (tree parms,
> >  
> >        packed_args = make_tree_vec (TREE_VEC_LENGTH (packed_parms));
> >      }
> > -  /* Check if we have a placeholder pack, which indicates we're
> > -     in the context of a introduction list.  In that case we want
> > -     to match this pack to the single placeholder.  */
> > -  else if (arg_idx < nargs
> > -           && TREE_CODE (TREE_VEC_ELT (inner_args, arg_idx)) == WILDCARD_DECL
> > -           && WILDCARD_PACK_P (TREE_VEC_ELT (inner_args, arg_idx)))
> > -    {
> > -      nargs = arg_idx + 1;
> > -      packed_args = make_tree_vec (1);
> > -    }
> >    else
> >      packed_args = make_tree_vec (nargs - arg_idx);
> >  
> > @@ -16489,13 +16465,6 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
> >  	      {
> >  		int quals;
> >  
> > -		/* When building concept checks for the purpose of
> > -		   deducing placeholders, we can end up with wildcards
> > -		   where types are expected. Adjust this to the deduced
> > -		   value.  */
> > -		if (TREE_CODE (arg) == WILDCARD_DECL)
> > -		  arg = TREE_TYPE (TREE_TYPE (arg));
> > -
> >  		gcc_assert (TYPE_P (arg));
> >  
> >  		quals = cp_type_quals (arg) | cp_type_quals (t);
> > @@ -28559,8 +28528,7 @@ type_dependent_expression_p (tree expression)
> >  
> >    /* An unresolved name is always dependent.  */
> >    if (identifier_p (expression)
> > -      || TREE_CODE (expression) == USING_DECL
> > -      || TREE_CODE (expression) == WILDCARD_DECL)
> > +      || TREE_CODE (expression) == USING_DECL)
> >      return true;
> >  
> >    /* A lambda-expression in template context is dependent.  dependent_type_p is
> > @@ -29603,8 +29571,7 @@ placeholder_type_constraint_dependent_p (tree t)
> >        args = expand_template_argument_pack (args);
> >        first = TREE_VEC_ELT (args, 0);
> >      }
> > -  gcc_checking_assert (TREE_CODE (first) == WILDCARD_DECL
> > -		       || is_auto (first));
> > +  gcc_checking_assert (is_auto (first));
> >    for (int i = 1; i < TREE_VEC_LENGTH (args); ++i)
> >      if (dependent_template_arg_p (TREE_VEC_ELT (args, i)))
> >        return true;
> > -- 
> > 2.47.0.118.gfd3785337b
> > 
> > 
>
  
Jason Merrill Nov. 5, 2024, 8:29 p.m. UTC | #3
On 10/23/24 4:30 PM, Patrick Palka wrote:
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
> OK for trunk?
> 
> -- >8 --
> 
> This tree code was added as part of the initial Concepts TS
> implementation to support type-constraints introducing any kind
> of template-parameter, not just type template-parameters, e.g.
> 
>    template<int N> concept C = ...;
>    template<template<class> class TT> concept D = ...;
> 
>    template<C T, D U> void f(); // T is an NTTP of type int, U is a TTP
> 
> When resolving the type-constraint we would use WILDCARD_DECL as the
> dummy first argument during template argument coercion that is a valid
> argument for any kind of template parameter.
> 
> But Concepts TS support has been removed, and C++20 type-constraints are
> restricted to only introduce type template-parameters, and so we don't
> need this catch-all WILDCARD_DECL anymore; we can instead use an auto
> as the dummy first argument.
> 
> In passing introduce a helper for returning the prototype parameter
> (i.e. first template parameter) of a concept and use it.

Ah, exactly what I was missing in the first patch; let's squash this 
patch together with that one.  Then there's just the 
declares_constrained_type_template_parameter comment.

Jason
  

Patch

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 9394bea8835..d6a6ac03393 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -1154,9 +1154,8 @@  build_concept_id (tree expr)
 tree
 build_type_constraint (tree decl, tree args, tsubst_flags_t complain)
 {
-  tree wildcard = build_nt (WILDCARD_DECL);
   ++processing_template_decl;
-  tree check = build_concept_check (decl, wildcard, args, complain);
+  tree check = build_concept_check (decl, make_auto (), args, complain);
   --processing_template_decl;
   return check;
 }
@@ -1203,8 +1202,7 @@  finish_shorthand_constraint (tree decl, tree constr, bool is_non_type)
     {
       tree id = PLACEHOLDER_TYPE_CONSTRAINTS (constr);
       tree tmpl = TREE_OPERAND (id, 0);
-      tree parms = DECL_INNERMOST_TEMPLATE_PARMS (tmpl);
-      proto = TREE_VALUE (TREE_VEC_ELT (parms, 0));
+      proto = concept_prototype_parameter (tmpl);
       con = DECL_TEMPLATE_RESULT (tmpl);
       args = TREE_OPERAND (id, 1);
     }
diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
index cd379514991..69eed72a5a2 100644
--- a/gcc/cp/cp-objcp-common.cc
+++ b/gcc/cp/cp-objcp-common.cc
@@ -624,7 +624,6 @@  cp_common_init_ts (void)
 
   /* New decls.  */
   MARK_TS_DECL_COMMON (TEMPLATE_DECL);
-  MARK_TS_DECL_COMMON (WILDCARD_DECL);
 
   MARK_TS_DECL_NON_COMMON (USING_DECL);
 
diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
index 18f75108c7b..53511a6d8cc 100644
--- a/gcc/cp/cp-tree.def
+++ b/gcc/cp/cp-tree.def
@@ -487,12 +487,6 @@  DEFTREECODE (OMP_DEPOBJ, "omp_depobj", tcc_statement, 2)
 /* Used to represent information associated with constrained declarations. */
 DEFTREECODE (CONSTRAINT_INFO, "constraint_info", tcc_exceptional, 0)
 
-/* A wildcard declaration is a placeholder for a template parameter
-   used to resolve constrained-type-names in concepts.  During
-   resolution, the matching argument is saved as the TREE_TYPE
-   of the wildcard.  */
-DEFTREECODE (WILDCARD_DECL, "wildcard_decl", tcc_declaration, 0)
-
 /* A requires-expr has three operands. The first operand is
    its parameter list (possibly NULL). The second is a list of
    requirements, which are denoted by the _REQ* tree codes
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 6dcf32b178e..c25dafd5981 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -438,7 +438,6 @@  extern GTY(()) tree cp_global_trees[CPTI_MAX];
       TINFO_HAS_ACCESS_ERRORS (in TEMPLATE_INFO)
       SIZEOF_EXPR_TYPE_P (in SIZEOF_EXPR)
       COMPOUND_REQ_NOEXCEPT_P (in COMPOUND_REQ)
-      WILDCARD_PACK_P (in WILDCARD_DECL)
       BLOCK_OUTER_CURLY_BRACE_P (in BLOCK)
       FOLD_EXPR_MODIFY_P (*_FOLD_EXPR)
       IF_STMT_CONSTEXPR_P (IF_STMT)
@@ -4042,9 +4041,6 @@  struct GTY(()) lang_decl {
 #define PACK_EXPANSION_FORCE_EXTRA_ARGS_P(NODE) \
   TREE_LANG_FLAG_3 (PACK_EXPANSION_CHECK (NODE))
 
-/* True iff the wildcard can match a template parameter pack.  */
-#define WILDCARD_PACK_P(NODE) TREE_LANG_FLAG_0 (NODE)
-
 /* Determine if this is an argument pack.  */
 #define ARGUMENT_PACK_P(NODE)                          \
   (TREE_CODE (NODE) == TYPE_ARGUMENT_PACK              \
@@ -8879,18 +8875,10 @@  variable_template_p (tree t)
 
 /* True iff T is a concept.  */
 
-inline bool
-concept_definition_p (tree t)
-{
-  return TREE_CODE (STRIP_TEMPLATE (t)) == CONCEPT_DECL;
-}
-
-/* Same as above, but for const trees.  */
-
 inline bool
 concept_definition_p (const_tree t)
 {
-  return concept_definition_p (const_cast<tree> (t));
+  return TREE_CODE (STRIP_TEMPLATE (t)) == CONCEPT_DECL;
 }
 
 /* True if t is an expression that checks a concept.  */
@@ -8903,6 +8891,19 @@  concept_check_p (const_tree t)
   return false;
 }
 
+/* Return the prototype parameter of the concept T,
+   i.e. its first declared template parameter.  */
+
+inline tree
+concept_prototype_parameter (const_tree t)
+{
+  gcc_checking_assert (concept_definition_p (t));
+  if (TREE_CODE (t) == CONCEPT_DECL)
+    t = DECL_TI_TEMPLATE (t);
+  tree parms = DECL_INNERMOST_TEMPLATE_PARMS (t);
+  return TREE_VALUE (TREE_VEC_ELT (parms, 0));
+}
+
 /* Helpers for IMPLICIT_RVALUE_P to look through automatic dereference.  */
 
 inline bool
diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
index 65f70c595cf..c5b256f3907 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -1542,10 +1542,6 @@  dump_decl (cxx_pretty_printer *pp, tree t, int flags)
       dump_simple_decl (pp, t, TREE_TYPE (t), flags);
       break;
 
-    case WILDCARD_DECL:
-      pp_string (pp, "<wildcard>");
-      break;
-
     case TEMPLATE_ID_EXPR:
       {
 	tree name = TREE_OPERAND (t, 0);
@@ -2376,7 +2372,6 @@  dump_expr (cxx_pretty_printer *pp, tree t, int flags)
     case TEMPLATE_DECL:
     case NAMESPACE_DECL:
     case LABEL_DECL:
-    case WILDCARD_DECL:
     case OVERLOAD:
     case TYPE_DECL:
     case USING_DECL:
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 0bad62978dc..16e05acd7b8 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -20918,15 +20918,27 @@  cp_parser_placeholder_type_specifier (cp_parser *parser, location_t loc,
     /* A concept-name with no arguments can't be an expression.  */
     tentative = false;
 
+  tree con = STRIP_TEMPLATE (tmpl);
+  tree proto = concept_prototype_parameter (con);
   tsubst_flags_t complain = tentative ? tf_none : tf_warning_or_error;
 
+  /* A type constraint constrains a contextually determined type or type
+     parameter pack.  */
+  if (TREE_CODE (proto) != TYPE_DECL)
+    {
+      if (!tentative)
+	{
+	  auto_diagnostic_group d;
+	  error_at (loc, "%qE does not constrain a type", DECL_NAME (con));
+	  inform (DECL_SOURCE_LOCATION (con), "concept defined here");
+	}
+      return error_mark_node;
+    }
+
   /* Get the concept and prototype parameter for the constraint.  */
   tree check = build_type_constraint (tmpl, args, complain);
   if (check == error_mark_node)
     return error_mark_node;
-  tree con = STRIP_TEMPLATE (tmpl);
-  tree parms = DECL_INNERMOST_TEMPLATE_PARMS (tmpl);
-  tree proto = TREE_VALUE (TREE_VEC_ELT (parms, 0));
 
   /* As per the standard, require auto or decltype(auto).  */
   cp_token *placeholder = NULL, *close_paren = NULL;
@@ -20941,19 +20953,6 @@  cp_parser_placeholder_type_specifier (cp_parser *parser, location_t loc,
       close_paren = parens.require_close (parser);
     }
 
-  /* A type constraint constrains a contextually determined type or type
-     parameter pack.  */
-  if (TREE_CODE (proto) != TYPE_DECL)
-    {
-      if (!tentative)
-	{
-	  auto_diagnostic_group d;
-	  error_at (loc, "%qE does not constrain a type", DECL_NAME (con));
-	  inform (DECL_SOURCE_LOCATION (con), "concept defined here");
-	}
-      return error_mark_node;
-    }
-
   /* In a template parameter list, a type-parameter can be introduced
      by type-constraints alone.  */
   if (processing_template_parmlist && !placeholder)
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index ec4313090bd..9833b2bea5f 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -8539,16 +8539,6 @@  is_compatible_template_arg (tree parm, tree arg, tree args)
   return ttp_subsumes (parm_cons, arg);
 }
 
-// Convert a placeholder argument into a binding to the original
-// parameter. The original parameter is saved as the TREE_TYPE of
-// ARG.
-static inline tree
-convert_wildcard_argument (tree parm, tree arg)
-{
-  TREE_TYPE (arg) = parm;
-  return arg;
-}
-
 /* We can't fully resolve ARG given as a non-type template argument to TYPE,
    because one of them is dependent.  But we need to represent the
    conversion for the benefit of cp_tree_equal.  */
@@ -8603,10 +8593,6 @@  convert_template_argument (tree parm,
   if (parm == error_mark_node || error_operand_p (arg))
     return error_mark_node;
 
-  /* Trivially convert placeholders. */
-  if (TREE_CODE (arg) == WILDCARD_DECL)
-    return convert_wildcard_argument (parm, arg);
-
   if (arg == any_targ_node)
     return arg;
 
@@ -8988,16 +8974,6 @@  coerce_template_parameter_pack (tree parms,
 
       packed_args = make_tree_vec (TREE_VEC_LENGTH (packed_parms));
     }
-  /* Check if we have a placeholder pack, which indicates we're
-     in the context of a introduction list.  In that case we want
-     to match this pack to the single placeholder.  */
-  else if (arg_idx < nargs
-           && TREE_CODE (TREE_VEC_ELT (inner_args, arg_idx)) == WILDCARD_DECL
-           && WILDCARD_PACK_P (TREE_VEC_ELT (inner_args, arg_idx)))
-    {
-      nargs = arg_idx + 1;
-      packed_args = make_tree_vec (1);
-    }
   else
     packed_args = make_tree_vec (nargs - arg_idx);
 
@@ -16489,13 +16465,6 @@  tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	      {
 		int quals;
 
-		/* When building concept checks for the purpose of
-		   deducing placeholders, we can end up with wildcards
-		   where types are expected. Adjust this to the deduced
-		   value.  */
-		if (TREE_CODE (arg) == WILDCARD_DECL)
-		  arg = TREE_TYPE (TREE_TYPE (arg));
-
 		gcc_assert (TYPE_P (arg));
 
 		quals = cp_type_quals (arg) | cp_type_quals (t);
@@ -28559,8 +28528,7 @@  type_dependent_expression_p (tree expression)
 
   /* An unresolved name is always dependent.  */
   if (identifier_p (expression)
-      || TREE_CODE (expression) == USING_DECL
-      || TREE_CODE (expression) == WILDCARD_DECL)
+      || TREE_CODE (expression) == USING_DECL)
     return true;
 
   /* A lambda-expression in template context is dependent.  dependent_type_p is
@@ -29603,8 +29571,7 @@  placeholder_type_constraint_dependent_p (tree t)
       args = expand_template_argument_pack (args);
       first = TREE_VEC_ELT (args, 0);
     }
-  gcc_checking_assert (TREE_CODE (first) == WILDCARD_DECL
-		       || is_auto (first));
+  gcc_checking_assert (is_auto (first));
   for (int i = 1; i < TREE_VEC_LENGTH (args); ++i)
     if (dependent_template_arg_p (TREE_VEC_ELT (args, i)))
       return true;