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.
This commit is contained in:
parent
299ddc6121
commit
83fe2b9218
@ -1,3 +1,15 @@
|
||||
2020-01-15 Paolo Carlini <paolo.carlini@oracle.com>
|
||||
|
||||
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 <jason@redhat.com>
|
||||
|
||||
Revert
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -1,3 +1,9 @@
|
||||
2020-01-15 Paolo Carlini <paolo.carlini@oracle.com>
|
||||
|
||||
PR c++/91073
|
||||
* g++.dg/concepts/pr91073-1.C: New.
|
||||
* g++.dg/concepts/pr91073-2.C: Likewise.
|
||||
|
||||
2020-01-15 Wilco Dijkstra <wdijkstr@arm.com>
|
||||
|
||||
* gcc.dg/pr90838.c: New test.
|
||||
|
37
gcc/testsuite/g++.dg/concepts/pr91073-1.C
Normal file
37
gcc/testsuite/g++.dg/concepts/pr91073-1.C
Normal file
@ -0,0 +1,37 @@
|
||||
// { dg-do compile { target c++17 } }
|
||||
// { dg-options "-fconcepts" }
|
||||
|
||||
template<typename T, typename... Params>
|
||||
concept HasInit = requires(T t, Params... p) { t.init(p...); };
|
||||
|
||||
struct Initable { void init(int) { } };
|
||||
struct Createable { void create(int) { } };
|
||||
|
||||
struct Foo{
|
||||
template<typename CB>
|
||||
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<decltype(foo), int>)
|
||||
{
|
||||
foo.init(5);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
Foo f;
|
||||
return 0;
|
||||
}
|
19
gcc/testsuite/g++.dg/concepts/pr91073-2.C
Normal file
19
gcc/testsuite/g++.dg/concepts/pr91073-2.C
Normal file
@ -0,0 +1,19 @@
|
||||
// { dg-do compile { target c++17 } }
|
||||
// { dg-options "-fconcepts" }
|
||||
|
||||
template<typename P, typename Arghhh = void>
|
||||
concept one_or_two = true;
|
||||
|
||||
template<typename P>
|
||||
concept one = one_or_two<P>;
|
||||
|
||||
template<typename T>
|
||||
constexpr void
|
||||
foo()
|
||||
{
|
||||
if (one<T>) // OK
|
||||
{ }
|
||||
|
||||
if (one_or_two<T>) // { dg-bogus "before" }
|
||||
{ }
|
||||
}
|
Loading…
Reference in New Issue
Block a user