This patch makes tsubst_requires_expr avoid substituting into a requires-expression when partially instantiating a generic lambda. This is necessary in general to ensure that we always check requirements in lexical order (as in the first testcase below). A mechanism similar to PACK_EXPANSION_EXTRA_ARGS is added to remember template arguments and defer substitution of requires-expressions. Incidentally, this change also fixes the two mentioned PRs -- the problem there is that tsubst_requires_expr was performing semantic checks on template trees, and some of the checks are not prepared to handle such trees. With this patch, tsubst_requires_expr no longer does any semantic checking at all when processing_template_decl. gcc/cp/ChangeLog: PR c++/96409 PR c++/96410 * constraint.cc (tsubst_requires_expr): Use REQUIRES_EXPR_PARMS and REQUIRES_EXPR_REQS. Use REQUIRES_EXPR_EXTRA_ARGS, add_extra_args and build_extra_args to defer substitution until we have all the template arguments. (finish_requires_expr): Adjust the call to build_min so that REQUIRES_EXPR_EXTRA_ARGS gets set to NULL_TREE. * cp-tree.def (REQUIRES_EXPR): Give it a third operand. * cp-tree.h (REQUIRES_EXPR_PARMS, REQUIRES_EXPR_REQS, REQUIRES_EXPR_EXTRA_ARGS): Define. (add_extra_args, build_extra_args): Declare. gcc/testsuite/ChangeLog: PR c++/96409 PR c++/96410 * g++.dg/cpp2a/concepts-lambda13.C: New test. * g++.dg/cpp2a/concepts-lambda14.C: New test.
26 lines
769 B
C
26 lines
769 B
C
// 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" }
|