--- gcc/cp/cp-tree.def.jj	2024-07-25 21:34:46.791268760 +0200
+++ gcc/cp/cp-tree.def	2024-07-26 09:20:05.256197019 +0200
@@ -538,6 +538,12 @@ DEFTREECODE (ATOMIC_CONSTR, "atomic_cons
 DEFTREECODE (CONJ_CONSTR, "conj_constr", tcc_expression, 2)
 DEFTREECODE (DISJ_CONSTR, "disj_constr", tcc_expression, 2)
 
+/* Fold expanded constraint.
+   CONSTR_INFO provides source info to support diagnostics.
+   FOLD_CONSTR_EXPR is the constraint embedded in it,
+   FOLD_CONSTR_PACKS are the packs expanded by it.  */
+DEFTREECODE (FOLD_CONSTR, "fold_constr", tcc_expression, 2)
+
 /* The co_await expression is used to support coroutines.
 
   Op 0 is the cast expresssion (potentially modified by the
--- gcc/cp/cp-tree.h.jj	2024-07-26 08:34:18.104160097 +0200
+++ gcc/cp/cp-tree.h	2024-07-26 09:19:10.626908903 +0200
@@ -1679,11 +1679,12 @@ check_constraint_info (tree t)
 #define CONSTR_P(NODE)                  \
   (TREE_CODE (NODE) == ATOMIC_CONSTR    \
    || TREE_CODE (NODE) == CONJ_CONSTR   \
-   || TREE_CODE (NODE) == DISJ_CONSTR)
+   || TREE_CODE (NODE) == DISJ_CONSTR	\
+   || TREE_CODE (NODE) == FOLD_CONSTR)
 
 /* Valid for any normalized constraint.  */
 #define CONSTR_CHECK(NODE) \
-  TREE_CHECK3 (NODE, ATOMIC_CONSTR, CONJ_CONSTR, DISJ_CONSTR)
+  TREE_CHECK4 (NODE, ATOMIC_CONSTR, CONJ_CONSTR, DISJ_CONSTR, FOLD_CONSTR)
 
 /* The CONSTR_INFO stores normalization data for a constraint. It refers to
    the original expression and the expression or declaration
@@ -1724,6 +1725,18 @@ check_constraint_info (tree t)
 #define ATOMIC_CONSTR_EXPR(NODE) \
   CONSTR_EXPR (ATOMIC_CONSTR_CHECK (NODE))
 
+/* The constraint embedded in FOLD_CONSTR.  */
+#define FOLD_CONSTR_EXPR(NODE) \
+  TREE_OPERAND (FOLD_CONSTR_CHECK (NODE), 0)
+
+/* List of packs expanded by it.  */
+#define FOLD_CONSTR_PACKS(NODE) \
+  TREE_OPERAND (FOLD_CONSTR_CHECK (NODE), 1)
+
+/* True if FOLD_CONSTR has fold-operator ||, false for &&.  */
+#define FOLD_CONSTR_DISJ_P(NODE) \
+  TREE_STATIC (FOLD_CONSTR_CHECK (NODE))
+
 /* Whether a PARM_DECL represents a local parameter in a
    requires-expression.  */
 #define CONSTRAINT_VAR_P(NODE) \
--- gcc/cp/cp-objcp-common.cc.jj	2024-07-25 21:34:46.791268760 +0200
+++ gcc/cp/cp-objcp-common.cc	2024-07-26 08:34:40.532867127 +0200
@@ -705,6 +705,7 @@ cp_common_init_ts (void)
   MARK_TS_EXP (CONJ_CONSTR);
   MARK_TS_EXP (DISJ_CONSTR);
   MARK_TS_EXP (ATOMIC_CONSTR);
+  MARK_TS_EXP (FOLD_CONSTR);
   MARK_TS_EXP (NESTED_REQ);
   MARK_TS_EXP (REQUIRES_EXPR);
   MARK_TS_EXP (SIMPLE_REQ);
--- gcc/cp/constraint.cc.jj	2024-07-25 21:34:46.791268760 +0200
+++ gcc/cp/constraint.cc	2024-07-26 15:03:04.438445216 +0200
@@ -852,6 +852,39 @@ normalize_atom (tree t, tree args, norm_
   return atom;
 }
 
+/* Normalize {UNARY,BINARY}_{LEFT,RIGHT}_FOLD_EXPR.  */
+
+static tree
+normalize_fold_expr (tree t, tree args, norm_info info)
+{
+  if (cxx_dialect < cxx26
+      || (FOLD_EXPR_OP (t) != TRUTH_ANDIF_EXPR
+	  && FOLD_EXPR_OP (t) != TRUTH_ORIF_EXPR)
+      || FOLD_EXPR_MODIFY_P (t))
+    return normalize_atom (t, args, info);
+
+  tree norm
+    = normalize_expression (PACK_EXPANSION_PATTERN (FOLD_EXPR_PACK (t)),
+			    args, info);
+  tree ci = (info.generate_diagnostics
+	     ? build_tree_list (t, info.context) : NULL_TREE);
+  tree params = PACK_EXPANSION_PARAMETER_PACKS (FOLD_EXPR_PACK (t));
+  tree ret = build2 (FOLD_CONSTR, ci, norm, params);
+  if (FOLD_EXPR_OP (t) == TRUTH_ORIF_EXPR)
+    FOLD_CONSTR_DISJ_P (ret) = 1;
+  if (TREE_CODE (t) == BINARY_LEFT_FOLD_EXPR
+      || TREE_CODE (t) == BINARY_RIGHT_FOLD_EXPR)
+    {
+      tree init = normalize_expression (FOLD_EXPR_INIT (t), args, info);
+      tree_code code
+	= FOLD_EXPR_OP (t) == TRUTH_ANDIF_EXPR ? CONJ_CONSTR : DISJ_CONSTR;
+      if (TREE_CODE (t) == BINARY_LEFT_FOLD_EXPR)
+	std::swap (ret, init);
+      return build2 (code, ci, ret, init);
+    }
+  return ret;
+}
+
 /* Returns the normal form of an expression.  */
 
 static tree
@@ -869,6 +902,11 @@ normalize_expression (tree t, tree args,
       return normalize_logical_operation (t, args, CONJ_CONSTR, info);
     case TRUTH_ORIF_EXPR:
       return normalize_logical_operation (t, args, DISJ_CONSTR, info);
+    case UNARY_LEFT_FOLD_EXPR:
+    case UNARY_RIGHT_FOLD_EXPR:
+    case BINARY_LEFT_FOLD_EXPR:
+    case BINARY_RIGHT_FOLD_EXPR:
+      return normalize_fold_expr (t, args, info);
     default:
       return normalize_atom (t, args, info);
     }
@@ -1055,6 +1093,28 @@ atomic_constraints_identical_p (tree t1,
   return true;
 }
 
+/* Compare two fold expanded constraints T1 and T2.  */
+
+static bool
+fold_constraints_identical_p (tree t1, tree t2)
+{
+  gcc_assert (TREE_CODE (t1) == FOLD_CONSTR);
+  gcc_assert (TREE_CODE (t2) == FOLD_CONSTR);
+
+  if (FOLD_CONSTR_DISJ_P (t1) != FOLD_CONSTR_DISJ_P (t2))
+    return false;
+
+  tree p1 = FOLD_CONSTR_PACKS (t1);
+  tree p2 = FOLD_CONSTR_PACKS (t2);
+  for (; p1 && p2; p1 = TREE_CHAIN (p1), p2 = TREE_CHAIN (p2))
+    if (!template_args_equal (TREE_VALUE (p1), TREE_VALUE (p2)))
+      return false;
+  if (p1 || p2)
+    return false;
+  return constraints_equivalent_p (FOLD_CONSTR_EXPR (t1),
+				   FOLD_CONSTR_EXPR (t2));
+}
+
 /* True if T1 and T2 are equivalent, meaning they have the same syntactic
    structure and all corresponding constraints are identical.  */
 
@@ -1082,6 +1142,10 @@ constraints_equivalent_p (tree t1, tree
       if (!atomic_constraints_identical_p (t1, t2))
 	return false;
       break;
+    case FOLD_CONSTR:
+      if (!fold_constraints_identical_p (t1, t2))
+	return false;
+      break;
     default:
       gcc_unreachable ();
     }
@@ -1126,6 +1190,10 @@ add_constraint (tree t, hash& h)
     case ATOMIC_CONSTR:
       h.merge_hash (hash_atomic_constraint (t));
       break;
+    case FOLD_CONSTR:
+      h.add_int (FOLD_CONSTR_DISJ_P (t));
+      add_constraint (FOLD_CONSTR_EXPR (t), h);
+      break;
     default:
       gcc_unreachable ();
     }
