c++: remove function/var concepts code
Checks
Context |
Check |
Description |
linaro-tcwg-bot/tcwg_gcc_build--master-arm |
success
|
Build passed
|
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 |
success
|
Build passed
|
linaro-tcwg-bot/tcwg_gcc_check--master-arm |
success
|
Test passed
|
linaro-tcwg-bot/tcwg_gcc_check--master-aarch64 |
success
|
Test passed
|
Commit Message
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
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
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
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
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
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
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
>
>
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
@@ -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);
@@ -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);
}
@@ -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;
@@ -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)))
@@ -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
@@ -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);
@@ -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);
@@ -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
{
@@ -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;
@@ -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))
{
@@ -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 {
@@ -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" }
@@ -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" }
@@ -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" }
@@ -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