diff mbox series

c++: remove function/var concepts code

Message ID 20240802181221.18448-1-polacek@redhat.com
State New
Headers show
Series c++: remove function/var concepts code | expand

Commit Message

Marek Polacek Aug. 2, 2024, 6:12 p.m. UTC
Bootstrapped/regtested on x86_64-pc-linux-gnu.  Comments?

-- >8 --
This patch removes vestigial Concepts TS code as discussed in
<https://gcc.gnu.org/pipermail/gcc-patches/2024-July/657937.html>.

In particular, it removes code related to function/variable concepts.
That includes variable_concept_p and function_concept_p, which then
cascades into removing DECL_DECLARED_CONCEPT_P etc.  So I think we
no longer need to say "standard concept" since there are no non-standard
ones anymore.

I've added two new errors saying that "variable/function concepts are
no longer supported".

gcc/cp/ChangeLog:

	* constexpr.cc (cxx_eval_constant_expression): Don't call
	unpack_concept_check.  Add a concept_check_p assert.  Remove
	function_concept_p code.
	* constraint.cc (check_constraint_atom): Remove function concepts code.
	(unpack_concept_check): Remove.
	(get_concept_check_template): Remove Concepts TS code.
	(resolve_function_concept_overload): Remove.
	(resolve_function_concept_check): Remove.
	(resolve_concept_check): Remove Concepts TS code.
	(get_returned_expression): Remove.
	(get_variable_initializer): Remove.
	(get_concept_definition): Remove Concepts TS code.
	(normalize_concept_check): Likewise.
	(build_function_check): Remove.
	(build_variable_check): Remove.
	(build_standard_check): Use concept_definition_p instead of
	standard_concept_p.
	(build_concept_check): Remove variable_concept_p/function_concept_p
	code.
	(build_concept_id): Simplify.
	(build_type_constraint): Likewise.
	(placeholder_extract_concept_and_args): Likewise.
	(satisfy_nondeclaration_constraints): Likewise.
	(check_function_concept): Remove.
	(get_constraint_error_location): Remove Concepts TS code.
	* cp-tree.h (DECL_DECLARED_CONCEPT_P): Remove.
	(check_function_concept): Remove.
	(unpack_concept_check): Remove.
	(standard_concept_p): Remove.
	(variable_concept_p): Remove.
	(function_concept_p): Remove.
	(concept_definition_p): Simplify.
	(concept_check_p): Don't check for CALL_EXPR.
	* decl.cc (check_concept_refinement): Remove.
	(duplicate_decls): Remove check_concept_refinement code.
	(is_concept_var): Remove.
	(cp_finish_decl): Remove is_concept_var.
	(check_concept_fn): Remove.
	(grokfndecl): Give an error about function concepts not being supported
	anymore.  Remove unused code.
	(grokvardecl): Give an error about variable concepts not being
	supported anymore.
	(finish_function): Remove DECL_DECLARED_CONCEPT_P code.
	* decl2.cc (min_vis_expr_r): Use concept_definition_p instead of
	standard_concept_p.
	(maybe_instantiate_decl): Remove DECL_DECLARED_CONCEPT_P check.
	(mark_used): Likewise.
	* error.cc (dump_simple_decl): Use concept_definition_p instead of
	standard_concept_p.
	(dump_function_decl): Remove DECL_DECLARED_CONCEPT_P code.
	(print_concept_check_info): Don't call unpack_concept_check.
	* mangle.cc (write_type_constraint): Likewise.
	* parser.cc (cp_parser_nested_name_specifier_opt): Remove
	function_concept_p code.  Only check concept_definition_p, not
	variable_concept_p/standard_concept_p.
	(add_debug_begin_stmt): Remove DECL_DECLARED_CONCEPT_P code.
	(cp_parser_template_declaration_after_parameters): Remove a stale
	comment.
	* pt.cc (check_explicit_specialization): Remove
	DECL_DECLARED_CONCEPT_P code.
	(process_partial_specialization): Remove variable_concept_p code.
	(lookup_template_variable): Likewise.
	(tsubst_expr) <case CALL_EXPR>: Remove Concepts TS code and simplify.
	(do_decl_instantiation): Remove DECL_DECLARED_CONCEPT_P code.
	(instantiate_decl): Likewise.
	(placeholder_type_constraint_dependent_p): Don't call
	unpack_concept_check.  Add a concept_check_p assert.
	(convert_generic_types_to_packs): Likewise.
	* semantics.cc (finish_call_expr): Remove Concepts TS code and simplify.

gcc/testsuite/ChangeLog:

	* g++.dg/concepts/decl-diagnose.C: Adjust dg-error.
	* g++.dg/concepts/fn-concept2.C: Likewise.
	* g++.dg/concepts/pr71128.C: Likewise.
	* g++.dg/concepts/var-concept6.C: Likewise.
	* g++.dg/cpp2a/concepts.C: Likewise.
---
 gcc/cp/constexpr.cc                           |  13 +-
 gcc/cp/constraint.cc                          | 346 +-----------------
 gcc/cp/cp-tree.h                              |  71 +---
 gcc/cp/decl.cc                                | 118 +-----
 gcc/cp/decl2.cc                               |   4 +-
 gcc/cp/error.cc                               |  10 +-
 gcc/cp/mangle.cc                              |   4 +-
 gcc/cp/parser.cc                              |  16 +-
 gcc/cp/pt.cc                                  |  60 +--
 gcc/cp/semantics.cc                           |  17 +-
 gcc/testsuite/g++.dg/concepts/decl-diagnose.C |   8 +-
 gcc/testsuite/g++.dg/concepts/fn-concept2.C   |   4 +-
 gcc/testsuite/g++.dg/concepts/pr71128.C       |   8 +-
 gcc/testsuite/g++.dg/concepts/var-concept6.C  |   2 +-
 gcc/testsuite/g++.dg/cpp2a/concepts.C         |   4 +-
 15 files changed, 65 insertions(+), 620 deletions(-)


base-commit: a10436a8404ad2f0cc5aa4d6a0cc850abe5ef49e

Comments

