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