@@ -2163,6 +2231,29 @@ tsubst_parameter_mapping (tree map, tree
       tree parm = TREE_VALUE (p);
       tree arg = TREE_PURPOSE (p);
       tree new_arg;
+      if (cxx_dialect >= cxx26 && ARGUMENT_PACK_P (arg))
+	{
+	  /* template_parm_to_arg for packs wraps the template parm
+	     with {,NON}TYPE_ARGUMENT_PACK with pack expansion.
+	     For packs expanded by fold expanded constraint undo this
+	     here.  */
+	  tree v = ARGUMENT_PACK_ARGS (arg);
+	  if (TREE_VEC_LENGTH (v) == 1
+	      && PACK_EXPANSION_P (TREE_VEC_ELT (v, 0)))
+	    {
+	      tree t = PACK_EXPANSION_PATTERN (TREE_VEC_ELT (v, 0));
+	      tree e = STRIP_REFERENCE_REF (t);
+	      if (TEMPLATE_PARM_P (e))
+		{
+		  int level;
+		  int index;
+		  template_parm_level_and_index (e, &level, &index);
+		  tree a = TMPL_ARG (args, level, index);
+		  if (!ARGUMENT_PACK_P (a))
+		    arg = t;
+		}
+	    }
+	}
       if (ARGUMENT_PACK_P (arg))
 	new_arg = tsubst_argument_pack (arg, args, complain, in_decl);
       else
@@ -2187,7 +2278,8 @@ tsubst_parameter_mapping (tree map, tree
 }
 
 tree
-tsubst_parameter_mapping (tree map, tree args, tsubst_flags_t complain, tree in_decl)
+tsubst_parameter_mapping (tree map, tree args, tsubst_flags_t complain,
+			  tree in_decl)
 {
   return tsubst_parameter_mapping (map, args, subst_info (complain, in_decl));
 }
@@ -2831,6 +2924,101 @@ satisfy_atom (tree t, tree args, sat_inf
   return cache.save (inst_cache.save (result));
 }
 
+/* Compute the satisfaction of a fold expanded constraint.  */
+
+static tree
+satisfy_fold (tree t, tree args, sat_info info)
+{
+  tree orig_args = args;
+  int len = -1;
+  auto_vec <int, 8> indices;
+  for (tree p = FOLD_CONSTR_PACKS (t); p; p = TREE_CHAIN (p))
+    {
+      int level, index;
+      template_parm_level_and_index (TREE_VALUE (p), &level, &index);
+      tree a = TMPL_ARG (orig_args, level, index);
+      int this_len = TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (a));
+      if (len == -1)
+	len = this_len;
+      else if (this_len != len)
+	{
+	  if (info.diagnose_unsatisfaction_p ())
+	    {
+	      diagnosing_failed_constraint failure (t, args, info.noisy ());
+	      tree first = TREE_VALUE (FOLD_CONSTR_PACKS (t));
+	      cp_expr fold_expr = CONSTR_EXPR (t);
+	      inform (fold_expr.get_location (),
+		      "fold expanded constraint not satisfied because "
+		      "of pack length mismatch");
+	      if (TREE_CODE (first) == TYPE_PACK_EXPANSION)
+		inform (fold_expr.get_location (),
+			"%qT has length %d", first, len);
+	      else
+		inform (fold_expr.get_location (),
+			"%qE has length %d", first, len);
+	      if (TREE_CODE (TREE_VALUE (p)) == TYPE_PACK_EXPANSION)
+		inform (fold_expr.get_location (),
+			"%qT has length %d", TREE_VALUE (p), this_len);
+	      else
+		inform (fold_expr.get_location (),
+			"%qE has length %d", TREE_VALUE (p), this_len);
+	    }
+	  return error_mark_node;
+	}
+      if (len != 0)
+	{
+	  indices.safe_push (level);
+	  indices.safe_push (index);
+	}
+    }
+  gcc_checking_assert (len != -1);
+  if (len == 0)
+    {
+      /* For N = 0 fold expanded constraint with && fold operator is
+	 satisfied.  */
+      if (!FOLD_CONSTR_DISJ_P (t))
+	return boolean_true_node;
+      if (info.diagnose_unsatisfaction_p ())
+	{
+	  diagnosing_failed_constraint failure (t, args, info.noisy ());
+	  cp_expr fold_expr = CONSTR_EXPR (t);
+	  inform (fold_expr.get_location (),
+		  "fold expanded constraint not satisfied because "
+		  "of empty pack with %<||%> fold operator");
+	}
+      return boolean_false_node;
+    }
+  for (int i = 0; i < len; ++i)
+    {
+      unsigned j;
+      int level, index;
+      args = orig_args;
+      FOR_EACH_VEC_ELT (indices, j, level)
+	{
+	  ++j;
+	  indices.iterate (j, &index);
+	  if (orig_args == args)
+	    args = copy_node (orig_args);
+	  if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (orig_args))
+	    {
+	      tree v = TMPL_ARGS_LEVEL (orig_args, level);
+	      if (TMPL_ARGS_LEVEL (args, level) == v)
+		SET_TMPL_ARGS_LEVEL (args, level, copy_node (v));
+	    }
+	  tree a = TMPL_ARG (orig_args, level, index);
+	  TMPL_ARG (args, level, index)
+	    = TREE_VEC_ELT (ARGUMENT_PACK_ARGS (a), i);
+	}
+      tree result = satisfy_constraint_r (FOLD_CONSTR_EXPR (t), args, info);
+      if (result == error_mark_node)
+	return result;
+      if (result == (FOLD_CONSTR_DISJ_P (t)
+		     ? boolean_true_node : boolean_false_node))
+	return result;
+    }
+  return FOLD_CONSTR_DISJ_P (t) ? boolean_false_node : boolean_true_node;
+}
+
 /* Determine if the normalized constraint T is satisfied.
    Returns boolean_true_node if the expression/constraint is
    satisfied, boolean_false_node if not, and error_mark_node
@@ -2856,6 +3044,8 @@ satisfy_constraint_r (tree t, tree args,
       return satisfy_disjunction (t, args, info);
     case ATOMIC_CONSTR:
       return satisfy_atom (t, args, info);
+    case FOLD_CONSTR:
+      return satisfy_fold (t, args, info);
     default:
       gcc_unreachable ();
     }
--- gcc/cp/error.cc.jj	2024-07-25 21:34:46.793268734 +0200
+++ gcc/cp/error.cc	2024-07-26 08:41:23.555602719 +0200
@@ -3097,6 +3097,7 @@ dump_expr (cxx_pretty_printer *pp, tree
     case ATOMIC_CONSTR:
     case CONJ_CONSTR:
     case DISJ_CONSTR:
+    case FOLD_CONSTR:
       {
         pp_cxx_constraint (cxx_pp, t);
         break;
--- gcc/cp/logic.cc.jj	2024-07-25 21:34:46.793268734 +0200
+++ gcc/cp/logic.cc	2024-07-26 09:22:29.047325077 +0200
@@ -65,6 +65,8 @@ struct clause
     m_terms.push_back (t);
     if (TREE_CODE (t) == ATOMIC_CONSTR)
       m_set.add (t);
+    else if (TREE_CODE (t) == FOLD_CONSTR)
+      m_fold.safe_push (t);
 
     m_current = m_terms.begin ();
   }
@@ -74,8 +76,11 @@ struct clause
      copied list of terms.  */
 
   clause (clause const& c)