Jason Merrill Aug. 5, 2024, 4 p.m. UTC | #1
On 8/2/24 2:12 PM, Marek Polacek wrote:
> Bootstrapped/regtested on x86_64-pc-linux-gnu.  Comments?
> 
> -- >8 --
> This patch removes vestigial Concepts TS code as discussed in
> <https://gcc.gnu.org/pipermail/gcc-patches/2024-July/657937.html>.
> 
> In particular, it removes code related to function/variable concepts.
> That includes variable_concept_p and function_concept_p, which then
> cascades into removing DECL_DECLARED_CONCEPT_P etc.  So I think we
> no longer need to say "standard concept" since there are no non-standard
> ones anymore.
> 
> I've added two new errors saying that "variable/function concepts are
> no longer supported".
> 
> gcc/cp/ChangeLog:
> 
> 	* constexpr.cc (cxx_eval_constant_expression): Don't call
> 	unpack_concept_check.  Add a concept_check_p assert.  Remove
> 	function_concept_p code.
> 	* constraint.cc (check_constraint_atom): Remove function concepts code.
> 	(unpack_concept_check): Remove.
> 	(get_concept_check_template): Remove Concepts TS code.
> 	(resolve_function_concept_overload): Remove.
> 	(resolve_function_concept_check): Remove.
> 	(resolve_concept_check): Remove Concepts TS code.
> 	(get_returned_expression): Remove.
> 	(get_variable_initializer): Remove.
> 	(get_concept_definition): Remove Concepts TS code.
> 	(normalize_concept_check): Likewise.
> 	(build_function_check): Remove.
> 	(build_variable_check): Remove.
> 	(build_standard_check): Use concept_definition_p instead of
> 	standard_concept_p.
> 	(build_concept_check): Remove variable_concept_p/function_concept_p
> 	code.
> 	(build_concept_id): Simplify.
> 	(build_type_constraint): Likewise.
> 	(placeholder_extract_concept_and_args): Likewise.
> 	(satisfy_nondeclaration_constraints): Likewise.
> 	(check_function_concept): Remove.
> 	(get_constraint_error_location): Remove Concepts TS code.
> 	* cp-tree.h (DECL_DECLARED_CONCEPT_P): Remove.
> 	(check_function_concept): Remove.
> 	(unpack_concept_check): Remove.
> 	(standard_concept_p): Remove.
> 	(variable_concept_p): Remove.
> 	(function_concept_p): Remove.
> 	(concept_definition_p): Simplify.
> 	(concept_check_p): Don't check for CALL_EXPR.
> 	* decl.cc (check_concept_refinement): Remove.
> 	(duplicate_decls): Remove check_concept_refinement code.
> 	(is_concept_var): Remove.
> 	(cp_finish_decl): Remove is_concept_var.
> 	(check_concept_fn): Remove.
> 	(grokfndecl): Give an error about function concepts not being supported
> 	anymore.  Remove unused code.
> 	(grokvardecl): Give an error about variable concepts not being
> 	supported anymore.
> 	(finish_function): Remove DECL_DECLARED_CONCEPT_P code.
> 	* decl2.cc (min_vis_expr_r): Use concept_definition_p instead of
> 	standard_concept_p.
> 	(maybe_instantiate_decl): Remove DECL_DECLARED_CONCEPT_P check.
> 	(mark_used): Likewise.
> 	* error.cc (dump_simple_decl): Use concept_definition_p instead of
> 	standard_concept_p.
> 	(dump_function_decl): Remove DECL_DECLARED_CONCEPT_P code.
> 	(print_concept_check_info): Don't call unpack_concept_check.
> 	* mangle.cc (write_type_constraint): Likewise.
> 	* parser.cc (cp_parser_nested_name_specifier_opt): Remove
> 	function_concept_p code.  Only check concept_definition_p, not
> 	variable_concept_p/standard_concept_p.
> 	(add_debug_begin_stmt): Remove DECL_DECLARED_CONCEPT_P code.
> 	(cp_parser_template_declaration_after_parameters): Remove a stale
> 	comment.
> 	* pt.cc (check_explicit_specialization): Remove
> 	DECL_DECLARED_CONCEPT_P code.
> 	(process_partial_specialization): Remove variable_concept_p code.
> 	(lookup_template_variable): Likewise.
> 	(tsubst_expr) <case CALL_EXPR>: Remove Concepts TS code and simplify.
> 	(do_decl_instantiation): Remove DECL_DECLARED_CONCEPT_P code.
> 	(instantiate_decl): Likewise.
> 	(placeholder_type_constraint_dependent_p): Don't call
> 	unpack_concept_check.  Add a concept_check_p assert.
> 	(convert_generic_types_to_packs): Likewise.
> 	* semantics.cc (finish_call_expr): Remove Concepts TS code and simplify.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/concepts/decl-diagnose.C: Adjust dg-error.
> 	* g++.dg/concepts/fn-concept2.C: Likewise.
> 	* g++.dg/concepts/pr71128.C: Likewise.
> 	* g++.dg/concepts/var-concept6.C: Likewise.
> 	* g++.dg/cpp2a/concepts.C: Likewise.
> ---
>   gcc/cp/constexpr.cc                           |  13 +-
>   gcc/cp/constraint.cc                          | 346 +-----------------
>   gcc/cp/cp-tree.h                              |  71 +---
>   gcc/cp/decl.cc                                | 118 +-----
>   gcc/cp/decl2.cc                               |   4 +-
>   gcc/cp/error.cc                               |  10 +-
>   gcc/cp/mangle.cc                              |   4 +-
>   gcc/cp/parser.cc                              |  16 +-
>   gcc/cp/pt.cc                                  |  60 +--
>   gcc/cp/semantics.cc                           |  17 +-
>   gcc/testsuite/g++.dg/concepts/decl-diagnose.C |   8 +-
>   gcc/testsuite/g++.dg/concepts/fn-concept2.C   |   4 +-
>   gcc/testsuite/g++.dg/concepts/pr71128.C       |   8 +-
>   gcc/testsuite/g++.dg/concepts/var-concept6.C  |   2 +-
>   gcc/testsuite/g++.dg/cpp2a/concepts.C         |   4 +-
>   15 files changed, 65 insertions(+), 620 deletions(-)
> 
> diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> index 8277b3b79ba..b079be1b3d5 100644
> --- a/gcc/cp/constexpr.cc
> +++ b/gcc/cp/constexpr.cc
> @@ -8508,20 +8508,11 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
>         {
>           /* We can evaluate template-id that refers to a concept only if
>   	   the template arguments are non-dependent.  */
> -	tree id = unpack_concept_check (t);
> -	tree tmpl = TREE_OPERAND (id, 0);
> +	gcc_assert (concept_check_p (t));
> +	tree tmpl = TREE_OPERAND (t, 0);
>   	if (!concept_definition_p (tmpl))
>   	  internal_error ("unexpected template-id %qE", t);

It seems unnecessary to have both the assert and the internal_error 
here; I'd drop the internal_error.

> -/* The normal form of an atom depends on the expression.  The normal
> -   form of a function call to a function concept is a check constraint
> -   for that concept.  The normal form of a reference to a variable
> -   concept is a check constraint for that concept.  Otherwise, the
> -   constraint is a predicate constraint.  */
> +/* The normal form of an atom is a predicate constraint.  */

I think the term "predicate constraint" is also obsolete; it's now 
"atomic constraint".

> @@ -3952,8 +3950,8 @@ print_concept_check_info (diagnostic_context *context, tree expr, tree map, tree
>   {
>     gcc_assert (concept_check_p (expr));
>   
> -  tree id = unpack_concept_check (expr);
> -  tree tmpl = TREE_OPERAND (id, 0);
> +  tree tmpl = TREE_OPERAND (expr, 0);
> +  // ??? Can this go now that fn/var concepts have been removed?

I would definitely expect so, did you try?

I think we also want to adjust the 'concept bool' handling in 
cp_parser_decl_specifier_seq:

>           /* Warn for concept as a decl-specifier. We'll rewrite these as                                                           
>              concept declarations later.  */
>           {
>             cp_token *next = cp_lexer_peek_token (parser->lexer);
>             if (next->keyword == RID_BOOL)
> =>            permerror (next->location, "the %<bool%> keyword is not "
>                          "allowed in a C++20 concept definition");
>             else
>               error_at (token->location, "C++20 concept definition syntax "
>                         "is %<concept <name> = <expr>%>");
>           }

After the permerror let's skip the 'bool' token and continue trying to 
parse a concept declaration.  I think that should allow us to remove 
more of the code in grokfndecl/grokvardecl?

Jason
Marek Polacek Aug. 5, 2024, 6:44 p.m. UTC | #2
On Mon, Aug 05, 2024 at 12:00:04PM -0400, Jason Merrill wrote:
> On 8/2/24 2:12 PM, Marek Polacek wrote:
> > Bootstrapped/regtested on x86_64-pc-linux-gnu.  Comments?
> > 
> > -- >8 --
> > This patch removes vestigial Concepts TS code as discussed in
> > <https://gcc.gnu.org/pipermail/gcc-patches/2024-July/657937.html>.
> > 
> > In particular, it removes code related to function/variable concepts.
> > That includes variable_concept_p and function_concept_p, which then
> > cascades into removing DECL_DECLARED_CONCEPT_P etc.  So I think we
> > no longer need to say "standard concept" since there are no non-standard
> > ones anymore.
> > 
> > I've added two new errors saying that "variable/function concepts are
> > no longer supported".
> > 
> > gcc/cp/ChangeLog:
> > 
> > 	* constexpr.cc (cxx_eval_constant_expression): Don't call
> > 	unpack_concept_check.  Add a concept_check_p assert.  Remove
> > 	function_concept_p code.
> > 	* constraint.cc (check_constraint_atom): Remove function concepts code.
> > 	(unpack_concept_check): Remove.
> > 	(get_concept_check_template): Remove Concepts TS code.
> > 	(resolve_function_concept_overload): Remove.
> > 	(resolve_function_concept_check): Remove.
> > 	(resolve_concept_check): Remove Concepts TS code.
> > 	(get_returned_expression): Remove.
> > 	(get_variable_initializer): Remove.
> > 	(get_concept_definition): Remove Concepts TS code.
> > 	(normalize_concept_check): Likewise.
> > 	(build_function_check): Remove.
> > 	(build_variable_check): Remove.
> > 	(build_standard_check): Use concept_definition_p instead of
> > 	standard_concept_p.
> > 	(build_concept_check): Remove variable_concept_p/function_concept_p
> > 	code.
> > 	(build_concept_id): Simplify.
> > 	(build_type_constraint): Likewise.
> > 	(placeholder_extract_concept_and_args): Likewise.
> > 	(satisfy_nondeclaration_constraints): Likewise.
> > 	(check_function_concept): Remove.
> > 	(get_constraint_error_location): Remove Concepts TS code.
> > 	* cp-tree.h (DECL_DECLARED_CONCEPT_P): Remove.
> > 	(check_function_concept): Remove.
> > 	(unpack_concept_check): Remove.
> > 	(standard_concept_p): Remove.
> > 	(variable_concept_p): Remove.
> > 	(function_concept_p): Remove.
> > 	(concept_definition_p): Simplify.
> > 	(concept_check_p): Don't check for CALL_EXPR.
> > 	* decl.cc (check_concept_refinement): Remove.
> > 	(duplicate_decls): Remove check_concept_refinement code.
> > 	(is_concept_var): Remove.
> > 	(cp_finish_decl): Remove is_concept_var.
> > 	(check_concept_fn): Remove.
> > 	(grokfndecl): Give an error about function concepts not being supported
> > 	anymore.  Remove unused code.
> > 	(grokvardecl): Give an error about variable concepts not being
> > 	supported anymore.
> > 	(finish_function): Remove DECL_DECLARED_CONCEPT_P code.
> > 	* decl2.cc (min_vis_expr_r): Use concept_definition_p instead of
> > 	standard_concept_p.
> > 	(maybe_instantiate_decl): Remove DECL_DECLARED_CONCEPT_P check.
> > 	(mark_used): Likewise.
> > 	* error.cc (dump_simple_decl): Use concept_definition_p instead of
> > 	standard_concept_p.
> > 	(dump_function_decl): Remove DECL_DECLARED_CONCEPT_P code.
> > 	(print_concept_check_info): Don't call unpack_concept_check.
> > 	* mangle.cc (write_type_constraint): Likewise.
> > 	* parser.cc (cp_parser_nested_name_specifier_opt): Remove
> > 	function_concept_p code.  Only check concept_definition_p, not
> > 	variable_concept_p/standard_concept_p.
> > 	(add_debug_begin_stmt): Remove DECL_DECLARED_CONCEPT_P code.
> > 	(cp_parser_template_declaration_after_parameters): Remove a stale
> > 	comment.
> > 	* pt.cc (check_explicit_specialization): Remove
> > 	DECL_DECLARED_CONCEPT_P code.
> > 	(process_partial_specialization): Remove variable_concept_p code.
> > 	(lookup_template_variable): Likewise.
> > 	(tsubst_expr) <case CALL_EXPR>: Remove Concepts TS code and simplify.
> > 	(do_decl_instantiation): Remove DECL_DECLARED_CONCEPT_P code.
> > 	(instantiate_decl): Likewise.
> > 	(placeholder_type_constraint_dependent_p): Don't call
> > 	unpack_concept_check.  Add a concept_check_p assert.
> > 	(convert_generic_types_to_packs): Likewise.
> > 	* semantics.cc (finish_call_expr): Remove Concepts TS code and simplify.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > 	* g++.dg/concepts/decl-diagnose.C: Adjust dg-error.
> > 	* g++.dg/concepts/fn-concept2.C: Likewise.
> > 	* g++.dg/concepts/pr71128.C: Likewise.
> > 	* g++.dg/concepts/var-concept6.C: Likewise.
> > 	* g++.dg/cpp2a/concepts.C: Likewise.
> > ---
> >   gcc/cp/constexpr.cc                           |  13 +-
> >   gcc/cp/constraint.cc                          | 346 +-----------------
> >   gcc/cp/cp-tree.h                              |  71 +---
> >   gcc/cp/decl.cc                                | 118 +-----
> >   gcc/cp/decl2.cc                               |   4 +-
> >   gcc/cp/error.cc                               |  10 +-
> >   gcc/cp/mangle.cc                              |   4 +-
> >   gcc/cp/parser.cc                              |  16 +-
> >   gcc/cp/pt.cc                                  |  60 +--
> >   gcc/cp/semantics.cc                           |  17 +-
> >   gcc/testsuite/g++.dg/concepts/decl-diagnose.C |   8 +-
> >   gcc/testsuite/g++.dg/concepts/fn-concept2.C   |   4 +-
> >   gcc/testsuite/g++.dg/concepts/pr71128.C       |   8 +-
> >   gcc/testsuite/g++.dg/concepts/var-concept6.C  |   2 +-
> >   gcc/testsuite/g++.dg/cpp2a/concepts.C         |   4 +-
> >   15 files changed, 65 insertions(+), 620 deletions(-)
> > 
> > diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> > index 8277b3b79ba..b079be1b3d5 100644
> > --- a/gcc/cp/constexpr.cc
> > +++ b/gcc/cp/constexpr.cc
> > @@ -8508,20 +8508,11 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
> >         {
> >           /* We can evaluate template-id that refers to a concept only if
> >   	   the template arguments are non-dependent.  */
> > -	tree id = unpack_concept_check (t);
> > -	tree tmpl = TREE_OPERAND (id, 0);
> > +	gcc_assert (concept_check_p (t));
> > +	tree tmpl = TREE_OPERAND (t, 0);
> >   	if (!concept_definition_p (tmpl))
> >   	  internal_error ("unexpected template-id %qE", t);
> 
> It seems unnecessary to have both the assert and the internal_error here;
> I'd drop the internal_error.

Done.

> > -/* The normal form of an atom depends on the expression.  The normal
> > -   form of a function call to a function concept is a check constraint
> > -   for that concept.  The normal form of a reference to a variable
> > -   concept is a check constraint for that concept.  Otherwise, the
> > -   constraint is a predicate constraint.  */
> > +/* The normal form of an atom is a predicate constraint.  */
> 
> I think the term "predicate constraint" is also obsolete; it's now "atomic
> constraint".

Aha.  Done.

> > @@ -3952,8 +3950,8 @@ print_concept_check_info (diagnostic_context *context, tree expr, tree map, tree
> >   {
> >     gcc_assert (concept_check_p (expr));
> > -  tree id = unpack_concept_check (expr);
> > -  tree tmpl = TREE_OPERAND (id, 0);
> > +  tree tmpl = TREE_OPERAND (expr, 0);
> > +  // ??? Can this go now that fn/var concepts have been removed?
> 
> I would definitely expect so, did you try?

Yeah, it can go.
 
> I think we also want to adjust the 'concept bool' handling in
> cp_parser_decl_specifier_seq:
> 
> >           /* Warn for concept as a decl-specifier. We'll rewrite these
> > as
> > concept declarations later.  */
> >           {
> >             cp_token *next = cp_lexer_peek_token (parser->lexer);
> >             if (next->keyword == RID_BOOL)
> > =>            permerror (next->location, "the %<bool%> keyword is not "
> >                          "allowed in a C++20 concept definition");
> >             else
> >               error_at (token->location, "C++20 concept definition syntax "
> >                         "is %<concept <name> = <expr>%>");
> >           }
> 
> After the permerror let's skip the 'bool' token and continue trying to parse
> a concept declaration.  I think that should allow us to remove more of the
> code in grokfndecl/grokvardecl?

If by skip you mean cp_lexer_consume_token, then that results in worse
diagnostics for e.g.

  concept bool f3();

where it adds the extra "with no type" error:

t.C:3:9: error: the 'bool' keyword is not allowed in a C++20 concept definition [-fpermissive]
    3 | concept bool f3();
      |         ^~~~
t.C:3:14: error: ISO C++ forbids declaration of 'f3' with no type [-fpermissive]
    3 | concept bool f3();
      |              ^~
t.C:3:14: error: function concepts are no longer supported

Besides, I don't see what more I could remove in grokfndecl/grokvardecl.
Except this tiny bit, now added:

@@ -11307,7 +11307,7 @@ grokvardecl (tree type,
   // Handle explicit specializations and instantiations of variable templates.
   if (orig_declarator)
     decl = check_explicit_specialization (orig_declarator, decl,
-                     template_count, conceptp * 8);
+                     template_count, 0);

   return decl != error_mark_node ? decl : NULL_TREE;
 }


Marek
Jason Merrill Aug. 5, 2024, 6:52 p.m. UTC | #3
On 8/5/24 2:44 PM, Marek Polacek wrote:
> On Mon, Aug 05, 2024 at 12:00:04PM -0400, Jason Merrill wrote:

>> I think we also want to adjust the 'concept bool' handling in
>> cp_parser_decl_specifier_seq:
>>
>>>            /* Warn for concept as a decl-specifier. We'll rewrite these
>>> as
>>> concept declarations later.  */
>>>            {
>>>              cp_token *next = cp_lexer_peek_token (parser->lexer);
>>>              if (next->keyword == RID_BOOL)
>>> =>            permerror (next->location, "the %<bool%> keyword is not "
>>>                           "allowed in a C++20 concept definition");
>>>              else
>>>                error_at (token->location, "C++20 concept definition syntax "
>>>                          "is %<concept <name> = <expr>%>");
>>>            }
>>
>> After the permerror let's skip the 'bool' token and continue trying to parse
>> a concept declaration.  I think that should allow us to remove more of the
>> code in grokfndecl/grokvardecl?
> 
> If by skip you mean cp_lexer_consume_token, then that results in worse
> diagnostics for e.g.
> 
>    concept bool f3();
> 
> where it adds the extra "with no type" error:

Ah, yeah, cp_parser_decl_specifier_seq is too late for what I was 
thinking.  How about in cp_parser_template_declaration_after_parameters:

>   else if (flag_concepts
>            && cp_lexer_next_token_is_keyword (parser->lexer, RID_CONCEPT)
>            && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME))
>     /* -fconcept-ts 'concept bool' syntax is handled below, in                                                                      
>         cp_parser_single_declaration.  */
>     decl = cp_parser_concept_definition (parser);

What happens if we remove the CPP_NAME check, so we commit to concept 
parsing as soon as we see the keyword?

Jason
Marek Polacek Aug. 5, 2024, 8 p.m. UTC | #4
On Mon, Aug 05, 2024 at 02:52:32PM -0400, Jason Merrill wrote:
> On 8/5/24 2:44 PM, Marek Polacek wrote:
> > On Mon, Aug 05, 2024 at 12:00:04PM -0400, Jason Merrill wrote:
> 
> > > I think we also want to adjust the 'concept bool' handling in
> > > cp_parser_decl_specifier_seq:
> > > 
> > > >            /* Warn for concept as a decl-specifier. We'll rewrite these
> > > > as
> > > > concept declarations later.  */
> > > >            {
> > > >              cp_token *next = cp_lexer_peek_token (parser->lexer);
> > > >              if (next->keyword == RID_BOOL)
> > > > =>            permerror (next->location, "the %<bool%> keyword is not "
> > > >                           "allowed in a C++20 concept definition");
> > > >              else
> > > >                error_at (token->location, "C++20 concept definition syntax "
> > > >                          "is %<concept <name> = <expr>%>");
> > > >            }
> > > 
> > > After the permerror let's skip the 'bool' token and continue trying to parse
> > > a concept declaration.  I think that should allow us to remove more of the
> > > code in grokfndecl/grokvardecl?
> > 
> > If by skip you mean cp_lexer_consume_token, then that results in worse
> > diagnostics for e.g.
> > 
> >    concept bool f3();
> > 
> > where it adds the extra "with no type" error:
> 
> Ah, yeah, cp_parser_decl_specifier_seq is too late for what I was thinking.
> How about in cp_parser_template_declaration_after_parameters:
> 
> >   else if (flag_concepts
> >            && cp_lexer_next_token_is_keyword (parser->lexer, RID_CONCEPT)
> >            && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME))
> >     /* -fconcept-ts 'concept bool' syntax is handled below, in
> > cp_parser_single_declaration.  */
> >     decl = cp_parser_concept_definition (parser);
> 
> What happens if we remove the CPP_NAME check, so we commit to concept
> parsing as soon as we see the keyword?

Hmm, for 

  template<typename T>
  concept int f2() { return 0; }
  concept bool f3();

it produces this output:

t.C:2:9: error: expected identifier before 'int'
    2 | concept int f2() { return 0; }
      |         ^~~
t.C:2:31: error: expected ';' before 'concept'
    2 | concept int f2() { return 0; }
      |                               ^
      |                               ;
    3 | concept bool f3();
      | ~~~~~~~

In cp_parser_concept_definition we have

  cp_expr id = cp_parser_identifier (parser);
  if (id == error_mark_node)
    {
      cp_parser_skip_to_end_of_statement (parser);
      cp_parser_consume_semicolon_at_end_of_statement (parser);
      return NULL_TREE;
    }

cp_parser_identifier emits an error on the "int",
cp_parser_skip_to_end_of_statement consumes all tokens up to the '}'
(including) and then the next token is "concept", not a ';'.  After
cp_parser_consume_semicolon_at_end_of_statement we end up at EOF.  So
the whole f3 decl is skipped.

But the same thing will happen with a valid concept if you forget the ';':

  template<typename T>
  concept C = true
  concept bool f3();

so I can "fix" it by adding a "stray" ';' in the test.  That sound good?

Marek
Jason Merrill Aug. 5, 2024, 9:20 p.m. UTC | #5
On 8/5/24 4:00 PM, Marek Polacek wrote:
> On Mon, Aug 05, 2024 at 02:52:32PM -0400, Jason Merrill wrote:
>> On 8/5/24 2:44 PM, Marek Polacek wrote:
>>> On Mon, Aug 05, 2024 at 12:00:04PM -0400, Jason Merrill wrote:
>>
>>>> I think we also want to adjust the 'concept bool' handling in
>>>> cp_parser_decl_specifier_seq:
>>>>
>>>>>             /* Warn for concept as a decl-specifier. We'll rewrite these
>>>>> as
>>>>> concept declarations later.  */
>>>>>             {
>>>>>               cp_token *next = cp_lexer_peek_token (parser->lexer);
>>>>>               if (next->keyword == RID_BOOL)
>>>>> =>            permerror (next->location, "the %<bool%> keyword is not "
>>>>>                            "allowed in a C++20 concept definition");
>>>>>               else
>>>>>                 error_at (token->location, "C++20 concept definition syntax "
>>>>>                           "is %<concept <name> = <expr>%>");
>>>>>             }
>>>>
>>>> After the permerror let's skip the 'bool' token and continue trying to parse
>>>> a concept declaration.  I think that should allow us to remove more of the
>>>> code in grokfndecl/grokvardecl?
>>>
>>> If by skip you mean cp_lexer_consume_token, then that results in worse
>>> diagnostics for e.g.
>>>
>>>     concept bool f3();
>>>
>>> where it adds the extra "with no type" error:
>>
>> Ah, yeah, cp_parser_decl_specifier_seq is too late for what I was thinking.
>> How about in cp_parser_template_declaration_after_parameters:
>>
>>>    else if (flag_concepts
>>>             && cp_lexer_next_token_is_keyword (parser->lexer, RID_CONCEPT)
>>>             && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME))
>>>      /* -fconcept-ts 'concept bool' syntax is handled below, in
>>> cp_parser_single_declaration.  */
>>>      decl = cp_parser_concept_definition (parser);
>>
>> What happens if we remove the CPP_NAME check, so we commit to concept
>> parsing as soon as we see the keyword?
> 
> Hmm, for
> 
>    template<typename T>
>    concept int f2() { return 0; }
>    concept bool f3();
> 
> it produces this output:
> 
> t.C:2:9: error: expected identifier before 'int'
>      2 | concept int f2() { return 0; }
>        |         ^~~
> t.C:2:31: error: expected ';' before 'concept'
>      2 | concept int f2() { return 0; }
>        |                               ^
>        |                               ;
>      3 | concept bool f3();
>        | ~~~~~~~
> 
> In cp_parser_concept_definition we have
> 
>    cp_expr id = cp_parser_identifier (parser);
>    if (id == error_mark_node)
>      {
>        cp_parser_skip_to_end_of_statement (parser);
>        cp_parser_consume_semicolon_at_end_of_statement (parser);
>        return NULL_TREE;
>      }
> 
> cp_parser_identifier emits an error on the "int",
> cp_parser_skip_to_end_of_statement consumes all tokens up to the '}'
> (including) and then the next token is "concept", not a ';'.  After
> cp_parser_consume_semicolon_at_end_of_statement we end up at EOF.  So
> the whole f3 decl is skipped.
> 
> But the same thing will happen with a valid concept if you forget the ';':
> 
>    template<typename T>
>    concept C = true
>    concept bool f3();
> 
> so I can "fix" it by adding a "stray" ';' in the test.  That sound good?

Eh, I guess the current diagnostics are better, never mind.  OK with the 
small tweaks.

Jason
Patrick Palka Aug. 6, 2024, 1:56 a.m. UTC | #6
On Fri, 2 Aug 2024, Marek Polacek wrote:

> Bootstrapped/regtested on x86_64-pc-linux-gnu.  Comments?
> 
> -- >8 --
> This patch removes vestigial Concepts TS code as discussed in
> <https://gcc.gnu.org/pipermail/gcc-patches/2024-July/657937.html>.

Yay!  FWIW I think we can also remove the concept_check_p checks in

    cxx_eval_call_expression
    cxx_eval_outermost_constant_expr
    cp_genericize_r <case CALL_EXPR>
    check_noexcept_r

And perhaps we could rename *concept_check* to *concept_id* throughout
to match the standard terminology.

> 
> In particular, it removes code related to function/variable concepts.
> That includes variable_concept_p and function_concept_p, which then
> cascades into removing DECL_DECLARED_CONCEPT_P etc.  So I think we
> no longer need to say "standard concept" since there are no non-standard
> ones anymore.
> 
> I've added two new errors saying that "variable/function concepts are
> no longer supported".
> 
> gcc/cp/ChangeLog:
> 
> 	* constexpr.cc (cxx_eval_constant_expression): Don't call
> 	unpack_concept_check.  Add a concept_check_p assert.  Remove
> 	function_concept_p code.
> 	* constraint.cc (check_constraint_atom): Remove function concepts code.
> 	(unpack_concept_check): Remove.
> 	(get_concept_check_template): Remove Concepts TS code.
> 	(resolve_function_concept_overload): Remove.
> 	(resolve_function_concept_check): Remove.
> 	(resolve_concept_check): Remove Concepts TS code.
> 	(get_returned_expression): Remove.
> 	(get_variable_initializer): Remove.
> 	(get_concept_definition): Remove Concepts TS code.
> 	(normalize_concept_check): Likewise.
> 	(build_function_check): Remove.
> 	(build_variable_check): Remove.
> 	(build_standard_check): Use concept_definition_p instead of
> 	standard_concept_p.
> 	(build_concept_check): Remove variable_concept_p/function_concept_p
> 	code.
> 	(build_concept_id): Simplify.
> 	(build_type_constraint): Likewise.
> 	(placeholder_extract_concept_and_args): Likewise.
> 	(satisfy_nondeclaration_constraints): Likewise.
> 	(check_function_concept): Remove.
> 	(get_constraint_error_location): Remove Concepts TS code.
> 	* cp-tree.h (DECL_DECLARED_CONCEPT_P): Remove.
> 	(check_function_concept): Remove.
> 	(unpack_concept_check): Remove.
> 	(standard_concept_p): Remove.
> 	(variable_concept_p): Remove.
> 	(function_concept_p): Remove.
> 	(concept_definition_p): Simplify.
> 	(concept_check_p): Don't check for CALL_EXPR.
> 	* decl.cc (check_concept_refinement): Remove.
> 	(duplicate_decls): Remove check_concept_refinement code.
> 	(is_concept_var): Remove.
> 	(cp_finish_decl): Remove is_concept_var.
> 	(check_concept_fn): Remove.
> 	(grokfndecl): Give an error about function concepts not being supported
> 	anymore.  Remove unused code.
> 	(grokvardecl): Give an error about variable concepts not being
> 	supported anymore.
> 	(finish_function): Remove DECL_DECLARED_CONCEPT_P code.
> 	* decl2.cc (min_vis_expr_r): Use concept_definition_p instead of
> 	standard_concept_p.
> 	(maybe_instantiate_decl): Remove DECL_DECLARED_CONCEPT_P check.
> 	(mark_used): Likewise.
> 	* error.cc (dump_simple_decl): Use concept_definition_p instead of
> 	standard_concept_p.
> 	(dump_function_decl): Remove DECL_DECLARED_CONCEPT_P code.
> 	(print_concept_check_info): Don't call unpack_concept_check.
> 	* mangle.cc (write_type_constraint): Likewise.
> 	* parser.cc (cp_parser_nested_name_specifier_opt): Remove
> 	function_concept_p code.  Only check concept_definition_p, not
> 	variable_concept_p/standard_concept_p.
> 	(add_debug_begin_stmt): Remove DECL_DECLARED_CONCEPT_P code.
> 	(cp_parser_template_declaration_after_parameters): Remove a stale
> 	comment.
> 	* pt.cc (check_explicit_specialization): Remove
> 	DECL_DECLARED_CONCEPT_P code.
> 	(process_partial_specialization): Remove variable_concept_p code.
> 	(lookup_template_variable): Likewise.
> 	(tsubst_expr) <case CALL_EXPR>: Remove Concepts TS code and simplify.
> 	(do_decl_instantiation): Remove DECL_DECLARED_CONCEPT_P code.
> 	(instantiate_decl): Likewise.
> 	(placeholder_type_constraint_dependent_p): Don't call
> 	unpack_concept_check.  Add a concept_check_p assert.
> 	(convert_generic_types_to_packs): Likewise.
> 	* semantics.cc (finish_call_expr): Remove Concepts TS code and simplify.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/concepts/decl-diagnose.C: Adjust dg-error.
> 	* g++.dg/concepts/fn-concept2.C: Likewise.
> 	* g++.dg/concepts/pr71128.C: Likewise.
> 	* g++.dg/concepts/var-concept6.C: Likewise.
> 	* g++.dg/cpp2a/concepts.C: Likewise.
> ---
>  gcc/cp/constexpr.cc                           |  13 +-
>  gcc/cp/constraint.cc                          | 346 +-----------------
>  gcc/cp/cp-tree.h                              |  71 +---
>  gcc/cp/decl.cc                                | 118 +-----
>  gcc/cp/decl2.cc                               |   4 +-
>  gcc/cp/error.cc                               |  10 +-
>  gcc/cp/mangle.cc                              |   4 +-
>  gcc/cp/parser.cc                              |  16 +-
>  gcc/cp/pt.cc                                  |  60 +--
>  gcc/cp/semantics.cc                           |  17 +-
>  gcc/testsuite/g++.dg/concepts/decl-diagnose.C |   8 +-
>  gcc/testsuite/g++.dg/concepts/fn-concept2.C   |   4 +-
>  gcc/testsuite/g++.dg/concepts/pr71128.C       |   8 +-
>  gcc/testsuite/g++.dg/concepts/var-concept6.C  |   2 +-
>  gcc/testsuite/g++.dg/cpp2a/concepts.C         |   4 +-
>  15 files changed, 65 insertions(+), 620 deletions(-)
> 
> diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> index 8277b3b79ba..b079be1b3d5 100644
> --- a/gcc/cp/constexpr.cc
> +++ b/gcc/cp/constexpr.cc
> @@ -8508,20 +8508,11 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
>        {
>          /* We can evaluate template-id that refers to a concept only if
>  	   the template arguments are non-dependent.  */
> -	tree id = unpack_concept_check (t);
> -	tree tmpl = TREE_OPERAND (id, 0);
> +	gcc_assert (concept_check_p (t));
> +	tree tmpl = TREE_OPERAND (t, 0);
>  	if (!concept_definition_p (tmpl))
>  	  internal_error ("unexpected template-id %qE", t);
>  
> -	if (function_concept_p (tmpl))
> -	  {
> -	    if (!ctx->quiet)
> -	      error_at (cp_expr_loc_or_input_loc (t),
> -			"function concept must be called");
> -	    r = error_mark_node;
> -	    break;
> -	  }
> -
>  	if (!value_dependent_expression_p (t)
>  	    && !uid_sensitive_constexpr_evaluation_p ())
>  	  r = evaluate_concept_check (t);
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index 853ea8c4b93..2da482cc93d 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -167,19 +167,6 @@ check_constraint_atom (cp_expr expr)
>        return false;
>      }
>  
> -  /* Check that we're using function concepts correctly.  */
> -  if (concept_check_p (expr))
> -    {
> -      tree id = unpack_concept_check (expr);
> -      tree tmpl = TREE_OPERAND (id, 0);
> -      if (OVL_P (tmpl) && TREE_CODE (expr) == TEMPLATE_ID_EXPR)
> -        {
> -	  error_at (EXPR_LOC_OR_LOC (expr, input_location),
> -		    "function concept must be called");
> -	  return false;
> -	}
> -    }
> -
>    return true;
>  }
>  
> @@ -245,32 +232,13 @@ combine_constraint_expressions (tree lhs, tree rhs)
>    return finish_constraint_and_expr (UNKNOWN_LOCATION, lhs, rhs);
>  }
>  
> -/* Extract the template-id from a concept check.  For standard and variable
> -   checks, this is simply T.  For function concept checks, this is the
> -   called function.  */
> -
> -tree
> -unpack_concept_check (tree t)
> -{
> -  gcc_assert (concept_check_p (t));
> -
> -  if (TREE_CODE (t) == CALL_EXPR)
> -    t = CALL_EXPR_FN (t);
> -
> -  gcc_assert (TREE_CODE (t) == TEMPLATE_ID_EXPR);
> -  return t;
> -}
> -
>  /* Extract the TEMPLATE_DECL from a concept check.  */
>  
>  tree
>  get_concept_check_template (tree t)
>  {
> -  tree id = unpack_concept_check (t);
> -  tree tmpl = TREE_OPERAND (id, 0);
> -  if (OVL_P (tmpl))
> -    tmpl = OVL_FIRST (tmpl);
> -  return tmpl;
> +  gcc_assert (concept_check_p (t));
> +  return TREE_OPERAND (t, 0);
>  }
>  
>  /*---------------------------------------------------------------------------
> @@ -285,101 +253,6 @@ get_concept_check_template (tree t)
>     matched declaration, and whose purpose contains the coerced template
>     arguments that can be substituted into the call.  */
>  
> -/* Given an overload set OVL, try to find a unique definition that can be
> -   instantiated by the template arguments ARGS.
> -
> -   This function is not called for arbitrary call expressions.  In particular,
> -   the call expression must be written with explicit template arguments
> -   and no function arguments.  For example:
> -
> -        f<T, U>()
> -
> -   If a single match is found, this returns a TREE_LIST whose VALUE
> -   is the constraint function (not the template), and its PURPOSE is
> -   the complete set of arguments substituted into the parameter list.  */
> -
> -static tree
> -resolve_function_concept_overload (tree ovl, tree args)
> -{
> -  int nerrs = 0;
> -  tree cands = NULL_TREE;
> -  for (lkp_iterator iter (ovl); iter; ++iter)
> -    {
> -      tree tmpl = *iter;
> -      if (TREE_CODE (tmpl) != TEMPLATE_DECL)
> -        continue;
> -
> -      /* Don't try to deduce checks for non-concepts.  We often end up trying
> -         to resolve constraints in functional casts as part of a
> -	 postfix-expression.  We can save time and headaches by not
> -         instantiating those declarations.
> -
> -         NOTE: This masks a potential error, caused by instantiating
> -	 non-deduced contexts using placeholder arguments.  */
> -      tree fn = DECL_TEMPLATE_RESULT (tmpl);
> -      if (DECL_ARGUMENTS (fn))
> -        continue;
> -      if (!DECL_DECLARED_CONCEPT_P (fn))
> -        continue;
> -
> -      /* Remember the candidate if we can deduce a substitution.  */
> -      ++processing_template_decl;
> -      tree parms = TREE_VALUE (DECL_TEMPLATE_PARMS (tmpl));
> -      if (tree subst = coerce_template_parms (parms, args, tmpl, tf_none))
> -        {
> -          if (subst == error_mark_node)
> -            ++nerrs;
> -          else
> -	    cands = tree_cons (subst, fn, cands);
> -        }
> -      --processing_template_decl;
> -    }
> -
> -  if (!cands)
> -    /* We either had no candidates or failed deductions.  */
> -    return nerrs ? error_mark_node : NULL_TREE;
> -  else if (TREE_CHAIN (cands))
> -    /* There are multiple candidates.  */
> -    return error_mark_node;
> -
> -  return cands;
> -}
> -
> -/* Determine if the call expression CALL is a constraint check, and
> -   return the concept declaration and arguments being checked.  If CALL
> -   does not denote a constraint check, return NULL.  */
> -
> -tree
> -resolve_function_concept_check (tree call)
> -{
> -  gcc_assert (TREE_CODE (call) == CALL_EXPR);
> -
> -  /* A constraint check must be only a template-id expression.
> -     If it's a call to a base-link, its function(s) should be a
> -     template-id expression.  If this is not a template-id, then
> -     it cannot be a concept-check.  */
> -  tree target = CALL_EXPR_FN (call);
> -  if (BASELINK_P (target))
> -    target = BASELINK_FUNCTIONS (target);
> -  if (TREE_CODE (target) != TEMPLATE_ID_EXPR)
> -    return NULL_TREE;
> -
> -  /* Get the overload set and template arguments and try to
> -     resolve the target.  */
> -  tree ovl = TREE_OPERAND (target, 0);
> -
> -  /* This is a function call of a variable concept... ill-formed.  */
> -  if (TREE_CODE (ovl) == TEMPLATE_DECL)
> -    {
> -      error_at (location_of (call),
> -		"function call of variable concept %qE", call);
> -      return error_mark_node;
> -    }
> -
> -  tree args = TREE_OPERAND (target, 1);
> -  return resolve_function_concept_overload (ovl, args);
> -}
> -
>  /* Returns a pair containing the checked concept and its associated
>     prototype parameter.  The result is a TREE_LIST whose TREE_VALUE
>     is the concept (non-template) and whose TREE_PURPOSE contains
> @@ -390,20 +263,8 @@ tree
>  resolve_concept_check (tree check)
>  {
>    gcc_assert (concept_check_p (check));
> -  tree id = unpack_concept_check (check);
> -  tree tmpl = TREE_OPERAND (id, 0);
> -
> -  /* If this is an overloaded function concept, perform overload
> -     resolution (this only happens when deducing prototype parameters
> -     and template introductions).  */
> -  if (TREE_CODE (tmpl) == OVERLOAD)
> -    {
> -      if (OVL_CHAIN (tmpl))
> -	return resolve_function_concept_check (check);
> -      tmpl = OVL_FIRST (tmpl);
> -    }
> -
> -  tree args = TREE_OPERAND (id, 1);
> +  tree tmpl = TREE_OPERAND (check, 0);
> +  tree args = TREE_OPERAND (check, 1);
>    tree parms = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (tmpl));
>    ++processing_template_decl;
>    tree result = coerce_template_parms (parms, args, tmpl, tf_none);
> @@ -466,55 +327,13 @@ finish_type_constraints (tree spec, tree args, tsubst_flags_t complain)
>                         Expansion of concept definitions
>  ---------------------------------------------------------------------------*/
>  
> -/* Returns the expression of a function concept.  */
> -
> -static tree
> -get_returned_expression (tree fn)
> -{
> -  /* Extract the body of the function minus the return expression.  */
> -  tree body = DECL_SAVED_TREE (fn);
> -  if (!body)
> -    return error_mark_node;
> -  if (TREE_CODE (body) == BIND_EXPR)
> -    body = BIND_EXPR_BODY (body);
> -  if (TREE_CODE (body) != RETURN_EXPR)
> -    return error_mark_node;
> -
> -  return TREE_OPERAND (body, 0);
> -}
> -
> -/* Returns the initializer of a variable concept.  */
> -
> -static tree
> -get_variable_initializer (tree var)
> -{
> -  tree init = DECL_INITIAL (var);
> -  if (!init)
> -    return error_mark_node;
> -  if (BRACE_ENCLOSED_INITIALIZER_P (init)
> -      && CONSTRUCTOR_NELTS (init) == 1)
> -    init = CONSTRUCTOR_ELT (init, 0)->value;
> -  return init;
> -}
> -
> -/* Returns the definition of a variable or function concept.  */
> +/* Returns the definition of a concept.  */
>  
>  static tree
>  get_concept_definition (tree decl)
>  {
> -  if (TREE_CODE (decl) == OVERLOAD)
> -    decl = OVL_FIRST (decl);
> -
> -  if (TREE_CODE (decl) == TEMPLATE_DECL)
> -    decl = DECL_TEMPLATE_RESULT (decl);
> -
> -  if (TREE_CODE (decl) == CONCEPT_DECL)
> -    return DECL_INITIAL (decl);
> -  if (VAR_P (decl))
> -    return get_variable_initializer (decl);
> -  if (TREE_CODE (decl) == FUNCTION_DECL)
> -    return get_returned_expression (decl);
> -  gcc_unreachable ();
> +  gcc_assert (TREE_CODE (decl) == CONCEPT_DECL);
> +  return DECL_INITIAL (decl);
>  }
>  
>  /*---------------------------------------------------------------------------
> @@ -729,19 +548,9 @@ static GTY((deletable)) hash_table<norm_hasher> *norm_cache;
>  static tree
>  normalize_concept_check (tree check, tree args, norm_info info)
>  {
> -  tree id = unpack_concept_check (check);
> -  tree tmpl = TREE_OPERAND (id, 0);
> -  tree targs = TREE_OPERAND (id, 1);
> -
> -  /* A function concept is wrapped in an overload.  */
> -  if (TREE_CODE (tmpl) == OVERLOAD)
> -    {
> -      /* TODO: Can we diagnose this error during parsing?  */
> -      if (TREE_CODE (check) == TEMPLATE_ID_EXPR)
> -	error_at (EXPR_LOC_OR_LOC (check, input_location),
> -		  "function concept must be called");
> -      tmpl = OVL_FIRST (tmpl);
> -    }
> +  gcc_assert (concept_check_p (check));
> +  tree tmpl = TREE_OPERAND (check, 0);
> +  tree targs = TREE_OPERAND (check, 1);
>  
>    /* Substitute through the arguments of the concept check.  */
>    if (args)
> @@ -789,11 +598,7 @@ normalize_concept_check (tree check, tree args, norm_info info)
>  
>  static GTY((deletable)) hash_table<atom_hasher> *atom_cache;
>  
> -/* The normal form of an atom depends on the expression.  The normal
> -   form of a function call to a function concept is a check constraint
> -   for that concept.  The normal form of a reference to a variable
> -   concept is a check constraint for that concept.  Otherwise, the
> -   constraint is a predicate constraint.  */
> +/* The normal form of an atom is a predicate constraint.  */
>  
>  static tree
>  normalize_atom (tree t, tree args, norm_info info)
> @@ -1378,77 +1183,13 @@ build_concept_check_arguments (tree arg, tree rest)
>    return args;
>  }
>  
> -/* Builds an id-expression of the form `C<Args...>()` where C is a function
> -   concept.  */
> -
> -static tree
> -build_function_check (tree tmpl, tree args, tsubst_flags_t /*complain*/)
> -{
> -  if (TREE_CODE (tmpl) == TEMPLATE_DECL)
> -    {
> -      /* If we just got a template, wrap it in an overload so it looks like any
> -	 other template-id.  */
> -      tmpl = ovl_make (tmpl);
> -      TREE_TYPE (tmpl) = boolean_type_node;
> -    }
> -
> -  /* Perform function concept resolution now so we always have a single
> -     function of the overload set (even if we started with only one; the
> -     resolution function converts template arguments).  Note that we still
> -     wrap this in an overload set so we don't upset other parts of the
> -     compiler that expect template-ids referring to function concepts
> -     to have an overload set.  */
> -  tree info = resolve_function_concept_overload (tmpl, args);
> -  if (info == error_mark_node)
> -    return error_mark_node;
> -  if (!info)
> -    {
> -      error ("no matching concepts for %qE", tmpl);
> -      return error_mark_node;
> -    }
> -  args = TREE_PURPOSE (info);
> -  tmpl = DECL_TI_TEMPLATE (TREE_VALUE (info));
> -
> -  /* Rebuild the singleton overload set; mark the type bool.  */
> -  tmpl = ovl_make (tmpl, NULL_TREE);
> -  TREE_TYPE (tmpl) = boolean_type_node;
> -
> -  /* Build the id-expression around the overload set.  */
> -  tree id = build2 (TEMPLATE_ID_EXPR, boolean_type_node, tmpl, args);
> -
> -  /* Finally, build the call expression around the overload.  */
> -  ++processing_template_decl;
> -  vec<tree, va_gc> *fargs = make_tree_vector ();
> -  tree call = build_min_nt_call_vec (id, fargs);
> -  TREE_TYPE (call) = boolean_type_node;
> -  release_tree_vector (fargs);
> -  --processing_template_decl;
> -
> -  return call;
> -}
> -
> -/* Builds an id-expression of the form `C<Args...>` where C is a variable
> -   concept.  */
> -
> -static tree
> -build_variable_check (tree tmpl, tree args, tsubst_flags_t complain)
> -{
> -  gcc_assert (variable_concept_p (tmpl));
> -  gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL);
> -  tree parms = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (tmpl));
> -  args = coerce_template_parms (parms, args, tmpl, complain);
> -  if (args == error_mark_node)
> -    return error_mark_node;
> -  return build2 (TEMPLATE_ID_EXPR, boolean_type_node, tmpl, args);
> -}
> -
>  /* Builds an id-expression of the form `C<Args...>` where C is a standard
>     concept.  */
>  
>  static tree
>  build_standard_check (tree tmpl, tree args, tsubst_flags_t complain)
>  {
> -  gcc_assert (standard_concept_p (tmpl));
> +  gcc_assert (concept_definition_p (tmpl));
>    gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL);
>    if (TREE_DEPRECATED (DECL_TEMPLATE_RESULT (tmpl)))
>      warn_deprecated_use (DECL_TEMPLATE_RESULT (tmpl), NULL_TREE);
> @@ -1475,12 +1216,8 @@ build_concept_check (tree decl, tree arg, tree rest, tsubst_flags_t complain)
>  {
>    tree args = build_concept_check_arguments (arg, rest);
>  
> -  if (standard_concept_p (decl))
> +  if (concept_definition_p (decl))
>      return build_standard_check (decl, args, complain);
> -  if (variable_concept_p (decl))
> -    return build_variable_check (decl, args, complain);
> -  if (function_concept_p (decl))
> -    return build_function_check (decl, args, complain);
>  
>    return error_mark_node;
>  }
> @@ -1490,10 +1227,7 @@ build_concept_check (tree decl, tree arg, tree rest, tsubst_flags_t complain)
>  static tree
>  build_concept_id (tree decl, tree args)
>  {
> -  tree check = build_concept_check (decl, args, tf_warning_or_error);
> -  if (check == error_mark_node)
> -    return error_mark_node;
> -  return unpack_concept_check (check);
> +  return build_concept_check (decl, args, tf_warning_or_error);
>  }
>  
>  /* Build a template-id that can participate in a concept check, preserving
> @@ -1521,9 +1255,7 @@ build_type_constraint (tree decl, tree args, tsubst_flags_t complain)
>    ++processing_template_decl;
>    tree check = build_concept_check (decl, wildcard, args, complain);
>    --processing_template_decl;
> -  if (check == error_mark_node)
> -    return error_mark_node;
> -  return unpack_concept_check (check);
> +  return check;
>  }
>  
>  /* Returns a TYPE_DECL that contains sufficient information to
> @@ -1621,10 +1353,7 @@ placeholder_extract_concept_and_args (tree t, tree &tmpl, tree &args)
>  {
>    if (concept_check_p (t))
>      {
> -      t = unpack_concept_check (t);
>        tmpl = TREE_OPERAND (t, 0);
> -      if (TREE_CODE (tmpl) == OVERLOAD)
> -        tmpl = OVL_FIRST (tmpl);
>        args = TREE_OPERAND (t, 1);
>        return;
>      }
> @@ -2938,9 +2667,8 @@ satisfy_nondeclaration_constraints (tree t, tree args, sat_info info)
>    if (concept_check_p (t))
>      {
>        gcc_assert (!args);
> -      tree id = unpack_concept_check (t);
> -      args = TREE_OPERAND (id, 1);
> -      tree tmpl = get_concept_check_template (id);
> +      args = TREE_OPERAND (t, 1);
> +      tree tmpl = get_concept_check_template (t);
>        norm = normalize_concept_definition (tmpl, info.noisy ());
>      }
>    else if (TREE_CODE (t) == NESTED_REQ)
> @@ -3255,41 +2983,6 @@ finish_nested_requirement (location_t loc, tree expr)
>    return r;
>  }
>  
> -/* Check that FN satisfies the structural requirements of a
> -   function concept definition.  */
> -tree
> -check_function_concept (tree fn)
> -{
> -  /* Check that the function is comprised of only a return statement.  */
> -  tree body = DECL_SAVED_TREE (fn);
> -  if (TREE_CODE (body) == BIND_EXPR)
> -    body = BIND_EXPR_BODY (body);
> -
> -  /* Sometimes a function call results in the creation of clean up
> -     points.  Allow these to be preserved in the body of the
> -     constraint, as we might actually need them for some constexpr
> -     evaluations.  */
> -  if (TREE_CODE (body) == CLEANUP_POINT_EXPR)
> -    body = TREE_OPERAND (body, 0);
> -
> -  /* Check that the definition is written correctly.  */
> -  if (TREE_CODE (body) != RETURN_EXPR)
> -    {
> -      location_t loc = DECL_SOURCE_LOCATION (fn);
> -      if (TREE_CODE (body) == STATEMENT_LIST && !STATEMENT_LIST_HEAD (body))
> -	{
> -	  if (seen_error ())
> -	    /* The definition was probably erroneous, not empty.  */;
> -	  else
> -	    error_at (loc, "definition of concept %qD is empty", fn);
> -	}
> -      else
> -        error_at (loc, "definition of concept %qD has multiple statements", fn);
> -    }
> -
> -  return NULL_TREE;
> -}
> -
>  /*---------------------------------------------------------------------------
>                          Equivalence of constraints
>  ---------------------------------------------------------------------------*/
> @@ -3403,10 +3096,7 @@ get_constraint_error_location (tree t)
>    /* Otherwise, give the location as the defining concept.  */
>    else if (concept_check_p (src))
>      {
> -      tree id = unpack_concept_check (src);
> -      tree tmpl = TREE_OPERAND (id, 0);
> -      if (OVL_P (tmpl))
> -	tmpl = OVL_FIRST (tmpl);
> +      tree tmpl = TREE_OPERAND (src, 0);
>        return DECL_SOURCE_LOCATION (tmpl);
>      }
>  
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 238d786b067..c92ff707e3f 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -3524,12 +3524,6 @@ struct GTY(()) lang_decl {
>    (retrofit_lang_decl (FUNCTION_DECL_CHECK (NODE)),			\
>     LANG_DECL_FN_CHECK (NODE)->immediate_fn_p = true)
>  
> -// True if NODE was declared as 'concept'.  The flag implies that the
> -// declaration is constexpr, that the declaration cannot be specialized or
> -// refined, and that the result type must be convertible to bool.
> -#define DECL_DECLARED_CONCEPT_P(NODE) \
> -  (DECL_LANG_SPECIFIC (NODE)->u.base.concept_p)
> -
>  /* Nonzero if this DECL is the __PRETTY_FUNCTION__ variable in a
>     template function.  */
>  #define DECL_PRETTY_FUNCTION_P(NODE) \
> @@ -8582,7 +8576,6 @@ extern bool equivalent_placeholder_constraints  (tree, tree);
>  extern hashval_t iterative_hash_placeholder_constraint	(tree, hashval_t);
>  extern bool deduce_constrained_parameter        (tree, tree&, tree&);
>  extern tree resolve_constraint_check            (tree);
> -extern tree check_function_concept              (tree);
>  extern bool valid_requirements_p                (tree);
>  extern tree finish_concept_name                 (tree);
>  extern tree finish_shorthand_constraint         (tree, tree);
> @@ -8605,7 +8598,6 @@ struct processing_constraint_expression_sentinel
>  
>  extern bool processing_constraint_expression_p	();
>  
> -extern tree unpack_concept_check		(tree);
>  extern tree get_concept_check_template		(tree);
>  extern tree evaluate_concept_check              (tree);
>  extern bool constraints_satisfied_p		(tree, tree = NULL_TREE);
> @@ -8867,69 +8859,12 @@ variable_template_p (tree t)
>    return false;
>  }
>  
> -/* True iff T is a standard concept definition. This will return
> -   true for both the template and underlying declaration.  */
> -
> -inline bool
> -standard_concept_p (tree t)
> -{
> -  if (TREE_CODE (t) == TEMPLATE_DECL)
> -    t = DECL_TEMPLATE_RESULT (t);
> -  return TREE_CODE (t) == CONCEPT_DECL;
> -}
> -
> -/* True iff T is a variable concept definition. This will return
> -   true for both the template and the underlying declaration.  */
> -
> -inline bool
> -variable_concept_p (tree t)
> -{
> -  if (TREE_CODE (t) == TEMPLATE_DECL)
> -    t = DECL_TEMPLATE_RESULT (t);
> -  return VAR_P (t) && DECL_DECLARED_CONCEPT_P (t);
> -}
> -
> -/* True iff T is a function concept definition or an overload set
> -   containing multiple function concepts. This will return true for
> -   both the template and the underlying declaration.  */
> -
> -inline bool
> -function_concept_p (tree t)
> -{
> -  if (TREE_CODE (t) == OVERLOAD)
> -    t = OVL_FIRST (t);
> -  if (TREE_CODE (t) == TEMPLATE_DECL)
> -    t = DECL_TEMPLATE_RESULT (t);
> -  return TREE_CODE (t) == FUNCTION_DECL && DECL_DECLARED_CONCEPT_P (t);
> -}
> -
> -/* True iff T is a standard, variable, or function concept.  */
> +/* True iff T is a concept.  */
>  
>  inline bool
>  concept_definition_p (tree t)
>  {
> -  if (t == error_mark_node)
> -    return false;
> -
> -  /* Adjust for function concept overloads.  */
> -  if (TREE_CODE (t) == OVERLOAD)
> -    t = OVL_FIRST (t);
> -
> -  /* See through templates.  */
> -  if (TREE_CODE (t) == TEMPLATE_DECL)
> -    t = DECL_TEMPLATE_RESULT (t);
> -
> -  /* The obvious and easy case.  */
> -  if (TREE_CODE (t) == CONCEPT_DECL)
> -    return true;
> -
> -  /* Definitely not a concept.  */
> -  if (!VAR_OR_FUNCTION_DECL_P (t))
> -    return false;
> -  if (!DECL_LANG_SPECIFIC (t))
> -    return false;
> -
> -  return DECL_DECLARED_CONCEPT_P (t);
> +  return TREE_CODE (STRIP_TEMPLATE (t)) == CONCEPT_DECL;
>  }
>  
>  /* Same as above, but for const trees.  */
> @@ -8945,8 +8880,6 @@ concept_definition_p (const_tree t)
>  inline bool
>  concept_check_p (const_tree t)
>  {
> -  if (TREE_CODE (t) == CALL_EXPR)
> -    t = CALL_EXPR_FN (t);
>    if (t && TREE_CODE (t) == TEMPLATE_ID_EXPR)
>      return concept_definition_p (TREE_OPERAND (t, 0));
>    return false;
> diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> index 687ae6937f5..04877087dc7 100644
> --- a/gcc/cp/decl.cc
> +++ b/gcc/cp/decl.cc
> @@ -1467,36 +1467,6 @@ validate_constexpr_redeclaration (tree old_decl, tree new_decl)
>    return true;
>  }
>  
> -// If OLDDECL and NEWDECL are concept declarations with the same type
> -// (i.e., and template parameters), but different requirements,
> -// emit diagnostics and return true. Otherwise, return false.
> -static inline bool
> -check_concept_refinement (tree olddecl, tree newdecl)
> -{
> -  if (!DECL_DECLARED_CONCEPT_P (olddecl) || !DECL_DECLARED_CONCEPT_P (newdecl))
> -    return false;
> -
> -  tree d1 = DECL_TEMPLATE_RESULT (olddecl);
> -  tree d2 = DECL_TEMPLATE_RESULT (newdecl);
> -  if (TREE_CODE (d1) != TREE_CODE (d2))
> -    return false;
> -
> -  tree t1 = TREE_TYPE (d1);
> -  tree t2 = TREE_TYPE (d2);
> -  if (TREE_CODE (d1) == FUNCTION_DECL)
> -    {
> -      if (compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2))
> -          && comp_template_parms (DECL_TEMPLATE_PARMS (olddecl),
> -                                  DECL_TEMPLATE_PARMS (newdecl))
> -          && !equivalently_constrained (olddecl, newdecl))
> -        {
> -          error ("cannot specialize concept %q#D", olddecl);
> -          return true;
> -        }
> -    }
> -  return false;
> -}
> -
>  /* DECL is a redeclaration of a function or function template.  If
>     it does have default arguments issue a diagnostic.  Note: this
>     function is used to enforce the requirements in C++11 8.3.6 about
> @@ -1990,8 +1960,6 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
>  		return error_mark_node;
>  	      return NULL_TREE;
>  	    }
> -          else if (check_concept_refinement (olddecl, newdecl))
> -	    return error_mark_node;
>  	  return NULL_TREE;
>  	}
>        if (TREE_CODE (newdecl) == FUNCTION_DECL)
> @@ -8224,16 +8192,6 @@ value_dependent_init_p (tree init)
>    return false;
>  }
>  
> -// Returns true if a DECL is VAR_DECL with the concept specifier.
> -static inline bool
> -is_concept_var (tree decl)
> -{
> -  return (VAR_P (decl)
> -	  // Not all variables have DECL_LANG_SPECIFIC.
> -          && DECL_LANG_SPECIFIC (decl)
> -          && DECL_DECLARED_CONCEPT_P (decl));
> -}
> -
>  /* A helper function to be called via walk_tree.  If any label exists
>     under *TP, it is (going to be) forced.  Set has_forced_label_in_static.  */
>  
> @@ -8751,11 +8709,6 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
>  
>        if (!VAR_P (decl) || type_dependent_p)
>  	/* We can't do anything if the decl has dependent type.  */;
> -      else if (!init && is_concept_var (decl))
> -	{
> -	  error ("variable concept has no initializer");
> -	  init = boolean_true_node;
> -	}
>        else if (init
>  	       && (init_const_expr_p || DECL_DECLARED_CONSTEXPR_P (decl))
>  	       && !TYPE_REF_P (type)
> @@ -10547,26 +10500,6 @@ check_static_quals (tree decl, cp_cv_quals quals)
>  	   decl);
>  }
>  
> -// Check that FN takes no arguments and returns bool.
> -static void
> -check_concept_fn (tree fn)
> -{
> -  // A constraint is nullary.
> -  if (DECL_ARGUMENTS (fn))
> -    error_at (DECL_SOURCE_LOCATION (fn),
> -	      "concept %q#D declared with function parameters", fn);
> -
> -  // The declared return type of the concept shall be bool, and
> -  // it shall not be deduced from it definition.
> -  tree type = TREE_TYPE (TREE_TYPE (fn));
> -  if (is_auto (type))
> -    error_at (DECL_SOURCE_LOCATION (fn),
> -	      "concept %q#D declared with a deduced return type", fn);
> -  else if (type != boolean_type_node)
> -    error_at (DECL_SOURCE_LOCATION (fn),
> -	      "concept %q#D with non-%<bool%> return type %qT", fn, type);
> -}
> -
>  /* Helper function.  Replace the temporary this parameter injected
>     during cp_finish_omp_declare_simd with the real this parameter.  */
>  
> @@ -10637,10 +10570,9 @@ grokfndecl (tree ctype,
>    /* Was the concept specifier present?  */
>    bool concept_p = inlinep & 4;
>  
> -  /* Concept declarations must have a corresponding definition.  */
> -  if (concept_p && !funcdef_flag)
> +  if (concept_p)
>      {
> -      error_at (location, "concept %qD has no definition", declarator);
> +      error_at (location, "function concepts are no longer supported");
>        return NULL_TREE;
>      }
>  
> @@ -10667,11 +10599,6 @@ grokfndecl (tree ctype,
>  	    tmpl_reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
>  	}
>        tree ci = build_constraints (tmpl_reqs, decl_reqs);
> -      if (concept_p && ci)
> -        {
> -          error_at (location, "a function concept cannot be constrained");
> -          ci = NULL_TREE;
> -        }
>        /* C++20 CA378: Remove non-templated constrained functions.  */
>        /* [temp.friend]/9 A non-template friend declaration with a
>  	 requires-clause shall be a definition. A friend function template with
> @@ -10903,14 +10830,6 @@ grokfndecl (tree ctype,
>        SET_DECL_IMMEDIATE_FUNCTION_P (decl);
>      }
>  
> -  // If the concept declaration specifier was found, check
> -  // that the declaration satisfies the necessary requirements.
> -  if (concept_p)
> -    {
> -      DECL_DECLARED_CONCEPT_P (decl) = true;
> -      check_concept_fn (decl);
> -    }
> -
>    DECL_EXTERNAL (decl) = 1;
>    if (TREE_CODE (type) == FUNCTION_TYPE)
>      {
> @@ -11072,8 +10991,7 @@ grokfndecl (tree ctype,
>    decl = check_explicit_specialization (orig_declarator, decl,
>  					template_count,
>  					2 * funcdef_flag +
> -					4 * (friendp != 0) +
> -	                                8 * concept_p,
> +					4 * (friendp != 0),
>  					*attrlist);
>    if (decl == error_mark_node)
>      return NULL_TREE;
> @@ -11365,29 +11283,19 @@ grokvardecl (tree type,
>  		  "C language linkage");
>      }
>  
> -  /* Check that the variable can be safely declared as a concept.
> -     Note that this also forbids explicit specializations.  */
> +  /* Check if a variable is being declared as a concept.  */
>    if (conceptp)
>      {
>        if (!processing_template_decl)
> -        {
> -          error_at (declspecs->locations[ds_concept],
> -		    "a non-template variable cannot be %<concept%>");
> -          return NULL_TREE;
> -        }
> +	error_at (declspecs->locations[ds_concept],
> +		  "a non-template variable cannot be %<concept%>");
>        else if (!at_namespace_scope_p ())
> -	{
> -	  error_at (declspecs->locations[ds_concept],
> -		    "concept must be defined at namespace scope");
> -	  return NULL_TREE;
> -	}
> +	error_at (declspecs->locations[ds_concept],
> +		  "concept must be defined at namespace scope");
>        else
> -        DECL_DECLARED_CONCEPT_P (decl) = true;
> -      if (TEMPLATE_PARMS_CONSTRAINTS (current_template_parms))
> -        {
> -          error_at (location, "a variable concept cannot be constrained");
> -          TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = NULL_TREE;
> -        }
> +	error_at (declspecs->locations[ds_concept],
> +		  "variable concepts are no longer supported");
> +      return NULL_TREE;
>      }
>    else if (flag_concepts
>  	   && current_template_depth > template_class_depth (scope))
> @@ -18808,10 +18716,6 @@ finish_function (bool inline_p)
>        goto cleanup;
>      }
>  
> -  // If this is a concept, check that the definition is reasonable.
> -  if (DECL_DECLARED_CONCEPT_P (fndecl))
> -    check_function_concept (fndecl);
> -
>    if (flag_openmp)
>      if (tree attr = lookup_attribute ("omp declare variant base",
>  				      DECL_ATTRIBUTES (fndecl)))
> diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc
> index 6d674684931..695d5f8d790 100644
> --- a/gcc/cp/decl2.cc
> +++ b/gcc/cp/decl2.cc
> @@ -2723,7 +2723,7 @@ min_vis_expr_r (tree *tp, int */*walk_subtrees*/, void *data)
>        break;
>  
>      case TEMPLATE_DECL:
> -      if (DECL_ALIAS_TEMPLATE_P (t) || standard_concept_p (t))
> +      if (DECL_ALIAS_TEMPLATE_P (t) || concept_definition_p (t))
>  	/* FIXME: We don't maintain TREE_PUBLIC / DECL_VISIBILITY for
>  	   alias templates so we can't trust it here (PR107906).  Ditto
>  	   for concepts.  */
> @@ -5687,7 +5687,6 @@ maybe_instantiate_decl (tree decl)
>    if (VAR_OR_FUNCTION_DECL_P (decl)
>        && DECL_LANG_SPECIFIC (decl)
>        && DECL_TEMPLATE_INFO (decl)
> -      && !DECL_DECLARED_CONCEPT_P (decl)
>        && !uses_template_parms (DECL_TI_ARGS (decl)))
>      {
>        /* Instantiating a function will result in garbage collection.  We
> @@ -6084,7 +6083,6 @@ mark_used (tree decl, tsubst_flags_t complain /* = tf_warning_or_error */)
>      }
>    else if (VAR_OR_FUNCTION_DECL_P (decl)
>  	   && DECL_TEMPLATE_INFO (decl)
> -           && !DECL_DECLARED_CONCEPT_P (decl)
>  	   && (!DECL_EXPLICIT_INSTANTIATION (decl)
>  	       || always_instantiate_p (decl)))
>      /* If this is a function or variable that is an instance of some
> diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
> index d80bac822ba..aecbc4ff0d9 100644
> --- a/gcc/cp/error.cc
> +++ b/gcc/cp/error.cc
> @@ -1163,7 +1163,7 @@ dump_simple_decl (cxx_pretty_printer *pp, tree t, tree type, int flags)
>        else if (VAR_P (t) && DECL_DECLARED_CONSTEXPR_P (t))
>  	pp_cxx_ws_string (pp, "constexpr");
>  
> -      if (!standard_concept_p (t))
> +      if (!concept_definition_p (t))
>  	dump_type_prefix (pp, type, flags & ~TFF_UNQUALIFIED_NAME);
>        pp_maybe_space (pp);
>      }
> @@ -1806,9 +1806,7 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
>  
>        if (constexpr_p)
>          {
> -          if (DECL_DECLARED_CONCEPT_P (t))
> -            pp_cxx_ws_string (pp, "concept");
> -	  else if (DECL_IMMEDIATE_FUNCTION_P (t))
> +	  if (DECL_IMMEDIATE_FUNCTION_P (t))
>  	    pp_cxx_ws_string (pp, "consteval");
>  	  else
>  	    pp_cxx_ws_string (pp, "constexpr");
> @@ -3952,8 +3950,8 @@ print_concept_check_info (diagnostic_context *context, tree expr, tree map, tree
>  {
>    gcc_assert (concept_check_p (expr));
>  
> -  tree id = unpack_concept_check (expr);
> -  tree tmpl = TREE_OPERAND (id, 0);
> +  tree tmpl = TREE_OPERAND (expr, 0);
> +  // ??? Can this go now that fn/var concepts have been removed?
>    if (OVL_P (tmpl))
>      tmpl = OVL_FIRST (tmpl);
>  
> diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
> index e7391220234..46dc6923add 100644
> --- a/gcc/cp/mangle.cc
> +++ b/gcc/cp/mangle.cc
> @@ -901,9 +901,9 @@ write_tparms_constraints (tree constraints)
>  static void
>  write_type_constraint (tree cnst)
>  {
> -  if (!cnst) return;
> +  if (!cnst)
> +    return;
>  
> -  cnst = unpack_concept_check (cnst);
>    gcc_checking_assert (TREE_CODE (cnst) == TEMPLATE_ID_EXPR);
>  
>    tree concept_decl = get_concept_check_template (cnst);
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index eb102dea829..f625b0a310c 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -7161,18 +7161,13 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
>  		      tree fns = get_fns (tid);
>  		      if (OVL_SINGLE_P (fns))
>  			tmpl = OVL_FIRST (fns);
> -		      if (function_concept_p (fns))
> -			error_at (token->location, "concept-id %qD "
> -				  "in nested-name-specifier", tid);
> -		      else
> -			error_at (token->location, "function template-id "
> -				  "%qD in nested-name-specifier", tid);
> +		      error_at (token->location, "function template-id "
> +				"%qD in nested-name-specifier", tid);
>  		    }
>  		  else
>  		    {
>  		      tmpl = TREE_OPERAND (tid, 0);
> -		      if (variable_concept_p (tmpl)
> -			  || standard_concept_p (tmpl))
> +		      if (concept_definition_p (tmpl))
>  			error_at (token->location, "concept-id %qD "
>  				  "in nested-name-specifier", tid);
>  		      else
> @@ -12224,9 +12219,6 @@ add_debug_begin_stmt (location_t loc)
>  {
>    if (!MAY_HAVE_DEBUG_MARKER_STMTS)
>      return;
> -  if (DECL_DECLARED_CONCEPT_P (current_function_decl))
> -    /* A concept is never expanded normally.  */
> -    return;
>  
>    tree stmt = build0 (DEBUG_BEGIN_STMT, void_type_node);
>    SET_EXPR_LOCATION (stmt, loc);
> @@ -33087,8 +33079,6 @@ cp_parser_template_declaration_after_parameters (cp_parser* parser,
>    else if (flag_concepts
>             && cp_lexer_next_token_is_keyword (parser->lexer, RID_CONCEPT)
>  	   && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME))
> -    /* -fconcept-ts 'concept bool' syntax is handled below, in
> -	cp_parser_single_declaration.  */
>      decl = cp_parser_concept_definition (parser);
>    else
>      {
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 77fa5907c3d..35a9c5619f9 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -3232,14 +3232,6 @@ check_explicit_specialization (tree declarator,
>                tree tmpl_func = DECL_TEMPLATE_RESULT (gen_tmpl);
>                gcc_assert (TREE_CODE (tmpl_func) == FUNCTION_DECL);
>  
> -              /* A concept cannot be specialized.  */
> -              if (DECL_DECLARED_CONCEPT_P (tmpl_func))
> -                {
> -                  error ("explicit specialization of function concept %qD",
> -                         gen_tmpl);
> -                  return error_mark_node;
> -                }
> -
>                /* This specialization has the same linkage and visibility as
>                   the function template it specializes.  */
>                TREE_PUBLIC (decl) = TREE_PUBLIC (tmpl_func);
> @@ -5150,13 +5142,6 @@ process_partial_specialization (tree decl)
>  
>    gcc_assert (current_template_parms);
>  
> -  /* A concept cannot be specialized.  */
> -  if (flag_concepts && variable_concept_p (maintmpl))
> -    {
> -      error ("specialization of variable concept %q#D", maintmpl);
> -      return error_mark_node;
> -    }
> -
>    inner_parms = INNERMOST_TEMPLATE_PARMS (current_template_parms);
>    ntparms = TREE_VEC_LENGTH (inner_parms);
>  
> @@ -10532,9 +10517,6 @@ lookup_template_class (tree d1, tree arglist, tree in_decl, tree context,
>  tree
>  lookup_template_variable (tree templ, tree arglist, tsubst_flags_t complain)
>  {
> -  if (flag_concepts && variable_concept_p (templ))
> -    return build_concept_check (templ, arglist, tf_none);
> -
>    tree gen_templ = most_general_template (templ);
>    tree parms = DECL_INNERMOST_TEMPLATE_PARMS (gen_templ);
>    arglist = add_outermost_template_args (templ, arglist);
> @@ -20119,14 +20101,6 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
>  	    tree check = build_concept_check (templ, targs, complain);
>  	    if (check == error_mark_node)
>  	      RETURN (error_mark_node);
> -
> -	    tree id = unpack_concept_check (check);
> -
> -	    /* If we built a function concept check, return the underlying
> -	       template-id. So we can evaluate it as a function call.  */
> -	    if (function_concept_p (TREE_OPERAND (id, 0)))
> -	      RETURN (id);
> -
>  	    RETURN (check);
>  	  }
>  
> @@ -21096,19 +21070,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
>  	  ret = build_offset_ref_call_from_tree (function, &call_args,
>  						 complain);
>  	else if (concept_check_p (function))
> -	  {
> -	    /* FUNCTION is a template-id referring to a concept definition.  */
> -	    tree id = unpack_concept_check (function);
> -	    tree tmpl = TREE_OPERAND (id, 0);
> -	    tree args = TREE_OPERAND (id, 1);
> -
> -	    /* Calls to standard and variable concepts should have been
> -	       previously diagnosed.  */
> -	    gcc_assert (function_concept_p (tmpl));
> -
> -	    /* Ensure the result is wrapped as a call expression.  */
> -	    ret = build_concept_check (tmpl, args, tf_warning_or_error);
> -	  }
> +	  /* Calls to concepts should have been previously diagnosed.  */
> +	  gcc_assert (false);
>  	else
>  	  ret = finish_call_expr (function, &call_args,
>  				  /*disallow_virtual=*/qualified_p,
> @@ -26414,14 +26377,6 @@ do_decl_instantiation (tree decl, tree storage)
>        error ("explicit instantiation of non-template %q#D", decl);
>        return;
>      }
> -  else if (DECL_DECLARED_CONCEPT_P (decl))
> -    {
> -      if (VAR_P (decl))
> -	error ("explicit instantiation of variable concept %q#D", decl);
> -      else
> -	error ("explicit instantiation of function concept %q#D", decl);
> -      return;
> -    }
>  
>    bool var_templ = (DECL_TEMPLATE_INFO (decl)
>                      && variable_template_p (DECL_TI_TEMPLATE (decl)));
> @@ -27211,9 +27166,6 @@ instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p)
>       functions and static member variables.  */
>    gcc_assert (VAR_OR_FUNCTION_DECL_P (d));
>  
> -  /* A concept is never instantiated. */
> -  gcc_assert (!DECL_DECLARED_CONCEPT_P (d));
> -
>    gcc_checking_assert (!DECL_FUNCTION_SCOPE_P (d));
>  
>    if (modules_p ())
> @@ -29492,8 +29444,8 @@ make_constrained_decltype_auto (tree con, tree args)
>  static bool
>  placeholder_type_constraint_dependent_p (tree t)
>  {
> -  tree id = unpack_concept_check (t);
> -  tree args = TREE_OPERAND (id, 1);
> +  gcc_assert (concept_check_p (t));
> +  tree args = TREE_OPERAND (t, 1);
>    tree first = TREE_VEC_ELT (args, 0);
>    if (ARGUMENT_PACK_P (first))
>      {
> @@ -31452,8 +31404,8 @@ convert_generic_types_to_packs (tree parm, int start_idx, int end_idx)
>           requirements.  */
>        if (tree constr = TEMPLATE_PARM_CONSTRAINTS (node))
>  	{
> -	  tree id = unpack_concept_check (constr);
> -	  TREE_VEC_ELT (TREE_OPERAND (id, 1), 0) = t;
> +	  gcc_assert (concept_check_p (constr));
> +	  TREE_VEC_ELT (TREE_OPERAND (constr, 1), 0) = t;
>  	  /* Use UNKNOWN_LOCATION so write_template_args can tell the
>  	     difference between this and a fold the user wrote.  */
>  	  location_t loc = UNKNOWN_LOCATION;
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index 669da4ad969..e58612660c9 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -3067,20 +3067,9 @@ finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual,
>      }
>    else if (concept_check_p (fn))
>      {
> -      /* FN is actually a template-id referring to a concept definition.  */
> -      tree id = unpack_concept_check (fn);
> -      tree tmpl = TREE_OPERAND (id, 0);
> -      tree args = TREE_OPERAND (id, 1);
> -
> -      if (!function_concept_p (tmpl))
> -	{
> -	  error_at (EXPR_LOC_OR_LOC (fn, input_location),
> -		    "cannot call a concept as a function");
> -	  return error_mark_node;
> -	}
> -
> -      /* Ensure the result is wrapped as a call expression.  */
> -      result = build_concept_check (tmpl, args, tf_warning_or_error);
> +      error_at (EXPR_LOC_OR_LOC (fn, input_location),
> +		"cannot call a concept as a function");
> +      return error_mark_node;
>      }
>    else if (is_overloaded_fn (fn))
>      {
> diff --git a/gcc/testsuite/g++.dg/concepts/decl-diagnose.C b/gcc/testsuite/g++.dg/concepts/decl-diagnose.C
> index 0d10ce1ea9f..2bf1cd5ab17 100644
> --- a/gcc/testsuite/g++.dg/concepts/decl-diagnose.C
> +++ b/gcc/testsuite/g++.dg/concepts/decl-diagnose.C
> @@ -7,8 +7,8 @@ typedef concept int CINT; // { dg-error "'concept' cannot appear in a typedef de
>  void f(concept int); // { dg-error "a parameter cannot be declared 'concept'" }
>  
>  template<typename T>
> -concept int f2() { return 0; } // { dg-error "return type" }
> -concept bool f3(); // { dg-error "14:concept .f3. has no definition" }
> +concept int f2() { return 0; } // { dg-error "function concepts are no longer supported" }
> +concept bool f3(); // { dg-error "14:function concepts are no longer supported" }
>  		   // { dg-error "keyword is not allowed" "" { target *-*-* } .-1 }
>  
>  struct X
> @@ -26,11 +26,11 @@ struct X
>    concept X(); // { dg-error "a constructor cannot be 'concept'" }
>  };
>  
> -concept bool X2; // { dg-error "non-template variable" }
> +concept bool X2; // { dg-error "variable" }
>  	         // { dg-error "keyword is not allowed" "" { target *-*-* } .-1 }
>  
>  template<typename T>
> -  concept bool X3; // { dg-error "has no initializer" }
> +  concept bool X3; // { dg-error "variable concepts" }
>  		   // { dg-error "keyword is not allowed" "" { target *-*-* } .-1 }
>  
>  struct S {
> diff --git a/gcc/testsuite/g++.dg/concepts/fn-concept2.C b/gcc/testsuite/g++.dg/concepts/fn-concept2.C
> index 799e85de955..52ca8245c76 100644
> --- a/gcc/testsuite/g++.dg/concepts/fn-concept2.C
> +++ b/gcc/testsuite/g++.dg/concepts/fn-concept2.C
> @@ -3,7 +3,7 @@
>  // { dg-prune-output "concept definition syntax is" }
>  
>  template<typename T>
> -  concept auto C1() { return 0; } // { dg-error "16:concept .concept auto C1\\(\\). declared with a deduced return type" }
> +  concept auto C1() { return 0; } // { dg-error "16:function concepts are no longer supported" }
>  
>  template<typename T>
> -  concept int C2() { return 0; } // { dg-error "15:concept .concept int C2\\(\\). with non-.bool. return type .int." }
> +  concept int C2() { return 0; } // { dg-error "15:function concepts are no longer supported" }
> diff --git a/gcc/testsuite/g++.dg/concepts/pr71128.C b/gcc/testsuite/g++.dg/concepts/pr71128.C
> index 63b3d1dff78..a3d5357d432 100644
> --- a/gcc/testsuite/g++.dg/concepts/pr71128.C
> +++ b/gcc/testsuite/g++.dg/concepts/pr71128.C
> @@ -2,9 +2,9 @@
>  // { dg-options "-fconcepts" }
>  
>  template<typename T>
> -concept bool C() { return true; } // { dg-error "the .bool. keyword" }
> -template bool C<int>();  // { dg-error "explicit instantiation of function concept" }
> +concept bool C() { return true; } // { dg-error "the .bool. keyword|function concepts" }
> +template bool C<int>();  // { dg-error "template function|not a function template|expected" }
>  
>  template<typename T>
> -concept bool D = true;	// { dg-error "the .bool. keyword" }
> -template bool D<int>;  // { dg-error "explicit instantiation of variable concept" }
> +concept bool D = true;	// { dg-error "the .bool. keyword|variable concepts are no longer supported" }
> +template bool D<int>;  // { dg-error "not a template function|expected" }
> diff --git a/gcc/testsuite/g++.dg/concepts/var-concept6.C b/gcc/testsuite/g++.dg/concepts/var-concept6.C
> index 04298f47a92..062007a1291 100644
> --- a/gcc/testsuite/g++.dg/concepts/var-concept6.C
> +++ b/gcc/testsuite/g++.dg/concepts/var-concept6.C
> @@ -2,4 +2,4 @@
>  // { dg-options "-fconcepts" }
>  
>  template <class T>
> -concept int C = true;		// { dg-error "concept definition syntax" }
> +concept int C = true;		// { dg-error "concept definition syntax|variable concepts are no longer supported" }
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts.C b/gcc/testsuite/g++.dg/cpp2a/concepts.C
> index ebeeebf60bb..1b7a708659b 100644
> --- a/gcc/testsuite/g++.dg/cpp2a/concepts.C
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts.C
> @@ -18,9 +18,9 @@ void f3(T)
>  { }
>  
>  template<typename T>
> -concept bool C1 = true; // { dg-error "bool" }
> +concept bool C1 = true; // { dg-error "bool|variable concepts" }
>  template<typename T>
> -bool concept C2 = true; // { dg-error "concept definition syntax" }
> +bool concept C2 = true; // { dg-error "concept definition syntax|variable concepts" }
>  
>  template<typename T>
>  concept C3 = true; // OK
> 
> base-commit: a10436a8404ad2f0cc5aa4d6a0cc850abe5ef49e
> -- 
> 2.45.2
> 
>
Marek Polacek Aug. 6, 2024, 1:39 p.m. UTC | #7
On Mon, Aug 05, 2024 at 09:56:20PM -0400, Patrick Palka wrote:
> On Fri, 2 Aug 2024, Marek Polacek wrote:
> 
> > Bootstrapped/regtested on x86_64-pc-linux-gnu.  Comments?
> > 
> > -- >8 --
> > This patch removes vestigial Concepts TS code as discussed in
> > <https://gcc.gnu.org/pipermail/gcc-patches/2024-July/657937.html>.
> 
> Yay!  FWIW I think we can also remove the concept_check_p checks in
> 
>     cxx_eval_call_expression
>     cxx_eval_outermost_constant_expr
>     cp_genericize_r <case CALL_EXPR>
>     check_noexcept_r

Thanks, I'm testing a patch.
 
> And perhaps we could rename *concept_check* to *concept_id* throughout
> to match the standard terminology.

Maybe...

Marek
diff mbox series

Patch

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 8277b3b79ba..b079be1b3d5 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -8508,20 +8508,11 @@  cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       {
         /* We can evaluate template-id that refers to a concept only if
 	   the template arguments are non-dependent.  */
-	tree id = unpack_concept_check (t);
-	tree tmpl = TREE_OPERAND (id, 0);
+	gcc_assert (concept_check_p (t));
+	tree tmpl = TREE_OPERAND (t, 0);
 	if (!concept_definition_p (tmpl))
 	  internal_error ("unexpected template-id %qE", t);
 
-	if (function_concept_p (tmpl))
-	  {
-	    if (!ctx->quiet)
-	      error_at (cp_expr_loc_or_input_loc (t),
-			"function concept must be called");
-	    r = error_mark_node;
-	    break;
-	  }
-
 	if (!value_dependent_expression_p (t)
 	    && !uid_sensitive_constexpr_evaluation_p ())
 	  r = evaluate_concept_check (t);
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 853ea8c4b93..2da482cc93d 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -167,19 +167,6 @@  check_constraint_atom (cp_expr expr)
       return false;
     }
 
-  /* Check that we're using function concepts correctly.  */
-  if (concept_check_p (expr))
-    {
-      tree id = unpack_concept_check (expr);
-      tree tmpl = TREE_OPERAND (id, 0);
-      if (OVL_P (tmpl) && TREE_CODE (expr) == TEMPLATE_ID_EXPR)
-        {
-	  error_at (EXPR_LOC_OR_LOC (expr, input_location),
-		    "function concept must be called");
-	  return false;
-	}
-    }
-
   return true;
 }
 
@@ -245,32 +232,13 @@  combine_constraint_expressions (tree lhs, tree rhs)
   return finish_constraint_and_expr (UNKNOWN_LOCATION, lhs, rhs);
 }
 
-/* Extract the template-id from a concept check.  For standard and variable
-   checks, this is simply T.  For function concept checks, this is the
-   called function.  */
-
-tree
-unpack_concept_check (tree t)
-{
-  gcc_assert (concept_check_p (t));
-
-  if (TREE_CODE (t) == CALL_EXPR)
-    t = CALL_EXPR_FN (t);
-
-  gcc_assert (TREE_CODE (t) == TEMPLATE_ID_EXPR);
-  return t;
-}
-
 /* Extract the TEMPLATE_DECL from a concept check.  */
 
 tree
 get_concept_check_template (tree t)
 {
-  tree id = unpack_concept_check (t);
-  tree tmpl = TREE_OPERAND (id, 0);
-  if (OVL_P (tmpl))
-    tmpl = OVL_FIRST (tmpl);
-  return tmpl;
+  gcc_assert (concept_check_p (t));
+  return TREE_OPERAND (t, 0);
 }
 
 /*---------------------------------------------------------------------------
@@ -285,101 +253,6 @@  get_concept_check_template (tree t)
    matched declaration, and whose purpose contains the coerced template
    arguments that can be substituted into the call.  */
 
-/* Given an overload set OVL, try to find a unique definition that can be
-   instantiated by the template arguments ARGS.
-
-   This function is not called for arbitrary call expressions.  In particular,
-   the call expression must be written with explicit template arguments
-   and no function arguments.  For example:
-
-        f<T, U>()
-
-   If a single match is found, this returns a TREE_LIST whose VALUE
-   is the constraint function (not the template), and its PURPOSE is
-   the complete set of arguments substituted into the parameter list.  */
-
-static tree
-resolve_function_concept_overload (tree ovl, tree args)
-{
-  int nerrs = 0;
-  tree cands = NULL_TREE;
-  for (lkp_iterator iter (ovl); iter; ++iter)
-    {
-      tree tmpl = *iter;
-      if (TREE_CODE (tmpl) != TEMPLATE_DECL)
-        continue;
-
-      /* Don't try to deduce checks for non-concepts.  We often end up trying
-         to resolve constraints in functional casts as part of a
-	 postfix-expression.  We can save time and headaches by not
-         instantiating those declarations.
-
-         NOTE: This masks a potential error, caused by instantiating
-	 non-deduced contexts using placeholder arguments.  */
-      tree fn = DECL_TEMPLATE_RESULT (tmpl);
-      if (DECL_ARGUMENTS (fn))
-        continue;
-      if (!DECL_DECLARED_CONCEPT_P (fn))
-        continue;
-
-      /* Remember the candidate if we can deduce a substitution.  */
-      ++processing_template_decl;
-      tree parms = TREE_VALUE (DECL_TEMPLATE_PARMS (tmpl));
-      if (tree subst = coerce_template_parms (parms, args, tmpl, tf_none))
-        {
-          if (subst == error_mark_node)
-            ++nerrs;
-          else
-	    cands = tree_cons (subst, fn, cands);
-        }
-      --processing_template_decl;
-    }
-
-  if (!cands)
-    /* We either had no candidates or failed deductions.  */
-    return nerrs ? error_mark_node : NULL_TREE;
-  else if (TREE_CHAIN (cands))
-    /* There are multiple candidates.  */
-    return error_mark_node;
-
-  return cands;
-}
-
-/* Determine if the call expression CALL is a constraint check, and
-   return the concept declaration and arguments being checked.  If CALL
-   does not denote a constraint check, return NULL.  */
-
-tree
-resolve_function_concept_check (tree call)
-{
-  gcc_assert (TREE_CODE (call) == CALL_EXPR);
-
-  /* A constraint check must be only a template-id expression.
-     If it's a call to a base-link, its function(s) should be a
-     template-id expression.  If this is not a template-id, then
-     it cannot be a concept-check.  */
-  tree target = CALL_EXPR_FN (call);
-  if (BASELINK_P (target))
-    target = BASELINK_FUNCTIONS (target);
-  if (TREE_CODE (target) != TEMPLATE_ID_EXPR)
-    return NULL_TREE;
-
-  /* Get the overload set and template arguments and try to
-     resolve the target.  */
-  tree ovl = TREE_OPERAND (target, 0);
-
-  /* This is a function call of a variable concept... ill-formed.  */
-  if (TREE_CODE (ovl) == TEMPLATE_DECL)
-    {
-      error_at (location_of (call),
-		"function call of variable concept %qE", call);
-      return error_mark_node;
-    }
-
-  tree args = TREE_OPERAND (target, 1);
-  return resolve_function_concept_overload (ovl, args);
-}
-
 /* Returns a pair containing the checked concept and its associated
    prototype parameter.  The result is a TREE_LIST whose TREE_VALUE
    is the concept (non-template) and whose TREE_PURPOSE contains
@@ -390,20 +263,8 @@  tree
 resolve_concept_check (tree check)
 {
   gcc_assert (concept_check_p (check));
-  tree id = unpack_concept_check (check);
-  tree tmpl = TREE_OPERAND (id, 0);
-
-  /* If this is an overloaded function concept, perform overload
-     resolution (this only happens when deducing prototype parameters
-     and template introductions).  */
-  if (TREE_CODE (tmpl) == OVERLOAD)
-    {
-      if (OVL_CHAIN (tmpl))
-	return resolve_function_concept_check (check);
-      tmpl = OVL_FIRST (tmpl);
-    }
-
-  tree args = TREE_OPERAND (id, 1);
+  tree tmpl = TREE_OPERAND (check, 0);
+  tree args = TREE_OPERAND (check, 1);
   tree parms = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (tmpl));
   ++processing_template_decl;
   tree result = coerce_template_parms (parms, args, tmpl, tf_none);
@@ -466,55 +327,13 @@  finish_type_constraints (tree spec, tree args, tsubst_flags_t complain)
                        Expansion of concept definitions
 ---------------------------------------------------------------------------*/
 
-/* Returns the expression of a function concept.  */
-
-static tree
-get_returned_expression (tree fn)
-{
-  /* Extract the body of the function minus the return expression.  */
-  tree body = DECL_SAVED_TREE (fn);
-  if (!body)
-    return error_mark_node;
-  if (TREE_CODE (body) == BIND_EXPR)
-    body = BIND_EXPR_BODY (body);
-  if (TREE_CODE (body) != RETURN_EXPR)
-    return error_mark_node;
-
-  return TREE_OPERAND (body, 0);
-}
-
-/* Returns the initializer of a variable concept.  */
-
-static tree
-get_variable_initializer (tree var)
-{
-  tree init = DECL_INITIAL (var);
-  if (!init)
-    return error_mark_node;
-  if (BRACE_ENCLOSED_INITIALIZER_P (init)
-      && CONSTRUCTOR_NELTS (init) == 1)
-    init = CONSTRUCTOR_ELT (init, 0)->value;
-  return init;
-}
-
-/* Returns the definition of a variable or function concept.  */
+/* Returns the definition of a concept.  */
 
 static tree
 get_concept_definition (tree decl)
 {
-  if (TREE_CODE (decl) == OVERLOAD)
-    decl = OVL_FIRST (decl);
-
-  if (TREE_CODE (decl) == TEMPLATE_DECL)
-    decl = DECL_TEMPLATE_RESULT (decl);
-
-  if (TREE_CODE (decl) == CONCEPT_DECL)
-    return DECL_INITIAL (decl);
-  if (VAR_P (decl))
-    return get_variable_initializer (decl);
-  if (TREE_CODE (decl) == FUNCTION_DECL)
-    return get_returned_expression (decl);
-  gcc_unreachable ();
+  gcc_assert (TREE_CODE (decl) == CONCEPT_DECL);
+  return DECL_INITIAL (decl);
 }
 
 /*---------------------------------------------------------------------------
@@ -729,19 +548,9 @@  static GTY((deletable)) hash_table<norm_hasher> *norm_cache;
 static tree
 normalize_concept_check (tree check, tree args, norm_info info)
 {
-  tree id = unpack_concept_check (check);
-  tree tmpl = TREE_OPERAND (id, 0);
-  tree targs = TREE_OPERAND (id, 1);
-
-  /* A function concept is wrapped in an overload.  */
-  if (TREE_CODE (tmpl) == OVERLOAD)
-    {
-      /* TODO: Can we diagnose this error during parsing?  */
-      if (TREE_CODE (check) == TEMPLATE_ID_EXPR)
-	error_at (EXPR_LOC_OR_LOC (check, input_location),
-		  "function concept must be called");
-      tmpl = OVL_FIRST (tmpl);
-    }
+  gcc_assert (concept_check_p (check));
+  tree tmpl = TREE_OPERAND (check, 0);
+  tree targs = TREE_OPERAND (check, 1);
 
   /* Substitute through the arguments of the concept check.  */
   if (args)
@@ -789,11 +598,7 @@  normalize_concept_check (tree check, tree args, norm_info info)
 
 static GTY((deletable)) hash_table<atom_hasher> *atom_cache;
 
-/* The normal form of an atom depends on the expression.  The normal
-   form of a function call to a function concept is a check constraint
-   for that concept.  The normal form of a reference to a variable
-   concept is a check constraint for that concept.  Otherwise, the
-   constraint is a predicate constraint.  */
+/* The normal form of an atom is a predicate constraint.  */
 
 static tree
 normalize_atom (tree t, tree args, norm_info info)
@@ -1378,77 +1183,13 @@  build_concept_check_arguments (tree arg, tree rest)
   return args;
 }
 
-/* Builds an id-expression of the form `C<Args...>()` where C is a function
-   concept.  */
-
-static tree
-build_function_check (tree tmpl, tree args, tsubst_flags_t /*complain*/)
-{
-  if (TREE_CODE (tmpl) == TEMPLATE_DECL)
-    {
-      /* If we just got a template, wrap it in an overload so it looks like any
-	 other template-id.  */
-      tmpl = ovl_make (tmpl);
-      TREE_TYPE (tmpl) = boolean_type_node;
-    }
-
-  /* Perform function concept resolution now so we always have a single
-     function of the overload set (even if we started with only one; the
-     resolution function converts template arguments).  Note that we still
-     wrap this in an overload set so we don't upset other parts of the
-     compiler that expect template-ids referring to function concepts
-     to have an overload set.  */
-  tree info = resolve_function_concept_overload (tmpl, args);
-  if (info == error_mark_node)
-    return error_mark_node;
-  if (!info)
-    {
-      error ("no matching concepts for %qE", tmpl);
-      return error_mark_node;
-    }
-  args = TREE_PURPOSE (info);
-  tmpl = DECL_TI_TEMPLATE (TREE_VALUE (info));
-
-  /* Rebuild the singleton overload set; mark the type bool.  */
-  tmpl = ovl_make (tmpl, NULL_TREE);
-  TREE_TYPE (tmpl) = boolean_type_node;
-
-  /* Build the id-expression around the overload set.  */
-  tree id = build2 (TEMPLATE_ID_EXPR, boolean_type_node, tmpl, args);
-
-  /* Finally, build the call expression around the overload.  */
-  ++processing_template_decl;
-  vec<tree, va_gc> *fargs = make_tree_vector ();
-  tree call = build_min_nt_call_vec (id, fargs);
-  TREE_TYPE (call) = boolean_type_node;
-  release_tree_vector (fargs);
-  --processing_template_decl;
-
-  return call;
-}
-
-/* Builds an id-expression of the form `C<Args...>` where C is a variable
-   concept.  */
-
-static tree
-build_variable_check (tree tmpl, tree args, tsubst_flags_t complain)
-{
-  gcc_assert (variable_concept_p (tmpl));
-  gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL);
-  tree parms = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (tmpl));
-  args = coerce_template_parms (parms, args, tmpl, complain);
-  if (args == error_mark_node)
-    return error_mark_node;
-  return build2 (TEMPLATE_ID_EXPR, boolean_type_node, tmpl, args);
-}
-
 /* Builds an id-expression of the form `C<Args...>` where C is a standard
    concept.  */
 
 static tree
 build_standard_check (tree tmpl, tree args, tsubst_flags_t complain)
 {
-  gcc_assert (standard_concept_p (tmpl));
+  gcc_assert (concept_definition_p (tmpl));
   gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL);
   if (TREE_DEPRECATED (DECL_TEMPLATE_RESULT (tmpl)))
     warn_deprecated_use (DECL_TEMPLATE_RESULT (tmpl), NULL_TREE);
