[PATCH] c++: Implement C++29 P3822R2 - Conditional noexcept specifiers in compound requirements [PR125822]

Jakub Jelinek <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <aockT3ghScoHCPqm@tucnak>
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.