Hi! The following patch implements the C++29 P3822R2 - Conditional noexcept specifiers in compound requirements paper. For mangling I've used what the clang++ fork mentioned in the paper uses, so no N for no noexcept (as before) or noexcept (false), N for noexcept (as before) or noexcept (true) and C <expression> for noexcept (<expression>). I've also checked all these new testcases against that clang++ fork on godbolt (again, link in the paper), everything is accepted or rejected the same in both compilers, just there is apparently a difference in the mangling but preexisting and unrelated to this exact patch (the no N vs. N vs. C <expression> is actually the same).
So far lightly tested, ok for trunk if it passes full bootstrap/regtest? 2026-08-20 Jakub Jelinek <[email protected]> PR c++/125822 gcc/c-family/ * c-cppbuiltin.cc (c_cpp_builtins): Define __cpp_concepts to 202606L rather than 202002L for C++29. gcc/cp/ * cp-tree.def: Implement C++29 P3822R2 - Conditional noexcept specifiers in compound requirements. (COMPOUND_REQ): Use 3 operands rather than 2, adjust comment. * cp-tree.h (COMPOUND_REQ_NOEXCEPT_P): Remove. (finish_compound_requirement): Change last argument from bool to tree. * parser.cc (cp_parser_compound_requirement): Parse C++29 conditional noexcept in compound requirement. Pass a tree to finish_compound_requirement rather than bool. * constraint.cc (tsubst_compound_requirement): Read noexcept from TREE_OPERAND (req, 2) rather than COMPOUND_REQ_NOEXCEPT_P (req), instantiate, convert, evaluate and pass to finish_compound_requirement. (finish_compound_requirement): Change last argument from bool to tree, store it as third operand of COMPOUND_REQ rather than in COMPOUND_REQ_NOEXCEPT_P flag and call check_for_bare_parameter_packs on it. * cxx-pretty-print.cc (pp_cxx_compound_requirement): Print noexcept with argument if TREE_OPERAND (t, 2) is neither true nor false constant and check it for printing "noexcept" instead oof COMPOUND_REQ_NOEXCEPT_P flag. * mangle.cc (write_requirement): Don't use COMPOUND_REQ_NOEXCEPT_P flag, instead mangle without N or with N if third operand is false or true constant and as C <expression> otherwise. gcc/testsuite/ * g++.dg/cpp29/complex-req-noexcept1.C: New test. * g++.dg/cpp29/complex-req-noexcept2.C: New test. * g++.dg/cpp29/complex-req-noexcept3.C: New test. * g++.dg/cpp29/complex-req-noexcept4.C: New test. * g++.dg/cpp29/complex-req-noexcept5.C: New test. * g++.dg/cpp29/feat-cxx29.C: Expect __cpp_concepts 202606L rather than 202002L for C++29. --- gcc/c-family/c-cppbuiltin.cc.jj 2026-08-06 11:48:09.026003282 +0200 +++ gcc/c-family/c-cppbuiltin.cc 2026-08-20 17:03:31.614072266 +0200 @@ -1133,7 +1133,12 @@ c_cpp_builtins (cpp_reader *pfile) cpp_define (pfile, "__cpp_designated_initializers=202606L"); } if (flag_concepts && cxx_dialect > cxx14) - cpp_define (pfile, "__cpp_concepts=202002L"); + { + if (cxx_dialect > cxx26) + cpp_define (pfile, "__cpp_concepts=202606L"); + else + cpp_define (pfile, "__cpp_concepts=202002L"); + } else if (cxx_dialect >= cxx20) cpp_warn (pfile, "__cpp_concepts"); if (flag_contracts) --- gcc/cp/cp-tree.def.jj 2026-07-13 18:35:54.646463696 +0200 +++ gcc/cp/cp-tree.def 2026-08-20 13:25:10.643586955 +0200 @@ -515,10 +515,9 @@ DEFTREECODE (SIMPLE_REQ, "simple_req", t DEFTREECODE (TYPE_REQ, "type_req", tcc_expression, 1) /* A requirement for an expression and its properties. The - first operand is the expression, and the 2nd is its type. - The accessor COMPOUND_REQ_NOEXCEPT determines whether - the noexcept keyword was present. */ -DEFTREECODE (COMPOUND_REQ, "compound_req", tcc_expression, 2) + first operand is the expression, the 2nd is its type, + the third one is noexcept expression. */ +DEFTREECODE (COMPOUND_REQ, "compound_req", tcc_expression, 3) /* A requires clause within a requires expression. */ DEFTREECODE (NESTED_REQ, "nested_req", tcc_expression, 1) --- gcc/cp/cp-tree.h.jj 2026-08-04 12:48:37.000000000 +0200 +++ gcc/cp/cp-tree.h 2026-08-20 13:25:26.091389686 +0200 @@ -442,7 +442,6 @@ extern GTY(()) tree cp_global_trees[CPTI PACK_EXPANSION_LOCAL_P (in *_PACK_EXPANSION) TINFO_HAS_ACCESS_ERRORS (in TEMPLATE_INFO) SIZEOF_EXPR_TYPE_P (in SIZEOF_EXPR) - COMPOUND_REQ_NOEXCEPT_P (in COMPOUND_REQ) BLOCK_OUTER_CURLY_BRACE_P (in BLOCK) FOLD_EXPR_MODIFY_P (*_FOLD_EXPR) IF_STMT_CONSTEXPR_P (IF_STMT) @@ -1749,10 +1748,6 @@ check_constraint_info (tree t) #define TEMPLATE_PARM_CONSTRAINTS(NODE) \ TREE_TYPE (TREE_LIST_CHECK (NODE)) -/* Non-zero if the noexcept is present in a compound requirement. */ -#define COMPOUND_REQ_NOEXCEPT_P(NODE) \ - TREE_LANG_FLAG_0 (TREE_CHECK (NODE, COMPOUND_REQ)) - /* A TREE_LIST whose TREE_VALUE is the constraints on the 'auto' placeholder type NODE, used in an argument deduction constraint. The TREE_PURPOSE holds the set of template parameters that were in-scope when this 'auto' @@ -9364,7 +9359,7 @@ extern tree finish_shorthand_constraint extern tree finish_requires_expr (location_t, tree, tree); extern tree finish_simple_requirement (location_t, tree); extern tree finish_type_requirement (location_t, tree); -extern tree finish_compound_requirement (location_t, tree, tree, bool); +extern tree finish_compound_requirement (location_t, tree, tree, tree); extern tree finish_nested_requirement (location_t, tree); extern tree tsubst_requires_expr (tree, tree, tsubst_flags_t, tree); extern tree evaluate_requires_expr (tree); --- gcc/cp/parser.cc.jj 2026-08-06 10:56:18.062585734 +0200 +++ gcc/cp/parser.cc 2026-08-20 13:32:06.104289435 +0200 @@ -35287,8 +35287,10 @@ cp_parser_type_requirement (cp_parser *p /* Parse a compound requirement - compound-requirement: - '{' expression '}' 'noexcept' [opt] trailing-return-type [opt] ';' */ + compound-requirement: + '{' expression '}' 'noexcept' [opt] trailing-return-type [opt] ';' + '{' expression '}' noexcept-specifier [opt] trailing-return-type [opt] + ';' (C++29) */ static tree cp_parser_compound_requirement (cp_parser *parser) @@ -35320,11 +35322,21 @@ cp_parser_compound_requirement (cp_parse } /* Parse the optional noexcept. */ - bool noexcept_p = false; + tree noex = boolean_false_node; if (cp_lexer_next_token_is_keyword (parser->lexer, RID_NOEXCEPT)) { - cp_lexer_consume_token (parser->lexer); - noexcept_p = true; + if (cxx_dialect < cxx29 + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_PAREN)) + pedwarn (cp_lexer_peek_nth_token (parser->lexer, 2)->location, + OPT_Wc__29_extensions, + "conditional %<noexcept%> in compound requirement only " + "available with %<-std=c++2d%> or %<-std=gnu++2d%>"); + + noex = cp_parser_noexcept_specification_opt (parser, + CP_PARSER_FLAGS_NONE, + /*require_constexpr=*/true, + /*consumed_expr=*/NULL, + /*return_cond=*/true); } /* Parse the optional trailing return type. */ @@ -35376,7 +35388,7 @@ cp_parser_compound_requirement (cp_parse if (expr == error_mark_node || type == error_mark_node) return error_mark_node; - return finish_compound_requirement (loc, expr, type, noexcept_p); + return finish_compound_requirement (loc, expr, type, noex); } /* Parse a nested requirement. This is the same as a requires clause. --- gcc/cp/constraint.cc.jj 2026-07-13 18:35:54.645463709 +0200 +++ gcc/cp/constraint.cc 2026-08-20 17:32:32.501294056 +0200 @@ -1507,6 +1507,7 @@ tsubst_compound_requirement (tree t, tre { tree t0 = TREE_OPERAND (t, 0); tree t1 = TREE_OPERAND (t, 1); + tree noex = TREE_OPERAND (t, 2); tree expr = tsubst_valid_expression_requirement (t0, args, info); if (expr == error_mark_node) return error_mark_node; @@ -1516,8 +1517,17 @@ tsubst_compound_requirement (tree t, tre subst_info quiet (info.complain & ~tf_warning_or_error, info.in_decl); /* Check the noexcept condition. */ - bool noexcept_p = COMPOUND_REQ_NOEXCEPT_P (t); - if (noexcept_p && !processing_template_decl + noex = tsubst_expr (noex, args, info.complain, info.in_decl); + if (!instantiation_dependent_expression_p (noex)) + { + noex = build_converted_constant_bool_expr (noex, info.complain); + noex = instantiate_non_dependent_expr (noex, info.complain); + noex = cxx_constant_value (noex, info.complain); + } + if (noex == error_mark_node) + return error_mark_node; + if (!processing_template_decl + && integer_nonzerop (noex) && !expr_noexcept_p (expr, quiet.complain)) { if (info.diagnose_unsatisfaction_p ()) @@ -1573,8 +1583,7 @@ tsubst_compound_requirement (tree t, tre } if (processing_template_decl) - return finish_compound_requirement (EXPR_LOCATION (t), - expr, type, noexcept_p); + return finish_compound_requirement (EXPR_LOCATION (t), expr, type, noex); return boolean_true_node; } @@ -2984,14 +2993,17 @@ finish_type_requirement (location_t loc, its properties. If TYPE is non-null, then it specifies either an implicit conversion or argument deduction constraint, depending on whether any placeholders occur in the type name. - NOEXCEPT_P is true iff the noexcept keyword was specified. */ + NOEX is boolean_true_node iff the noexcept keyword was specified + or expression if noexcept (expr) was specified. */ tree -finish_compound_requirement (location_t loc, tree expr, tree type, bool noexcept_p) +finish_compound_requirement (location_t loc, tree expr, tree type, + tree noex) { - tree req = build_nt (COMPOUND_REQ, expr, type); + if (check_for_bare_parameter_packs (noex)) + noex = error_mark_node; + tree req = build_nt (COMPOUND_REQ, expr, type, noex); SET_EXPR_LOCATION (req, loc); - COMPOUND_REQ_NOEXCEPT_P (req) = noexcept_p; return req; } --- gcc/cp/cxx-pretty-print.cc.jj 2026-07-13 18:35:54.647463684 +0200 +++ gcc/cp/cxx-pretty-print.cc 2026-08-20 13:53:34.718015103 +0200 @@ -2860,8 +2860,14 @@ pp_cxx_compound_requirement (cxx_pretty_ pp->expression (TREE_OPERAND (t, 0)); pp_cxx_right_brace (pp); - if (COMPOUND_REQ_NOEXCEPT_P (t)) + if (TREE_OPERAND (t, 2) == boolean_true_node) pp_cxx_ws_string (pp, "noexcept"); + else if (TREE_OPERAND (t, 2) != boolean_false_node) + { + pp_cxx_ws_string (pp, "noexcept("); + pp->expression (TREE_OPERAND (t, 2)); + pp_cxx_right_paren (pp); + } if (tree type = TREE_OPERAND (t, 1)) { --- gcc/cp/mangle.cc.jj 2026-08-19 09:02:35.350546050 +0200 +++ gcc/cp/mangle.cc 2026-08-20 16:41:21.225644857 +0200 @@ -3214,15 +3214,23 @@ write_requirement (tree req) switch (tree_code code = TREE_CODE (req)) { /* # simple-requirement or compound-requirement - <requirement> ::= X <expression> [ N ] [ R <type-constraint> ] */ + <requirement> ::= X <expression> [ N ] [ R <type-constraint> ] + X <expression> C <expression> + [ R <type-constraint> ] */ case SIMPLE_REQ: case COMPOUND_REQ: write_char ('X'); write_expression (op); if (code == SIMPLE_REQ) break; - if (COMPOUND_REQ_NOEXCEPT_P (req)) + if (operand_equal_p (TREE_OPERAND (req, 2), boolean_true_node)) write_char ('N'); + else if (TREE_OPERAND (req, 2) != error_mark_node + && !operand_equal_p (TREE_OPERAND (req, 2), boolean_false_node)) + { + write_char ('C'); + write_expression (TREE_OPERAND (req, 2)); + } if (tree constr = TREE_OPERAND (req, 1)) { write_char ('R'); --- gcc/testsuite/g++.dg/cpp29/complex-req-noexcept1.C.jj 2026-08-20 15:33:37.653755051 +0200 +++ gcc/testsuite/g++.dg/cpp29/complex-req-noexcept1.C 2026-08-20 17:17:49.968363935 +0200 @@ -0,0 +1,73 @@ +// C++29 P3822R2 - Conditional noexcept specifiers in compound requirements +// { dg-do compile { target c++20 } } +// { dg-options "" } + +int foo (); +int bar () noexcept; +struct A { int foo (); }; +struct B { int foo () noexcept; }; +struct C { int foo (); char c[42]; }; +struct D { int foo () noexcept; char c[42]; }; +struct E { long foo (); }; +struct F { long foo () noexcept; }; +struct G { long foo (); char c[42]; }; +struct H { long foo () noexcept; char c[42]; }; +template <bool B> +struct J { constexpr operator bool () { return B; }; }; +template <typename T, typename U> +constexpr bool s = false; +template <typename T> +constexpr bool s <T, T> = true; +template <typename T, typename U> +concept S = s <T, U>; + +static_assert (!requires { { foo () } noexcept; }); +static_assert (!requires { { foo () } noexcept (true); }); // { dg-warning "conditional 'noexcept' in compound requirement only available with" "" { target c++26_down } } +static_assert (requires { { foo () } noexcept (false); }); // { dg-warning "conditional 'noexcept' in compound requirement only available with" "" { target c++26_down } } +static_assert (!requires { { foo () } noexcept (42 == 42); }); // { dg-warning "conditional 'noexcept' in compound requirement only available with" "" { target c++26_down } } +static_assert (requires { { foo () } noexcept (42 != 42); }); // { dg-warning "conditional 'noexcept' in compound requirement only available with" "" { target c++26_down } } +static_assert (!requires { { foo () } noexcept (J <true> {}); });// { dg-warning "conditional 'noexcept' in compound requirement only available with" "" { target c++26_down } } +static_assert (requires { { foo () } noexcept (J <false> {}); });// { dg-warning "conditional 'noexcept' in compound requirement only available with" "" { target c++26_down } } +static_assert (requires { { bar () } noexcept; }); +static_assert (requires { { bar () } noexcept (true); }); // { dg-warning "conditional 'noexcept' in compound requirement only available with" "" { target c++26_down } } +static_assert (requires { { bar () } noexcept (false); }); // { dg-warning "conditional 'noexcept' in compound requirement only available with" "" { target c++26_down } } +static_assert (requires { { bar () } noexcept (42 == 42); }); // { dg-warning "conditional 'noexcept' in compound requirement only available with" "" { target c++26_down } } +static_assert (requires { { bar () } noexcept (42 != 42); }); // { dg-warning "conditional 'noexcept' in compound requirement only available with" "" { target c++26_down } } +static_assert (requires { { bar () } noexcept (J <true> {}); });// { dg-warning "conditional 'noexcept' in compound requirement only available with" "" { target c++26_down } } +static_assert (requires { { bar () } noexcept (J <false> {}); });// { dg-warning "conditional 'noexcept' in compound requirement only available with" "" { target c++26_down } } + +template <typename T, bool B> +concept V = requires (T t) { { t.foo () } noexcept (B); }; // { dg-warning "conditional 'noexcept' in compound requirement only available with" "" { target c++26_down } } + +static_assert (V <A, false>); +static_assert (!V <A, true>); +static_assert (V <B, false>); +static_assert (V <B, true>); + +template <typename T> +concept W = requires (T t) { + { t.foo () } noexcept (sizeof (T) > sizeof (A)) -> S <int>; // { dg-warning "conditional 'noexcept' in compound requirement only available with" "" { target c++26_down } } +}; + +static_assert (W <A>); +static_assert (W <B>); +static_assert (!W <C>); +static_assert (W <D>); +static_assert (!W <E>); +static_assert (!W <F>); +static_assert (!W <G>); +static_assert (!W <H>); + +template <typename T> +struct I { static constexpr bool i = sizeof (T) > sizeof (A); }; +template <typename T> +concept Z = requires (T t) { { t.foo () } noexcept (I <T>::i); }; // { dg-warning "conditional 'noexcept' in compound requirement only available with" "" { target c++26_down } } + +static_assert (Z <A>); +static_assert (Z <B>); +static_assert (!Z <C>); +static_assert (Z <D>); +static_assert (Z <E>); +static_assert (Z <F>); +static_assert (!Z <G>); +static_assert (Z <H>); --- gcc/testsuite/g++.dg/cpp29/complex-req-noexcept2.C.jj 2026-08-20 16:26:29.493864020 +0200 +++ gcc/testsuite/g++.dg/cpp29/complex-req-noexcept2.C 2026-08-20 16:45:52.376233696 +0200 @@ -0,0 +1,39 @@ +// C++29 P3822R2 - Conditional noexcept specifiers in compound requirements +// { dg-do compile { target c++20 } } +// { dg-options "" } + +template <typename T, int N> +concept A = sizeof (T) < N; +template <typename T> +concept B = A <T, 1000>; +template <typename T> +struct C { using type = T; }; + +template <typename T> +void foo (int n) +requires requires { + T (); + n; + n == T (); + { T () + 1 } -> B; + { T () - 1 } noexcept; + { T () * 1 } noexcept -> A <1234>; + { T () + 2 } noexcept (true); // { dg-warning "conditional 'noexcept' in compound requirement only available with" "" { target c++26_down } } + { T () - 2 } noexcept (true) -> A <1234>; // { dg-warning "conditional 'noexcept' in compound requirement only available with" "" { target c++26_down } } + { T () * 2 } noexcept (false); // { dg-warning "conditional 'noexcept' in compound requirement only available with" "" { target c++26_down } } + { T () + 3 } noexcept (false) -> A <1234>; // { dg-warning "conditional 'noexcept' in compound requirement only available with" "" { target c++26_down } } + { T () - 3 } noexcept (sizeof (T) > 100); // { dg-warning "conditional 'noexcept' in compound requirement only available with" "" { target c++26_down } } + { T () * 3 } noexcept (sizeof (T) > 100) -> A <1234>; // { dg-warning "conditional 'noexcept' in compound requirement only available with" "" { target c++26_down } } + typename T; + typename C <T>; + typename C <T>::type; + typename C <decltype (n)>; + requires A <T, 256>; +} +{ +} + +template +void foo <int> (int); + +// { dg-final { scan-assembler "_Z3fooIiEviQrqXcvT__EXfL0p_XeqfL0p_cvS0__EXplcvS0__ELi1ER1BXmicvS0__ELi1ENXmlcvS0__ELi1ENR1AILi1234EEXplcvS0__ELi2ENXmicvS0__ELi2ENR1AILi1234EEXmlcvS0__ELi2EXplcvS0__ELi3ER1AILi1234EEXmicvS0__ELi3ECgtstS0_Li100EXmlcvS0__ELi3ECgtstS0_Li100ER1AILi1234EETS0_T1CIS0_ETNS2_4typeETS1_IiEQ1AIS0_Li256EEE" } } --- gcc/testsuite/g++.dg/cpp29/complex-req-noexcept3.C.jj 2026-08-20 16:55:21.258146332 +0200 +++ gcc/testsuite/g++.dg/cpp29/complex-req-noexcept3.C 2026-08-20 17:00:35.320255521 +0200 @@ -0,0 +1,46 @@ +// C++29 P3822R2 - Conditional noexcept specifiers in compound requirements +// { dg-do compile { target c++29 } } + +#include <concepts> +#include <memory> +#include <type_traits> +#include <utility> + +template <typename R, typename... Args> +struct vtbl { virtual auto call (Args &&...) -> R = 0; virtual ~vtbl () noexcept {}; }; + +template <typename T, typename R, typename... Args> +struct impl : vtbl <R, Args...> { + impl (auto &&y) : x { std::forward <decltype (y)> (y) } {} + auto call (Args &&...xs) -> R override { return x (static_cast <Args &&> (xs)...); } + T x; +}; + +template <typename F> +struct any_f; + +template <typename X, bool noexc, typename R, typename...Args> +concept invocable_r = requires (X x, Args...xs) { + { x (static_cast <Args> (xs)...) } noexcept (noexc) -> std::convertible_to <R>; +}; + +template <typename X, typename T> +concept not_same = !std::same_as <std::decay_t <X>, T>; + +template <typename R, typename... Args, bool noexc> +struct any_f <R (Args...) noexcept (noexc)> { + template <not_same <any_f> T> + any_f (T &&x) + requires invocable_r <T &, noexc, R, Args...> + : f (new impl <std::decay_t <T>, R, Args...> (std::forward <T> (x))) {} + auto operator () (std::convertible_to <Args> auto &&...xs) noexcept (noexc) -> R { + return f->call (std::forward <decltype (xs)> (xs)...); + } + std::unique_ptr <vtbl <R, Args...>> f; +}; + +int +main () +{ + any_f <int (long, long) noexcept> x ([] (long, long) noexcept -> int { return 2; }); +} --- gcc/testsuite/g++.dg/cpp29/complex-req-noexcept4.C.jj 2026-08-20 17:05:04.962912426 +0200 +++ gcc/testsuite/g++.dg/cpp29/complex-req-noexcept4.C 2026-08-20 17:34:41.880668366 +0200 @@ -0,0 +1,29 @@ +// C++29 P3822R2 - Conditional noexcept specifiers in compound requirements +// { dg-do compile { target c++20 } } +// { dg-options "" } + +int foo (); +int bar () noexcept; +template <bool N> +struct A {}; +template <bool N> +struct B { constexpr operator bool () { return N; }; }; +struct C { int foo (); }; +struct D { int foo () noexcept (true); }; + +static_assert (requires { { foo () } noexcept (B <false> {}); }); // { dg-warning "conditional 'noexcept' in compound requirement only available with" "" { target c++26_down } } +static_assert (!requires { { foo () } noexcept (B <true> {}); }); // { dg-warning "conditional 'noexcept' in compound requirement only available with" "" { target c++26_down } } +static_assert (requires { { bar () } noexcept (B <false> {}); }); // { dg-warning "conditional 'noexcept' in compound requirement only available with" "" { target c++26_down } } +static_assert (requires { { bar () } noexcept (B <true> {}); }); // { dg-warning "conditional 'noexcept' in compound requirement only available with" "" { target c++26_down } } + +template <typename T, typename U> +concept V = requires (T t) { { t.foo () } noexcept (U {}); }; // { dg-warning "conditional 'noexcept' in compound requirement only available with" "" { target c++26_down } } + +static_assert (!V <C, A <false>>); +static_assert (!V <C, A <true>>); +static_assert (!V <D, A <false>>); +static_assert (!V <D, A <true>>); +static_assert (V <C, B <false>>); +static_assert (!V <C, B <true>>); +static_assert (V <D, B <false>>); +static_assert (V <D, B <true>>); --- gcc/testsuite/g++.dg/cpp29/complex-req-noexcept5.C.jj 2026-08-20 17:34:18.478962415 +0200 +++ gcc/testsuite/g++.dg/cpp29/complex-req-noexcept5.C 2026-08-20 17:38:13.250012440 +0200 @@ -0,0 +1,27 @@ +// C++29 P3822R2 - Conditional noexcept specifiers in compound requirements +// { dg-do compile { target c++20 } } +// { dg-options "" } + +int foo (); +int bar () noexcept; +template <bool N> +struct A {}; +template <bool N> +struct B { constexpr operator bool () { return N; }; }; +struct C { int foo (); }; +struct D { int foo () noexcept (true); }; + +bool a = requires { { foo () } noexcept (A <false> {}); }; // { dg-warning "conditional 'noexcept' in compound requirement only available with" "" { target c++26_down } } +// { dg-error "could not convert 'A<false>\\\(\\\)' from 'A<false>' to 'bool'" "" { target *-*-* } .-1 } +bool b = requires { { foo () } noexcept (A <true> {}); }; // { dg-warning "conditional 'noexcept' in compound requirement only available with" "" { target c++26_down } } +// { dg-error "could not convert 'A<true>\\\(\\\)' from 'A<true>' to 'bool'" "" { target *-*-* } .-1 } + +template <typename T, typename U> +concept V = requires (T t) { { t.foo () } noexcept (U {}); }; // { dg-warning "conditional 'noexcept' in compound requirement only available with" "" { target c++26_down } } +// { dg-error "could not convert 'A<false>\\\(\\\)' from 'A<false>' to 'bool'" "" { target *-*-* } .-1 } +// { dg-error "could not convert 'A<true>\\\(\\\)' from 'A<true>' to 'bool'" "" { target *-*-* } .-2 } + +static_assert (V <C, A <false>>); // { dg-error "static assertion failed" } +static_assert (V <C, A <true>>); // { dg-error "static assertion failed" } +static_assert (V <D, A <false>>); // { dg-error "static assertion failed" } +static_assert (V <D, A <true>>); // { dg-error "static assertion failed" } --- gcc/testsuite/g++.dg/cpp29/feat-cxx29.C.jj 2026-08-06 11:49:25.894550497 +0200 +++ gcc/testsuite/g++.dg/cpp29/feat-cxx29.C 2026-08-20 17:01:07.882852265 +0200 @@ -487,8 +487,8 @@ #ifndef __cpp_concepts # error "__cpp_concepts" -#elif __cpp_concepts != 202002 -# error "__cpp_concepts != 202002" +#elif __cpp_concepts != 202606 +# error "__cpp_concepts != 202606" #endif #ifndef __cpp_using_enum Jakub