-    : m_terms (c.m_terms), m_set (c.m_set), m_current (m_terms.begin ())
+    : m_terms (c.m_terms), m_set (c.m_set), m_fold (c.m_fold.length ()),
+      m_current (m_terms.begin ())
   {
+    for (auto v : &c.m_fold)
+      m_fold.quick_push (v);
     std::advance (m_current, std::distance (c.begin (), c.current ()));
   }
 
@@ -109,6 +114,8 @@ struct clause
 	if (m_set.add (t))
 	  return std::make_pair (m_terms.erase (iter), true);
       }
+    else if (TREE_CODE (t) == FOLD_CONSTR)
+      m_fold.safe_push (t);
     *iter = t;
     return std::make_pair (iter, false);
   }
@@ -126,6 +133,8 @@ struct clause
 	if (m_set.add (t))
 	  return std::make_pair (iter, false);
       }
+    else if (TREE_CODE (t) == FOLD_CONSTR)
+      m_fold.safe_push (t);
     return std::make_pair (m_terms.insert (iter, t), true);
   }
 
@@ -166,6 +175,12 @@ struct clause
     return m_set.contains (t);
   }
 
+  /* Returns vector of FOLD_CONSTR terms.  */
+
+  auto_vec<tree> &folds ()
+  {
+    return m_fold;
+  }
 
   /* Returns an iterator to the first clause in the formula.  */
 
@@ -204,6 +219,7 @@ struct clause
 
   std::list<tree> m_terms; /* The list of terms.  */
   hash_set<tree, false, atom_hasher> m_set; /* The set of atomic constraints.  */
+  auto_vec<tree> m_fold; /* The vector of fold expanded constraints.  */
   iterator m_current; /* The current term.  */
 };
 
@@ -340,7 +356,7 @@ conjunction_p (tree t)
 static inline bool
 atomic_p (tree t)
 {
-  return TREE_CODE (t) == ATOMIC_CONSTR;
+  return TREE_CODE (t) == ATOMIC_CONSTR || TREE_CODE (t) == FOLD_CONSTR;
 }
 
 /* Recursively count the number of clauses produced when converting T
@@ -626,7 +642,7 @@ decompose_disjunction (formula& f, claus
     branch_clause (f, c, t);
 }
 
-/* An atomic constraint is already decomposed.  */
+/* An atomic or fold expanded constraint is already decomposed.  */
 inline void
 decompose_atom (clause& c)
 {
@@ -691,13 +707,48 @@ derive_atomic_proof (clause& c, tree t)
   return c.contains (t);
 }
 