@@ -1475,12 +1216,8 @@  build_concept_check (tree decl, tree arg, tree rest, tsubst_flags_t complain)
 {
   tree args = build_concept_check_arguments (arg, rest);
 
-  if (standard_concept_p (decl))
+  if (concept_definition_p (decl))
     return build_standard_check (decl, args, complain);
-  if (variable_concept_p (decl))
-    return build_variable_check (decl, args, complain);
-  if (function_concept_p (decl))
-    return build_function_check (decl, args, complain);
 
   return error_mark_node;
 }
@@ -1490,10 +1227,7 @@  build_concept_check (tree decl, tree arg, tree rest, tsubst_flags_t complain)
 static tree
 build_concept_id (tree decl, tree args)
 {
-  tree check = build_concept_check (decl, args, tf_warning_or_error);
-  if (check == error_mark_node)
-    return error_mark_node;
-  return unpack_concept_check (check);
+  return build_concept_check (decl, args, tf_warning_or_error);
 }
 
 /* Build a template-id that can participate in a concept check, preserving
@@ -1521,9 +1255,7 @@  build_type_constraint (tree decl, tree args, tsubst_flags_t complain)
   ++processing_template_decl;
   tree check = build_concept_check (decl, wildcard, args, complain);
   --processing_template_decl;
-  if (check == error_mark_node)
-    return error_mark_node;
-  return unpack_concept_check (check);
+  return check;
 }
 
 /* Returns a TYPE_DECL that contains sufficient information to
@@ -1621,10 +1353,7 @@  placeholder_extract_concept_and_args (tree t, tree &tmpl, tree &args)
 {
   if (concept_check_p (t))
     {
-      t = unpack_concept_check (t);
       tmpl = TREE_OPERAND (t, 0);
-      if (TREE_CODE (tmpl) == OVERLOAD)
-        tmpl = OVL_FIRST (tmpl);
       args = TREE_OPERAND (t, 1);
       return;
     }
@@ -2938,9 +2667,8 @@  satisfy_nondeclaration_constraints (tree t, tree args, sat_info info)
   if (concept_check_p (t))
     {
       gcc_assert (!args);
-      tree id = unpack_concept_check (t);
-      args = TREE_OPERAND (id, 1);
-      tree tmpl = get_concept_check_template (id);
+      args = TREE_OPERAND (t, 1);
+      tree tmpl = get_concept_check_template (t);
       norm = normalize_concept_definition (tmpl, info.noisy ());
     }
   else if (TREE_CODE (t) == NESTED_REQ)
@@ -3255,41 +2983,6 @@  finish_nested_requirement (location_t loc, tree expr)
   return r;
 }
 
-/* Check that FN satisfies the structural requirements of a
-   function concept definition.  */
-tree
-check_function_concept (tree fn)
-{
-  /* Check that the function is comprised of only a return statement.  */
-  tree body = DECL_SAVED_TREE (fn);
-  if (TREE_CODE (body) == BIND_EXPR)
-    body = BIND_EXPR_BODY (body);
-
-  /* Sometimes a function call results in the creation of clean up
-     points.  Allow these to be preserved in the body of the
-     constraint, as we might actually need them for some constexpr
-     evaluations.  */
-  if (TREE_CODE (body) == CLEANUP_POINT_EXPR)
-    body = TREE_OPERAND (body, 0);
-
-  /* Check that the definition is written correctly.  */
-  if (TREE_CODE (body) != RETURN_EXPR)
-    {
-      location_t loc = DECL_SOURCE_LOCATION (fn);
-      if (TREE_CODE (body) == STATEMENT_LIST && !STATEMENT_LIST_HEAD (body))
-	{
-	  if (seen_error ())
-	    /* The definition was probably erroneous, not empty.  */;
-	  else
-	    error_at (loc, "definition of concept %qD is empty", fn);
-	}
-      else
-        error_at (loc, "definition of concept %qD has multiple statements", fn);
-    }
-
-  return NULL_TREE;
-}
-
 /*---------------------------------------------------------------------------
                         Equivalence of constraints
 ---------------------------------------------------------------------------*/
