diff mbox series

[3/2] c++: remove WILDCARD_DECL

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

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;
diff mbox series

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;