/* A requires-expression is an unevaluated context. */
cp_unevaluated u;
- tree parms = TREE_OPERAND (t, 0);
+ args = add_extra_args (REQUIRES_EXPR_EXTRA_ARGS (t), args);
+ if (processing_template_decl)
+ {
+ /* We're partially instantiating a generic lambda. Substituting into
+ this requires-expression now may cause its requirements to get
+ checked out of order, so instead just remember the template
+ arguments and wait until we can substitute them all at once. */
+ t = copy_node (t);
+ REQUIRES_EXPR_EXTRA_ARGS (t) = build_extra_args (t, args, complain);
+ return t;
+ }
+
+ tree parms = REQUIRES_EXPR_PARMS (t);
if (parms)
{
parms = tsubst_constraint_variables (parms, args, info);
return boolean_false_node;
}
- tree reqs = TREE_OPERAND (t, 1);
+ tree reqs = REQUIRES_EXPR_REQS (t);
reqs = tsubst_requirement_body (reqs, args, info);
if (reqs == error_mark_node)
return boolean_false_node;
- if (processing_template_decl)
- return finish_requires_expr (cp_expr_location (t), parms, reqs);
-
return boolean_true_node;
}
}
/* Build the node. */
- tree r = build_min (REQUIRES_EXPR, boolean_type_node, parms, reqs);
+ tree r = build_min (REQUIRES_EXPR, boolean_type_node, parms, reqs, NULL_TREE);
TREE_SIDE_EFFECTS (r) = false;
TREE_CONSTANT (r) = true;
SET_EXPR_LOCATION (r, loc);
of the wildcard. */
DEFTREECODE (WILDCARD_DECL, "wildcard_decl", tcc_declaration, 0)
-/* A requires-expr is a binary expression. The first operand is
+/* A requires-expr has three operands. The first operand is
its parameter list (possibly NULL). The second is a list of
requirements, which are denoted by the _REQ* tree codes
- below. */
-DEFTREECODE (REQUIRES_EXPR, "requires_expr", tcc_expression, 2)
+ below. The third is a TREE_VEC of template arguments to
+ be applied when substituting into the parameter list and
+ requirements, set by tsubst_requires_expr for partial instantiations. */
+DEFTREECODE (REQUIRES_EXPR, "requires_expr", tcc_expression, 3)
/* A requirement for an expression. */
DEFTREECODE (SIMPLE_REQ, "simple_req", tcc_expression, 1)
#define CONSTRAINED_PARM_PROTOTYPE(NODE) \
DECL_INITIAL (TYPE_DECL_CHECK (NODE))
+/* The list of local parameters introduced by this requires-expression,
+ in the form of a chain of PARM_DECLs. */
+#define REQUIRES_EXPR_PARMS(NODE) \
+ TREE_OPERAND (TREE_CHECK (NODE, REQUIRES_EXPR), 0)
+
+/* A TREE_LIST of the requirements for this requires-expression.
+ The requirements are stored in lexical order within the TREE_VALUE
+ of each TREE_LIST node. The TREE_PURPOSE of each node is unused. */
+#define REQUIRES_EXPR_REQS(NODE) \
+ TREE_OPERAND (TREE_CHECK (NODE, REQUIRES_EXPR), 1)
+
+/* Like PACK_EXPANSION_EXTRA_ARGS, for requires-expressions. */
+#define REQUIRES_EXPR_EXTRA_ARGS(NODE) \
+ TREE_OPERAND (TREE_CHECK (NODE, REQUIRES_EXPR), 2)
+
enum cp_tree_node_structure_enum {
TS_CP_GENERIC,
TS_CP_IDENTIFIER,
extern bool builtin_guide_p (const_tree);
extern void store_explicit_specifier (tree, tree);
extern tree add_outermost_template_args (tree, tree);
+extern tree add_extra_args (tree, tree);
+extern tree build_extra_args (tree, tree, tsubst_flags_t);
/* in rtti.c */
/* A vector of all tinfo decls that haven't been emitted yet. */
--- /dev/null
+// { dg-do compile { target c++20 } }
+
+template<typename T>
+struct S {
+ using type = T::type; // { dg-bogus "" }
+};
+
+template<typename T>
+auto f() {
+ return [] <typename U> (U) {
+ // Verify that partial instantiation of this generic lambda doesn't cause
+ // these requirements to get checked out of order.
+ static_assert(!requires { typename U::type; typename S<T>::type; });
+ return 0;
+ };
+}
+
+int a = f<int>()(0);
--- /dev/null
+// PR c++/96410
+// { dg-do compile { target c++20 } }
+
+struct S { using blah = void; };
+
+template <typename T> constexpr bool trait = !__is_same(T, S);
+template <typename T> concept C = trait<T>;
+
+template<typename T>
+void foo() noexcept(!__is_same(T, void)) { }
+
+template<typename U>
+auto f() {
+ return []<typename T>(T, bool a = requires { C<T>; }){
+ static_assert(requires { requires C<U> && (C<T> || C<T>); }); // { dg-error "assert" }
+ static_assert(requires { C<T>; });
+ static_assert(requires { { foo<T>() } noexcept -> C; });
+ static_assert(!requires { typename T::blah; }); // { dg-error "assert" }
+ return 0;
+ };
+}
+
+auto g = f<int>(); // { dg-bogus "" }
+int n = g(0); // { dg-bogus "" }
+int m = g(S{}); // { dg-message "required from here" }