+/* Derive a proof of the fold expanded constraint T in clause C.  */
+
+static bool
+derive_fold_proof (clause& c, tree t, rules r)
+{
+  auto_vec<tree> &folds = c.folds ();
+  for (auto v : &folds)
+    /* [temp.constr.order]/1 - a fold expanded constraint A subsumes
+       another fold expanded constraint B if they are compatible for
+       subsumption, have the same fold-operator, and the constraint
+       of A subsumes that of B.  */
+    if (FOLD_CONSTR_DISJ_P (v) == FOLD_CONSTR_DISJ_P (t))
+      {
+	bool compat = false;
+	for (tree p1 = FOLD_CONSTR_PACKS (t); p1 && !compat;
+	     p1 = TREE_CHAIN (p1))
+	  for (tree p2 = FOLD_CONSTR_PACKS (v); p2;
+	       p2 = TREE_CHAIN (p2))
+	    /* [temp.constr.fold]/5 - Two fold expanded constraints are
+	       compatible for subsumption if their respective constraints
+	       both contain an equivalent unexpanded pack.  */
+	    if (template_args_equal (TREE_VALUE (p1), TREE_VALUE (p2)))
+	      {
+		compat = true;
+		break;
+	      }
+	if (compat
+	    && (r == left
+		? subsumes (FOLD_CONSTR_EXPR (v), FOLD_CONSTR_EXPR (t))
+		: subsumes (FOLD_CONSTR_EXPR (t), FOLD_CONSTR_EXPR (v))))
+	  return true;
+      }
+  return false;
+}
+
 /* Derive a proof of T from the terms in C.  */
 
 static bool
 derive_proof (clause& c, tree t, rules r)
 {
   switch (TREE_CODE (t))
-  {
+    {
     case CONJ_CONSTR:
       if (r == left)
         return derive_proof_for_both_operands (c, t, r);
@@ -708,9 +759,13 @@ derive_proof (clause& c, tree t, rules r
         return derive_proof_for_either_operand (c, t, r);
       else
 	return derive_proof_for_both_operands (c, t, r);
-    default:
+    case ATOMIC_CONSTR:
       return derive_atomic_proof (c, t);
-  }
+    case FOLD_CONSTR:
+      return derive_fold_proof (c, t, r);
+    default:
+      gcc_unreachable ();
+    }
 }
 
 /* Key/value pair for caching subsumption results.  This associates a pair of
@@ -787,7 +842,7 @@ save_subsumption (tree t1, tree t2, bool
 static bool
 subsumes_constraints_nonnull (tree lhs, tree rhs)
 {
-  auto_timevar time (TV_CONSTRAINT_SUB);
+  auto_cond_timevar time (TV_CONSTRAINT_SUB);
 
   if (bool *b = lookup_subsumption (lhs, rhs))
     return *b;
--- gcc/cp/cxx-pretty-print.cc.jj	2024-07-25 21:34:46.793268734 +0200
+++ gcc/cp/cxx-pretty-print.cc	2024-07-26 14:19:27.435984262 +0200
@@ -1259,6 +1259,7 @@ cxx_pretty_printer::expression (tree t)
     case ATOMIC_CONSTR:
     case CONJ_CONSTR:
     case DISJ_CONSTR:
+    case FOLD_CONSTR:
       pp_cxx_constraint (this, t);
       break;
 
@@ -2882,6 +2883,19 @@ pp_cxx_disjunction (cxx_pretty_printer *
 }
 
 void
+pp_cxx_fold_expanded_constraint (cxx_pretty_printer *pp, tree t)
+{
+  pp_left_paren (pp);
+  pp_cxx_constraint (pp, FOLD_CONSTR_EXPR (t));
+  pp_space (pp);
+  if (FOLD_CONSTR_DISJ_P (t))
+    pp_string (pp, "\\/");
+  else
+    pp_string (pp, "/\\");
+  pp_string (pp, " ...)");
+}
+
+void
 pp_cxx_constraint (cxx_pretty_printer *pp, tree t)
 {
   if (t == error_mark_node)
@@ -2901,6 +2915,10 @@ pp_cxx_constraint (cxx_pretty_printer *p
       pp_cxx_disjunction (pp, t);
       break;
 
+    case FOLD_CONSTR:
+      pp_cxx_fold_expanded_constraint (pp, t);
+      break;
+
     case EXPR_PACK_EXPANSION:
       pp->expression (TREE_OPERAND (t, 0));
       break;
--- gcc/testsuite/g++.dg/concepts/diagnostic3.C.jj	2023-10-16 17:25:32.456781462 +0200
+++ gcc/testsuite/g++.dg/concepts/diagnostic3.C	2024-07-26 09:32:49.042262192 +0200
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++2a } }
+// { dg-do compile { target c++20 } }
 
 template<typename T>
   inline constexpr bool foo_v = false;
@@ -7,7 +7,7 @@ template<typename T>
   concept foo = (bool)(foo_v<T> | foo_v<T&>);
 
 template<typename... Ts>
-requires (foo<Ts> && ...) // { dg-message "19:with Ts = .int, char... evaluated to .false." }
+requires (foo<Ts> && ...) // { dg-message "19:with Ts = .int, char... evaluated to .false." "" { target c++23_down } }
 void
 bar()
 { }
@@ -16,7 +16,7 @@ template<int>
 struct S { };
 
 template<int... Is>
-requires (foo<S<Is>> && ...) // { dg-message "22:with Is = .2, 3, 4... evaluated to .false." }
+requires (foo<S<Is>> && ...) // { dg-message "22:with Is = .2, 3, 4... evaluated to .false." "" { target c++23_down } }
 void
 baz()
 { }
--- gcc/testsuite/g++.dg/concepts/variadic2.C.jj	2024-07-25 21:34:46.809268529 +0200
+++ gcc/testsuite/g++.dg/concepts/variadic2.C	2024-07-26 08:34:40.535867087 +0200
@@ -13,6 +13,7 @@ constexpr int f(Ts...) { return 1; }
 
 int main()
 {
-  static_assert(f(42) == 1); // { dg-error "ambiguous" }
-  // The associated constraints of the two functions are incomparable.
+  static_assert(f(42) == 1); // { dg-error "ambiguous" "" { target c++23_down } }
+  // The associated constraints of the two functions are incomparable before
+  // C++26.
 }
--- gcc/testsuite/g++.dg/concepts/variadic4.C.jj	2024-07-25 21:34:46.809268529 +0200
+++ gcc/testsuite/g++.dg/concepts/variadic4.C	2024-07-26 08:34:40.535867087 +0200
@@ -12,9 +12,9 @@ struct zip;
 
 template<Sequence... Seqs>
     requires requires { typename list<Seqs...>; } // && (Sequence<Seqs> && ...)
-struct zip<Seqs...> {}; // { dg-error "does not specialize" }
+struct zip<Seqs...> {}; // { dg-error "does not specialize" "" { target c++23_down } }
 // The constraints of the specialization and the sequence are not
-// comparable; the specializations are unordered.
+// comparable before C++26; the specializations are unordered.
 
 int main()
 {
--- gcc/testsuite/g++.dg/cpp2a/concepts-requires33.C	2022-12-05 11:10:37.712671571 +0100
+++ gcc/testsuite/g++.dg/cpp2a/concepts-requires33.C	2024-07-26 18:37:41.867864077 +0200
@@ -2,7 +2,7 @@
 // { dg-do compile { target c++20 } }
 
 template<class... T>
-void f() requires (requires (T x) { true; } && ...);
+void f() requires (requires (T x) { true; } && ...); // { dg-error "invalid parameter type 'void'" "" { target c++26 } }
 
 int main() {
   f<int>();
--- gcc/testsuite/g++.dg/cpp26/fold-constr1.C.jj	2024-07-26 08:34:40.535867087 +0200
+++ gcc/testsuite/g++.dg/cpp26/fold-constr1.C	2024-07-26 08:34:40.535867087 +0200
@@ -0,0 +1,37 @@
+// P2963R3 - Ordering of constraints involving fold expressions
+// { dg-do compile { target c++20 } }
+
+template <class U> concept isint = __is_same (U, int);
+
+template <class... V> requires (isint<V> && ...)
+constexpr int foo (V...) { return 1; };
+
+template <class... U> requires (... || isint<U>)
+constexpr int bar (U...) { return 1; };
+
+template <class T, class... S> requires (isint<S> && ... && isint<T>)
+constexpr int baz (T, S...) { return 1; }
+
+template <class T, class... R> requires (isint<T> || ... || isint<R>)
+constexpr int qux (T, R...) { return 1; }
+
+int v1 = foo ();
+int v2 = bar ();			// { dg-error "no matching function for call to" }
+int v3 = foo (1, 2);
+int v4 = bar (1, 2);
+int v5 = foo (1L, 2);			// { dg-error "no matching function for call to" }
+int v6 = foo (1, 2L);			// { dg-error "no matching function for call to" }
+int v7 = bar (1L, 2);
+int v8 = bar (2L, 3.0, 4, 5.0);
+int v9 = bar (2LL, 3.0f, 5.0, 6ULL, 2U);// { dg-error "no matching function for call to" }
+int v10 = baz ();			// { dg-error "no matching function for call to" }
+int v11 = baz (1);
+int v12 = baz (1L);			// { dg-error "no matching function for call to" }
+int v13 = baz (1, 2, 3, 4, 5);
+int v14 = baz (1, 2, 3L, 4, 5);		// { dg-error "no matching function for call to" }
+int v15 = qux ();			// { dg-error "no matching function for call to" }
+int v16 = qux (1);
+int v17 = qux (1L);			// { dg-error "no matching function for call to" }
+int v18 = qux (1, 2.0, 3LL);
+int v19 = qux (1L, 2.0f, 3, 4ULL);
+int v20 = qux (0.0f, 1L, 2.0, 3L);	// { dg-error "no matching function for call to" }
--- gcc/testsuite/g++.dg/cpp26/fold-constr2.C.jj	2024-07-26 08:34:40.535867087 +0200
+++ gcc/testsuite/g++.dg/cpp26/fold-constr2.C	2024-07-26 08:34:40.535867087 +0200
@@ -0,0 +1,56 @@
+// P2963R3 - Ordering of constraints involving fold expressions
+// { dg-do compile { target c++20 } }
+
+template <class T> concept C1 = true;
+template <class T> concept C2 = C1<T> && true;
+template <class T> concept C3 = C1<T> && __is_same (T, int);
+
+template <class T> requires (C1<T>)
+constexpr bool foo (T) { return false; };
+template <class... T> requires (C2<T> && ...)
+constexpr bool foo (T...) { return true; };
+
+static_assert (!foo (0));
+static_assert (!foo (1));
+
+template <class... T> requires (C1<T> && ...)
+constexpr bool bar (T...) { return false; };
+template <class... T> requires (C2<T> && ...)
+constexpr bool bar (T...) { return true; };
+
+static_assert (bar (0));		// { dg-error "call of overloaded 'bar\\\(int\\\)' is ambiguous" "" { target c++23_down } }
+static_assert (bar ());			// { dg-error "call of overloaded 'bar\\\(\\\)' is ambiguous" "" { target c++23_down } }
+static_assert (bar (1, 2));		// { dg-error "call of overloaded 'bar\\\(int, int\\\)' is ambiguous" "" { target c++23_down } }
+
+template <class... T> requires (C1<T> && ...)
+constexpr bool baz (T...) { return false; };
+template <class... T> requires (... && (C1<T> && true))
+constexpr bool baz (T...) { return true; };
+
+static_assert (baz (0));		// { dg-error "call of overloaded 'baz\\\(int\\\)' is ambiguous" "" { target c++23_down } }
+static_assert (baz ());			// { dg-error "call of overloaded 'baz\\\(\\\)' is ambiguous" "" { target c++23_down } }
+static_assert (baz (1, 2));		// { dg-error "call of overloaded 'baz\\\(int, int\\\)' is ambiguous" "" { target c++23_down } }
+
+template <typename... T> requires (C1<T> || ... || true)
+constexpr bool qux (T...) { return false; };
+template <typename... T> requires (C2<T> && ... && true)
+constexpr bool qux (T...) { return true; };
+
+static_assert (qux (0));		// { dg-error "call of overloaded 'qux\\\(int\\\)' is ambiguous" "" { target c++23_down } }
+static_assert (qux ());			// { dg-error "call of overloaded 'qux\\\(\\\)' is ambiguous" "" { target c++23_down } }
+
+constexpr bool quux (C1 auto...) { return false; }
+constexpr bool quux (C3 auto...) { return true; }
+
+static_assert (quux ());		// { dg-error "call of overloaded 'quux\\\(\\\)' is ambiguous" "" { target c++23_down } }
+static_assert (quux (0, 0));		// { dg-error "call of overloaded 'quux\\\(int, int\\\)' is ambiguous" "" { target c++23_down } }
+static_assert (!quux (0L, 0));
+
+template <C1... T>
+constexpr bool corge (C1 auto...) { return false; }
+template <C3... T>
+constexpr bool corge (C3 auto...) { return true; }
+
+static_assert (corge ());		// { dg-error "call of overloaded 'corge\\\(\\\)' is ambiguous" "" { target c++23_down } }
+static_assert (corge (0, 0));		// { dg-error "call of overloaded 'corge\\\(int, int\\\)' is ambiguous" "" { target c++23_down } }
+static_assert (!corge (0L, 0));
--- gcc/testsuite/g++.dg/cpp26/fold-constr3.C.jj	2024-07-26 08:34:40.535867087 +0200
+++ gcc/testsuite/g++.dg/cpp26/fold-constr3.C	2024-07-26 11:12:09.129830502 +0200
@@ -0,0 +1,15 @@
+// P2963R3 - Ordering of constraints involving fold expressions
+// { dg-do compile { target c++20 } }
+
+template <typename ...V> struct A;
+struct Thingy {
+  static constexpr int compare (const Thingy &) { return 1; }
+};
+template <typename ...T, typename ...U>
+void f (A<T ...> *, A<U ...> *)
+requires (T::compare (U{}) && ...);	// { dg-error "has type 'int', not 'bool'" "" { target c++26 } }
+void
+g (A<Thingy, Thingy> *ap)
+{
+  f (ap, ap);				// { dg-error "no matching function for call to" "" { target c++26 } }
+}
--- gcc/testsuite/g++.dg/cpp26/fold-constr4.C.jj	2024-07-26 08:34:40.535867087 +0200
+++ gcc/testsuite/g++.dg/cpp26/fold-constr4.C	2024-07-26 08:34:40.535867087 +0200
@@ -0,0 +1,48 @@
+// P2963R3 - Ordering of constraints involving fold expressions
+// { dg-do compile { target c++20 } }
+
+template <class T> concept C1 = true;
+template <class T> concept C2 = C1<T> && true;
+
+template <class... T> requires (C1<T> && ...)
+constexpr bool foo (T...) { return false; };
+template <class... T> requires (C2<T> || ...)
+constexpr bool foo (T...) { return true; };
+
+static_assert (foo (0));	// { dg-error "call of overloaded 'foo\\\(int\\\)' is ambiguous" }
+
+template <class... T> requires (C1<T> || ...)
+constexpr bool bar (T...) { return false; };
+template <class... T> requires (C2<T> && ...)
+constexpr bool bar (T...) { return true; };
+
+static_assert (bar (0));	// { dg-error "call of overloaded 'bar\\\(int\\\)' is ambiguous" }
+
+template <class... T> requires (C1<T> || ...)
+constexpr bool baz (T...) { return false; };
+template <class... T> requires (C2<T> || ...)
+constexpr bool baz (T...) { return true; };
+
+static_assert (baz (0));	// { dg-error "call of overloaded 'baz\\\(int\\\)' is ambiguous" "" { target c++23_down } }
+static_assert (baz ());		// { dg-error "no matching function for call to 'baz\\\(\\\)'" }
+static_assert (baz (1, 2));	// { dg-error "call of overloaded 'baz\\\(int, int\\\)' is ambiguous" "" { target c++23_down } }
+
+template <class... T>
+struct U {
+  template <class... V> requires (... && C1<V>)
+  static constexpr bool foo () { return false; }
+  template <class... V> requires (... && C2<V>)
+  static constexpr bool foo () { return true; }
+  template <class... V> requires (... && C1<T>)
+  static constexpr bool bar () { return false; }
+  template <class... V> requires (... && C2<T>)
+  static constexpr bool bar () { return true; }
+  template <class... V> requires (... && C1<V>)
+  static constexpr bool baz () { return false; }
+  template <class... V> requires (... && C2<T>)
+  static constexpr bool baz () { return true; }
+};
+
+static_assert (U<int>::foo<int> ());	// { dg-error "call of overloaded 'foo\\\(\\\)' is ambiguous" "" { target c++23_down } }
+static_assert (U<int>::bar<int> ());	// { dg-error "call of overloaded 'bar\\\(\\\)' is ambiguous" "" { target c++23_down } }
+static_assert (U<int>::baz<int> ());	// { dg-error "call of overloaded 'baz\\\(\\\)' is ambiguous" }
--- gcc/testsuite/g++.dg/cpp26/fold-constr5.C.jj	2024-07-26 08:34:40.535867087 +0200
+++ gcc/testsuite/g++.dg/cpp26/fold-constr5.C	2024-07-26 13:37:12.802463309 +0200
@@ -0,0 +1,77 @@
+// P2963R3 - Ordering of constraints involving fold expressions
+// { dg-do compile { target c++20 } }
+
+struct A {
+  using type = int;
+};
+struct B {
+  using type = long;
+};
+
+template <class T> concept C = sizeof (T) < sizeof (int) * 64;
+
+template <class... T> requires (C<typename T::type> && ...)	// { dg-error "is not a class, struct, or union type" "" { target c++23_down } }
+constexpr bool foo () { return true; };
+
+static_assert (foo <> ());
+static_assert (foo <A> ());
+static_assert (foo <B, A, A, B> ());
+static_assert (foo <int> ());					// { dg-error "no matching function for call" }
+static_assert (foo <B, long> ());				// { dg-error "no matching function for call" }
+static_assert (foo <unsigned, A, A> ());			// { dg-error "no matching function for call" }
+// { dg-error "is not a class, struct, or union type" "" { target c++26 } .-3 }
+// { dg-error "is not a class, struct, or union type" "" { target c++26 } .-3 }
+// { dg-error "is not a class, struct, or union type" "" { target c++26 } .-3 }
+
+template <class T, class... U> requires (C<typename U::type> && ... && C<typename T::type>)	// { dg-error "is not a class, struct, or union type" "" { target c++23_down } }
+constexpr bool bar () { return true; };
+
+static_assert (bar <A> ());
+static_assert (bar <B, A, A, B> ());
+static_assert (bar <int> ());					// { dg-error "no matching function for call" }
+static_assert (bar <B, long> ());				// { dg-error "no matching function for call" }
+static_assert (bar <unsigned, A, A> ());			// { dg-error "no matching function for call" }
+// { dg-error "is not a class, struct, or union type" "" { target c++26 } .-3 }
+// { dg-error "is not a class, struct, or union type" "" { target c++26 } .-3 }
+// { dg-error "is not a class, struct, or union type" "" { target c++26 } .-3 }
+
+template <class T, class... U> requires (C<typename T::type> && ... && C<typename U::type>)	// { dg-error "is not a class, struct, or union type" "" { target c++23_down } }
+constexpr bool baz () { return true; };
+
+static_assert (baz <A> ());
+static_assert (baz <B, A, A, B> ());
+static_assert (baz <int> ());					// { dg-error "no matching function for call" }
+static_assert (baz <B, long> ());				// { dg-error "no matching function for call" }
+static_assert (baz <unsigned, A, A> ());			// { dg-error "no matching function for call" }
+// { dg-error "is not a class, struct, or union type" "" { target c++26 } .-3 }
+// { dg-error "is not a class, struct, or union type" "" { target c++26 } .-3 }
+// { dg-error "is not a class, struct, or union type" "" { target c++26 } .-3 }
+
+template <class... T> requires (C<typename T::type> || ...)	// { dg-error "is not a class, struct, or union type" "" { target c++23_down } }
+constexpr bool qux () { return true; };
+
+static_assert (qux <> ());					// { dg-error "no matching function for call" }
+static_assert (qux <A> ());
+static_assert (qux <B, A, A, B> ());
+static_assert (qux <int> ());					// { dg-error "no matching function for call" }
+static_assert (qux <B, long> ());				// { dg-error "no matching function for call" "" { target c++23_down } }
+static_assert (qux <unsigned, A, A> ());			// { dg-error "no matching function for call" "" { target c++23_down } }
+// { dg-error "is not a class, struct, or union type" "" { target c++26 } .-3 }
+
+template <class T, class... U> requires (C<typename U::type> || ... || C<typename T::type>)	// { dg-error "is not a class, struct, or union type" "" { target c++23_down } }
+constexpr bool corge () { return true; };
+
+static_assert (corge <A> ());
+static_assert (corge <B, A, A, B> ());
+static_assert (corge <int> ());					// { dg-error "no matching function for call" }
+static_assert (corge <B, long> ());				// { dg-error "no matching function for call" "" { target c++23_down } }
+static_assert (corge <unsigned, A, A> ());			// { dg-error "no matching function for call" "" { target c++23_down } }
+
+template <class T, class... U> requires (C<typename T::type> || ... || C<typename U::type>)	// { dg-error "is not a class, struct, or union type" "" { target c++23_down } }
+constexpr bool garply () { return true; };
+
+static_assert (garply <A> ());
+static_assert (garply <B, A, A, B> ());
+static_assert (garply <int> ());				// { dg-error "no matching function for call" }
+static_assert (garply <B, long> ());				// { dg-error "no matching function for call" "" { target c++23_down } }
+static_assert (garply <unsigned, A, A> ());			// { dg-error "no matching function for call" "" { target c++23_down } }
--- gcc/testsuite/g++.dg/cpp26/fold-constr6.C.jj	2024-07-26 08:34:40.535867087 +0200
+++ gcc/testsuite/g++.dg/cpp26/fold-constr6.C	2024-07-26 14:32:28.121132795 +0200
@@ -0,0 +1,20 @@
+// P2963R3 - Ordering of constraints involving fold expressions
+// { dg-do compile { target c++20 } }
+
+template <class T> concept C1 = true;
+template <class T> concept C2 = C1<T> && true;
+
+template <class... T>
+struct U {
+  template <class... V> requires ((C1<T> && ...) && ... && C1<V>)
+  static constexpr bool foo () { return false; }
+  template <class... V> requires ((C2<T> && ...) && ... && C2<V>)
+  static constexpr bool foo () { return true; }
+  template <class... V> requires ((C1<T> && ...) && ... && C1<V>)
+  static constexpr bool bar () { return false; }
+  template <class... V> requires ((C2<V> && ...) && ... && C2<T>)
+  static constexpr bool bar () { return true; }
+};
+
+static_assert (U<int>::foo<int> ());	// { dg-error "call of overloaded 'foo\\\(\\\)' is ambiguous" "" { target c++23_down } }
+static_assert (U<int>::bar<int> ());	// { dg-error "call of overloaded 'bar\\\(\\\)' is ambiguous" "" { target c++23_down } }
--- gcc/testsuite/g++.dg/cpp26/fold-constr7.C.jj	2024-07-26 11:35:01.499085336 +0200
+++ gcc/testsuite/g++.dg/cpp26/fold-constr7.C	2024-07-26 15:11:46.186674513 +0200
@@ -0,0 +1,11 @@
+// P2963R3 - Ordering of constraints involving fold expressions
+// { dg-do compile { target c++20 } }
+
+template <class T> concept C1 = true;
+template <class T> concept C2 = C1<T> && true;
+
+template <class... T> requires ((((sizeof (T) + ...) < 8 * sizeof (int)) && C2<T>) && ...)
+constexpr bool foo (T...) { return true; };
+
+static_assert (foo (0));
+static_assert (foo (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)); // { dg-error "no matching function for call" }
--- gcc/testsuite/g++.dg/cpp26/fold-constr8.C.jj	2024-07-26 15:05:59.636183243 +0200
+++ gcc/testsuite/g++.dg/cpp26/fold-constr8.C	2024-07-26 15:05:15.027759668 +0200
@@ -0,0 +1,22 @@
+// P2963R3 - Ordering of constraints involving fold expressions
+// { dg-do compile { target c++20 } }
+
+template <class T> concept C = __is_same (T, int);
+
+template <class ...T>
+struct A {};
+
+template <class ...T, class ...U> requires ((C<T> && C<U>) && ...)	// { dg-error "mismatched argument pack lengths while expanding '\\\(C<T> \\\&\\\& C<U>\\\)'" "" { target c++23_down } }
+constexpr bool foo (A<T...>, A<U...>) { return true; };
+// { dg-message "fold expanded constraint not satisfied because of pack length mismatch" "" { target c++26 } .-2 }
+// { dg-message "'U' has length 3" "" { target c++26 } .-3 }
+// { dg-message "'T' has length 2" "" { target c++26 } .-4 }
+
+static_assert (foo (A<int, int, int> {}, A<int, int, int> {}));
+static_assert (foo (A<int, int> {}, A<int, int, int> {}));	// { dg-error "no matching function for call to" }
+
+template <class ...T> requires (C<T> || ...)			// { dg-message "fold expanded constraint not satisfied because of empty pack with '||' fold operator" "" { target c++26 } }
+constexpr bool bar (T...) { return true; };
+
+static_assert (bar (0));
+static_assert (bar ());						// { dg-error "no matching function for call to" }
--- gcc/testsuite/g++.dg/cpp26/fold-constr9.C.jj	2024-07-26 15:12:12.570331261 +0200
+++ gcc/testsuite/g++.dg/cpp26/fold-constr9.C	2024-07-26 15:12:06.613408758 +0200
@@ -0,0 +1,11 @@
+// P2963R3 - Ordering of constraints involving fold expressions
+// { dg-do compile { target c++20 } }
+
+template <class T> concept C = __is_same (T, int);
+
+template <class... T> requires ((C<T> && ...) && ... && C<T>)
+constexpr bool foo (T...) { return true; }
+
+static_assert (foo ());
+static_assert (foo (1, 2, 3));
+static_assert (foo (1L, 2L)); // { dg-error "no matching function for call" }
--- gcc/testsuite/g++.dg/cpp26/fold-constr10.C.jj	2024-07-26 16:02:26.099421284 +0200
+++ gcc/testsuite/g++.dg/cpp26/fold-constr10.C	2024-07-26 16:03:35.256534023 +0200
@@ -0,0 +1,67 @@
+// P2963R3 - Ordering of constraints involving fold expressions
+// { dg-do compile { target c++20 } }
+
+struct A {
+  using type = int;
+};
+struct B {
+  using type = long;
+};
+
+template <class T> concept C = true;
+
+template <class... T> requires (C<typename T::type> && ...)	// { dg-error "is not a class, struct, or union type" "" { target c++23_down } }
+constexpr bool foo () { return true; };
+
+static_assert (foo <> ());
+static_assert (foo <A> ());
+static_assert (foo <B, A, A, B> ());
+static_assert (foo <int> ());					// { dg-error "no matching function for call" "" { target c++23_down } }
+static_assert (foo <B, long> ());				// { dg-error "no matching function for call" "" { target c++23_down } }
+static_assert (foo <unsigned, A, A> ());			// { dg-error "no matching function for call" "" { target c++23_down } }
+
+template <class T, class... U> requires (C<typename U::type> && ... && C<typename T::type>)	// { dg-error "is not a class, struct, or union type" "" { target c++23_down } }
+constexpr bool bar () { return true; };
+
+static_assert (bar <A> ());
+static_assert (bar <B, A, A, B> ());
+static_assert (bar <int> ());					// { dg-error "no matching function for call" "" { target c++23_down } }
+static_assert (bar <B, long> ());				// { dg-error "no matching function for call" "" { target c++23_down } }
+static_assert (bar <unsigned, A, A> ());			// { dg-error "no matching function for call" "" { target c++23_down } }
+
+template <class T, class... U> requires (C<typename T::type> && ... && C<typename U::type>)	// { dg-error "is not a class, struct, or union type" "" { target c++23_down } }
+constexpr bool baz () { return true; };
+
+static_assert (baz <A> ());
+static_assert (baz <B, A, A, B> ());
+static_assert (baz <int> ());					// { dg-error "no matching function for call" "" { target c++23_down } }
+static_assert (baz <B, long> ());				// { dg-error "no matching function for call" "" { target c++23_down } }
+static_assert (baz <unsigned, A, A> ());			// { dg-error "no matching function for call" "" { target c++23_down } }
+
+template <class... T> requires (C<typename T::type> || ...)	// { dg-error "is not a class, struct, or union type" "" { target c++23_down } }
+constexpr bool qux () { return true; };
+
+static_assert (qux <> ());					// { dg-error "no matching function for call" }
+static_assert (qux <A> ());
+static_assert (qux <B, A, A, B> ());
+static_assert (qux <int> ());					// { dg-error "no matching function for call" "" { target c++23_down } }
+static_assert (qux <B, long> ());				// { dg-error "no matching function for call" "" { target c++23_down } }
+static_assert (qux <unsigned, A, A> ());			// { dg-error "no matching function for call" "" { target c++23_down } }
+
+template <class T, class... U> requires (C<typename U::type> || ... || C<typename T::type>)	// { dg-error "is not a class, struct, or union type" "" { target c++23_down } }
+constexpr bool corge () { return true; };
+
+static_assert (corge <A> ());
+static_assert (corge <B, A, A, B> ());
+static_assert (corge <int> ());					// { dg-error "no matching function for call" "" { target c++23_down } }
+static_assert (corge <B, long> ());				// { dg-error "no matching function for call" "" { target c++23_down } }
+static_assert (corge <unsigned, A, A> ());			// { dg-error "no matching function for call" "" { target c++23_down } }
+
+template <class T, class... U> requires (C<typename T::type> || ... || C<typename U::type>)	// { dg-error "is not a class, struct, or union type" "" { target c++23_down } }
+constexpr bool garply () { return true; };
+
+static_assert (garply <A> ());
+static_assert (garply <B, A, A, B> ());
+static_assert (garply <int> ());				// { dg-error "no matching function for call" "" { target c++23_down } }
+static_assert (garply <B, long> ());				// { dg-error "no matching function for call" "" { target c++23_down } }
+static_assert (garply <unsigned, A, A> ());			// { dg-error "no matching function for call" "" { target c++23_down } }
