@@ -309,7 +309,10 @@ struct GTY(()) cp_binding_level {
/* true for SK_FUNCTION_PARMS of immediate functions. */
unsigned immediate_fn_ctx_p : 1;
- /* 22 bits left to fill a 32-bit word. */
+ /* True for SK_FUNCTION_PARMS of a requires-expression. */
+ unsigned requires_expression: 1;
+
+ /* 21 bits left to fill a 32-bit word. */
};
/* The binding level currently in effect. */
@@ -29964,7 +29964,8 @@ cp_parser_requires_expression (cp_parser *parser)
scope_sentinel ()
{
++cp_unevaluated_operand;
- begin_scope (sk_block, NULL_TREE);
+ begin_scope (sk_function_parms, NULL_TREE);
+ current_binding_level->requires_expression = true;
}
~scope_sentinel ()
@@ -48082,7 +48083,7 @@ static tree
synthesize_implicit_template_parm (cp_parser *parser, tree constr)
{
/* A requires-clause is not a function and cannot have placeholders. */
- if (current_binding_level->kind == sk_block)
+ if (current_binding_level->requires_expression)
{
error ("placeholder type not allowed in this context");
return error_mark_node;
@@ -12,7 +12,7 @@ concept C0 = requires (auto x) { // { dg-error "placeholder type" }
template<typename T>
concept C1 = requires (C1 auto x) { // { dg-error "not been declared|placeholder|two or more|in requirements" }
x; // { dg-error "not declared" }
- { x } -> c; // { dg-message "is invalid" }
+ { x } -> c; // { dg-message "is invalid|not declared" }
};
template<typename T>
new file mode 100644
@@ -0,0 +1,13 @@
+// PR c++/101677
+// { dg-do compile { target c++20 } }
+
+template<class T>
+concept C_bug_with_forward_decl = requires(T& t){
+ t.template f<class S>();
+};
+
+struct good {
+ template<class T> void f() {}
+};
+
+static_assert(C_bug_with_forward_decl<good>);