@@ -3403,10 +3096,7 @@  get_constraint_error_location (tree t)
   /* Otherwise, give the location as the defining concept.  */
   else if (concept_check_p (src))
     {
-      tree id = unpack_concept_check (src);
-      tree tmpl = TREE_OPERAND (id, 0);
-      if (OVL_P (tmpl))
-	tmpl = OVL_FIRST (tmpl);
+      tree tmpl = TREE_OPERAND (src, 0);
       return DECL_SOURCE_LOCATION (tmpl);
     }
 
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 238d786b067..c92ff707e3f 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -3524,12 +3524,6 @@  struct GTY(()) lang_decl {
   (retrofit_lang_decl (FUNCTION_DECL_CHECK (NODE)),			\
    LANG_DECL_FN_CHECK (NODE)->immediate_fn_p = true)
 
-// True if NODE was declared as 'concept'.  The flag implies that the
-// declaration is constexpr, that the declaration cannot be specialized or
-// refined, and that the result type must be convertible to bool.
-#define DECL_DECLARED_CONCEPT_P(NODE) \
-  (DECL_LANG_SPECIFIC (NODE)->u.base.concept_p)
-
 /* Nonzero if this DECL is the __PRETTY_FUNCTION__ variable in a
    template function.  */
 #define DECL_PRETTY_FUNCTION_P(NODE) \
@@ -8582,7 +8576,6 @@  extern bool equivalent_placeholder_constraints  (tree, tree);
 extern hashval_t iterative_hash_placeholder_constraint	(tree, hashval_t);
 extern bool deduce_constrained_parameter        (tree, tree&, tree&);
 extern tree resolve_constraint_check            (tree);
-extern tree check_function_concept              (tree);
 extern bool valid_requirements_p                (tree);
 extern tree finish_concept_name                 (tree);
 extern tree finish_shorthand_constraint         (tree, tree);
@@ -8605,7 +8598,6 @@  struct processing_constraint_expression_sentinel
 
 extern bool processing_constraint_expression_p	();
 
-extern tree unpack_concept_check		(tree);
 extern tree get_concept_check_template		(tree);
 extern tree evaluate_concept_check              (tree);
 extern bool constraints_satisfied_p		(tree, tree = NULL_TREE);
@@ -8867,69 +8859,12 @@  variable_template_p (tree t)
   return false;
 }
 
