From 83fe2b921830c177e3dee514aa07cbc7c8ceef1c Mon Sep 17 00:00:00 2001 From: Paolo Carlini Date: Wed, 15 Jan 2020 22:28:46 +0100 Subject: [PATCH] Fix "PR c++/91073 if constexpr no longer works directly with Concepts." This is a rather serious regression, filed in July 2019. Luckily the fix is simple: is localized to parser.c and cp-tree.h in cp and boils down to only a few lines. Testing OK on x86_64-linux. Approved off-line by Jason Merrill. /cp PR c++/91073 * cp-tree.h (is_constrained_auto): New. * parser.c (cp_parser_maybe_commit_to_declaration): Correctly handle concept-check expressions; take a cp_decl_specifier_seq* instead of a bool. (cp_parser_condition): Update call. (cp_parser_simple_declaration): Likewise. (cp_parser_placeholder_type_specifier): Correctly handle concept-check expressions. /testsuite PR c++/91073 * g++.dg/concepts/pr91073-1.C: New. * g++.dg/concepts/pr91073-2.C: Likewise. --- gcc/cp/ChangeLog | 12 ++++++++++ gcc/cp/cp-tree.h | 8 +++++++ gcc/cp/parser.c | 26 +++++++++++++--------- gcc/testsuite/ChangeLog | 6 +++++ gcc/testsuite/g++.dg/concepts/pr91073-1.C | 37 +++++++++++++++++++++++++++++++ gcc/testsuite/g++.dg/concepts/pr91073-2.C | 19 ++++++++++++++++ 6 files changed, 98 insertions(+), 10 deletions(-) create mode 100644 gcc/testsuite/g++.dg/concepts/pr91073-1.C create mode 100644 gcc/testsuite/g++.dg/concepts/pr91073-2.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 4a15579..47d55e5 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,15 @@ +2020-01-15 Paolo Carlini + + PR c++/91073 + * cp-tree.h (is_constrained_auto): New. + * parser.c (cp_parser_maybe_commit_to_declaration): Correctly + handle concept-check expressions; take a cp_decl_specifier_seq* + instead of a bool. + (cp_parser_condition): Update call. + (cp_parser_simple_declaration): Likewise. + (cp_parser_placeholder_type_specifier): Correctly handle + concept-check expressions. + 2020-01-15 Jason Merrill Revert diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 2b08d1b..48cc441 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -8069,6 +8069,14 @@ concept_check_p (const_tree t) return false; } +/* True if t is a "constrained auto" type-specifier. */ + +inline bool +is_constrained_auto (const_tree t) +{ + return is_auto (t) && PLACEHOLDER_TYPE_CONSTRAINTS (t); +} + #if CHECKING_P namespace selftest { extern void run_cp_tests (void); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 2ddbe13..c5f9798 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -12053,18 +12053,22 @@ cp_parser_selection_statement (cp_parser* parser, bool *if_p, } /* Helper function for cp_parser_condition and cp_parser_simple_declaration. - If we have seen at least one decl-specifier, and the next token - is not a parenthesis, then we must be looking at a declaration. - (After "int (" we might be looking at a functional cast.) */ + If we have seen at least one decl-specifier, and the next token is not + a parenthesis (after "int (" we might be looking at a functional cast) + neither we are dealing with a concept-check expression then we must be + looking at a declaration. */ static void cp_parser_maybe_commit_to_declaration (cp_parser* parser, - bool any_specifiers_p) + cp_decl_specifier_seq *decl_specs) { - if (any_specifiers_p + if (decl_specs->any_specifiers_p && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN) && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE) - && !cp_parser_error_occurred (parser)) + && !cp_parser_error_occurred (parser) + && !(decl_specs->type + && TREE_CODE (decl_specs->type) == TYPE_DECL + && is_constrained_auto (TREE_TYPE (decl_specs->type)))) cp_parser_commit_to_tentative_parse (parser); } @@ -12139,8 +12143,7 @@ cp_parser_condition (cp_parser* parser) decl-specifiers. */ tree prefix_attributes = type_specifiers.attributes; - cp_parser_maybe_commit_to_declaration (parser, - type_specifiers.any_specifiers_p); + cp_parser_maybe_commit_to_declaration (parser, &type_specifiers); /* If all is well, we might be looking at a declaration. */ if (!cp_parser_error_occurred (parser)) @@ -13535,8 +13538,7 @@ cp_parser_simple_declaration (cp_parser* parser, goto done; } - cp_parser_maybe_commit_to_declaration (parser, - decl_specifiers.any_specifiers_p); + cp_parser_maybe_commit_to_declaration (parser, &decl_specifiers); /* Look for C++17 decomposition declaration. */ for (size_t n = 1; ; n++) @@ -18266,6 +18268,10 @@ cp_parser_placeholder_type_specifier (cp_parser *parser, location_t loc, && !parser->in_result_type_constraint_p && !placeholder) { + if (tentative) + /* Perhaps it's a concept-check expression (c++/91073). */ + return error_mark_node; + tree id = build_nt (TEMPLATE_ID_EXPR, tmpl, args); tree expr = DECL_P (orig_tmpl) ? DECL_NAME (con) : id; error_at (input_location, diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 769020d..143fda9 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2020-01-15 Paolo Carlini + + PR c++/91073 + * g++.dg/concepts/pr91073-1.C: New. + * g++.dg/concepts/pr91073-2.C: Likewise. + 2020-01-15 Wilco Dijkstra * gcc.dg/pr90838.c: New test. diff --git a/gcc/testsuite/g++.dg/concepts/pr91073-1.C b/gcc/testsuite/g++.dg/concepts/pr91073-1.C new file mode 100644 index 0000000..f5f3821 --- /dev/null +++ b/gcc/testsuite/g++.dg/concepts/pr91073-1.C @@ -0,0 +1,37 @@ +// { dg-do compile { target c++17 } } +// { dg-options "-fconcepts" } + +template +concept HasInit = requires(T t, Params... p) { t.init(p...); }; + +struct Initable { void init(int) { } }; +struct Createable { void create(int) { } }; + +struct Foo{ + template + void for_each(CB&& cb) + { + Initable i; + Createable c; + cb(i); + cb(c); + } + + Foo() + { + struct Bar { int x; }; + for_each( + [&](auto& foo){ + if constexpr (HasInit) + { + foo.init(5); + } + }); + } +}; + +int main() +{ + Foo f; + return 0; +} diff --git a/gcc/testsuite/g++.dg/concepts/pr91073-2.C b/gcc/testsuite/g++.dg/concepts/pr91073-2.C new file mode 100644 index 0000000..2900aae --- /dev/null +++ b/gcc/testsuite/g++.dg/concepts/pr91073-2.C @@ -0,0 +1,19 @@ +// { dg-do compile { target c++17 } } +// { dg-options "-fconcepts" } + +template +concept one_or_two = true; + +template +concept one = one_or_two

; + +template +constexpr void +foo() +{ + if (one) // OK + { } + + if (one_or_two) // { dg-bogus "before" } + { } +} -- 2.7.4