-/* True iff T is a standard concept definition. This will return
-   true for both the template and underlying declaration.  */
-
-inline bool
-standard_concept_p (tree t)
-{
-  if (TREE_CODE (t) == TEMPLATE_DECL)
-    t = DECL_TEMPLATE_RESULT (t);
-  return TREE_CODE (t) == CONCEPT_DECL;
-}
-
-/* True iff T is a variable concept definition. This will return
-   true for both the template and the underlying declaration.  */
-
-inline bool
-variable_concept_p (tree t)
-{
-  if (TREE_CODE (t) == TEMPLATE_DECL)
-    t = DECL_TEMPLATE_RESULT (t);
-  return VAR_P (t) && DECL_DECLARED_CONCEPT_P (t);
-}
-
-/* True iff T is a function concept definition or an overload set
-   containing multiple function concepts. This will return true for
-   both the template and the underlying declaration.  */
-
-inline bool
-function_concept_p (tree t)
-{
-  if (TREE_CODE (t) == OVERLOAD)
-    t = OVL_FIRST (t);
-  if (TREE_CODE (t) == TEMPLATE_DECL)
-    t = DECL_TEMPLATE_RESULT (t);
-  return TREE_CODE (t) == FUNCTION_DECL && DECL_DECLARED_CONCEPT_P (t);
-}
-
-/* True iff T is a standard, variable, or function concept.  */
+/* True iff T is a concept.  */
 
 inline bool
 concept_definition_p (tree t)
 {
-  if (t == error_mark_node)
-    return false;
-
-  /* Adjust for function concept overloads.  */
-  if (TREE_CODE (t) == OVERLOAD)
-    t = OVL_FIRST (t);
-
-  /* See through templates.  */
-  if (TREE_CODE (t) == TEMPLATE_DECL)
-    t = DECL_TEMPLATE_RESULT (t);
-
-  /* The obvious and easy case.  */
-  if (TREE_CODE (t) == CONCEPT_DECL)
-    return true;
-
-  /* Definitely not a concept.  */
-  if (!VAR_OR_FUNCTION_DECL_P (t))
-    return false;
-  if (!DECL_LANG_SPECIFIC (t))
-    return false;
-
-  return DECL_DECLARED_CONCEPT_P (t);
+  return TREE_CODE (STRIP_TEMPLATE (t)) == CONCEPT_DECL;
 }
 
 /* Same as above, but for const trees.  */
@@ -8945,8 +8880,6 @@  concept_definition_p (const_tree t)
 inline bool
 concept_check_p (const_tree t)
 {
-  if (TREE_CODE (t) == CALL_EXPR)
-    t = CALL_EXPR_FN (t);
   if (t && TREE_CODE (t) == TEMPLATE_ID_EXPR)
     return concept_definition_p (TREE_OPERAND (t, 0));
   return false;
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 687ae6937f5..04877087dc7 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -1467,36 +1467,6 @@  validate_constexpr_redeclaration (tree old_decl, tree new_decl)
   return true;
 }
 
-// If OLDDECL and NEWDECL are concept declarations with the same type
-// (i.e., and template parameters), but different requirements,
-// emit diagnostics and return true. Otherwise, return false.
-static inline bool
-check_concept_refinement (tree olddecl, tree newdecl)
-{
-  if (!DECL_DECLARED_CONCEPT_P (olddecl) || !DECL_DECLARED_CONCEPT_P (newdecl))
-    return false;
-
-  tree d1 = DECL_TEMPLATE_RESULT (olddecl);
-  tree d2 = DECL_TEMPLATE_RESULT (newdecl);
-  if (TREE_CODE (d1) != TREE_CODE (d2))
-    return false;
-
-  tree t1 = TREE_TYPE (d1);
-  tree t2 = TREE_TYPE (d2);
-  if (TREE_CODE (d1) == FUNCTION_DECL)
-    {
-      if (compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2))
-          && comp_template_parms (DECL_TEMPLATE_PARMS (olddecl),
-                                  DECL_TEMPLATE_PARMS (newdecl))
-          && !equivalently_constrained (olddecl, newdecl))
-        {
-          error ("cannot specialize concept %q#D", olddecl);
-          return true;
-        }
-    }
-  return false;
-}
-
 /* DECL is a redeclaration of a function or function template.  If
    it does have default arguments issue a diagnostic.  Note: this
    function is used to enforce the requirements in C++11 8.3.6 about
@@ -1990,8 +1960,6 @@  duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
 		return error_mark_node;
 	      return NULL_TREE;
 	    }
-          else if (check_concept_refinement (olddecl, newdecl))
-	    return error_mark_node;
 	  return NULL_TREE;
 	}
       if (TREE_CODE (newdecl) == FUNCTION_DECL)
@@ -8224,16 +8192,6 @@  value_dependent_init_p (tree init)
   return false;
 }
 
-// Returns true if a DECL is VAR_DECL with the concept specifier.
-static inline bool
-is_concept_var (tree decl)
-{
-  return (VAR_P (decl)
-	  // Not all variables have DECL_LANG_SPECIFIC.
-          && DECL_LANG_SPECIFIC (decl)
-          && DECL_DECLARED_CONCEPT_P (decl));
-}
-
 /* A helper function to be called via walk_tree.  If any label exists
    under *TP, it is (going to be) forced.  Set has_forced_label_in_static.  */
 
@@ -8751,11 +8709,6 @@  cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
 
       if (!VAR_P (decl) || type_dependent_p)
 	/* We can't do anything if the decl has dependent type.  */;
-      else if (!init && is_concept_var (decl))
-	{
-	  error ("variable concept has no initializer");
-	  init = boolean_true_node;
-	}
       else if (init
 	       && (init_const_expr_p || DECL_DECLARED_CONSTEXPR_P (decl))
 	       && !TYPE_REF_P (type)
@@ -10547,26 +10500,6 @@  check_static_quals (tree decl, cp_cv_quals quals)
 	   decl);
 }
 
-// Check that FN takes no arguments and returns bool.
-static void
-check_concept_fn (tree fn)
-{
-  // A constraint is nullary.
-  if (DECL_ARGUMENTS (fn))
-    error_at (DECL_SOURCE_LOCATION (fn),
-	      "concept %q#D declared with function parameters", fn);
-
-  // The declared return type of the concept shall be bool, and
-  // it shall not be deduced from it definition.
-  tree type = TREE_TYPE (TREE_TYPE (fn));
-  if (is_auto (type))
-    error_at (DECL_SOURCE_LOCATION (fn),
-	      "concept %q#D declared with a deduced return type", fn);
-  else if (type != boolean_type_node)
-    error_at (DECL_SOURCE_LOCATION (fn),
-	      "concept %q#D with non-%<bool%> return type %qT", fn, type);
-}
-
 /* Helper function.  Replace the temporary this parameter injected
    during cp_finish_omp_declare_simd with the real this parameter.  */
 
@@ -10637,10 +10570,9 @@  grokfndecl (tree ctype,
   /* Was the concept specifier present?  */
   bool concept_p = inlinep & 4;
 
-  /* Concept declarations must have a corresponding definition.  */
-  if (concept_p && !funcdef_flag)
+  if (concept_p)
     {
-      error_at (location, "concept %qD has no definition", declarator);
+      error_at (location, "function concepts are no longer supported");
       return NULL_TREE;
     }
 
@@ -10667,11 +10599,6 @@  grokfndecl (tree ctype,
 	    tmpl_reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
 	}
       tree ci = build_constraints (tmpl_reqs, decl_reqs);
-      if (concept_p && ci)
-        {
-          error_at (location, "a function concept cannot be constrained");
-          ci = NULL_TREE;
-        }
       /* C++20 CA378: Remove non-templated constrained functions.  */
       /* [temp.friend]/9 A non-template friend declaration with a
 	 requires-clause shall be a definition. A friend function template with
@@ -10903,14 +10830,6 @@  grokfndecl (tree ctype,
       SET_DECL_IMMEDIATE_FUNCTION_P (decl);
     }
 
-  // If the concept declaration specifier was found, check
-  // that the declaration satisfies the necessary requirements.
-  if (concept_p)
-    {
-      DECL_DECLARED_CONCEPT_P (decl) = true;
-      check_concept_fn (decl);
-    }
-
   DECL_EXTERNAL (decl) = 1;
   if (TREE_CODE (type) == FUNCTION_TYPE)
     {
@@ -11072,8 +10991,7 @@  grokfndecl (tree ctype,
   decl = check_explicit_specialization (orig_declarator, decl,
 					template_count,
 					2 * funcdef_flag +
-					4 * (friendp != 0) +
-	                                8 * concept_p,
+					4 * (friendp != 0),
 					*attrlist);
   if (decl == error_mark_node)
     return NULL_TREE;
@@ -11365,29 +11283,19 @@  grokvardecl (tree type,
 		  "C language linkage");
     }
 
-  /* Check that the variable can be safely declared as a concept.
-     Note that this also forbids explicit specializations.  */
+  /* Check if a variable is being declared as a concept.  */
   if (conceptp)
     {
       if (!processing_template_decl)
-        {
-          error_at (declspecs->locations[ds_concept],
-		    "a non-template variable cannot be %<concept%>");
-          return NULL_TREE;
-        }
+	error_at (declspecs->locations[ds_concept],
+		  "a non-template variable cannot be %<concept%>");
       else if (!at_namespace_scope_p ())
-	{
-	  error_at (declspecs->locations[ds_concept],
-		    "concept must be defined at namespace scope");
-	  return NULL_TREE;
-	}
+	error_at (declspecs->locations[ds_concept],
+		  "concept must be defined at namespace scope");
       else
-        DECL_DECLARED_CONCEPT_P (decl) = true;
-      if (TEMPLATE_PARMS_CONSTRAINTS (current_template_parms))
-        {
-          error_at (location, "a variable concept cannot be constrained");
-          TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = NULL_TREE;
-        }
+	error_at (declspecs->locations[ds_concept],
+		  "variable concepts are no longer supported");
+      return NULL_TREE;
     }
   else if (flag_concepts
 	   && current_template_depth > template_class_depth (scope))
@@ -18808,10 +18716,6 @@  finish_function (bool inline_p)
       goto cleanup;
     }
 
-  // If this is a concept, check that the definition is reasonable.
-  if (DECL_DECLARED_CONCEPT_P (fndecl))
-    check_function_concept (fndecl);
-
   if (flag_openmp)
     if (tree attr = lookup_attribute ("omp declare variant base",
 				      DECL_ATTRIBUTES (fndecl)))
diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc
index 6d674684931..695d5f8d790 100644
--- a/gcc/cp/decl2.cc
+++ b/gcc/cp/decl2.cc
@@ -2723,7 +2723,7 @@  min_vis_expr_r (tree *tp, int */*walk_subtrees*/, void *data)
       break;
 
     case TEMPLATE_DECL:
-      if (DECL_ALIAS_TEMPLATE_P (t) || standard_concept_p (t))
+      if (DECL_ALIAS_TEMPLATE_P (t) || concept_definition_p (t))
 	/* FIXME: We don't maintain TREE_PUBLIC / DECL_VISIBILITY for
 	   alias templates so we can't trust it here (PR107906).  Ditto
 	   for concepts.  */
@@ -5687,7 +5687,6 @@  maybe_instantiate_decl (tree decl)
   if (VAR_OR_FUNCTION_DECL_P (decl)
       && DECL_LANG_SPECIFIC (decl)
       && DECL_TEMPLATE_INFO (decl)
-      && !DECL_DECLARED_CONCEPT_P (decl)
       && !uses_template_parms (DECL_TI_ARGS (decl)))
     {
       /* Instantiating a function will result in garbage collection.  We
@@ -6084,7 +6083,6 @@  mark_used (tree decl, tsubst_flags_t complain /* = tf_warning_or_error */)
     }
   else if (VAR_OR_FUNCTION_DECL_P (decl)
 	   && DECL_TEMPLATE_INFO (decl)
-           && !DECL_DECLARED_CONCEPT_P (decl)
 	   && (!DECL_EXPLICIT_INSTANTIATION (decl)
 	       || always_instantiate_p (decl)))
     /* If this is a function or variable that is an instance of some
diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
index d80bac822ba..aecbc4ff0d9 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -1163,7 +1163,7 @@  dump_simple_decl (cxx_pretty_printer *pp, tree t, tree type, int flags)
       else if (VAR_P (t) && DECL_DECLARED_CONSTEXPR_P (t))
 	pp_cxx_ws_string (pp, "constexpr");
 
-      if (!standard_concept_p (t))
+      if (!concept_definition_p (t))
 	dump_type_prefix (pp, type, flags & ~TFF_UNQUALIFIED_NAME);
       pp_maybe_space (pp);
     }
@@ -1806,9 +1806,7 @@  dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
 
       if (constexpr_p)
         {
-          if (DECL_DECLARED_CONCEPT_P (t))
-            pp_cxx_ws_string (pp, "concept");
-	  else if (DECL_IMMEDIATE_FUNCTION_P (t))
+	  if (DECL_IMMEDIATE_FUNCTION_P (t))
 	    pp_cxx_ws_string (pp, "consteval");
 	  else
 	    pp_cxx_ws_string (pp, "constexpr");
@@ -3952,8 +3950,8 @@  print_concept_check_info (diagnostic_context *context, tree expr, tree map, tree
 {
   gcc_assert (concept_check_p (expr));
 
-  tree id = unpack_concept_check (expr);
-  tree tmpl = TREE_OPERAND (id, 0);
+  tree tmpl = TREE_OPERAND (expr, 0);
+  // ??? Can this go now that fn/var concepts have been removed?
   if (OVL_P (tmpl))
     tmpl = OVL_FIRST (tmpl);
 
diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
index e7391220234..46dc6923add 100644
--- a/gcc/cp/mangle.cc
+++ b/gcc/cp/mangle.cc
@@ -901,9 +901,9 @@  write_tparms_constraints (tree constraints)
 static void
 write_type_constraint (tree cnst)
 {
-  if (!cnst) return;
+  if (!cnst)
+    return;
 
-  cnst = unpack_concept_check (cnst);
   gcc_checking_assert (TREE_CODE (cnst) == TEMPLATE_ID_EXPR);
 
   tree concept_decl = get_concept_check_template (cnst);
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index eb102dea829..f625b0a310c 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -7161,18 +7161,13 @@  cp_parser_nested_name_specifier_opt (cp_parser *parser,
 		      tree fns = get_fns (tid);
 		      if (OVL_SINGLE_P (fns))
 			tmpl = OVL_FIRST (fns);
-		      if (function_concept_p (fns))
-			error_at (token->location, "concept-id %qD "
-				  "in nested-name-specifier", tid);
-		      else
-			error_at (token->location, "function template-id "
-				  "%qD in nested-name-specifier", tid);
+		      error_at (token->location, "function template-id "
+				"%qD in nested-name-specifier", tid);
 		    }
 		  else
 		    {
 		      tmpl = TREE_OPERAND (tid, 0);
-		      if (variable_concept_p (tmpl)
-			  || standard_concept_p (tmpl))
+		      if (concept_definition_p (tmpl))
 			error_at (token->location, "concept-id %qD "
 				  "in nested-name-specifier", tid);
 		      else
@@ -12224,9 +12219,6 @@  add_debug_begin_stmt (location_t loc)
 {
   if (!MAY_HAVE_DEBUG_MARKER_STMTS)
     return;
-  if (DECL_DECLARED_CONCEPT_P (current_function_decl))
-    /* A concept is never expanded normally.  */
-    return;
 
   tree stmt = build0 (DEBUG_BEGIN_STMT, void_type_node);
   SET_EXPR_LOCATION (stmt, loc);
@@ -33087,8 +33079,6 @@  cp_parser_template_declaration_after_parameters (cp_parser* parser,
   else if (flag_concepts
            && cp_lexer_next_token_is_keyword (parser->lexer, RID_CONCEPT)
 	   && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME))
-    /* -fconcept-ts 'concept bool' syntax is handled below, in
-	cp_parser_single_declaration.  */
     decl = cp_parser_concept_definition (parser);
   else
     {
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 77fa5907c3d..35a9c5619f9 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -3232,14 +3232,6 @@  check_explicit_specialization (tree declarator,
               tree tmpl_func = DECL_TEMPLATE_RESULT (gen_tmpl);
               gcc_assert (TREE_CODE (tmpl_func) == FUNCTION_DECL);
 
-              /* A concept cannot be specialized.  */
-              if (DECL_DECLARED_CONCEPT_P (tmpl_func))
-                {
-                  error ("explicit specialization of function concept %qD",
-                         gen_tmpl);
-                  return error_mark_node;
-                }
-
               /* This specialization has the same linkage and visibility as
                  the function template it specializes.  */
               TREE_PUBLIC (decl) = TREE_PUBLIC (tmpl_func);
@@ -5150,13 +5142,6 @@  process_partial_specialization (tree decl)
 
   gcc_assert (current_template_parms);
 
-  /* A concept cannot be specialized.  */
-  if (flag_concepts && variable_concept_p (maintmpl))
-    {
-      error ("specialization of variable concept %q#D", maintmpl);
-      return error_mark_node;
-    }
-
   inner_parms = INNERMOST_TEMPLATE_PARMS (current_template_parms);
   ntparms = TREE_VEC_LENGTH (inner_parms);
 
@@ -10532,9 +10517,6 @@  lookup_template_class (tree d1, tree arglist, tree in_decl, tree context,
 tree
 lookup_template_variable (tree templ, tree arglist, tsubst_flags_t complain)
 {
-  if (flag_concepts && variable_concept_p (templ))
-    return build_concept_check (templ, arglist, tf_none);
-
   tree gen_templ = most_general_template (templ);
   tree parms = DECL_INNERMOST_TEMPLATE_PARMS (gen_templ);
   arglist = add_outermost_template_args (templ, arglist);
@@ -20119,14 +20101,6 @@  tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	    tree check = build_concept_check (templ, targs, complain);
 	    if (check == error_mark_node)
 	      RETURN (error_mark_node);
-
-	    tree id = unpack_concept_check (check);
-
-	    /* If we built a function concept check, return the underlying
-	       template-id. So we can evaluate it as a function call.  */
-	    if (function_concept_p (TREE_OPERAND (id, 0)))
-	      RETURN (id);
-
 	    RETURN (check);
 	  }
 
@@ -21096,19 +21070,8 @@  tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	  ret = build_offset_ref_call_from_tree (function, &call_args,
 						 complain);
 	else if (concept_check_p (function))
-	  {
-	    /* FUNCTION is a template-id referring to a concept definition.  */
-	    tree id = unpack_concept_check (function);
-	    tree tmpl = TREE_OPERAND (id, 0);
-	    tree args = TREE_OPERAND (id, 1);
-
-	    /* Calls to standard and variable concepts should have been
-	       previously diagnosed.  */
-	    gcc_assert (function_concept_p (tmpl));
-
-	    /* Ensure the result is wrapped as a call expression.  */
-	    ret = build_concept_check (tmpl, args, tf_warning_or_error);
-	  }
+	  /* Calls to concepts should have been previously diagnosed.  */
+	  gcc_assert (false);
 	else
 	  ret = finish_call_expr (function, &call_args,
 				  /*disallow_virtual=*/qualified_p,
@@ -26414,14 +26377,6 @@  do_decl_instantiation (tree decl, tree storage)
       error ("explicit instantiation of non-template %q#D", decl);
       return;
     }
-  else if (DECL_DECLARED_CONCEPT_P (decl))
-    {
-      if (VAR_P (decl))
-	error ("explicit instantiation of variable concept %q#D", decl);
-      else
-	error ("explicit instantiation of function concept %q#D", decl);
-      return;
-    }
 
   bool var_templ = (DECL_TEMPLATE_INFO (decl)
                     && variable_template_p (DECL_TI_TEMPLATE (decl)));
@@ -27211,9 +27166,6 @@  instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p)
      functions and static member variables.  */
   gcc_assert (VAR_OR_FUNCTION_DECL_P (d));
 
-  /* A concept is never instantiated. */
-  gcc_assert (!DECL_DECLARED_CONCEPT_P (d));
-
   gcc_checking_assert (!DECL_FUNCTION_SCOPE_P (d));
 
   if (modules_p ())
@@ -29492,8 +29444,8 @@  make_constrained_decltype_auto (tree con, tree args)
 static bool
 placeholder_type_constraint_dependent_p (tree t)
 {
-  tree id = unpack_concept_check (t);
-  tree args = TREE_OPERAND (id, 1);
+  gcc_assert (concept_check_p (t));
+  tree args = TREE_OPERAND (t, 1);
   tree first = TREE_VEC_ELT (args, 0);
   if (ARGUMENT_PACK_P (first))
     {
@@ -31452,8 +31404,8 @@  convert_generic_types_to_packs (tree parm, int start_idx, int end_idx)
          requirements.  */
       if (tree constr = TEMPLATE_PARM_CONSTRAINTS (node))
 	{
-	  tree id = unpack_concept_check (constr);
-	  TREE_VEC_ELT (TREE_OPERAND (id, 1), 0) = t;
+	  gcc_assert (concept_check_p (constr));
+	  TREE_VEC_ELT (TREE_OPERAND (constr, 1), 0) = t;
 	  /* Use UNKNOWN_LOCATION so write_template_args can tell the
 	     difference between this and a fold the user wrote.  */
 	  location_t loc = UNKNOWN_LOCATION;
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 669da4ad969..e58612660c9 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -3067,20 +3067,9 @@  finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual,
     }
   else if (concept_check_p (fn))
     {
-      /* FN is actually a template-id referring to a concept definition.  */
-      tree id = unpack_concept_check (fn);
-      tree tmpl = TREE_OPERAND (id, 0);
-      tree args = TREE_OPERAND (id, 1);
-
-      if (!function_concept_p (tmpl))
-	{
-	  error_at (EXPR_LOC_OR_LOC (fn, input_location),
-		    "cannot call a concept as a function");
-	  return error_mark_node;
-	}
-
-      /* Ensure the result is wrapped as a call expression.  */
-      result = build_concept_check (tmpl, args, tf_warning_or_error);
+      error_at (EXPR_LOC_OR_LOC (fn, input_location),
+		"cannot call a concept as a function");
+      return error_mark_node;
     }
   else if (is_overloaded_fn (fn))
     {
diff --git a/gcc/testsuite/g++.dg/concepts/decl-diagnose.C b/gcc/testsuite/g++.dg/concepts/decl-diagnose.C
index 0d10ce1ea9f..2bf1cd5ab17 100644
--- a/gcc/testsuite/g++.dg/concepts/decl-diagnose.C
+++ b/gcc/testsuite/g++.dg/concepts/decl-diagnose.C
@@ -7,8 +7,8 @@  typedef concept int CINT; // { dg-error "'concept' cannot appear in a typedef de
 void f(concept int); // { dg-error "a parameter cannot be declared 'concept'" }
 
 template<typename T>
-concept int f2() { return 0; } // { dg-error "return type" }
-concept bool f3(); // { dg-error "14:concept .f3. has no definition" }
+concept int f2() { return 0; } // { dg-error "function concepts are no longer supported" }
+concept bool f3(); // { dg-error "14:function concepts are no longer supported" }
 		   // { dg-error "keyword is not allowed" "" { target *-*-* } .-1 }
 
 struct X
@@ -26,11 +26,11 @@  struct X
   concept X(); // { dg-error "a constructor cannot be 'concept'" }
 };
 
-concept bool X2; // { dg-error "non-template variable" }
+concept bool X2; // { dg-error "variable" }
 	         // { dg-error "keyword is not allowed" "" { target *-*-* } .-1 }
 
 template<typename T>
-  concept bool X3; // { dg-error "has no initializer" }
+  concept bool X3; // { dg-error "variable concepts" }
 		   // { dg-error "keyword is not allowed" "" { target *-*-* } .-1 }
 
 struct S {
diff --git a/gcc/testsuite/g++.dg/concepts/fn-concept2.C b/gcc/testsuite/g++.dg/concepts/fn-concept2.C
index 799e85de955..52ca8245c76 100644
--- a/gcc/testsuite/g++.dg/concepts/fn-concept2.C
+++ b/gcc/testsuite/g++.dg/concepts/fn-concept2.C
@@ -3,7 +3,7 @@ 
 // { dg-prune-output "concept definition syntax is" }
 
 template<typename T>
-  concept auto C1() { return 0; } // { dg-error "16:concept .concept auto C1\\(\\). declared with a deduced return type" }
+  concept auto C1() { return 0; } // { dg-error "16:function concepts are no longer supported" }
 
 template<typename T>
-  concept int C2() { return 0; } // { dg-error "15:concept .concept int C2\\(\\). with non-.bool. return type .int." }
+  concept int C2() { return 0; } // { dg-error "15:function concepts are no longer supported" }
diff --git a/gcc/testsuite/g++.dg/concepts/pr71128.C b/gcc/testsuite/g++.dg/concepts/pr71128.C
index 63b3d1dff78..a3d5357d432 100644
--- a/gcc/testsuite/g++.dg/concepts/pr71128.C
+++ b/gcc/testsuite/g++.dg/concepts/pr71128.C
@@ -2,9 +2,9 @@ 
 // { dg-options "-fconcepts" }
 
 template<typename T>
-concept bool C() { return true; } // { dg-error "the .bool. keyword" }
-template bool C<int>();  // { dg-error "explicit instantiation of function concept" }
+concept bool C() { return true; } // { dg-error "the .bool. keyword|function concepts" }
+template bool C<int>();  // { dg-error "template function|not a function template|expected" }
 
 template<typename T>
-concept bool D = true;	// { dg-error "the .bool. keyword" }
-template bool D<int>;  // { dg-error "explicit instantiation of variable concept" }
+concept bool D = true;	// { dg-error "the .bool. keyword|variable concepts are no longer supported" }
+template bool D<int>;  // { dg-error "not a template function|expected" }
diff --git a/gcc/testsuite/g++.dg/concepts/var-concept6.C b/gcc/testsuite/g++.dg/concepts/var-concept6.C
index 04298f47a92..062007a1291 100644
--- a/gcc/testsuite/g++.dg/concepts/var-concept6.C
+++ b/gcc/testsuite/g++.dg/concepts/var-concept6.C
@@ -2,4 +2,4 @@ 
 // { dg-options "-fconcepts" }
 
 template <class T>
-concept int C = true;		// { dg-error "concept definition syntax" }
+concept int C = true;		// { dg-error "concept definition syntax|variable concepts are no longer supported" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts.C b/gcc/testsuite/g++.dg/cpp2a/concepts.C
index ebeeebf60bb..1b7a708659b 100644
--- a/gcc/testsuite/g++.dg/cpp2a/concepts.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts.C
@@ -18,9 +18,9 @@  void f3(T)
 { }
 
 template<typename T>
-concept bool C1 = true; // { dg-error "bool" }
+concept bool C1 = true; // { dg-error "bool|variable concepts" }
 template<typename T>
-bool concept C2 = true; // { dg-error "concept definition syntax" }
+bool concept C2 = true; // { dg-error "concept definition syntax|variable concepts" }
 
 template<typename T>
 concept C3 = true; // OK