diff gcc/cp/constraint.cc @ 145:1830386684a0

gcc-9.2.0
author anatofuz
date Thu, 13 Feb 2020 11:34:05 +0900
parents 84e7813d76e9
children
line wrap: on
line diff
--- a/gcc/cp/constraint.cc	Thu Oct 25 07:37:49 2018 +0900
+++ b/gcc/cp/constraint.cc	Thu Feb 13 11:34:05 2020 +0900
@@ -1,5 +1,5 @@
 /* Processing rules for constraints.
-   Copyright (C) 2013-2018 Free Software Foundation, Inc.
+   Copyright (C) 2013-2020 Free Software Foundation, Inc.
    Contributed by Andrew Sutton (andrew.n.sutton@gmail.com)
 
 This file is part of GCC.
@@ -46,89 +46,191 @@
 #include "toplev.h"
 #include "type-utils.h"
 
+static tree satisfaction_value (tree t);
+
+/* When we're parsing or substuting a constraint expression, we have slightly
+   different expression semantics.  In particular, we don't want to reduce a
+   concept-id to a satisfaction value.  */
+
+processing_constraint_expression_sentinel::
+processing_constraint_expression_sentinel ()
+{
+  ++scope_chain->x_processing_constraint;
+}
+
+processing_constraint_expression_sentinel::
+~processing_constraint_expression_sentinel ()
+{
+  --scope_chain->x_processing_constraint;
+}
+
+bool
+processing_constraint_expression_p ()
+{
+  return scope_chain->x_processing_constraint != 0;
+}
+
 /*---------------------------------------------------------------------------
-                       Operations on constraints
+		       Constraint expressions
 ---------------------------------------------------------------------------*/
 
-/* Returns true if C is a constraint tree code. Note that ERROR_MARK
-   is a valid constraint.  */
+/* Information provided to substitution.  */
+
+struct subst_info
+{
+  subst_info (tsubst_flags_t cmp, tree in)
+    : complain (cmp), in_decl (in)
+  { }
+
+  /* True if we should not diagnose errors.  */
+  bool quiet() const
+  {
+    return complain == tf_none;
+  }
+
+  /* True if we should diagnose errors.  */
+  bool noisy() const
+  {
+    return !quiet ();
+  }
+
+  tsubst_flags_t complain;
+  tree in_decl;
+};
+
+static tree satisfy_constraint (tree, tree, subst_info);
+
+/* True if T is known to be some type other than bool. Note that this
+   is false for dependent types and errors.  */
 
 static inline bool
-constraint_p (tree_code c)
+known_non_bool_p (tree t)
 {
-  return ((PRED_CONSTR <= c && c <= DISJ_CONSTR)
-          || c == EXPR_PACK_EXPANSION
-          || c == ERROR_MARK);
+  return (t && !WILDCARD_TYPE_P (t) && TREE_CODE (t) != BOOLEAN_TYPE);
 }
 
-/* Returns true if T is a constraint. Note that error_mark_node
-   is a valid constraint.  */
-
-bool
-constraint_p (tree t)
+static bool
+check_constraint_atom (cp_expr expr)
+{
+  if (known_non_bool_p (TREE_TYPE (expr)))
+    {
+      error_at (expr.get_location (),
+		"constraint expression does not have type %<bool%>");
+      return false;
+    }
+
+  /* Check that we're using function concepts correctly.  */
+  if (concept_check_p (expr))
+    {
+      tree id = unpack_concept_check (expr);
+      tree tmpl = TREE_OPERAND (id, 0);
+      if (OVL_P (tmpl) && TREE_CODE (expr) == TEMPLATE_ID_EXPR)
+        {
+	  error_at (EXPR_LOC_OR_LOC (expr, input_location),
+		    "function concept must be called");
+	  return false;
+	}
+    }
+
+  return true;
+}
+
+static bool
+check_constraint_operands (location_t, cp_expr lhs, cp_expr rhs)
 {
-  return constraint_p (TREE_CODE (t));
+  return check_constraint_atom (lhs) && check_constraint_atom (rhs);
 }
 
-/* Returns the conjunction of two constraints A and B. Note that
-   conjoining a non-null constraint with NULL_TREE is an identity
-   operation. That is, for non-null A,
-
-      conjoin_constraints(a, NULL_TREE) == a
-
-   and
-
-      conjoin_constraints (NULL_TREE, a) == a
-
-   If both A and B are NULL_TREE, the result is also NULL_TREE. */
+/* Validate the semantic properties of the constraint expression.  */
+
+static cp_expr
+finish_constraint_binary_op (location_t loc,
+			     tree_code code,
+			     cp_expr lhs,
+			     cp_expr rhs)
+{
+  gcc_assert (processing_constraint_expression_p ());
+  if (lhs == error_mark_node || rhs == error_mark_node)
+    return error_mark_node;
+  if (!check_constraint_operands (loc, lhs, rhs))
+    return error_mark_node;
+  tree overload;
+  tree expr = build_x_binary_op (loc, code,
+				 lhs, TREE_CODE (lhs),
+				 rhs, TREE_CODE (rhs),
+				 &overload, tf_none);
+  /* When either operand is dependent, the overload set may be non-empty.  */
+  if (expr == error_mark_node)
+    return error_mark_node;
+  SET_EXPR_LOCATION (expr, loc);
+  return expr;
+}
+
+cp_expr
+finish_constraint_or_expr (location_t loc, cp_expr lhs, cp_expr rhs)
+{
+  return finish_constraint_binary_op (loc, TRUTH_ORIF_EXPR, lhs, rhs);
+}
+
+cp_expr
+finish_constraint_and_expr (location_t loc, cp_expr lhs, cp_expr rhs)
+{
+  return finish_constraint_binary_op (loc, TRUTH_ANDIF_EXPR, lhs, rhs);
+}
+
+cp_expr
+finish_constraint_primary_expr (cp_expr expr)
+{
+  if (expr == error_mark_node)
+    return error_mark_node;
+  if (!check_constraint_atom (expr))
+    return cp_expr (error_mark_node, expr.get_location ());
+  return expr;
+}
+
+/* Combine two constraint-expressions with a logical-and.  */
 
 tree
-conjoin_constraints (tree a, tree b)
+combine_constraint_expressions (tree lhs, tree rhs)
 {
-  gcc_assert (a ? constraint_p (a) : true);
-  gcc_assert (b ? constraint_p (b) : true);
-  if (a)
-    return b ? build_nt (CONJ_CONSTR, a, b) : a;
-  else if (b)
-    return b;
-  else
-    return NULL_TREE;
+  processing_constraint_expression_sentinel pce;
+  if (!lhs)
+    return rhs;
+  if (!rhs)
+    return lhs;
+  return finish_constraint_and_expr (input_location, lhs, rhs);
 }
 
-/* Transform the vector of expressions in the T into a conjunction
-   of requirements. T must be a TREE_VEC. */
+/* Extract the template-id from a concept check. For standard and variable
+   checks, this is simply T. For function concept checks, this is the
+   called function.  */
 
 tree
-conjoin_constraints (tree t)
-{
-  gcc_assert (TREE_CODE (t) == TREE_VEC);
-  tree r = NULL_TREE;
-  for (int i = 0; i < TREE_VEC_LENGTH (t); ++i)
-    r = conjoin_constraints (r, TREE_VEC_ELT (t, i));
-  return r;
-}
-
-/* Returns true if T is a call expression to a function
-   concept. */
-
-bool
-function_concept_check_p (tree t)
+unpack_concept_check (tree t)
 {
-  gcc_assert (TREE_CODE (t) == CALL_EXPR);
-  tree fn = CALL_EXPR_FN (t);
-  if (fn != NULL_TREE
-      && TREE_CODE (fn) == TEMPLATE_ID_EXPR)
-    {
-      tree f1 = OVL_FIRST (TREE_OPERAND (fn, 0));
-      if (TREE_CODE (f1) == TEMPLATE_DECL
-	  && DECL_DECLARED_CONCEPT_P (DECL_TEMPLATE_RESULT (f1)))
-        return true;
-    }
-  return false;
+  gcc_assert (concept_check_p (t));
+
+  if (TREE_CODE (t) == CALL_EXPR)
+    t = CALL_EXPR_FN (t);
+
+  gcc_assert (TREE_CODE (t) == TEMPLATE_ID_EXPR);
+  return t;
 }
 
-/* Returns true if any of the arguments in the template
-   argument list is a wildcard or wildcard pack.  */
+/* Extract the TEMPLATE_DECL from a concept check.  */
+
+tree
+get_concept_check_template (tree t)
+{
+  tree id = unpack_concept_check (t);
+  tree tmpl = TREE_OPERAND (id, 0);
+  if (OVL_P (tmpl))
+    tmpl = OVL_FIRST (tmpl);
+  return tmpl;
+}
+
+/* Returns true if any of the arguments in the template argument list is
+   a wildcard or wildcard pack.  */
 
 bool
 contains_wildcard_p (tree args)
@@ -142,89 +244,56 @@
   return false;
 }
 
-/* Build a new call expression, but don't actually generate a
-   new function call. We just want the tree, not the semantics.  */
-
-inline tree
-build_call_check (tree id)
-{
-  ++processing_template_decl;
-  vec<tree, va_gc> *fargs = make_tree_vector();
-  tree call = finish_call_expr (id, &fargs, false, false, tf_none);
-  release_tree_vector (fargs);
-  --processing_template_decl;
-  return call;
-}
-
-/* Build an expression that will check a variable concept. If any
-   argument contains a wildcard, don't try to finish the variable
-   template because we can't substitute into a non-existent
-   declaration.  */
-
-tree
-build_variable_check (tree id)
-{
-  gcc_assert (TREE_CODE (id) == TEMPLATE_ID_EXPR);
-  if (contains_wildcard_p (TREE_OPERAND (id, 1)))
-    return id;
-
-  ++processing_template_decl;
-  tree var = finish_template_variable (id);
-  --processing_template_decl;
-  return var;
-}
-
 /*---------------------------------------------------------------------------
                     Resolution of qualified concept names
 ---------------------------------------------------------------------------*/
 
-/* This facility is used to resolve constraint checks from
-   requirement expressions. A constraint check is a call to
-   a function template declared with the keyword 'concept'.
-
-   The result of resolution is a pair (a TREE_LIST) whose value
-   is the matched declaration, and whose purpose contains the
-   coerced template arguments that can be substituted into the
-   call.  */
-
-// Given an overload set OVL, try to find a unique definition that can be
-// instantiated by the template arguments ARGS.
-//
-// This function is not called for arbitrary call expressions. In particular,
-// the call expression must be written with explicit template arguments
-// and no function arguments. For example:
-//
-//      f<T, U>()
-//
-// If a single match is found, this returns a TREE_LIST whose VALUE
-// is the constraint function (not the template), and its PURPOSE is
-// the complete set of arguments substituted into the parameter list.
+/* This facility is used to resolve constraint checks from requirement
+   expressions. A constraint check is a call to a function template declared
+   with the keyword 'concept'.
+
+   The result of resolution is a pair (a TREE_LIST) whose value is the
+   matched declaration, and whose purpose contains the coerced template
+   arguments that can be substituted into the call.  */
+
+/* Given an overload set OVL, try to find a unique definition that can be
+   instantiated by the template arguments ARGS.
+
+   This function is not called for arbitrary call expressions. In particular,
+   the call expression must be written with explicit template arguments
+   and no function arguments. For example:
+
+        f<T, U>()
+
+   If a single match is found, this returns a TREE_LIST whose VALUE
+   is the constraint function (not the template), and its PURPOSE is
+   the complete set of arguments substituted into the parameter list.  */
+
 static tree
-resolve_constraint_check (tree ovl, tree args)
+resolve_function_concept_overload (tree ovl, tree args)
 {
   int nerrs = 0;
   tree cands = NULL_TREE;
   for (lkp_iterator iter (ovl); iter; ++iter)
     {
-      // Get the next template overload.
       tree tmpl = *iter;
       if (TREE_CODE (tmpl) != TEMPLATE_DECL)
         continue;
 
-      // Don't try to deduce checks for non-concepts. We often
-      // end up trying to resolve constraints in functional casts
-      // as part of a postfix-expression. We can save time and
-      // headaches by not instantiating those declarations.
-      //
-      // NOTE: This masks a potential error, caused by instantiating
-      // non-deduced contexts using placeholder arguments.
+      /* Don't try to deduce checks for non-concepts. We often end up trying
+         to resolve constraints in functional casts as part of a
+         postfix-expression. We can save time and headaches by not
+         instantiating those declarations.
+
+         NOTE: This masks a potential error, caused by instantiating
+         non-deduced contexts using placeholder arguments. */
       tree fn = DECL_TEMPLATE_RESULT (tmpl);
       if (DECL_ARGUMENTS (fn))
         continue;
       if (!DECL_DECLARED_CONCEPT_P (fn))
         continue;
 
-      // Remember the candidate if we can deduce a substitution.
+      /* Remember the candidate if we can deduce a substitution.  */
       ++processing_template_decl;
       tree parms = TREE_VALUE (DECL_TEMPLATE_PARMS (tmpl));
       if (tree subst = coerce_template_parms (parms, args, tmpl))
@@ -247,29 +316,30 @@
   return cands;
 }
 
-// Determine if the the call expression CALL is a constraint check, and
-// return the concept declaration and arguments being checked. If CALL
-// does not denote a constraint check, return NULL.
+/* Determine if the the call expression CALL is a constraint check, and
+   return the concept declaration and arguments being checked. If CALL
+   does not denote a constraint check, return NULL.  */
+
 tree
-resolve_constraint_check (tree call)
+resolve_function_concept_check (tree call)
 {
   gcc_assert (TREE_CODE (call) == CALL_EXPR);
 
-  // A constraint check must be only a template-id expression. If
-  // it's a call to a base-link, its function(s) should be a
-  // template-id expression. If this is not a template-id, then it
-  // cannot be a concept-check.
+  /* A constraint check must be only a template-id expression.
+     If it's a call to a base-link, its function(s) should be a
+     template-id expression. If this is not a template-id, then
+     it cannot be a concept-check.  */
   tree target = CALL_EXPR_FN (call);
   if (BASELINK_P (target))
     target = BASELINK_FUNCTIONS (target);
   if (TREE_CODE (target) != TEMPLATE_ID_EXPR)
     return NULL_TREE;
 
-  // Get the overload set and template arguments and try to
-  // resolve the target.
+  /* Get the overload set and template arguments and try to
+     resolve the target.  */
   tree ovl = TREE_OPERAND (target, 0);
 
-  /* This is a function call of a variable concept... ill-formed. */
+  /* This is a function call of a variable concept... ill-formed.  */
   if (TREE_CODE (ovl) == TEMPLATE_DECL)
     {
       error_at (location_of (call),
@@ -278,59 +348,52 @@
     }
 
   tree args = TREE_OPERAND (target, 1);
-  return resolve_constraint_check (ovl, args);
+  return resolve_function_concept_overload (ovl, args);
 }
 
-/* Returns a pair containing the checked variable concept
-   and its associated prototype parameter.  The result
-   is a TREE_LIST whose TREE_VALUE is the variable concept
-   and whose TREE_PURPOSE is the prototype parameter.  */
+/* Returns a pair containing the checked concept and its associated
+   prototype parameter. The result is a TREE_LIST whose TREE_VALUE
+   is the concept (non-template) and whose TREE_PURPOSE contains
+   the converted template arguments, including the deduced prototype
+   parameter (in position 0). */
 
 tree
-resolve_variable_concept_check (tree id)
+resolve_concept_check (tree check)
 {
+  gcc_assert (concept_check_p (check));
+  tree id = unpack_concept_check (check);
   tree tmpl = TREE_OPERAND (id, 0);
+
+  /* If this is an overloaded function concept, perform overload
+     resolution (this only happens when deducing prototype parameters
+     and template introductions).  */
+  if (TREE_CODE (tmpl) == OVERLOAD)
+    {
+      if (OVL_CHAIN (tmpl))
+	return resolve_function_concept_check (check);
+      tmpl = OVL_FIRST (tmpl);
+    }
+
   tree args = TREE_OPERAND (id, 1);
-
-  if (!variable_concept_p (tmpl))
-    return NULL_TREE;
-
-  /* Make sure that we have the right parameters before
-     assuming that it works.  Note that failing to deduce
-     will result in diagnostics.  */
   tree parms = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (tmpl));
   ++processing_template_decl;
   tree result = coerce_template_parms (parms, args, tmpl);
   --processing_template_decl;
-  if (result != error_mark_node)
-    {
-      tree decl = DECL_TEMPLATE_RESULT (tmpl);
-      return build_tree_list (result, decl);
-    }
-  else
+  if (result == error_mark_node)
     return error_mark_node;
+  return build_tree_list (result, DECL_TEMPLATE_RESULT (tmpl));
 }
 
-
-/* Given a call expression or template-id expression to
-  a concept EXPR possibly including a wildcard, deduce
-  the concept being checked and the prototype parameter.
-  Returns true if the constraint and prototype can be
-  deduced and false otherwise.  Note that the CHECK and
-  PROTO arguments are set to NULL_TREE if this returns
-  false.  */
+/* Given a call expression or template-id expression to a concept EXPR
+   possibly including a wildcard, deduce the concept being checked and
+   the prototype parameter. Returns true if the constraint and prototype
+   can be deduced and false otherwise.  Note that the CHECK and PROTO
+   arguments are set to NULL_TREE if this returns false.  */
 
 bool
 deduce_constrained_parameter (tree expr, tree& check, tree& proto)
 {
-  tree info = NULL_TREE;
-  if (TREE_CODE (expr) == TEMPLATE_ID_EXPR)
-    info = resolve_variable_concept_check (expr);
-  else if (TREE_CODE (expr) == CALL_EXPR)
-    info = resolve_constraint_check (expr);
-  else
-    gcc_unreachable ();
-
+  tree info = resolve_concept_check (expr);
   if (info && info != error_mark_node)
     {
       check = TREE_VALUE (info);
@@ -340,135 +403,48 @@
       proto = TREE_TYPE (arg);
       return true;
     }
+
   check = proto = NULL_TREE;
   return false;
 }
 
-// Given a call expression or template-id expression to a concept, EXPR,
-// deduce the concept being checked and return the template arguments.
-// Returns NULL_TREE if deduction fails.
+/* Given a call expression or template-id expression to a concept, EXPR,
+   deduce the concept being checked and return the template arguments.
+   Returns NULL_TREE if deduction fails.  */
 static tree
-deduce_concept_introduction (tree expr)
+deduce_concept_introduction (tree check)
 {
-  tree info = NULL_TREE;
-  if (TREE_CODE (expr) == TEMPLATE_ID_EXPR)
-    info = resolve_variable_concept_check (expr);
-  else if (TREE_CODE (expr) == CALL_EXPR)
-    info = resolve_constraint_check (expr);
-  else
-    gcc_unreachable ();
-
+  tree info = resolve_concept_check (check);
   if (info && info != error_mark_node)
     return TREE_PURPOSE (info);
   return NULL_TREE;
 }
 
-namespace {
-
-/*---------------------------------------------------------------------------
-                       Constraint implication learning
----------------------------------------------------------------------------*/
-
-/* The implication context determines how we memoize concept checks.
-   Given two checks C1 and C2, the direction of implication depends
-   on whether we are learning implications of a conjunction or disjunction.
-   For example:
-
-      template<typename T> concept bool C = ...;
-      template<typenaem T> concept bool D = C<T> && true;
-
-   From this, we can learn that D<T> implies C<T>. We cannot learn,
-   without further testing, that C<T> does not imply D<T>. If, for
-   example, C<T> were defined as true, then these constraints would
-   be logically equivalent.
-
-   In rare cases, we may start with a logical equivalence. For example:
-
-      template<typename T> concept bool C = ...;
-      template<typename T> concept bool D = C<T>;
-
-   Here, we learn that C<T> implies D<T> and vice versa.   */
-
-enum implication_context
-{
-  conjunction_cxt, /* C1 implies C2. */
-  disjunction_cxt, /* C2 implies C1. */
-  equivalence_cxt  /* C1 implies C2, C2 implies C1. */
-};
-
-void learn_implications(tree, tree, implication_context);
-
-void
-learn_implication (tree parent, tree child, implication_context cxt)
+/* Build a constrained placeholder type where SPEC is a type-constraint.
+   SPEC can be anything were concept_definition_p is true.
+
+   If DECLTYPE_P is true, then the placeholder is decltype(auto).
+
+   Returns a pair whose FIRST is the concept being checked and whose
+   SECOND is the prototype parameter.  */
+
+tree_pair
+finish_type_constraints (tree spec, tree args, tsubst_flags_t complain)
 {
-  switch (cxt)
-    {
-      case conjunction_cxt:
-        save_subsumption_result (parent, child, true);
-        break;
-      case disjunction_cxt:
-        save_subsumption_result (child, parent, true);
-        break;
-      case equivalence_cxt:
-        save_subsumption_result (parent, child, true);
-        save_subsumption_result (child, parent, true);
-        break;
-    }
-}
-
-void
-learn_logical_operation (tree parent, tree constr, implication_context cxt)
-{
-  learn_implications (parent, TREE_OPERAND (constr, 0), cxt);
-  learn_implications (parent, TREE_OPERAND (constr, 1), cxt);
-}
-
-void
-learn_implications (tree parent, tree constr, implication_context cxt)
-{
-  switch (TREE_CODE (constr))
-    {
-      case CHECK_CONSTR:
-        return learn_implication (parent, constr, cxt);
-
-      case CONJ_CONSTR:
-        if (cxt == disjunction_cxt)
-          return;
-        return learn_logical_operation (parent, constr, cxt);
-
-      case DISJ_CONSTR:
-        if (cxt == conjunction_cxt)
-          return;
-        return learn_logical_operation (parent, constr, cxt);
-
-      default:
-        break;
-    }
-}
-
-/* Quickly scan the top-level constraints of CONSTR to learn and
-   cache logical relations between concepts.  The search does not
-   include conjunctions of disjunctions or vice versa.  */
-
-void
-learn_implications (tree tmpl, tree args, tree constr)
-{
-  /* Don't memoize relations between non-dependent arguemnts. It's not
-     helpful. */
-  if (!uses_template_parms (args))
-    return;
-
-  /* Build a check constraint for the purpose of caching. */
-  tree parent = build_nt (CHECK_CONSTR, tmpl, args);
-
-  /* Start learning based on the kind of the top-level contraint. */
-  if (TREE_CODE (constr) == CONJ_CONSTR)
-    return learn_logical_operation (parent, constr, conjunction_cxt);
-  else if (TREE_CODE (constr) == DISJ_CONSTR)
-    return learn_logical_operation (parent, constr, disjunction_cxt);
-  else if (TREE_CODE (constr) == CHECK_CONSTR)
-    /* This is the rare concept alias case. */
-    return learn_implication (parent, constr, equivalence_cxt);
+  gcc_assert (concept_definition_p (spec));
+
+  /* Build an initial concept check.  */
+  tree check = build_type_constraint (spec, args, complain);
+  if (check == error_mark_node)
+    return std::make_pair (error_mark_node, NULL_TREE);
+
+  /* Extract the concept and prototype parameter from the check. */
+  tree con;
+  tree proto;
+  if (!deduce_constrained_parameter (check, con, proto))
+    return std::make_pair (error_mark_node, NULL_TREE);
+
+  return std::make_pair (con, proto);
 }
 
 /*---------------------------------------------------------------------------
@@ -477,7 +453,7 @@
 
 /* Returns the expression of a function concept. */
 
-tree
+static tree
 get_returned_expression (tree fn)
 {
   /* Extract the body of the function minus the return expression.  */
@@ -494,322 +470,238 @@
 
 /* Returns the initializer of a variable concept. */
 
-tree
+static tree
 get_variable_initializer (tree var)
 {
   tree init = DECL_INITIAL (var);
   if (!init)
     return error_mark_node;
+  if (BRACE_ENCLOSED_INITIALIZER_P (init)
+      && CONSTRUCTOR_NELTS (init) == 1)
+    init = CONSTRUCTOR_ELT (init, 0)->value;
   return init;
 }
 
 /* Returns the definition of a variable or function concept.  */
 
-tree
+static tree
 get_concept_definition (tree decl)
 {
+  if (TREE_CODE (decl) == OVERLOAD)
+    decl = OVL_FIRST (decl);
+
+  if (TREE_CODE (decl) == TEMPLATE_DECL)
+    decl = DECL_TEMPLATE_RESULT (decl);
+
+  if (TREE_CODE (decl) == CONCEPT_DECL)
+    return DECL_INITIAL (decl);
   if (VAR_P (decl))
     return get_variable_initializer (decl);
-  else if (TREE_CODE (decl) == FUNCTION_DECL)
+  if (TREE_CODE (decl) == FUNCTION_DECL)
     return get_returned_expression (decl);
   gcc_unreachable ();
 }
 
-int expansion_level = 0;
-
-struct expanding_concept_sentinel
-{
-  expanding_concept_sentinel ()
-  {
-    ++expansion_level;
-  }
-
-  ~expanding_concept_sentinel()
-  {
-    --expansion_level;
-  }
-};
-
-
-} /* namespace */
-
-/* Returns true when a concept is being expanded.  */
-
-bool
-expanding_concept()
-{
-  return expansion_level > 0;
-}
-
-/* Expand a concept declaration (not a template) and its arguments to
-   a constraint defined by the concept's initializer or definition.  */
-
-tree
-expand_concept (tree decl, tree args)
-{
-  expanding_concept_sentinel sentinel;
-
-  if (TREE_CODE (decl) == TEMPLATE_DECL)
-    decl = DECL_TEMPLATE_RESULT (decl);
-  tree tmpl = DECL_TI_TEMPLATE (decl);
-
-  /* Check for a previous specialization. */
-  if (tree spec = get_concept_expansion (tmpl, args))
-    return spec;
-
-  /* Substitute the arguments to form a new definition expression.  */
-  tree def = get_concept_definition (decl);
-
-  ++processing_template_decl;
-  tree result = tsubst_expr (def, args, tf_none, NULL_TREE, true);
-  --processing_template_decl;
-  if (result == error_mark_node)
-    return error_mark_node;
-
-  /* And lastly, normalize it, check for implications, and save
-     the specialization for later.  */
-  tree norm = normalize_expression (result);
-  learn_implications (tmpl, args, norm);
-  return save_concept_expansion (tmpl, args, norm);
-}
-
-
 /*---------------------------------------------------------------------------
-                Stepwise normalization of expressions
+		      Normalization of expressions
 
 This set of functions will transform an expression into a constraint
-in a sequence of steps. Normalization does not not look into concept
-definitions.
+in a sequence of steps.
 ---------------------------------------------------------------------------*/
 
+void
+debug_parameter_mapping (tree map)
+{
+  for (tree p = map; p; p = TREE_CHAIN (p))
+    {
+      tree parm = TREE_VALUE (p);
+      tree arg = TREE_PURPOSE (p);
+      if (TYPE_P (parm))
+	verbatim ("MAP %qD TO %qT", TEMPLATE_TYPE_DECL (parm), arg);
+      else
+	verbatim ("MAP %qD TO %qE", TEMPLATE_PARM_DECL (parm), arg);
+      // debug_tree (parm);
+      // debug_tree (arg);
+    }
+}
+
+void
+debug_argument_list (tree args)
+{
+  for (int i = 0; i < TREE_VEC_LENGTH (args); ++i)
+    {
+      tree arg = TREE_VEC_ELT (args, i);
+      if (TYPE_P (arg))
+	verbatim ("ARG %qT", arg);
+      else
+	verbatim ("ARG %qE", arg);
+    }
+}
+
+/* Associate each parameter in PARMS with its corresponding template
+   argument in ARGS.  */
+
+static tree
+map_arguments (tree parms, tree args)
+{
+  for (tree p = parms; p; p = TREE_CHAIN (p))
+    {
+      int level;
+      int index;
+      template_parm_level_and_index (TREE_VALUE (p), &level, &index);
+      TREE_PURPOSE (p) = TMPL_ARG (args, level, index);
+    }
+  return parms;
+}
+
+/* Build the parameter mapping for EXPR using ARGS.  */
+
+static tree
+build_parameter_mapping (tree expr, tree args, tree decl)
+{
+  tree ctx_parms = NULL_TREE;
+  if (decl)
+    {
+      gcc_assert (TREE_CODE (decl) == TEMPLATE_DECL);
+      ctx_parms = DECL_TEMPLATE_PARMS (decl);
+    }
+  else if (current_template_parms)
+    {
+      /* TODO: This should probably be the only case, but because the
+	 point of declaration of concepts is currently set after the
+	 initializer, the template parameter lists are not available
+	 when normalizing concept definitions, hence the case above.  */
+      ctx_parms = current_template_parms;
+    }
+
+  tree parms = find_template_parameters (expr, ctx_parms);
+  tree map = map_arguments (parms, args);
+  return map;
+}
+
+/* True if the parameter mappings of two atomic constraints are equivalent.  */
+
+static bool
+parameter_mapping_equivalent_p (tree t1, tree t2)
+{
+  tree map1 = ATOMIC_CONSTR_MAP (t1);
+  tree map2 = ATOMIC_CONSTR_MAP (t2);
+  while (map1 && map2)
+    {
+      tree arg1 = TREE_PURPOSE (map1);
+      tree arg2 = TREE_PURPOSE (map2);
+      if (!template_args_equal (arg1, arg2))
+        return false;
+      map1 = TREE_CHAIN (map1);
+      map2 = TREE_CHAIN (map2);
+    }
+  return true;
+}
+
+/* Provides additional context for normalization.  */
+
+struct norm_info : subst_info
+{
+  explicit norm_info (tsubst_flags_t complain)
+    : subst_info (tf_warning_or_error | complain, NULL_TREE),
+      context()
+  {}
+
+  /* Construct a top-level context for DECL.  */
+
+  norm_info (tree in_decl, tsubst_flags_t complain)
+    : subst_info (tf_warning_or_error | complain, in_decl),
+      context (make_context (in_decl))
+  {}
+
+  bool generate_diagnostics() const
+  {
+    return complain & tf_norm;
+  }
+
+  tree make_context(tree in_decl)
+  {
+    if (generate_diagnostics ())
+      return build_tree_list (NULL_TREE, in_decl);
+    return NULL_TREE;
+  }
+
+  void update_context(tree expr, tree args)
+  {
+    if (generate_diagnostics ())
+      {
+	tree map = build_parameter_mapping (expr, args, in_decl);
+	context = tree_cons (map, expr, context);
+      }
+    in_decl = get_concept_check_template (expr);
+  }
+
+  /* Provides information about the source of a constraint. This is a
+     TREE_LIST whose VALUE is either a concept check or a constrained
+     declaration. The PURPOSE, for concept checks is a parameter mapping
+     for that check.  */
+
+  tree context;
+};
+
+static tree normalize_expression (tree, tree, norm_info);
+
 /* Transform a logical-or or logical-and expression into either
    a conjunction or disjunction. */
 
-tree
-normalize_logical_operation (tree t, tree_code c)
-{
-  tree t0 = normalize_expression (TREE_OPERAND (t, 0));
-  tree t1 = normalize_expression (TREE_OPERAND (t, 1));
-  return build_nt (c, t0, t1);
-}
-
-/* A simple requirement T introduces an expression constraint
-   for its expression. */
-
-inline tree
-normalize_simple_requirement (tree t)
-{
-  return build_nt (EXPR_CONSTR, TREE_OPERAND (t, 0));
-}
-
-/* A type requirement T introduce a type constraint for its type.  */
-
-inline tree
-normalize_type_requirement (tree t)
-{
-  return build_nt (TYPE_CONSTR, TREE_OPERAND (t, 0));
-}
-
-/* A compound requirement T introduces a conjunction of constraints
-   depending on its form.  The conjunction always includes an
-   expression constraint for the expression of the requirement.
-   If a trailing return type was specified, the conjunction includes
-   either an implicit conversion constraint or an argument deduction
-   constraint.  If the noexcept specifier is present, the conjunction
-   includes an exception constraint.  */
-
-tree
-normalize_compound_requirement (tree t)
+static tree
+normalize_logical_operation (tree t, tree args, tree_code c, norm_info info)
 {
-  tree expr = TREE_OPERAND (t, 0);
-  tree constr = build_nt (EXPR_CONSTR, TREE_OPERAND (t, 0));
-
-  /* If a type is given, append an implicit conversion or
-     argument deduction constraint.  */
-  if (tree type = TREE_OPERAND (t, 1))
-    {
-      tree type_constr;
-      /* TODO: We should be extracting a list of auto nodes
-         from type_uses_auto, not a single node */
-      if (tree placeholder = type_uses_auto (type))
-        type_constr = build_nt (DEDUCT_CONSTR, expr, type, placeholder);
-      else
-        type_constr = build_nt (ICONV_CONSTR, expr, type);
-      constr = conjoin_constraints (constr, type_constr);
-    }
-
-  /* If noexcept is present, append an exception constraint. */
-  if (COMPOUND_REQ_NOEXCEPT_P (t))
-    {
-      tree except = build_nt (EXCEPT_CONSTR, expr);
-      constr = conjoin_constraints (constr, except);
-    }
-
-  return constr;
+  tree t0 = normalize_expression (TREE_OPERAND (t, 0), args, info);
+  tree t1 = normalize_expression (TREE_OPERAND (t, 1), args, info);
+
+  /* Build a new info object for the constraint.  */
+  tree ci = info.generate_diagnostics()
+    ? build_tree_list (t, info.context)
+    : NULL_TREE;
+
+  return build2 (c, ci, t0, t1);
 }
 
-/* A nested requirement T introduces a conjunction of constraints
-   corresponding to its constraint-expression.
-
-   If the result of transforming T is error_mark_node, the resulting
-   constraint is a predicate constraint whose operand is also
-   error_mark_node. This preserves the constraint structure, but
-   will guarantee that the constraint is never satisfied.  */
-
-inline tree
-normalize_nested_requirement (tree t)
-{
-  return normalize_expression (TREE_OPERAND (t, 0));
-}
-
-/* Transform a requirement T into one or more constraints.  */
-
-tree
-normalize_requirement (tree t)
+static tree
+normalize_concept_check (tree check, tree args, norm_info info)
 {
-  switch (TREE_CODE (t))
-    {
-    case SIMPLE_REQ:
-      return normalize_simple_requirement (t);
-
-    case TYPE_REQ:
-      return normalize_type_requirement (t);
-
-    case COMPOUND_REQ:
-      return normalize_compound_requirement (t);
-
-    case NESTED_REQ:
-      return normalize_nested_requirement (t);
-
-    default:
-      gcc_unreachable ();
-    }
-  return error_mark_node;
-}
-
-/* Transform a sequence of requirements into a conjunction of
-   constraints. */
-
-tree
-normalize_requirements (tree t)
-{
-  tree result = NULL_TREE;
-  for (; t; t = TREE_CHAIN (t))
+  tree id = unpack_concept_check (check);
+  tree tmpl = TREE_OPERAND (id, 0);
+  tree targs = TREE_OPERAND (id, 1);
+
+  /* A function concept is wrapped in an overload.  */
+  if (TREE_CODE (tmpl) == OVERLOAD)
     {
-      tree constr = normalize_requirement (TREE_VALUE (t));
-      result = conjoin_constraints (result, constr);
-    }
-  return result;
-}
-
-/* The normal form of a requires-expression is a parameterized
-   constraint having the same parameters and a conjunction of
-   constraints representing the normal form of requirements.  */
-
-tree
-normalize_requires_expression (tree t)
-{
-  tree operand = normalize_requirements (TREE_OPERAND (t, 1));
-  if (tree parms = TREE_OPERAND (t, 0))
-    return build_nt (PARM_CONSTR, parms, operand);
-  else
-    return operand;
-}
-
-/* For a template-id referring to a variable concept, returns
-   a check constraint. Otherwise, returns a predicate constraint. */
-
-tree
-normalize_template_id_expression (tree t)
-{
-  if (tree info = resolve_variable_concept_check (t))
-    {
-      if (info == error_mark_node)
-        {
-          /* We get this when the template arguments don't match
-             the variable concept. */
-          error ("invalid reference to concept %qE", t);
-          return error_mark_node;
-        }
-
-      tree decl = TREE_VALUE (info);
-      tree args = TREE_PURPOSE (info);
-      return build_nt (CHECK_CONSTR, decl, args);
-    }
-
-  /* Check that we didn't refer to a function concept like a variable.  */
-  tree fn = OVL_FIRST (TREE_OPERAND (t, 0));
-  if (TREE_CODE (fn) == TEMPLATE_DECL
-      && DECL_DECLARED_CONCEPT_P (DECL_TEMPLATE_RESULT (fn)))
-    {
-      error_at (location_of (t),
-		"invalid reference to function concept %qD", fn);
-      return error_mark_node;
+      /* TODO: Can we diagnose this error during parsing?  */
+      if (TREE_CODE (check) == TEMPLATE_ID_EXPR)
+	error_at (EXPR_LOC_OR_LOC (check, input_location),
+		  "function concept must be called");
+      tmpl = OVL_FIRST (tmpl);
     }
 
-  return build_nt (PRED_CONSTR, t);
-}
-
-/* For a call expression to a function concept, returns a check
-   constraint. Otherwise, returns a predicate constraint. */
-
-tree
-normalize_call_expression (tree t)
-{
-  /* Try to resolve this function call as a concept.  If not, then
-     it can be returned as a predicate constraint.  */
-  tree check = resolve_constraint_check (t);
-  if (!check)
-    return build_nt (PRED_CONSTR, t);
-  if (check == error_mark_node)
-    {
-      /* TODO: Improve diagnostics. We could report why the reference
-         is invalid. */
-      error ("invalid reference to concept %qE", t);
-      return error_mark_node;
-    }
-
-  tree fn = TREE_VALUE (check);
-  tree args = TREE_PURPOSE (check);
-  return build_nt (CHECK_CONSTR, fn, args);
-}
-
-/* If T is a call to an overloaded && or || operator, diagnose that
-   as a non-SFINAEable error.  Returns true if an error is emitted.
-
-   TODO: It would be better to diagnose this at the point of definition,
-   if possible. Perhaps we should immediately do a first-pass normalization
-   of a concept definition to catch obvious non-dependent errors like
-   this.  */
-
-bool
-check_for_logical_overloads (tree t)
-{
-  if (TREE_CODE (t) != CALL_EXPR)
-    return false;
-
-  tree fn = CALL_EXPR_FN (t);
-
-  /* For member calls, try extracting the function from the
-     component ref.  */
-  if (TREE_CODE (fn) == COMPONENT_REF)
-    {
-      fn = TREE_OPERAND (fn, 1);
-      if (TREE_CODE (fn) == BASELINK)
-        fn = BASELINK_FUNCTIONS (fn);
-    }
-
-  if (TREE_CODE (fn) != FUNCTION_DECL)
-    return false;
-
-  if (DECL_OVERLOADED_OPERATOR_P (fn))
-    {
-      location_t loc = cp_expr_loc_or_loc (t, input_location);
-      error_at (loc, "constraint %qE, uses overloaded operator", t);
-      return true;
-    }
-
-  return false;
+  /* Substitute through the arguments of the concept check. */
+  targs = tsubst_template_args (targs, args, info.complain, info.in_decl);
+  if (targs == error_mark_node)
+    return error_mark_node;
+
+  /* Build the substitution for the concept definition.  */
+  tree parms = TREE_VALUE (DECL_TEMPLATE_PARMS (tmpl));
+  /* Turn on template processing; coercing non-type template arguments
+     will automatically assume they're non-dependent.  */
+  ++processing_template_decl;
+  tree subst = coerce_template_parms (parms, targs, tmpl);
+  --processing_template_decl;
+  if (subst == error_mark_node)
+    return error_mark_node;
+
+  /* The concept may have been ill-formed.  */
+  tree def = get_concept_definition (DECL_TEMPLATE_RESULT (tmpl));
+  if (def == error_mark_node)
+    return error_mark_node;
+
+  info.update_context (check, args);
+  return normalize_expression (def, subst, info);
 }
 
 /* The normal form of an atom depends on the expression. The normal
@@ -818,135 +710,26 @@
    concept is a check constraint for that concept. Otherwise, the
    constraint is a predicate constraint.  */
 
-tree
-normalize_atom (tree t)
-{
-  /* We can get constraints pushed down through pack expansions, so
-     just return them. */
-  if (constraint_p (t))
-    return t;
-
-  tree type = TREE_TYPE (t);
-  if (!type || type_unknown_p (t) || TREE_CODE (type) == TEMPLATE_TYPE_PARM)
-    ;
-  else if (!dependent_type_p (type))
-    {
-      if (check_for_logical_overloads (t))
-        return error_mark_node;
-
-      type = cv_unqualified (type);
-      if (!same_type_p (type, boolean_type_node))
-	{
-	  error ("predicate constraint %q+E does not have type %<bool%>", t);
-	  return error_mark_node;
-	}
-    }
-
-  if (TREE_CODE (t) == TEMPLATE_ID_EXPR)
-    return normalize_template_id_expression (t);
-  if (TREE_CODE (t) == CALL_EXPR)
-    return normalize_call_expression (t);
-  return build_nt (PRED_CONSTR, t);
-}
-
-/* Push down the pack expansion EXP into the leaves of the constraint PAT.  */
-
-tree
-push_down_pack_expansion (tree exp, tree pat)
-{
-  switch (TREE_CODE (pat))
-    {
-    case CONJ_CONSTR:
-    case DISJ_CONSTR:
-      {
-	pat = copy_node (pat);
-	TREE_OPERAND (pat, 0)
-	  = push_down_pack_expansion (exp, TREE_OPERAND (pat, 0));
-	TREE_OPERAND (pat, 1)
-	  = push_down_pack_expansion (exp, TREE_OPERAND (pat, 1));
-	return pat;
-      }
-    default:
-      {
-	exp = copy_node (exp);
-	SET_PACK_EXPANSION_PATTERN (exp, pat);
-	return exp;
-      }
-    }
-}
-
-/* Transform a pack expansion into a constraint.  First we transform the
-   pattern of the pack expansion, then we push the pack expansion down into the
-   leaves of the constraint so that partial ordering will work.  */
-
-tree
-normalize_pack_expansion (tree t)
+static tree
+normalize_atom (tree t, tree args, norm_info info)
 {
-  tree pat = normalize_expression (PACK_EXPANSION_PATTERN (t));
-  return push_down_pack_expansion (t, pat);
-}
-
-/* Transform an expression into a constraint.  */
-
-tree
-normalize_any_expression (tree t)
-{
-  switch (TREE_CODE (t))
-    {
-    case TRUTH_ANDIF_EXPR:
-      return normalize_logical_operation (t, CONJ_CONSTR);
-
-    case TRUTH_ORIF_EXPR:
-      return normalize_logical_operation (t, DISJ_CONSTR);
-
-    case REQUIRES_EXPR:
-      return normalize_requires_expression (t);
-
-    case BIND_EXPR:
-      return normalize_expression (BIND_EXPR_BODY (t));
-
-    case EXPR_PACK_EXPANSION:
-      return normalize_pack_expansion (t);
-
-    default:
-      /* All other constraints are atomic. */
-      return normalize_atom (t);
-    }
+  /* Concept checks are not atomic.  */
+  if (concept_check_p (t))
+    return normalize_concept_check (t, args, info);
+
+  /* Build the parameter mapping for the atom.  */
+  tree map = build_parameter_mapping (t, args, info.in_decl);
+
+  /* Build a new info object for the atom.  */
+  tree ci = build_tree_list (t, info.context);
+
+  return build1 (ATOMIC_CONSTR, ci, map);
 }
 
-/* Transform a statement into an expression.  */
-tree
-normalize_any_statement (tree t)
-{
-  switch (TREE_CODE (t))
-    {
-    case RETURN_EXPR:
-      return normalize_expression (TREE_OPERAND (t, 0));
-    default:
-      gcc_unreachable ();
-    }
-  return error_mark_node;
-}
-
-/* Reduction rules for the declaration T.  */
-
-tree
-normalize_any_declaration (tree t)
-{
-  switch (TREE_CODE (t))
-    {
-    case VAR_DECL:
-      return normalize_atom (t);
-    default:
-      gcc_unreachable ();
-    }
-  return error_mark_node;
-}
-
-/* Returns the normal form of a constraint expression. */
-
-tree
-normalize_expression (tree t)
+/* Returns the normal form of an expression. */
+
+static tree
+normalize_expression (tree t, tree args, norm_info info)
 {
   if (!t)
     return NULL_TREE;
@@ -954,133 +737,297 @@
   if (t == error_mark_node)
     return error_mark_node;
 
-  switch (TREE_CODE_CLASS (TREE_CODE (t)))
-    {
-    case tcc_unary:
-    case tcc_binary:
-    case tcc_expression:
-    case tcc_vl_exp:
-      return normalize_any_expression (t);
-
-    case tcc_statement:
-      return normalize_any_statement (t);
-
-    case tcc_declaration:
-      return normalize_any_declaration (t);
-
-    case tcc_exceptional:
-    case tcc_constant:
-    case tcc_reference:
-    case tcc_comparison:
-      /* These are all atomic predicate constraints. */
-      return normalize_atom (t);
-
-    default:
-      /* Unhandled node kind. */
-      gcc_unreachable ();
-    }
-  return error_mark_node;
-}
-
-
-/*---------------------------------------------------------------------------
-                        Constraint normalization
----------------------------------------------------------------------------*/
-
-tree normalize_constraint (tree);
-
-/* The normal form of the disjunction T0 /\ T1 is the conjunction
-   of the normal form of T0 and the normal form of T1.  */
-
-inline tree
-normalize_conjunction (tree t)
-{
-  tree t0 = normalize_constraint (TREE_OPERAND (t, 0));
-  tree t1 = normalize_constraint (TREE_OPERAND (t, 1));
-  return build_nt (CONJ_CONSTR, t0, t1);
-}
-
-/* The normal form of the disjunction T0 \/ T1 is the disjunction
-   of the normal form of T0 and the normal form of T1.  */
-
-inline tree
-normalize_disjunction (tree t)
-{
-  tree t0 = normalize_constraint (TREE_OPERAND (t, 0));
-  tree t1 = normalize_constraint (TREE_OPERAND (t, 1));
-  return build_nt (DISJ_CONSTR, t0, t1);
-}
-
-/* A predicate constraint is normalized in two stages.  First all
-   references specializations of concepts are replaced by their
-   substituted definitions.  Then, the resulting expression is
-   transformed into a constraint by transforming && expressions
-   into conjunctions and || into disjunctions.  */
-
-tree
-normalize_predicate_constraint (tree t)
-{
-  ++processing_template_decl;
-  tree expr = PRED_CONSTR_EXPR (t);
-  tree constr = normalize_expression (expr);
-  --processing_template_decl;
-  return constr;
-}
-
-/* The normal form of a parameterized constraint is the normal
-   form of its operand.  */
-
-tree
-normalize_parameterized_constraint (tree t)
-{
-  tree parms = PARM_CONSTR_PARMS (t);
-  tree operand = normalize_constraint (PARM_CONSTR_OPERAND (t));
-  return build_nt (PARM_CONSTR, parms, operand);
-}
-
-/* Normalize the constraint T by reducing it so that it is
-   comprised of only conjunctions and disjunctions of atomic
-   constraints.  */
-
-tree
-normalize_constraint (tree t)
-{
-  if (!t)
-    return NULL_TREE;
-
-  if (t == error_mark_node)
-    return t;
-
   switch (TREE_CODE (t))
     {
-      case CONJ_CONSTR:
-        return normalize_conjunction (t);
-
-      case DISJ_CONSTR:
-        return normalize_disjunction (t);
-
-      case PRED_CONSTR:
-        return normalize_predicate_constraint (t);
-
-      case PARM_CONSTR:
-        return normalize_parameterized_constraint (t);
-
-      case EXPR_CONSTR:
-      case TYPE_CONSTR:
-      case ICONV_CONSTR:
-      case DEDUCT_CONSTR:
-      case EXCEPT_CONSTR:
-        /* These constraints are defined to be atomic. */
-        return t;
-
-      default:
-        /* CONSTR was not a constraint. */
-        gcc_unreachable();
+    case TRUTH_ANDIF_EXPR:
+      return normalize_logical_operation (t, args, CONJ_CONSTR, info);
+    case TRUTH_ORIF_EXPR:
+      return normalize_logical_operation (t, args, DISJ_CONSTR, info);
+    default:
+      return normalize_atom (t, args, info);
+    }
+}
+
+/* Cache of the normalized form of constraints.  Marked as deletable because it
+   can all be recalculated.  */
+static GTY((deletable)) hash_map<tree,tree> *normalized_map;
+
+static tree
+get_normalized_constraints (tree t, tree args, norm_info info)
+{
+  auto_timevar time (TV_CONSTRAINT_NORM);
+  return normalize_expression (t, args, info);
+}
+
+/* Returns the normalized constraints from a constraint-info object
+   or NULL_TREE if the constraints are null. ARGS provide the initial
+   arguments for normalization and IN_DECL provides the declaration
+   to which the constraints belong.  */
+
+static tree
+get_normalized_constraints_from_info (tree ci, tree args, tree in_decl,
+				      bool diag = false)
+{
+  if (ci == NULL_TREE)
+    return NULL_TREE;
+
+  /* Substitution errors during normalization are fatal.  */
+  ++processing_template_decl;
+  norm_info info (in_decl, diag ? tf_norm : tf_none);
+  tree t = get_normalized_constraints (CI_ASSOCIATED_CONSTRAINTS (ci),
+				       args, info);
+  --processing_template_decl;
+
+  return t;
+}
+
+/* Returns the normalized constraints for the declaration D.  */
+
+static tree
+get_normalized_constraints_from_decl (tree d, bool diag = false)
+{
+  tree tmpl;
+  tree decl;
+
+  /* For inherited constructors, consider the original declaration;
+     it has the correct template information attached. */
+  d = strip_inheriting_ctors (d);
+
+  if (TREE_CODE (d) == TEMPLATE_DECL)
+    {
+      tmpl = d;
+      decl = DECL_TEMPLATE_RESULT (tmpl);
+    }
+  else
+    {
+      if (tree ti = DECL_TEMPLATE_INFO (d))
+	tmpl = TI_TEMPLATE (ti);
+      else
+	tmpl = NULL_TREE;
+      decl = d;
     }
-  return error_mark_node;
+
+  /* Get the most general template for the declaration, and compute
+     arguments from that. This ensures that the arguments used for
+     normalization are always template parameters and not arguments
+     used for outer specializations.  For example:
+
+        template<typename T>
+        struct S {
+	  template<typename U> requires C<T, U> void f(U);
+        };
+
+        S<int>::f(0);
+
+     When we normalize the requirements for S<int>::f, we want the
+     arguments to be {T, U}, not {int, U}. One reason for this is that
+     accepting the latter causes the template parameter level of U
+     to be reduced in a way that makes it overly difficult substitute
+     concrete arguments (i.e., eventually {int, int} during satisfaction.  */
+  if (tmpl)
+  {
+    if (DECL_LANG_SPECIFIC(tmpl) && !DECL_TEMPLATE_SPECIALIZATION (tmpl))
+      tmpl = most_general_template (tmpl);
+  }
+
+  /* If we're not diagnosing errors, use cached constraints, if any.  */
+  if (!diag)
+    if (tree *p = hash_map_safe_get (normalized_map, tmpl))
+      return *p;
+
+  tree args = generic_targs_for (tmpl);
+  tree ci = get_constraints (decl);
+  tree norm = get_normalized_constraints_from_info (ci, args, tmpl, diag);
+
+  if (!diag)
+    hash_map_safe_put<hm_ggc> (normalized_map, tmpl, norm);
+
+  return norm;
+}
+
+/* Returns the normal form of TMPL's definition.  */
+
+static tree
+normalize_concept_definition (tree tmpl, bool diag = false)
+{
+  if (!diag)
+    if (tree *p = hash_map_safe_get (normalized_map, tmpl))
+      return *p;
+
+  gcc_assert (concept_definition_p (tmpl));
+  if (OVL_P (tmpl))
+    tmpl = OVL_FIRST (tmpl);
+  gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL);
+  tree args = generic_targs_for (tmpl);
+  tree def = get_concept_definition (DECL_TEMPLATE_RESULT (tmpl));
+  ++processing_template_decl;
+  norm_info info (tmpl, diag ? tf_norm : tf_none);
+  tree norm = get_normalized_constraints (def, args, info);
+  --processing_template_decl;
+
+  if (!diag)
+    hash_map_safe_put<hm_ggc> (normalized_map, tmpl, norm);
+
+  return norm;
+}
+
+/* Returns the normal form of TMPL's requirements.  */
+
+static tree
+normalize_template_requirements (tree tmpl, bool diag = false)
+{
+  return get_normalized_constraints_from_decl (tmpl, diag);
+}
+
+/* Returns the normal form of TMPL's requirements.  */
+
+static tree
+normalize_nontemplate_requirements (tree decl, bool diag = false)
+{
+  return get_normalized_constraints_from_decl (decl, diag);
+}
+
+/* Normalize an EXPR as a constraint using ARGS.  */
+
+static tree
+normalize_constraint_expression (tree expr, tree args, bool diag = false)
+{
+  if (!expr || expr == error_mark_node)
+    return expr;
+  ++processing_template_decl;
+  norm_info info (diag ? tf_norm : tf_none);
+  tree norm = get_normalized_constraints (expr, args, info);
+  --processing_template_decl;
+  return norm;
 }
 
-
+/* Normalize an EXPR as a constraint.  */
+
+static tree
+normalize_constraint_expression (tree expr, bool diag = false)
+{
+  if (!expr || expr == error_mark_node)
+    return expr;
+
+  /* For concept checks, use the supplied template arguments as those used
+     for normalization. Otherwise, there are no template arguments.  */
+  tree args;
+  if (concept_check_p (expr))
+    {
+      tree id = unpack_concept_check (expr);
+      args = TREE_OPERAND (id, 1);
+    }
+  else
+    args = NULL_TREE;
+
+  return normalize_constraint_expression (expr, args, diag);
+}
+
+/* 17.4.1.2p2. Two constraints are identical if they are formed
+   from the same expression and the targets of the parameter mapping
+   are equivalent.  */
+
+bool
+atomic_constraints_identical_p (tree t1, tree t2)
+{
+  gcc_assert (TREE_CODE (t1) == ATOMIC_CONSTR);
+  gcc_assert (TREE_CODE (t2) == ATOMIC_CONSTR);
+
+  if (ATOMIC_CONSTR_EXPR (t1) != ATOMIC_CONSTR_EXPR (t2))
+    return false;
+
+  if (!parameter_mapping_equivalent_p (t1, t2))
+    return false;
+
+  return true;
+}
+
+/* True if T1 and T2 are equivalent, meaning they have the same syntactic
+   structure and all corresponding constraints are identical.  */
+
+bool
+constraints_equivalent_p (tree t1, tree t2)
+{
+  gcc_assert (CONSTR_P (t1));
+  gcc_assert (CONSTR_P (t2));
+
+  if (TREE_CODE (t1) != TREE_CODE (t2))
+    return false;
+
+  switch (TREE_CODE (t1))
+  {
+  case CONJ_CONSTR:
+  case DISJ_CONSTR:
+    if (!constraints_equivalent_p (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)))
+      return false;
+    if (!constraints_equivalent_p (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1)))
+      return false;
+    break;
+  case ATOMIC_CONSTR:
+    if (!atomic_constraints_identical_p(t1, t2))
+      return false;
+    break;
+  default:
+    gcc_unreachable ();
+  }
+  return true;
+}
+
+/* Compute the hash value for T.  */
+
+hashval_t
+hash_atomic_constraint (tree t)
+{
+  gcc_assert (TREE_CODE (t) == ATOMIC_CONSTR);
+
+  /* Hash the identity of the expression.  */
+  hashval_t val = htab_hash_pointer (ATOMIC_CONSTR_EXPR (t));
+
+  /* Hash the targets of the parameter map.  */
+  tree p = ATOMIC_CONSTR_MAP (t);
+  while (p)
+    {
+      val = iterative_hash_template_arg (TREE_PURPOSE (p), val);
+      p = TREE_CHAIN (p);
+    }
+
+  return val;
+}
+
+namespace inchash
+{
+
+static void
+add_constraint (tree t, hash& h)
+{
+  h.add_int(TREE_CODE (t));
+  switch (TREE_CODE (t))
+  {
+  case CONJ_CONSTR:
+  case DISJ_CONSTR:
+    add_constraint (TREE_OPERAND (t, 0), h);
+    add_constraint (TREE_OPERAND (t, 1), h);
+    break;
+  case ATOMIC_CONSTR:
+    h.merge_hash (hash_atomic_constraint (t));
+    break;
+  default:
+    gcc_unreachable ();
+  }
+}
+
+}
+
+/* Computes a hash code for the constraint T.  */
+
+hashval_t
+iterative_hash_constraint (tree t, hashval_t val)
+{
+  gcc_assert (CONSTR_P (t));
+  inchash::hash h (val);
+  inchash::add_constraint (t, h);
+  return h.end ();
+}
 
 // -------------------------------------------------------------------------- //
 // Constraint Semantic Processing
@@ -1094,21 +1041,21 @@
 {
   if (!current_template_parms)
     return NULL_TREE;
-  tree tmpl_constr = TEMPLATE_PARM_CONSTRAINTS (current_template_parms);
+  tree tmpl_constr = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
   return build_constraints (tmpl_constr, NULL_TREE);
 }
 
-// If the recently parsed TYPE declares or defines a template or template
-// specialization, get its corresponding constraints from the current
-// template parameters and bind them to TYPE's declaration.
+/* If the recently parsed TYPE declares or defines a template or
+   template specialization, get its corresponding constraints from the
+   current template parameters and bind them to TYPE's declaration.  */
+
 tree
 associate_classtype_constraints (tree type)
 {
-  if (!type || type == error_mark_node || TREE_CODE (type) != RECORD_TYPE)
+  if (!type || type == error_mark_node || !CLASS_TYPE_P (type))
     return type;
 
-  // An explicit class template specialization has no template
-  // parameters.
+  /* An explicit class template specialization has no template parameters.  */
   if (!current_template_parms)
     return type;
 
@@ -1117,17 +1064,19 @@
       tree decl = TYPE_STUB_DECL (type);
       tree ci = current_template_constraints ();
 
-      // An implicitly instantiated member template declaration already
-      // has associated constraints. If it is defined outside of its
-      // class, then we need match these constraints against those of
-      // original declaration.
+      /* An implicitly instantiated member template declaration already
+	 has associated constraints. If it is defined outside of its
+	 class, then we need match these constraints against those of
+	 original declaration.  */
       if (tree orig_ci = get_constraints (decl))
         {
           if (!equivalent_constraints (ci, orig_ci))
             {
-              // FIXME: Improve diagnostics.
-              error ("%qT does not match any declaration", type);
-              return error_mark_node;
+	      error ("%qT does not match original declaration", type);
+	      tree tmpl = CLASSTYPE_TI_TEMPLATE (type);
+	      location_t loc = DECL_SOURCE_LOCATION (tmpl);
+	      inform (loc, "original template declaration here");
+	      /* Fall through, so that we define the type anyway.  */
             }
           return type;
         }
@@ -1136,17 +1085,14 @@
   return type;
 }
 
-namespace {
-
-// Create an empty constraint info block.
-inline tree_constraint_info*
+/* Create an empty constraint info block.  */
+
+static inline tree_constraint_info*
 build_constraint_info ()
 {
   return (tree_constraint_info *)make_node (CONSTRAINT_INFO);
 }
 
-} // namespace
-
 /* Build a constraint-info object that contains the associated constraints
    of a declaration.  This also includes the declaration's template
    requirements (TREQS) and any trailing requirements for a function
@@ -1156,27 +1102,143 @@
    this returns NULL_TREE, indicating an unconstrained declaration.  */
 
 tree
-build_constraints (tree tmpl_reqs, tree decl_reqs)
+build_constraints (tree tr, tree dr)
 {
-  gcc_assert (tmpl_reqs ? constraint_p (tmpl_reqs) : true);
-  gcc_assert (decl_reqs ? constraint_p (decl_reqs) : true);
-
-  if (!tmpl_reqs && !decl_reqs)
+  if (!tr && !dr)
     return NULL_TREE;
 
   tree_constraint_info* ci = build_constraint_info ();
-  ci->template_reqs = tmpl_reqs;
-  ci->declarator_reqs = decl_reqs;
-  ci->associated_constr = conjoin_constraints (tmpl_reqs, decl_reqs);
+  ci->template_reqs = tr;
+  ci->declarator_reqs = dr;
+  ci->associated_constr = combine_constraint_expressions (tr, dr);
 
   return (tree)ci;
 }
 
-namespace {
+/* Add constraint RHS to the end of CONSTRAINT_INFO ci.  */
+
+tree
+append_constraint (tree ci, tree rhs)
+{
+  tree tr = ci ? CI_TEMPLATE_REQS (ci) : NULL_TREE;
+  tree dr = ci ? CI_DECLARATOR_REQS (ci) : NULL_TREE;
+  dr = combine_constraint_expressions (dr, rhs);
+  if (ci)
+    {
+      CI_DECLARATOR_REQS (ci) = dr;
+      tree ac = combine_constraint_expressions (tr, dr);
+      CI_ASSOCIATED_CONSTRAINTS (ci) = ac;
+    }
+  else
+    ci = build_constraints (tr, dr);
+  return ci;
+}
+
+/* A mapping from declarations to constraint information.  */
+
+static GTY ((cache)) decl_tree_cache_map *decl_constraints;
+
+/* Returns the template constraints of declaration T. If T is not
+   constrained, return NULL_TREE. Note that T must be non-null. */
+
+tree
+get_constraints (const_tree t)
+{
+  if (!flag_concepts)
+    return NULL_TREE;
+  if (!decl_constraints)
+    return NULL_TREE;
+
+  gcc_assert (DECL_P (t));
+  if (TREE_CODE (t) == TEMPLATE_DECL)
+    t = DECL_TEMPLATE_RESULT (t);
+  tree* found = decl_constraints->get (CONST_CAST_TREE (t));
+  if (found)
+    return *found;
+  else
+    return NULL_TREE;
+}
+
+/* Associate the given constraint information CI with the declaration
+   T. If T is a template, then the constraints are associated with
+   its underlying declaration. Don't build associations if CI is
+   NULL_TREE.  */
+
+void
+set_constraints (tree t, tree ci)
+{
+  if (!ci)
+    return;
+  gcc_assert (t && flag_concepts);
+  if (TREE_CODE (t) == TEMPLATE_DECL)
+    t = DECL_TEMPLATE_RESULT (t);
+  bool found = hash_map_safe_put<hm_ggc> (decl_constraints, t, ci);
+  gcc_assert (!found);
+}
+
+/* Remove the associated constraints of the declaration T.  */
+
+void
+remove_constraints (tree t)
+{
+  gcc_assert (DECL_P (t));
+  if (TREE_CODE (t) == TEMPLATE_DECL)
+    t = DECL_TEMPLATE_RESULT (t);
+
+  if (decl_constraints)
+    decl_constraints->remove (t);
+}
+
+/* If DECL is a friend, substitute into REQS to produce requirements suitable
+   for declaration matching.  */
+
+tree
+maybe_substitute_reqs_for (tree reqs, const_tree decl_)
+{
+  if (reqs == NULL_TREE)
+    return NULL_TREE;
+  tree decl = CONST_CAST_TREE (decl_);
+  tree result = STRIP_TEMPLATE (decl);
+  if (DECL_FRIEND_P (result))
+    {
+      tree tmpl = decl == result ? DECL_TI_TEMPLATE (result) : decl;
+      tree gargs = generic_targs_for (tmpl);
+      processing_template_decl_sentinel s;
+      if (uses_template_parms (gargs))
+	++processing_template_decl;
+      reqs = tsubst_constraint (reqs, gargs,
+				tf_warning_or_error, NULL_TREE);
+    }
+  return reqs;
+}
+
+/* Returns the template-head requires clause for the template
+   declaration T or NULL_TREE if none.  */
+
+tree
+get_template_head_requirements (tree t)
+{
+  tree ci = get_constraints (t);
+  if (!ci)
+    return NULL_TREE;
+  return CI_TEMPLATE_REQS (ci);
+}
+
+/* Returns the trailing requires clause of the declarator of
+   a template declaration T or NULL_TREE if none.  */
+
+tree
+get_trailing_function_requirements (tree t)
+{
+  tree ci = get_constraints (t);
+  if (!ci)
+    return NULL_TREE;
+  return CI_DECLARATOR_REQS (ci);
+}
 
 /* Construct a sequence of template arguments by prepending
    ARG to REST. Either ARG or REST may be null. */
-tree
+static tree
 build_concept_check_arguments (tree arg, tree rest)
 {
   gcc_assert (rest ? TREE_CODE (rest) == TREE_VEC : true);
@@ -1200,27 +1262,156 @@
   return args;
 }
 
-} // namespace
-
-/* Construct an expression that checks the concept given by
-   TARGET. The TARGET must be:
-
-   - an OVERLOAD referring to one or more function concepts
-   - a BASELINK referring to an overload set of the above, or
-   - a TEMPLTATE_DECL referring to a variable concept.
-
-   ARG and REST are the explicit template arguments for the
-   eventual concept check. */
+/* Builds an id-expression of the form `C<Args...>()` where C is a function
+   concept.  */
+
+static tree
+build_function_check (tree tmpl, tree args, tsubst_flags_t /*complain*/)
+{
+  if (TREE_CODE (tmpl) == TEMPLATE_DECL)
+    {
+      /* If we just got a template, wrap it in an overload so it looks like any
+	 other template-id. */
+      tmpl = ovl_make (tmpl);
+      TREE_TYPE (tmpl) = boolean_type_node;
+    }
+
+  /* Perform function concept resolution now so we always have a single
+     function of the overload set (even if we started with only one; the
+     resolution function converts template arguments). Note that we still
+     wrap this in an overload set so we don't upset other parts of the
+     compiler that expect template-ids referring to function concepts
+     to have an overload set.  */
+  tree info = resolve_function_concept_overload (tmpl, args);
+  if (info == error_mark_node)
+    return error_mark_node;
+  if (!info)
+    {
+      error ("no matching concepts for %qE", tmpl);
+      return error_mark_node;
+    }
+  args = TREE_PURPOSE (info);
+  tmpl = DECL_TI_TEMPLATE (TREE_VALUE (info));
+
+  /* Rebuild the singleton overload set; mark the type bool.  */
+  tmpl = ovl_make (tmpl, NULL_TREE);
+  TREE_TYPE (tmpl) = boolean_type_node;
+
+  /* Build the id-expression around the overload set.  */
+  tree id = build2 (TEMPLATE_ID_EXPR, boolean_type_node, tmpl, args);
+
+  /* Finally, build the call expression around the overload.  */
+  ++processing_template_decl;
+  vec<tree, va_gc> *fargs = make_tree_vector ();
+  tree call = build_min_nt_call_vec (id, fargs);
+  TREE_TYPE (call) = boolean_type_node;
+  release_tree_vector (fargs);
+  --processing_template_decl;
+
+  return call;
+}
+
+/* Builds an id-expression of the form `C<Args...>` where C is a variable
+   concept.  */
+
+static tree
+build_variable_check (tree tmpl, tree args, tsubst_flags_t complain)
+{
+  gcc_assert (variable_concept_p (tmpl));
+  gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL);
+  tree parms = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (tmpl));
+  args = coerce_template_parms (parms, args, tmpl, complain);
+  if (args == error_mark_node)
+    return error_mark_node;
+  return build2 (TEMPLATE_ID_EXPR, boolean_type_node, tmpl, args);
+}
+
+/* Builds an id-expression of the form `C<Args...>` where C is a standard
+   concept.  */
+
+static tree
+build_standard_check (tree tmpl, tree args, tsubst_flags_t complain)
+{
+  gcc_assert (standard_concept_p (tmpl));
+  gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL);
+  tree parms = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (tmpl));
+  args = coerce_template_parms (parms, args, tmpl, complain);
+  if (args == error_mark_node)
+    return error_mark_node;
+  return build2 (TEMPLATE_ID_EXPR, boolean_type_node, tmpl, args);
+}
+
+/* Construct an expression that checks TARGET using ARGS.  */
+
 tree
-build_concept_check (tree target, tree arg, tree rest)
+build_concept_check (tree target, tree args, tsubst_flags_t complain)
 {
+  return build_concept_check (target, NULL_TREE, args, complain);
+}
+
+/* Construct an expression that checks the concept given by DECL. If
+   concept_definition_p (DECL) is false, this returns null.  */
+
+tree
+build_concept_check (tree decl, tree arg, tree rest, tsubst_flags_t complain)
+{
+  if (arg == NULL_TREE && rest == NULL_TREE)
+    {
+      tree id = build_nt (TEMPLATE_ID_EXPR, decl, rest);
+      error ("invalid use concept %qE", id);
+      return error_mark_node;
+    }
+
   tree args = build_concept_check_arguments (arg, rest);
-  if (variable_template_p (target))
-    return build_variable_check (lookup_template_variable (target, args));
-  else
-    return build_call_check (lookup_template_function (target, args));
+
+  if (standard_concept_p (decl))
+    return build_standard_check (decl, args, complain);
+  if (variable_concept_p (decl))
+    return build_variable_check (decl, args, complain);
+  if (function_concept_p (decl))
+    return build_function_check (decl, args, complain);
+
+  return error_mark_node;
+}
+
+/* Build a template-id that can participate in a concept check.  */
+
+static tree
+build_concept_id (tree decl, tree args)
+{
+  tree check = build_concept_check (decl, args, tf_warning_or_error);
+  if (check == error_mark_node)
+    return error_mark_node;
+  return unpack_concept_check (check);
 }
 
+/* Build a template-id that can participate in a concept check, preserving
+   the source location of the original template-id.  */
+
+tree
+build_concept_id (tree expr)
+{
+  gcc_assert (TREE_CODE (expr) == TEMPLATE_ID_EXPR);
+  tree id = build_concept_id (TREE_OPERAND (expr, 0), TREE_OPERAND (expr, 1));
+  protected_set_expr_location (id, cp_expr_location (expr));
+  return id;
+}
+
+/* Build as template-id with a placeholder that can be used as a
+   type constraint.
+
+   Note that this will diagnose errors if the initial concept check
+   cannot be built.  */
+
+tree
+build_type_constraint (tree decl, tree args, tsubst_flags_t complain)
+{
+  tree wildcard = build_nt (WILDCARD_DECL);
+  tree check = build_concept_check (decl, wildcard, args, complain);
+  if (check == error_mark_node)
+    return error_mark_node;
+  return unpack_concept_check (check);
+}
 
 /* Returns a TYPE_DECL that contains sufficient information to
    build a template parameter of the same kind as PROTO and
@@ -1241,17 +1432,14 @@
   return decl;
 }
 
-/* Create a constraint expression for the given DECL that
-   evaluates the requirements specified by CONSTR, a TYPE_DECL
-   that contains all the information necessary to build the
-   requirements (see finish_concept_name for the layout of
-   that TYPE_DECL).
-
-   Note that the constraints are neither reduced nor decomposed.
-   That is done only after the requires clause has been parsed
-   (or not).
-
-   This will always return a CHECK_CONSTR. */
+/* Create a constraint expression for the given DECL that evaluates the
+   requirements specified by CONSTR, a TYPE_DECL that contains all the
+   information necessary to build the requirements (see finish_concept_name
+   for the layout of that TYPE_DECL).
+
+   Note that the constraints are neither reduced nor decomposed. That is
+   done only after the requires clause has been parsed (or not).  */
+
 tree
 finish_shorthand_constraint (tree decl, tree constr)
 {
@@ -1266,41 +1454,46 @@
   tree con = CONSTRAINED_PARM_CONCEPT (constr);
   tree args = CONSTRAINED_PARM_EXTRA_ARGS (constr);
 
-  /* If the parameter declaration is variadic, but the concept
-     is not then we need to apply the concept to every element
-     in the pack.  */
-  bool is_proto_pack = template_parameter_pack_p (proto);
-  bool is_decl_pack = template_parameter_pack_p (decl);
-  bool apply_to_all_p = is_decl_pack && !is_proto_pack;
+  /* The TS lets use shorthand to constrain a pack of arguments, but the
+     standard does not.
+
+     For the TS, consider:
+
+	template<C... Ts> struct s;
+
+     If C is variadic (and because Ts is a pack), we associate the
+     constraint C<Ts...>. In all other cases, we associate
+     the constraint (C<Ts> && ...).
+
+     The standard behavior cannot be overridden by -fconcepts-ts.  */
+  bool variadic_concept_p = template_parameter_pack_p (proto);
+  bool declared_pack_p = template_parameter_pack_p (decl);
+  bool apply_to_each_p = (cxx_dialect >= cxx2a) ? true : !variadic_concept_p;
 
   /* Get the argument and overload used for the requirement
      and adjust it if we're going to expand later.  */
   tree arg = template_parm_to_arg (build_tree_list (NULL_TREE, decl));
-  if (apply_to_all_p)
+  if (apply_to_each_p && declared_pack_p)
     arg = PACK_EXPANSION_PATTERN (TREE_VEC_ELT (ARGUMENT_PACK_ARGS (arg), 0));
 
-  /* Build the concept check. If it the constraint needs to be
-     applied to all elements of the parameter pack, then make
-     the constraint an expansion. */
+  /* Build the concept constraint-expression.  */
   tree tmpl = DECL_TI_TEMPLATE (con);
-  tree check = VAR_P (con) ? tmpl : ovl_make (tmpl);
-  check = build_concept_check (check, arg, args);
-
-  /* Make the check a pack expansion if needed.
-
-     FIXME: We should be making a fold expression. */
-  if (apply_to_all_p)
-    {
-      check = make_pack_expansion (check);
-      TREE_TYPE (check) = boolean_type_node;
-    }
-
-  return normalize_expression (check);
+  tree check = tmpl;
+  if (TREE_CODE (con) == FUNCTION_DECL)
+    check = ovl_make (tmpl);
+  check = build_concept_check (check, arg, args, tf_warning_or_error);
+
+  /* Make the check a fold-expression if needed.  */
+  if (apply_to_each_p && declared_pack_p)
+    check = finish_left_unary_fold_expr (check, TRUTH_ANDIF_EXPR);
+
+  return check;
 }
 
 /* Returns a conjunction of shorthand requirements for the template
    parameter list PARMS. Note that the requirements are stored in
    the TYPE of each tree node. */
+
 tree
 get_shorthand_constraints (tree parms)
 {
@@ -1310,94 +1503,219 @@
     {
       tree parm = TREE_VEC_ELT (parms, i);
       tree constr = TEMPLATE_PARM_CONSTRAINTS (parm);
-      result = conjoin_constraints (result, constr);
+      result = combine_constraint_expressions (result, constr);
     }
   return result;
 }
 
-// Returns and chains a new parameter for PARAMETER_LIST which will conform
-// to the prototype given by SRC_PARM.  The new parameter will have its
-// identifier and location set according to IDENT and PARM_LOC respectively.
+/* Get the deduced wildcard from a DEDUCED placeholder.  If the deduced
+   wildcard is a pack, return the first argument of that pack.  */
+
 static tree
-process_introduction_parm (tree parameter_list, tree src_parm)
+get_deduced_wildcard (tree wildcard)
+{
+  if (ARGUMENT_PACK_P (wildcard))
+    wildcard = TREE_VEC_ELT (ARGUMENT_PACK_ARGS (wildcard), 0);
+  gcc_assert (TREE_CODE (wildcard) == WILDCARD_DECL);
+  return wildcard;
+}
+
+/* Returns the prototype parameter for the nth deduced wildcard.  */
+
+static tree
+get_introduction_prototype (tree wildcards, int index)
+{
+  return TREE_TYPE (get_deduced_wildcard (TREE_VEC_ELT (wildcards, index)));
+}
+
+/* Introduce a type template parameter.  */
+
+static tree
+introduce_type_template_parameter (tree wildcard, bool& non_type_p)
 {
-  // If we have a pack, we should have a single pack argument which is the
-  // placeholder we want to look at.
-  bool is_parameter_pack = ARGUMENT_PACK_P (src_parm);
-  if (is_parameter_pack)
-    src_parm = TREE_VEC_ELT (ARGUMENT_PACK_ARGS (src_parm), 0);
-
-  // At this point we should have a wildcard, but we want to
-  // grab the associated decl from it.  Also grab the stored
-  // identifier and location that should be chained to it in
-  // a PARM_DECL.
-  gcc_assert (TREE_CODE (src_parm) == WILDCARD_DECL);
-
-  tree ident = DECL_NAME (src_parm);
-  location_t parm_loc = DECL_SOURCE_LOCATION (src_parm);
-
-  // If we expect a pack and the deduced template is not a pack, or if the
-  // template is using a pack and we didn't declare a pack, throw an error.
-  if (is_parameter_pack != WILDCARD_PACK_P (src_parm))
-    {
-      error_at (parm_loc, "cannot match pack for introduced parameter");
-      tree err_parm = build_tree_list (error_mark_node, error_mark_node);
-      return chainon (parameter_list, err_parm);
-    }
-
-  src_parm = TREE_TYPE (src_parm);
+  non_type_p = false;
+  return finish_template_type_parm (class_type_node, DECL_NAME (wildcard));
+}
+
+/* Introduce a template template parameter.  */
+
+static tree
+introduce_template_template_parameter (tree wildcard, bool& non_type_p)
+{
+  non_type_p = false;
+  begin_template_parm_list ();
+  current_template_parms = DECL_TEMPLATE_PARMS (TREE_TYPE (wildcard));
+  end_template_parm_list ();
+  return finish_template_template_parm (class_type_node, DECL_NAME (wildcard));
+}
+
+/* Introduce a template non-type parameter.  */
+
+static tree
+introduce_nontype_template_parameter (tree wildcard, bool& non_type_p)
+{
+  non_type_p = true;
+  tree parm = copy_decl (TREE_TYPE (wildcard));
+  DECL_NAME (parm) = DECL_NAME (wildcard);
+  return parm;
+}
+
+/* Introduce a single template parameter.  */
+
+static tree
+build_introduced_template_parameter (tree wildcard, bool& non_type_p)
+{
+  tree proto = TREE_TYPE (wildcard);
 
   tree parm;
-  bool is_non_type;
-  if (TREE_CODE (src_parm) == TYPE_DECL)
-    {
-      is_non_type = false;
-      parm = finish_template_type_parm (class_type_node, ident);
-    }
-  else if (TREE_CODE (src_parm) == TEMPLATE_DECL)
+  if (TREE_CODE (proto) == TYPE_DECL)
+    parm = introduce_type_template_parameter (wildcard, non_type_p);
+  else if (TREE_CODE (proto) == TEMPLATE_DECL)
+    parm = introduce_template_template_parameter (wildcard, non_type_p);
+  else
+    parm = introduce_nontype_template_parameter (wildcard, non_type_p);
+
+  /* Wrap in a TREE_LIST for process_template_parm. Note that introduced
+     parameters do not retain the defaults from the source parameter.  */
+  return build_tree_list (NULL_TREE, parm);
+}
+
+/* Introduce a single template parameter.  */
+
+static tree
+introduce_template_parameter (tree parms, tree wildcard)
+{
+  gcc_assert (!ARGUMENT_PACK_P (wildcard));
+  tree proto = TREE_TYPE (wildcard);
+  location_t loc = DECL_SOURCE_LOCATION (wildcard);
+
+  /* Diagnose the case where we have C{...Args}.  */
+  if (WILDCARD_PACK_P (wildcard))
     {
-      is_non_type = false;
-      begin_template_parm_list ();
-      current_template_parms = DECL_TEMPLATE_PARMS (src_parm);
-      end_template_parm_list ();
-      parm = finish_template_template_parm (class_type_node, ident);
-    }
-  else
-    {
-      is_non_type = true;
-
-      // Since we don't have a declarator, so we can copy the source
-      // parameter and change the name and eventually the location.
-      parm = copy_decl (src_parm);
-      DECL_NAME (parm) = ident;
+      tree id = DECL_NAME (wildcard);
+      error_at (loc, "%qE cannot be introduced with an ellipsis %<...%>", id);
+      inform (DECL_SOURCE_LOCATION (proto), "prototype declared here");
     }
 
-  // Wrap in a TREE_LIST for process_template_parm.  Introductions do not
-  // retain the defaults from the source template.
-  parm = build_tree_list (NULL_TREE, parm);
-
-  return process_template_parm (parameter_list, parm_loc, parm,
-                                is_non_type, is_parameter_pack);
+  bool non_type_p;
+  tree parm = build_introduced_template_parameter (wildcard, non_type_p);
+  return process_template_parm (parms, loc, parm, non_type_p, false);
+}
+
+/* Introduce a template parameter pack.  */
+
+static tree
+introduce_template_parameter_pack (tree parms, tree wildcard)
+{
+  bool non_type_p;
+  tree parm = build_introduced_template_parameter (wildcard, non_type_p);
+  location_t loc = DECL_SOURCE_LOCATION (wildcard);
+  return process_template_parm (parms, loc, parm, non_type_p, true);
+}
+
+/* Introduce the nth template parameter.  */
+
+static tree
+introduce_template_parameter (tree parms, tree wildcards, int& index)
+{
+  tree deduced = TREE_VEC_ELT (wildcards, index++);
+  return introduce_template_parameter (parms, deduced);
+}
+
+/* Introduce either a template parameter pack or a list of template
+   parameters.  */
+
+static tree
+introduce_template_parameters (tree parms, tree wildcards, int& index)
+{
+  /* If the prototype was a parameter, we better have deduced an
+     argument pack, and that argument must be the last deduced value
+     in the wildcard vector.  */
+  tree deduced = TREE_VEC_ELT (wildcards, index++);
+  gcc_assert (ARGUMENT_PACK_P (deduced));
+  gcc_assert (index == TREE_VEC_LENGTH (wildcards));
+
+  /* Introduce each element in the pack.  */
+  tree args = ARGUMENT_PACK_ARGS (deduced);
+  for (int i = 0; i < TREE_VEC_LENGTH (args); ++i)
+    {
+      tree arg = TREE_VEC_ELT (args, i);
+      if (WILDCARD_PACK_P (arg))
+	parms = introduce_template_parameter_pack (parms, arg);
+      else
+	parms = introduce_template_parameter (parms, arg);
+    }
+
+  return parms;
 }
 
-/* Associates a constraint check to the current template based
-   on the introduction parameters.  INTRO_LIST must be a TREE_VEC
-   of WILDCARD_DECLs containing a chained PARM_DECL which
-   contains the identifier as well as the source location.
-   TMPL_DECL is the decl for the concept being used.  If we
-   take a concept, C, this will form a check in the form of
-   C<INTRO_LIST> filling in any extra arguments needed by the
-   defaults deduced.
-
-   Returns NULL_TREE if no concept could be matched and
-   error_mark_node if an error occurred when matching.  */
+/* Builds the template parameter list PARMS by chaining introduced
+   parameters from the WILDCARD vector.  INDEX is the position of
+   the current parameter.  */
+
+static tree
+process_introduction_parms (tree parms, tree wildcards, int& index)
+{
+  tree proto = get_introduction_prototype (wildcards, index);
+  if (template_parameter_pack_p (proto))
+    return introduce_template_parameters (parms, wildcards, index);
+  else
+    return introduce_template_parameter (parms, wildcards, index);
+}
+
+/* Ensure that all template parameters have been introduced for the concept
+   named in CHECK.  If not, emit a diagnostic.
+
+   Note that implicitly introducing a parameter with a default argument
+     creates a case where a parameter is declared, but unnamed, making
+     it unusable in the definition.  */
+
+static bool
+check_introduction_list (tree intros, tree check)
+{
+  check = unpack_concept_check (check);
+  tree tmpl = TREE_OPERAND (check, 0);
+  if (OVL_P (tmpl))
+    tmpl = OVL_FIRST (tmpl);
+
+  tree parms = DECL_INNERMOST_TEMPLATE_PARMS (tmpl);
+  if (TREE_VEC_LENGTH (intros) < TREE_VEC_LENGTH (parms))
+    {
+      error_at (input_location, "all template parameters of %qD must "
+				"be introduced", tmpl);
+      return false;
+    }
+
+   return true;
+}
+
+/* Associates a constraint check to the current template based on the
+   introduction parameters.  INTRO_LIST must be a TREE_VEC of WILDCARD_DECLs
+   containing a chained PARM_DECL which contains the identifier as well as
+   the source location. TMPL_DECL is the decl for the concept being used.
+   If we take a concept, C, this will form a check in the form of
+   C<INTRO_LIST> filling in any extra arguments needed by the defaults
+   deduced.
+
+   Returns NULL_TREE if no concept could be matched and error_mark_node if
+   an error occurred when matching.  */
+
 tree
-finish_template_introduction (tree tmpl_decl, tree intro_list)
+finish_template_introduction (tree tmpl_decl,
+			      tree intro_list,
+			      location_t intro_loc)
 {
-  /* Deduce the concept check.  */
-  tree expr = build_concept_check (tmpl_decl, NULL_TREE, intro_list);
+  /* Build a concept check to deduce the actual parameters.  */
+  tree expr = build_concept_check (tmpl_decl, intro_list, tf_none);
   if (expr == error_mark_node)
-    return NULL_TREE;
+    {
+      error_at (intro_loc, "cannot deduce template parameters from "
+			   "introduction list");
+      return error_mark_node;
+    }
+
+  if (!check_introduction_list (intro_list, expr))
+    return error_mark_node;
 
   tree parms = deduce_concept_introduction (expr);
   if (!parms)
@@ -1407,9 +1725,15 @@
   tree parm_list = NULL_TREE;
   begin_template_parm_list ();
   int nargs = MIN (TREE_VEC_LENGTH (parms), TREE_VEC_LENGTH (intro_list));
-  for (int n = 0; n < nargs; ++n)
-    parm_list = process_introduction_parm (parm_list, TREE_VEC_ELT (parms, n));
+  for (int n = 0; n < nargs; )
+    parm_list = process_introduction_parms (parm_list, parms, n);
   parm_list = end_template_parm_list (parm_list);
+
+  /* Update the number of arguments to reflect the number of deduced
+     template parameter introductions.  */
+  nargs = TREE_VEC_LENGTH (parm_list);
+
+  /* Determine if any errors occurred during matching.  */
   for (int i = 0; i < TREE_VEC_LENGTH (parm_list); ++i)
     if (TREE_VALUE (TREE_VEC_ELT (parm_list, i)) == error_mark_node)
       {
@@ -1418,7 +1742,7 @@
       }
 
   /* Build a concept check for our constraint.  */
-  tree check_args = make_tree_vec (TREE_VEC_LENGTH (parms));
+  tree check_args = make_tree_vec (nargs);
   int n = 0;
   for (; n < TREE_VEC_LENGTH (parm_list); ++n)
     {
@@ -1432,22 +1756,33 @@
   for (; n < TREE_VEC_LENGTH (parms); ++n)
     TREE_VEC_ELT (check_args, n) = TREE_VEC_ELT (parms, n);
 
-  /* Associate the constraint. */
-  tree check = build_concept_check (tmpl_decl, NULL_TREE, check_args);
-  tree constr = normalize_expression (check);
-  TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = constr;
+  /* Associate the constraint.  */
+  tree check = build_concept_check (tmpl_decl,
+				    check_args,
+				    tf_warning_or_error);
+  TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = check;
 
   return parm_list;
 }
 
 
-/* Given the predicate constraint T from a constrained-type-specifier, extract
+/* Given the concept check T from a constrained-type-specifier, extract
    its TMPL and ARGS.  FIXME why do we need two different forms of
    constrained-type-specifier?  */
 
 void
 placeholder_extract_concept_and_args (tree t, tree &tmpl, tree &args)
 {
+  if (concept_check_p (t))
+    {
+      t = unpack_concept_check (t);
+      tmpl = TREE_OPERAND (t, 0);
+      if (TREE_CODE (tmpl) == OVERLOAD)
+        tmpl = OVL_FIRST (tmpl);
+      args = TREE_OPERAND (t, 1);
+      return;
+    }
+
   if (TREE_CODE (t) == TYPE_DECL)
     {
       /* A constrained parameter.  Build a constraint check
@@ -1458,20 +1793,10 @@
       placeholder_extract_concept_and_args (check, tmpl, args);
       return;
     }
-
-  if (TREE_CODE (t) == CHECK_CONSTR)
-    {
-      tree decl = CHECK_CONSTR_CONCEPT (t);
-      tmpl = DECL_TI_TEMPLATE (decl);
-      args = CHECK_CONSTR_ARGS (t);
-      return;
-    }
-
-    gcc_unreachable ();
 }
 
 /* Returns true iff the placeholders C1 and C2 are equivalent.  C1
-   and C2 can be either CHECK_CONSTR or TEMPLATE_TYPE_PARM.  */
+   and C2 can be either TEMPLATE_TYPE_PARM or template-ids.  */
 
 bool
 equivalent_placeholder_constraints (tree c1, tree c2)
@@ -1516,7 +1841,7 @@
   return true;
 }
 
-/* Return a hash value for the placeholder PRED_CONSTR C.  */
+/* Return a hash value for the placeholder ATOMIC_CONSTR C.  */
 
 hashval_t
 hash_placeholder_constraint (tree c)
@@ -1533,178 +1858,198 @@
   return val;
 }
 
-/*---------------------------------------------------------------------------
-                        Constraint substitution
----------------------------------------------------------------------------*/
-
-/* The following functions implement substitution rules for constraints.
-   Substitution without checking constraints happens only in the
-   instantiation of class templates. For example:
-
-      template<C1 T> struct S {
-        void f(T) requires C2<T>;
-        void g(T) requires T::value;
-      };
-
-      S<int> s; // error instantiating S<int>::g(T)
-
-   When we instantiate S, we substitute into its member declarations,
-   including their constraints. However, those constraints are not
-   checked. Substituting int into C2<T> yields C2<int>, and substituting
-   into T::value yields a substitution failure, making the program
-   ill-formed.
-
-   Note that we only ever substitute into the associated constraints
-   of a declaration. That is, substitution is defined only for predicate
-   constraints and conjunctions. */
-
-/* Substitute into the predicate constraints. Returns error_mark_node
-   if the substitution into the expression fails. */
-tree
-tsubst_predicate_constraint (tree t, tree args,
-                             tsubst_flags_t complain, tree in_decl)
+/* Substitute through the simple requirement.  */
+
+static tree
+tsubst_valid_expression_requirement (tree t, tree args, subst_info info)
 {
-  tree expr = PRED_CONSTR_EXPR (t);
-  ++processing_template_decl;
-  tree result = tsubst_expr (expr, args, complain, in_decl, false);
-  --processing_template_decl;
-  return build_nt (PRED_CONSTR, result);
+  return tsubst_expr (t, args, info.complain, info.in_decl, false);
 }
 
-/* Substitute into a check constraint. */
-
-tree
-tsubst_check_constraint (tree t, tree args,
-                         tsubst_flags_t complain, tree in_decl)
+
+/* Substitute through the simple requirement.  */
+
+static tree
+tsubst_simple_requirement (tree t, tree args, subst_info info)
 {
-  tree decl = CHECK_CONSTR_CONCEPT (t);
-  tree tmpl = DECL_TI_TEMPLATE (decl);
-  tree targs = CHECK_CONSTR_ARGS (t);
-
-  /* Substitute through by building an template-id expression
-     and then substituting into that. */
-  tree expr = build_nt (TEMPLATE_ID_EXPR, tmpl, targs);
-  ++processing_template_decl;
-  tree result = tsubst_expr (expr, args, complain, in_decl, false);
-  --processing_template_decl;
-
-  if (result == error_mark_node)
+  tree t0 = TREE_OPERAND (t, 0);
+  tree expr = tsubst_valid_expression_requirement (t0, args, info);
+  if (expr == error_mark_node)
     return error_mark_node;
-
-  /* Extract the results and rebuild the check constraint. */
-  decl = DECL_TEMPLATE_RESULT (TREE_OPERAND (result, 0));
-  args = TREE_OPERAND (result, 1);
-
-  return build_nt (CHECK_CONSTR, decl, args);
+  return finish_simple_requirement (EXPR_LOCATION (t), expr);
 }
 
-/* Substitute into the conjunction of constraints. Returns
-   error_mark_node if substitution into either operand fails. */
-
-tree
-tsubst_logical_operator (tree t, tree args,
-			 tsubst_flags_t complain, tree in_decl)
+/* Substitute through the type requirement.  */
+
+static tree
+tsubst_type_requirement (tree t, tree args, subst_info info)
 {
   tree t0 = TREE_OPERAND (t, 0);
-  tree r0 = tsubst_constraint (t0, args, complain, in_decl);
-  if (r0 == error_mark_node)
-    return error_mark_node;
-  tree t1 = TREE_OPERAND (t, 1);
-  tree r1 = tsubst_constraint (t1, args, complain, in_decl);
-  if (r1 == error_mark_node)
-    return error_mark_node;
-  return build_nt (TREE_CODE (t), r0, r1);
-}
-
-namespace {
-
-/* Substitute ARGS into the expression constraint T.  */
-
-tree
-tsubst_expr_constr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
-{
-  cp_unevaluated guard;
-  tree expr = EXPR_CONSTR_EXPR (t);
-  tree ret = tsubst_expr (expr, args, complain, in_decl, false);
-  if (ret == error_mark_node)
-    return error_mark_node;
-  return build_nt (EXPR_CONSTR, ret);
-}
-
-/* Substitute ARGS into the type constraint T.  */
-
-tree
-tsubst_type_constr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
-{
-  tree type = TYPE_CONSTR_TYPE (t);
-  tree ret = tsubst (type, args, complain, in_decl);
-  if (ret == error_mark_node)
-    return error_mark_node;
-  return build_nt (TYPE_CONSTR, ret);
-}
-
-/* Substitute ARGS into the implicit conversion constraint T.  */
-
-tree
-tsubst_implicit_conversion_constr (tree t, tree args, tsubst_flags_t complain,
-                                   tree in_decl)
-{
-  cp_unevaluated guard;
-  tree expr = ICONV_CONSTR_EXPR (t);
-  tree type = ICONV_CONSTR_TYPE (t);
-  tree new_expr = tsubst_expr (expr, args, complain, in_decl, false);
-  if (new_expr == error_mark_node)
+  tree type = tsubst (t0, args, info.complain, info.in_decl);
+  if (type == error_mark_node)
     return error_mark_node;
-  tree new_type = tsubst (type, args, complain, in_decl);
-  if (new_type == error_mark_node)
-    return error_mark_node;
-  return build_nt (ICONV_CONSTR, new_expr, new_type);
+  return finish_type_requirement (EXPR_LOCATION (t), type);
 }
 
-/* Substitute ARGS into the argument deduction constraint T.  */
-
-tree
-tsubst_argument_deduction_constr (tree t, tree args, tsubst_flags_t complain,
-                                  tree in_decl)
+/* True if TYPE can be deduced from EXPR.  */
+
+static bool
+type_deducible_p (tree expr, tree type, tree placeholder, tree args,
+                  subst_info info)
 {
-  cp_unevaluated guard;
-  tree expr = DEDUCT_CONSTR_EXPR (t);
-  tree pattern = DEDUCT_CONSTR_PATTERN (t);
-  tree autos = DEDUCT_CONSTR_PLACEHOLDER(t);
-  tree new_expr = tsubst_expr (expr, args, complain, in_decl, false);
-  if (new_expr == error_mark_node)
+  /* Make sure deduction is performed against ( EXPR ), so that
+     references are preserved in the result.  */
+  expr = force_paren_expr_uneval (expr);
+
+  /* Replace the constraints with the instantiated constraints. This
+     substitutes args into any template parameters in the trailing
+     result type.  */
+  tree saved_constr = PLACEHOLDER_TYPE_CONSTRAINTS (placeholder);
+  tree subst_constr
+    = tsubst_constraint (saved_constr,
+			 args,
+			 info.complain | tf_partial,
+			 info.in_decl);
+
+  if (subst_constr == error_mark_node)
+    return false;
+
+  PLACEHOLDER_TYPE_CONSTRAINTS (placeholder) = subst_constr;
+
+  /* Temporarily unlink the canonical type.  */
+  tree saved_type = TYPE_CANONICAL (placeholder);
+  TYPE_CANONICAL (placeholder) = NULL_TREE;
+
+  tree deduced_type
+    = do_auto_deduction (type,
+			 expr,
+			 placeholder,
+			 info.complain,
+			 adc_requirement);
+
+  PLACEHOLDER_TYPE_CONSTRAINTS (placeholder) = saved_constr;
+  TYPE_CANONICAL (placeholder) = saved_type;
+
+  if (deduced_type == error_mark_node)
+    return false;
+
+  return true;
+}
+
+/* True if EXPR can not be converted to TYPE.  */
+
+static bool
+expression_convertible_p (tree expr, tree type, subst_info info)
+{
+  tree conv =
+    perform_direct_initialization_if_possible (type, expr, false,
+					       info.complain);
+  if (conv == error_mark_node)
+    return false;
+  if (conv == NULL_TREE)
+    {
+      if (info.complain & tf_error)
+        {
+          location_t loc = EXPR_LOC_OR_LOC (expr, input_location);
+          error_at (loc, "cannot convert %qE to %qT", expr, type);
+        }
+      return false;
+    }
+  return true;
+}
+
+
+/* Substitute through the compound requirement.  */
+
+static tree
+tsubst_compound_requirement (tree t, tree args, subst_info info)
+{
+  tree t0 = TREE_OPERAND (t, 0);
+  tree t1 = TREE_OPERAND (t, 1);
+  tree expr = tsubst_valid_expression_requirement (t0, args, info);
+  if (expr == error_mark_node)
     return error_mark_node;
-  /* It seems like substituting through the pattern will not affect the
-     placeholders.  We should (?) be able to reuse the existing list
-     without any problems.  If not, then we probably want to create a
-     new list of placeholders and then instantiate the pattern using
-     those.  */
-  tree new_pattern = tsubst (pattern, args, complain, in_decl);
-  if (new_pattern == error_mark_node)
+
+  /* Check the noexcept condition.  */
+  bool noexcept_p = COMPOUND_REQ_NOEXCEPT_P (t);
+  if (noexcept_p && !expr_noexcept_p (expr, tf_none))
+    return error_mark_node;
+
+  /* Substitute through the type expression, if any.  */
+  tree type = tsubst (t1, args, info.complain, info.in_decl);
+  if (type == error_mark_node)
     return error_mark_node;
-  return build_nt (DEDUCT_CONSTR, new_expr, new_pattern, autos);
+
+  /* Check expression against the result type.  */
+  if (type)
+    {
+      if (tree placeholder = type_uses_auto (type))
+	{
+	  if (!type_deducible_p (expr, type, placeholder, args, info))
+	    return error_mark_node;
+	}
+      else if (!expression_convertible_p (expr, type, info))
+	return error_mark_node;
+    }
+
+  return finish_compound_requirement (EXPR_LOCATION (t),
+				      expr, type, noexcept_p);
+}
+
+static tree
+tsubst_nested_requirement (tree t, tree args, subst_info info)
+{
+  gcc_assert (!uses_template_parms (args));
+
+  /* Ensure that we're in an evaluation context prior to satisfaction.  */
+  tree norm = TREE_VALUE (TREE_TYPE (t));
+  tree result = satisfy_constraint (norm, args, info);
+  if (result != boolean_true_node)
+    return error_mark_node;
+  return result;
 }
 
-/* Substitute ARGS into the exception constraint T.  */
-
-tree
-tsubst_exception_constr (tree t, tree args, tsubst_flags_t complain,
-			 tree in_decl)
+/* Substitute ARGS into the requirement T.  */
+
+static tree
+tsubst_requirement (tree t, tree args, subst_info info)
 {
-  cp_unevaluated guard;
-  tree expr = EXCEPT_CONSTR_EXPR (t);
-  tree ret = tsubst_expr (expr, args, complain, in_decl, false);
-  if (ret == error_mark_node)
-    return error_mark_node;
-  return build_nt (EXCEPT_CONSTR, ret);
+  iloc_sentinel loc_s (cp_expr_location (t));
+  switch (TREE_CODE (t))
+    {
+    case SIMPLE_REQ:
+      return tsubst_simple_requirement (t, args, info);
+    case TYPE_REQ:
+      return tsubst_type_requirement (t, args, info);
+    case COMPOUND_REQ:
+      return tsubst_compound_requirement (t, args, info);
+    case NESTED_REQ:
+      return tsubst_nested_requirement (t, args, info);
+    default:
+      break;
+    }
+  gcc_unreachable ();
 }
 
-/* A subroutine of tsubst_constraint_variables. Register local
-   specializations for each of parameter in PARMS and its
-   corresponding substituted constraint variable in VARS.
-   Returns VARS. */
-
-tree
+/* Substitute ARGS into the list of requirements T. Note that
+   substitution failures here result in ill-formed programs. */
+
+static tree
+tsubst_requirement_body (tree t, tree args, subst_info info)
+{
+  tree result = NULL_TREE;
+  while (t)
+    {
+      tree req = tsubst_requirement (TREE_VALUE (t), args, info);
+      if (req == error_mark_node)
+	return error_mark_node;
+      result = tree_cons (NULL_TREE, req, result);
+      t = TREE_CHAIN (t);
+    }
+  return nreverse (result);
+}
+
+static tree
 declare_constraint_vars (tree parms, tree vars)
 {
   tree s = vars;
@@ -1724,6 +2069,24 @@
   return vars;
 }
 
+/* Substitute through as if checking function parameter types. This
+   will diagnose common parameter type errors.  Returns error_mark_node
+   if an error occurred.  */
+
+static tree
+check_constaint_variables (tree t, tree args, subst_info info)
+{
+  tree types = NULL_TREE;
+  tree p = t;
+  while (p && !VOID_TYPE_P (p))
+    {
+      types = tree_cons (NULL_TREE, TREE_TYPE (p), types);
+      p = TREE_CHAIN (p);
+    }
+  types = chainon (nreverse (types), void_list_node);
+  return tsubst_function_parms (types, args, info.complain, info.in_decl);
+}
+
 /* A subroutine of tsubst_parameterized_constraint. Substitute ARGS
    into the parameter list T, producing a sequence of constraint
    variables, declared in the current scope.
@@ -1732,171 +2095,81 @@
    prior to calling this function since this substitution will
    declare the substituted parameters. */
 
-tree
-tsubst_constraint_variables (tree t, tree args,
-                             tsubst_flags_t complain, tree in_decl)
+static tree
+tsubst_constraint_variables (tree t, tree args, subst_info info)
 {
+  /* Perform a trial substitution to check for type errors.  */
+  tree parms = check_constaint_variables (t, args, info);
+  if (parms == error_mark_node)
+    return error_mark_node;
+
   /* Clear cp_unevaluated_operand across tsubst so that we get a proper chain
      of PARM_DECLs.  */
   int saved_unevaluated_operand = cp_unevaluated_operand;
   cp_unevaluated_operand = 0;
-  tree vars = tsubst (t, args, complain, in_decl);
+  tree vars = tsubst (t, args, info.complain, info.in_decl);
   cp_unevaluated_operand = saved_unevaluated_operand;
   if (vars == error_mark_node)
     return error_mark_node;
   return declare_constraint_vars (t, vars);
 }
 
-/* Substitute ARGS into the parameterized constraint T.  */
-
-tree
-tsubst_parameterized_constraint (tree t, tree args,
-				 tsubst_flags_t complain, tree in_decl)
-{
-  local_specialization_stack stack;
-  tree vars = tsubst_constraint_variables (PARM_CONSTR_PARMS (t),
-					   args, complain, in_decl);
-  if (vars == error_mark_node)
-    return error_mark_node;
-  tree expr = tsubst_constraint (PARM_CONSTR_OPERAND (t), args,
-				 complain, in_decl);
-  if (expr == error_mark_node)
-    return error_mark_node;
-  return build_nt (PARM_CONSTR, vars, expr);
-}
-
-/* Substitute ARGS into the simple requirement T. Note that
-   substitution may result in an ill-formed expression without
-   causing the program to be ill-formed. In such cases, the
-   requirement wraps an error_mark_node. */
-
-inline tree
-tsubst_simple_requirement (tree t, tree args,
-                           tsubst_flags_t complain, tree in_decl)
-{
-  ++processing_template_decl;
-  tree expr = tsubst_expr (TREE_OPERAND (t, 0), args, complain, in_decl, false);
-  --processing_template_decl;
-  return finish_simple_requirement (expr);
-}
-
-/* Substitute ARGS into the type requirement T. Note that
-   substitution may result in an ill-formed type without
-   causing the program to be ill-formed. In such cases, the
-   requirement wraps an error_mark_node. */
-
-inline tree
-tsubst_type_requirement (tree t, tree args,
-                         tsubst_flags_t complain, tree in_decl)
-{
-  ++processing_template_decl;
-  tree type = tsubst (TREE_OPERAND (t, 0), args, complain, in_decl);
-  --processing_template_decl;
-  return finish_type_requirement (type);
-}
-
-/* Substitute args into the compound requirement T. If substituting
-   into either the expression or the type fails, the corresponding
-   operands in the resulting node will be error_mark_node. This
-   preserves a requirement for the purpose of partial ordering, but
-   it will never be satisfied. */
-
-tree
-tsubst_compound_requirement (tree t, tree args,
-                             tsubst_flags_t complain, tree in_decl)
-{
-  ++processing_template_decl;
-  tree expr = tsubst_expr (TREE_OPERAND (t, 0), args, complain, in_decl, false);
-  tree type = tsubst (TREE_OPERAND (t, 1), args, complain, in_decl);
-  --processing_template_decl;
-  bool noexcept_p = COMPOUND_REQ_NOEXCEPT_P (t);
-  return finish_compound_requirement (expr, type, noexcept_p);
-}
-
-/* Substitute ARGS into the nested requirement T. */
-
-tree
-tsubst_nested_requirement (tree t, tree args,
-                           tsubst_flags_t complain, tree in_decl)
-{
-  ++processing_template_decl;
-  tree expr = tsubst_expr (TREE_OPERAND (t, 0), args, complain, in_decl, false);
-  --processing_template_decl;
-  return finish_nested_requirement (expr);
-}
-
-/* Substitute ARGS into the requirement T.  */
-
-inline tree
-tsubst_requirement (tree t, tree args, tsubst_flags_t complain, tree in_decl)
-{
-  switch (TREE_CODE (t))
-    {
-    case SIMPLE_REQ:
-      return tsubst_simple_requirement (t, args, complain, in_decl);
-    case TYPE_REQ:
-      return tsubst_type_requirement (t, args, complain, in_decl);
-    case COMPOUND_REQ:
-      return tsubst_compound_requirement (t, args, complain, in_decl);
-    case NESTED_REQ:
-      return tsubst_nested_requirement (t, args, complain, in_decl);
-    default:
-      gcc_unreachable ();
-    }
-  return error_mark_node;
-}
-
-/* Substitute ARGS into the list of requirements T. Note that
-   substitution failures here result in ill-formed programs. */
-
-tree
-tsubst_requirement_body (tree t, tree args,
-                         tsubst_flags_t complain, tree in_decl)
-{
-  tree r = NULL_TREE;
-  while (t)
-    {
-      tree e = tsubst_requirement (TREE_VALUE (t), args, complain, in_decl);
-      if (e == error_mark_node)
-        return error_mark_node;
-      r = tree_cons (NULL_TREE, e, r);
-      t = TREE_CHAIN (t);
-    }
-  /* Ensure that the order of constraints is the same as the original.  */
-  return nreverse (r);
-}
-
-} /* namespace */
-
-/* Substitute ARGS into the requires expression T. Note that this
-   results in the re-declaration of local parameters when
-   substituting through the parameter list. If either substitution
-   fails, the program is ill-formed. */
+/* Substitute ARGS into the requires-expression T. [8.4.7]p6. The
+   substitution of template arguments into a requires-expression
+   may result in the formation of invalid types or expressions
+   in its requirements ... In such cases, the expression evaluates
+   to false; it does not cause the program to be ill-formed.
+
+   However, there are cases where substitution must produce a
+   new requires-expression, that is not a template constraint.
+   For example:
+
+        template<typename T>
+        class X {
+          template<typename U>
+          static constexpr bool var = requires (U u) { T::fn(u); };
+        };
+
+   In the instantiation of X<Y> (assuming Y defines fn), then the
+   instantiated requires-expression would include Y::fn(u). If any
+   substitution in the requires-expression fails, we can immediately
+   fold the expression to false, as would be the case e.g., when
+   instantiation X<int>.  */
 
 tree
 tsubst_requires_expr (tree t, tree args,
-                      tsubst_flags_t complain, tree in_decl)
+		      tsubst_flags_t complain, tree in_decl)
 {
-  local_specialization_stack stack;
+  local_specialization_stack stack (lss_copy);
+
+  subst_info info (complain, in_decl);
+
+  /* A requires-expression is an unevaluated context.  */
+  cp_unevaluated u;
 
   tree parms = TREE_OPERAND (t, 0);
   if (parms)
     {
-      parms = tsubst_constraint_variables (parms, args, complain, in_decl);
+      parms = tsubst_constraint_variables (parms, args, info);
       if (parms == error_mark_node)
-        return error_mark_node;
+	return boolean_false_node;
     }
 
   tree reqs = TREE_OPERAND (t, 1);
-  reqs = tsubst_requirement_body (reqs, args, complain, in_decl);
+  reqs = tsubst_requirement_body (reqs, args, info);
   if (reqs == error_mark_node)
-    return error_mark_node;
-
-  return finish_requires_expr (parms, reqs);
+    return boolean_false_node;
+
+  /* In certain cases, produce a new requires-expression.
+     Otherwise the value of the expression is true.  */
+  if (processing_template_decl && uses_template_parms (args))
+    return finish_requires_expr (cp_expr_location (t), parms, reqs);
+
+  return boolean_true_node;
 }
 
 /* Substitute ARGS into the constraint information CI, producing a new
-   constraint record. */
+   constraint record.  */
 
 tree
 tsubst_constraint_info (tree t, tree args,
@@ -1905,378 +2178,414 @@
   if (!t || t == error_mark_node || !check_constraint_info (t))
     return NULL_TREE;
 
-  tree tmpl_constr = NULL_TREE;
-  if (tree r = CI_TEMPLATE_REQS (t))
-    tmpl_constr = tsubst_constraint (r, args, complain, in_decl);
-
-  tree decl_constr = NULL_TREE;
-  if (tree r = CI_DECLARATOR_REQS (t))
-    decl_constr = tsubst_constraint (r, args, complain, in_decl);
-
-  return build_constraints (tmpl_constr, decl_constr);
+  tree tr = tsubst_constraint (CI_TEMPLATE_REQS (t), args, complain, in_decl);
+  tree dr = tsubst_constraint (CI_DECLARATOR_REQS (t), args, complain, in_decl);
+  return build_constraints (tr, dr);
 }
 
-/* Substitute ARGS into the constraint T. */
+/* Substitute through a parameter mapping, in order to get the actual
+   arguments used to instantiate an atomic constraint.  This may fail
+   if the substitution into arguments produces something ill-formed.  */
+
+static tree
+tsubst_parameter_mapping (tree map, tree args, subst_info info)
+{
+  if (!map)
+    return NULL_TREE;
+
+  tsubst_flags_t complain = info.complain;
+  tree in_decl = info.in_decl;
+
+  tree result = NULL_TREE;
+  for (tree p = map; p; p = TREE_CHAIN (p))
+    {
+      if (p == error_mark_node)
+        return error_mark_node;
+      tree parm = TREE_VALUE (p);
+      tree arg = TREE_PURPOSE (p);
+      tree new_arg = NULL_TREE;
+      if (TYPE_P (arg))
+        {
+          /* If a template parameter is declared with a placeholder, we can
+             get those in the argument list if decltype is applied to the
+             placeholder. For example:
+
+		template<auto T>
+		  requires C<decltype(T)>
+		void f() { }
+
+	     The normalized argument for C will be an auto type, so we'll
+             need to deduce the actual argument from the corresponding
+             initializer (whatever argument is provided for T), and use
+             that result in the instantiated parameter mapping.  */
+          if (tree auto_node = type_uses_auto (arg))
+            {
+              int level;
+              int index;
+	      template_parm_level_and_index (parm, &level, &index);
+	      tree init = TMPL_ARG (args, level, index);
+              new_arg = do_auto_deduction (arg, init, auto_node,
+					   complain, adc_variable_type,
+					   make_tree_vec (0));
+            }
+        }
+      else if (ARGUMENT_PACK_P (arg))
+	new_arg = tsubst_argument_pack (arg, args, complain, in_decl);
+      if (!new_arg)
+	new_arg = tsubst_template_arg (arg, args, complain, in_decl);
+      if (new_arg == error_mark_node)
+	return error_mark_node;
+
+      result = tree_cons (new_arg, parm, result);
+    }
+  return nreverse (result);
+}
 
 tree
-tsubst_constraint (tree t, tree args, tsubst_flags_t complain, tree in_decl)
+tsubst_parameter_mapping (tree map, tree args, tsubst_flags_t complain, tree in_decl)
 {
-  if (t == NULL_TREE || t == error_mark_node)
-    return t;
-  switch (TREE_CODE (t))
-  {
-  case PRED_CONSTR:
-    return tsubst_predicate_constraint (t, args, complain, in_decl);
-  case CHECK_CONSTR:
-    return tsubst_check_constraint (t, args, complain, in_decl);
-  case CONJ_CONSTR:
-  case DISJ_CONSTR:
-    return tsubst_logical_operator (t, args, complain, in_decl);
-  case PARM_CONSTR:
-    return tsubst_parameterized_constraint (t, args, complain, in_decl);
-  case EXPR_CONSTR:
-    return tsubst_expr_constr (t, args, complain, in_decl);
-  case TYPE_CONSTR:
-    return tsubst_type_constr (t, args, complain, in_decl);
-  case ICONV_CONSTR:
-    return tsubst_implicit_conversion_constr (t, args, complain, in_decl);
-  case DEDUCT_CONSTR:
-    return tsubst_argument_deduction_constr (t, args, complain, in_decl);
-  case EXCEPT_CONSTR:
-    return tsubst_exception_constr (t, args, complain, in_decl);
-  default:
-    gcc_unreachable ();
-  }
-  return error_mark_node;
+  return tsubst_parameter_mapping (map, args, subst_info (complain, in_decl));
 }
 
 /*---------------------------------------------------------------------------
                         Constraint satisfaction
 ---------------------------------------------------------------------------*/
 
-/* The following functions determine if a constraint, when
-   substituting template arguments, is satisfied. For convenience,
-   satisfaction reduces a constraint to either true or false (and
-   nothing else). */
-
-namespace {
-
-tree satisfy_constraint_1 (tree, tree, tsubst_flags_t, tree);
-
-/* Check the constraint pack expansion.  */
-
-tree
-satisfy_pack_expansion (tree t, tree args,
-                      tsubst_flags_t complain, tree in_decl)
+/* Hash functions for satisfaction entries.  */
+
+struct GTY((for_user)) sat_entry
+{
+  tree constr;
+  tree args;
+  tree result;
+};
+
+struct sat_hasher : ggc_ptr_hash<sat_entry>
+{
+  static hashval_t hash (sat_entry *e)
+  {
+    hashval_t value = hash_atomic_constraint (e->constr);
+    return iterative_hash_template_arg (e->args, value);
+  }
+
+  static bool equal (sat_entry *e1, sat_entry *e2)
+  {
+    if (!atomic_constraints_identical_p (e1->constr, e2->constr))
+      return false;
+    return template_args_equal (e1->args, e2->args);
+  }
+};
+
+/* Cache the result of satisfy_atom.  */
+static GTY((deletable)) hash_table<sat_hasher> *sat_cache;
+
+/* Cache the result of constraint_satisfaction_value.  */
+static GTY((deletable)) hash_map<tree, tree> *decl_satisfied_cache;
+
+static tree
+get_satisfaction (tree constr, tree args)
+{
+  if (!sat_cache)
+    return NULL_TREE;
+  sat_entry elt = { constr, args, NULL_TREE };
+  sat_entry* found = sat_cache->find (&elt);
+  if (found)
+    return found->result;
+  else
+    return NULL_TREE;
+}
+
+static void
+save_satisfaction (tree constr, tree args, tree result)
 {
-  /* Get the vector of satisfaction results.
-     gen_elem_of_pack_expansion_instantiation will check that each element of
-     the expansion is satisfied.  */
-  tree exprs = tsubst_pack_expansion (t, args, complain, in_decl);
-
-  if (exprs == error_mark_node)
-    return boolean_false_node;
-
-  /* TODO: It might be better to normalize each expanded term
-     and evaluate them separately. That would provide better
-     opportunities for diagnostics.  */
-  for (int i = 0; i < TREE_VEC_LENGTH (exprs); ++i)
-    if (TREE_VEC_ELT (exprs, i) != boolean_true_node)
-      return boolean_false_node;
-  return boolean_true_node;
+  if (!sat_cache)
+    sat_cache = hash_table<sat_hasher>::create_ggc (31);
+  sat_entry elt = {constr, args, result};
+  sat_entry** slot = sat_cache->find_slot (&elt, INSERT);
+  sat_entry* entry = ggc_alloc<sat_entry> ();
+  *entry = elt;
+  *slot = entry;
+}
+
+void
+clear_satisfaction_cache ()
+{
+  if (sat_cache)
+    sat_cache->empty ();
+  if (decl_satisfied_cache)
+    decl_satisfied_cache->empty ();
 }
 
-/* A predicate constraint is satisfied if its expression evaluates
-   to true. If substitution into that node fails, the constraint
-   is not satisfied ([temp.constr.pred]).
-
-   Note that a predicate constraint is a constraint expression
-   of type bool. If neither of those are true, the program is
-   ill-formed; they are not SFINAE'able errors. */
+/* A tool to help manage satisfaction caching in satisfy_constraint_r.
+   Note the cache is only used when not diagnosing errors.  */
+
+struct satisfaction_cache
+{
+  satisfaction_cache (tree constr, tree args, tsubst_flags_t complain)
+    : constr(constr), args(args), complain(complain)
+  { }
+
+  tree get ()
+  {
+    if (complain == tf_none)
+      return get_satisfaction (constr, args);
+    return NULL_TREE;
+  }
+
+  tree save (tree result)
+  {
+    if (complain == tf_none)
+      save_satisfaction (constr, args, result);
+    return result;
+  }
+
+  tree constr;
+  tree args;
+  tsubst_flags_t complain;
+};
+
+static int satisfying_constraint = 0;
+
+/* Returns true if we are currently satisfying a constraint.
+
+   This is used to guard against recursive calls to evaluate_concept_check
+   during template argument substitution.
+
+   TODO: Do we need this now that we fully normalize prior to evaluation?
+   I think not. */
+
+bool
+satisfying_constraint_p ()
+{
+  return satisfying_constraint;
+}
+
+/* Substitute ARGS into constraint-expression T during instantiation of
+   a member of a class template.  */
 
 tree
-satisfy_predicate_constraint (tree t, tree args,
-                              tsubst_flags_t complain, tree in_decl)
+tsubst_constraint (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 {
-  tree expr = TREE_OPERAND (t, 0);
-
-  /* We should never have a naked pack expansion in a predicate constraint.  */
-  gcc_assert (TREE_CODE (expr) != EXPR_PACK_EXPANSION);
-
-  /* If substitution into the expression fails, the constraint
-     is not satisfied.  */
-  expr = tsubst_expr (expr, args, complain, in_decl, false);
-  if (expr == error_mark_node)
-    return boolean_false_node;
-
-  /* A predicate constraint shall have type bool. In some
-     cases, substitution gives us const-qualified bool, which
-     is also acceptable.  */
-  tree type = cv_unqualified (TREE_TYPE (expr));
-  if (!same_type_p (type, boolean_type_node))
-    {
-      error_at (cp_expr_loc_or_loc (expr, input_location),
-                "constraint %qE does not have type %qT",
-                expr, boolean_type_node);
-      return boolean_false_node;
-    }
-
-  return cxx_constant_value (expr);
+  /* We also don't want to evaluate concept-checks when substituting the
+     constraint-expressions of a declaration.  */
+  processing_constraint_expression_sentinel s;
+  tree expr = tsubst_expr (t, args, complain, in_decl, false);
+  return expr;
 }
 
-/* A concept check constraint like C<CARGS> is satisfied if substituting ARGS
-   into CARGS succeeds and C is satisfied for the resulting arguments.  */
-
-tree
-satisfy_check_constraint (tree t, tree args,
-                          tsubst_flags_t complain, tree in_decl)
+static tree satisfy_constraint_r (tree, tree, subst_info info);
+
+/* Compute the satisfaction of a conjunction.  */
+
+static tree
+satisfy_conjunction (tree t, tree args, subst_info info)
 {
-  tree decl = CHECK_CONSTR_CONCEPT (t);
-  tree tmpl = DECL_TI_TEMPLATE (decl);
-  tree cargs = CHECK_CONSTR_ARGS (t);
-
-  /* Instantiate the concept check arguments.  */
-  tree targs = tsubst (cargs, args, tf_none, NULL_TREE);
-  if (targs == error_mark_node)
-    return boolean_false_node;
-
-  /* Search for a previous value.  */
-  if (tree prev = lookup_concept_satisfaction (tmpl, targs))
-    return prev;
-
-  /* Expand the concept; failure here implies non-satisfaction.  */
-  tree def = expand_concept (decl, targs);
-  if (def == error_mark_node)
-    return memoize_concept_satisfaction (tmpl, args, boolean_false_node);
-
-  /* Recursively satisfy the constraint.  */
-  tree result = satisfy_constraint_1 (def, targs, complain, in_decl);
-  return memoize_concept_satisfaction (tmpl, targs, result);
+  tree lhs = satisfy_constraint_r (TREE_OPERAND (t, 0), args, info);
+  if (lhs == error_mark_node || lhs == boolean_false_node)
+    return lhs;
+  return satisfy_constraint_r (TREE_OPERAND (t, 1), args, info);
 }
 
-/* Check an expression constraint. The constraint is satisfied if
-   substitution succeeds ([temp.constr.expr]).
-
-   Note that the expression is unevaluated. */
-
-tree
-satisfy_expression_constraint (tree t, tree args,
-                               tsubst_flags_t complain, tree in_decl)
+/* Compute the satisfaction of a disjunction.  */
+
+static tree
+satisfy_disjunction (tree t, tree args, subst_info info)
 {
-  cp_unevaluated guard;
-  deferring_access_check_sentinel deferring;
-
-  tree expr = EXPR_CONSTR_EXPR (t);
-  tree check = tsubst_expr (expr, args, complain, in_decl, false);
-  if (check == error_mark_node)
-    return boolean_false_node;
-  if (!perform_deferred_access_checks (tf_none))
-    return boolean_false_node;
-  return boolean_true_node;
+  /* Evaluate the operands quietly.  */
+  subst_info quiet (tf_none, NULL_TREE);
+
+  /* Register the constraint for diagnostics, if needed.  */
+  diagnosing_failed_constraint failure (t, args, info.noisy ());
+
+  tree lhs = satisfy_constraint_r (TREE_OPERAND (t, 0), args, quiet);
+  if (lhs == boolean_true_node)
+    return boolean_true_node;
+  tree rhs = satisfy_constraint_r (TREE_OPERAND (t, 1), args, quiet);
+  if (rhs != boolean_true_node && info.noisy ())
+    {
+      location_t loc = cp_expr_location (CONSTR_EXPR (t));
+      inform (loc, "neither operand of the disjunction is satisfied");
+      /* TODO: Replay the LHS and RHS to find failures in both branches.  */
+      // satisfy_constraint_r (TREE_OPERAND (t, 0), args, info);
+      // satisfy_constraint_r (TREE_OPERAND (t, 1), args, info);
+    }
+  return rhs;
 }
 
-/* Check a type constraint. The constraint is satisfied if
-   substitution succeeds. */
-
-inline tree
-satisfy_type_constraint (tree t, tree args,
-                         tsubst_flags_t complain, tree in_decl)
-{
-  deferring_access_check_sentinel deferring;
-  tree type = TYPE_CONSTR_TYPE (t);
-  gcc_assert (TYPE_P (type) || type == error_mark_node);
-  tree check = tsubst (type, args, complain, in_decl);
-  if (error_operand_p (check))
-    return boolean_false_node;
-  if (!perform_deferred_access_checks (complain))
-    return boolean_false_node;
-  return boolean_true_node;
-}
-
-/* Check an implicit conversion constraint.  */
+/* Ensures that T is a truth value and not (accidentally, as sometimes
+   happens) an integer value.  */
 
 tree
-satisfy_implicit_conversion_constraint (tree t, tree args,
-                                        tsubst_flags_t complain, tree in_decl)
+satisfaction_value (tree t)
 {
-  /* Don't tsubst as if we're processing a template. If we try
-     to we can end up generating template-like expressions
-     (e.g., modop-exprs) that aren't properly typed.  */
-  tree expr =
-    tsubst_expr (ICONV_CONSTR_EXPR (t), args, complain, in_decl, false);
-  if (expr == error_mark_node)
-    return boolean_false_node;
-
-  /* Get the transformed target type.  */
-  tree type = tsubst (ICONV_CONSTR_TYPE (t), args, complain, in_decl);
-  if (type == error_mark_node)
-    return boolean_false_node;
-
-  /* Attempt the conversion as a direct initialization
-     of the form TYPE <unspecified> = EXPR.  */
-  tree conv =
-    perform_direct_initialization_if_possible (type, expr, false, complain);
-  if (conv == NULL_TREE || conv == error_mark_node)
-    return boolean_false_node;
-  else
+  if (t == error_mark_node)
+    return t;
+  if (t == boolean_true_node || t == integer_one_node)
     return boolean_true_node;
-}
-
-/* Check an argument deduction constraint. */
-
-tree
-satisfy_argument_deduction_constraint (tree t, tree args,
-                                       tsubst_flags_t complain, tree in_decl)
-{
-  /* Substitute through the expression. */
-  tree expr = DEDUCT_CONSTR_EXPR (t);
-  tree init = tsubst_expr (expr, args, complain, in_decl, false);
-  if (expr == error_mark_node)
+  if (t == boolean_false_node || t == integer_zero_node)
     return boolean_false_node;
 
-  /* Perform auto or decltype(auto) deduction to get the result. */
-  tree pattern = DEDUCT_CONSTR_PATTERN (t);
-  tree placeholder = DEDUCT_CONSTR_PLACEHOLDER (t);
-  tree constr = PLACEHOLDER_TYPE_CONSTRAINTS (placeholder);
-  tree type_canonical = TYPE_CANONICAL (placeholder);
-  PLACEHOLDER_TYPE_CONSTRAINTS (placeholder)
-    = tsubst_constraint (constr, args, complain|tf_partial, in_decl);
-  TYPE_CANONICAL (placeholder) = NULL_TREE;
-  tree type = do_auto_deduction (pattern, init, placeholder,
-                                 complain, adc_requirement);
-  PLACEHOLDER_TYPE_CONSTRAINTS (placeholder) = constr;
-  TYPE_CANONICAL (placeholder) = type_canonical;
-  if (type == error_mark_node)
-    return boolean_false_node;
-
-  return boolean_true_node;
+  /* Anything else should be invalid.  */
+  gcc_assert (false);
 }
 
-/* Check an exception constraint. An exception constraint for an
-   expression e is satisfied when noexcept(e) is true. */
-
-tree
-satisfy_exception_constraint (tree t, tree args,
-                              tsubst_flags_t complain, tree in_decl)
-{
-  tree expr = EXCEPT_CONSTR_EXPR (t);
-  tree check = tsubst_expr (expr, args, complain, in_decl, false);
-  if (check == error_mark_node)
-    return boolean_false_node;
-
-  if (expr_noexcept_p (check, complain))
-    return boolean_true_node;
-  else
-    return boolean_false_node;
-}
-
-/* Check a parameterized constraint. */
+/* Build a new template argument list with template arguments corresponding
+   to the parameters used in an atomic constraint.  */
 
 tree
-satisfy_parameterized_constraint (tree t, tree args,
-                                  tsubst_flags_t complain, tree in_decl)
+get_mapped_args (tree map)
 {
-  local_specialization_stack stack;
-  tree parms = PARM_CONSTR_PARMS (t);
-  tree vars = tsubst_constraint_variables (parms, args, complain, in_decl);
-  if (vars == error_mark_node)
-    return boolean_false_node;
-  tree constr = PARM_CONSTR_OPERAND (t);
-  return satisfy_constraint_1 (constr, args, complain, in_decl);
+  /* No map, no arguments.  */
+  if (!map)
+    return NULL_TREE;
+
+  /* Find the mapped parameter with the highest level.  */
+  int count = 0;
+  for (tree p = map; p; p = TREE_CHAIN (p))
+    {
+      int level;
+      int index;
+      template_parm_level_and_index (TREE_VALUE (p), &level, &index);
+      if (level > count)
+        count = level;
+    }
+
+  /* Place each argument at its corresponding position in the argument
+     list. Note that the list will be sparse (not all arguments supplied),
+     but instantiation is guaranteed to only use the parameters in the
+     mapping, so null arguments would never be used.  */
+  auto_vec< vec<tree> > lists (count);
+  lists.quick_grow_cleared (count);
+  for (tree p = map; p; p = TREE_CHAIN (p))
+    {
+      int level;
+      int index;
+      template_parm_level_and_index (TREE_VALUE (p), &level, &index);
+
+      /* Insert the argument into its corresponding position.  */
+      vec<tree> &list = lists[level - 1];
+      if (index >= (int)list.length ())
+	list.safe_grow_cleared (index + 1);
+      list[index] = TREE_PURPOSE (p);
+    }
+
+  /* Build the new argument list.  */
+  tree args = make_tree_vec (lists.length ());
+  for (unsigned i = 0; i != lists.length (); ++i)
+    {
+      vec<tree> &list = lists[i];
+      tree level = make_tree_vec (list.length ());
+      for (unsigned j = 0; j < list.length(); ++j)
+	TREE_VEC_ELT (level, j) = list[j];
+      SET_TMPL_ARGS_LEVEL (args, i + 1, level);
+      list.release ();
+    }
+  SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (args, 0);
+
+  return args;
 }
 
-/* Check that the conjunction of constraints is satisfied. Note
-   that if left operand is not satisfied, the right operand
-   is not checked.
-
-   FIXME: Check that this wouldn't result in a user-defined
-   operator. Note that this error is partially diagnosed in
-   satisfy_predicate_constraint. It would be nice to diagnose
-   the overload, but I don't think it's strictly necessary.  */
-
-tree
-satisfy_conjunction (tree t, tree args, tsubst_flags_t complain, tree in_decl)
+static void diagnose_atomic_constraint (tree, tree, subst_info);
+
+/* Compute the satisfaction of an atomic constraint.  */
+
+static tree
+satisfy_atom (tree t, tree args, subst_info info)
 {
-  tree t0 = satisfy_constraint_1 (TREE_OPERAND (t, 0), args, complain, in_decl);
-  if (t0 == boolean_false_node)
-    return boolean_false_node;
-  return satisfy_constraint_1 (TREE_OPERAND (t, 1), args, complain, in_decl);
+  satisfaction_cache cache (t, args, info.complain);
+  if (tree r = cache.get ())
+    return r;
+
+  /* Perform substitution quietly.  */
+  subst_info quiet (tf_none, NULL_TREE);
+
+  /* In case there is a diagnostic, we want to establish the context
+     prior to printing errors.  If no errors occur, this context is
+     removed before returning.  */
+  diagnosing_failed_constraint failure (t, args, info.noisy ());
+
+  /* Instantiate the parameter mapping.  */
+  tree map = tsubst_parameter_mapping (ATOMIC_CONSTR_MAP (t), args, quiet);
+  if (map == error_mark_node)
+    {
+      /* If instantiation of the parameter mapping fails, the program
+         is ill-formed.  */
+      if (info.noisy())
+	tsubst_parameter_mapping (ATOMIC_CONSTR_MAP (t), args, info);
+      return cache.save (boolean_false_node);
+    }
+
+  /* Rebuild the argument vector from the parameter mapping.  */
+  args = get_mapped_args (map);
+
+  /* Apply the parameter mapping (i.e., just substitute).  */
+  tree expr = ATOMIC_CONSTR_EXPR (t);
+  tree result = tsubst_expr (expr, args, quiet.complain, quiet.in_decl, false);
+  if (result == error_mark_node)
+    {
+      /* If substitution results in an invalid type or expression, the constraint
+	 is not satisfied. Replay the substitution.  */
+      if (info.noisy ())
+	tsubst_expr (expr, args, info.complain, info.in_decl, false);
+      return cache.save (boolean_false_node);
+    }
+
+  location_t loc = cp_expr_loc_or_input_loc (expr);
+
+  /* [17.4.1.2] ... lvalue-to-value conversion is performed as necessary,
+     and EXPR shall be a constant expression of type bool.  */
+  result = force_rvalue (result, info.complain);
+  if (result == error_mark_node)
+    return cache.save (error_mark_node);
+  if (!same_type_p (TREE_TYPE (result), boolean_type_node))
+    {
+      if (info.noisy ())
+	error_at (loc, "constraint does not have type %<bool%>");
+      return cache.save (error_mark_node);
+    }
+
+  /* Compute the value of the constraint.  */
+  result = satisfaction_value (cxx_constant_value (result));
+  if (result == boolean_false_node && info.noisy ())
+    diagnose_atomic_constraint (t, args, info);
+
+  return cache.save (result);
 }
 
-/* Check that the disjunction of constraints is satisfied. Note
-   that if the left operand is satisfied, the right operand is not
-   checked.  */
-
-tree
-satisfy_disjunction (tree t, tree args, tsubst_flags_t complain, tree in_decl)
+/* 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
+   if the there was an error evaluating the constraint.
+
+   The parameter mapping of atomic constraints is simply the
+   set of template arguments that will be substituted into
+   the expression, regardless of template parameters appearing
+   withing. Whether a template argument is used in the atomic
+   constraint only matters for subsumption.  */
+
+static tree
+satisfy_constraint_r (tree t, tree args, subst_info info)
 {
-  tree t0 = satisfy_constraint_1 (TREE_OPERAND (t, 0), args, complain, in_decl);
-  if (t0 == boolean_true_node)
-    return boolean_true_node;
-  return satisfy_constraint_1 (TREE_OPERAND (t, 1), args, complain, in_decl);
-}
-
-/* Dispatch to an appropriate satisfaction routine depending on the
-   tree code of T.  */
-
-tree
-satisfy_constraint_1 (tree t, tree args, tsubst_flags_t complain, tree in_decl)
-{
-  gcc_assert (!processing_template_decl);
-
-  if (!t)
-    return boolean_false_node;
-
   if (t == error_mark_node)
-    return boolean_false_node;
+    return error_mark_node;
 
   switch (TREE_CODE (t))
-  {
-  case PRED_CONSTR:
-    return satisfy_predicate_constraint (t, args, complain, in_decl);
-
-  case CHECK_CONSTR:
-    return satisfy_check_constraint (t, args, complain, in_decl);
-
-  case EXPR_CONSTR:
-    return satisfy_expression_constraint (t, args, complain, in_decl);
-
-  case TYPE_CONSTR:
-    return satisfy_type_constraint (t, args, complain, in_decl);
-
-  case ICONV_CONSTR:
-    return satisfy_implicit_conversion_constraint (t, args, complain, in_decl);
-
-  case DEDUCT_CONSTR:
-    return satisfy_argument_deduction_constraint (t, args, complain, in_decl);
-
-  case EXCEPT_CONSTR:
-    return satisfy_exception_constraint (t, args, complain, in_decl);
-
-  case PARM_CONSTR:
-    return satisfy_parameterized_constraint (t, args, complain, in_decl);
-
-  case CONJ_CONSTR:
-    return satisfy_conjunction (t, args, complain, in_decl);
-
-  case DISJ_CONSTR:
-    return satisfy_disjunction (t, args, complain, in_decl);
-
-  case EXPR_PACK_EXPANSION:
-    return satisfy_pack_expansion (t, args, complain, in_decl);
-
-  default:
-    gcc_unreachable ();
-  }
-  return boolean_false_node;
+    {
+    case CONJ_CONSTR:
+      return satisfy_conjunction (t, args, info);
+    case DISJ_CONSTR:
+      return satisfy_disjunction (t, args, info);
+    case ATOMIC_CONSTR:
+      return satisfy_atom (t, args, info);
+    default:
+      gcc_unreachable ();
+    }
 }
 
-/* Check that the constraint is satisfied, according to the rules
-   for that constraint. Note that each satisfy_* function returns
-   true or false, depending on whether it is satisfied or not.  */
-
-tree
-satisfy_constraint (tree t, tree args)
+/* Check that the normalized constraint T is satisfied for ARGS.  */
+
+static tree
+satisfy_constraint (tree t, tree args, subst_info info)
 {
   auto_timevar time (TV_CONSTRAINT_SAT);
 
@@ -2284,155 +2593,208 @@
      to non-dependent terms, so we want to ensure full checking here.  */
   processing_template_decl_sentinel proc (true);
 
-  /* Avoid early exit in tsubst and tsubst_copy from null args; since earlier
-     substitution was done with processing_template_decl forced on, there will
-     be expressions that still need semantic processing, possibly buried in
-     decltype or a template argument.  */
-  if (args == NULL_TREE)
-    args = make_tree_vec (1);
-
-  return satisfy_constraint_1 (t, args, tf_none, NULL_TREE);
+  /* We need to check access during satisfaction.  */
+  deferring_access_check_sentinel acs (dk_no_deferred);
+
+  return satisfy_constraint_r (t, args, info);
 }
 
-/* Check the associated constraints in CI against the given
-   ARGS, returning true when the constraints are satisfied
-   and false otherwise.  */
-
-tree
-satisfy_associated_constraints (tree ci, tree args)
+/* Check the normalized constraints T against ARGS, returning a satisfaction
+   value (either true, false, or error).  */
+
+static tree
+satisfy_associated_constraints (tree t, tree args, subst_info info)
 {
-  /* If there are no constraints then this is trivially satisfied. */
-  if (!ci)
+  /* If there are no constraints then this is trivially satisfied.  */
+  if (!t)
     return boolean_true_node;
 
   /* If any arguments depend on template parameters, we can't
-     check constraints. */
+     check constraints. Pretend they're satisfied for now.  */
   if (args && uses_template_parms (args))
     return boolean_true_node;
 
-  /* Check if we've seen a previous result. */
-  if (tree prev = lookup_constraint_satisfaction (ci, args))
-    return prev;
-
-  /* Actually test for satisfaction. */
-  tree result = satisfy_constraint (CI_ASSOCIATED_CONSTRAINTS (ci), args);
-  return memoize_constraint_satisfaction (ci, args, result);
+  return satisfy_constraint (t, args, info);
 }
 
-} /* namespace */
-
-/* Evaluate the given constraint, returning boolean_true_node
-   if the constraint is satisfied and boolean_false_node
-   otherwise. */
-
-tree
-evaluate_constraints (tree constr, tree args)
+/* Evaluate EXPR as a constraint expression using ARGS, returning a
+   satisfaction value. */
+
+static tree
+satisfy_constraint_expression (tree t, tree args, subst_info info)
 {
-  gcc_assert (constraint_p (constr));
-  return satisfy_constraint (constr, args);
+  if (t == error_mark_node)
+    return error_mark_node;
+
+  gcc_assert (EXPR_P (t));
+
+  /* Get the normalized constraints.  */
+  tree norm;
+  if (args == NULL_TREE && concept_check_p (t))
+    {
+      tree id = unpack_concept_check (t);
+      args = TREE_OPERAND (id, 1);
+      tree tmpl = get_concept_check_template (id);
+      norm = normalize_concept_definition (tmpl, info.noisy ());
+    }
+  else
+    norm = normalize_constraint_expression (t, info.noisy ());
+
+  /* Perform satisfaction.  */
+  return satisfy_constraint (norm, args, info);
 }
 
-/* Evaluate the function concept FN by substituting its own args
-   into its definition and evaluating that as the result. Returns
-   boolean_true_node if the constraints are satisfied and
-   boolean_false_node otherwise.  */
+/* Used only to evaluate requires-expressions during constant expression
+   evaluation.  */
 
 tree
-evaluate_function_concept (tree fn, tree args)
+satisfy_constraint_expression (tree expr)
 {
-  tree constr = build_nt (CHECK_CONSTR, fn, args);
-  return satisfy_constraint (constr, args);
-}
-
-/* Evaluate the variable concept VAR by substituting its own args into
-   its initializer and checking the resulting constraint. Returns
-   boolean_true_node if the constraints are satisfied and
-   boolean_false_node otherwise.  */
-
-tree
-evaluate_variable_concept (tree var, tree args)
-{
-  tree constr = build_nt (CHECK_CONSTR, var, args);
-  return satisfy_constraint (constr, args);
+  subst_info info (tf_none, NULL_TREE);
+  return satisfy_constraint_expression (expr, NULL_TREE, info);
 }
 
-/* Evaluate the given expression as if it were a predicate
-   constraint. Returns boolean_true_node if the constraint
-   is satisfied and boolean_false_node otherwise. */
-
-tree
-evaluate_constraint_expression (tree expr, tree args)
+static tree
+satisfy_declaration_constraints (tree t, subst_info info)
 {
-  tree constr = normalize_expression (expr);
-  return satisfy_constraint (constr, args);
-}
-
-/* Returns true if the DECL's constraints are satisfied.
-   This is used in cases where a declaration is formed but
-   before it is used (e.g., overload resolution). */
-
-bool
-constraints_satisfied_p (tree decl)
-{
-  /* Get the constraints to check for satisfaction. This depends
-     on whether we're looking at a template specialization or not. */
-  tree ci;
+  gcc_assert (DECL_P (t));
+
+  /* For inherited constructors, consider the original declaration;
+     it has the correct template information attached. */
+  if (flag_new_inheriting_ctors)
+    t = strip_inheriting_ctors (t);
+
+  /* Update the declaration for diagnostics.  */
+  info.in_decl = t;
+
+  if (info.quiet ())
+    if (tree *result = hash_map_safe_get (decl_satisfied_cache, t))
+      return *result;
+
+  /* Get the normalized constraints.  */
+  tree norm = NULL_TREE;
   tree args = NULL_TREE;
-  if (tree ti = DECL_TEMPLATE_INFO (decl))
+  if (tree ti = DECL_TEMPLATE_INFO (t))
     {
       tree tmpl = TI_TEMPLATE (ti);
-      ci = get_constraints (tmpl);
-      int depth = TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl));
-      args = get_innermost_template_args (TI_ARGS (ti), depth);
+      norm = normalize_template_requirements (tmpl, info.noisy ());
+
+      /* The initial parameter mapping is the complete set of
+	 template arguments substituted into the declaration.  */
+      args = TI_ARGS (ti);
     }
   else
     {
-      ci = get_constraints (decl);
+      /* These should be empty until we allow constraints on non-templates.  */
+      norm = normalize_nontemplate_requirements (t, info.noisy ());
+    }
+
+  tree result = boolean_true_node;
+  if (norm)
+    {
+      if (!push_tinst_level (t))
+	return result;
+      push_access_scope (t);
+      result = satisfy_associated_constraints (norm, args, info);
+      pop_access_scope (t);
+      pop_tinst_level ();
+    }
+
+  if (info.quiet ())
+    hash_map_safe_put<hm_ggc> (decl_satisfied_cache, t, result);
+
+  return result;
+}
+
+static tree
+satisfy_declaration_constraints (tree t, tree args, subst_info info)
+{
+  /* Update the declaration for diagnostics.  */
+  info.in_decl = t;
+
+  gcc_assert (TREE_CODE (t) == TEMPLATE_DECL);
+  if (tree norm = normalize_template_requirements (t, info.noisy ()))
+    {
+      tree pattern = DECL_TEMPLATE_RESULT (t);
+      push_access_scope (pattern);
+      tree result = satisfy_associated_constraints (norm, args, info);
+      pop_access_scope (pattern);
+      return result;
     }
 
-  tree eval = satisfy_associated_constraints (ci, args);
-  return eval == boolean_true_node;
+  return boolean_true_node;
+}
+
+static tree
+constraint_satisfaction_value (tree t, tsubst_flags_t complain)
+{
+  subst_info info (complain, NULL_TREE);
+  if (DECL_P (t))
+    return satisfy_declaration_constraints (t, info);
+  else
+    return satisfy_constraint_expression (t, NULL_TREE, info);
 }
 
-/* Returns true if the constraints are satisfied by ARGS.
-   Here, T can be either a constraint or a constrained
-   declaration.  */
+static tree
+constraint_satisfaction_value (tree t, tree args, tsubst_flags_t complain)
+{
+  subst_info info (complain, NULL_TREE);
+  if (DECL_P (t))
+    return satisfy_declaration_constraints (t, args, info);
+  else
+    return satisfy_constraint_expression (t, args, info);
+}
+
+/* True iff the result of satisfying T is BOOLEAN_TRUE_NODE and false
+   otherwise, even in the case of errors.  */
+
+bool
+constraints_satisfied_p (tree t)
+{
+  return constraint_satisfaction_value (t, tf_none) == boolean_true_node;
+}
+
+/* True iff the result of satisfying T with ARGS is BOOLEAN_TRUE_NODE
+    and false otherwise, even in the case of errors.  */
 
 bool
 constraints_satisfied_p (tree t, tree args)
 {
-  tree eval;
-  if (constraint_p (t))
-    eval = evaluate_constraints (t, args);
-  else
-    eval = satisfy_associated_constraints (get_constraints (t), args);
-  return eval == boolean_true_node;
+  return constraint_satisfaction_value (t, args, tf_none) == boolean_true_node;
 }
 
-namespace
+/* Evaluate a concept check of the form C<ARGS>. This is only used for the
+   evaluation of template-ids as id-expressions.  */
+
+tree
+evaluate_concept_check (tree check, tsubst_flags_t complain)
 {
-
-/* Normalize EXPR and determine if the resulting constraint is
-   satisfied by ARGS. Returns true if and only if the constraint
-   is satisfied.  This is used extensively by diagnostics to
-   determine causes for failure.  */
-
-inline bool
-constraint_expression_satisfied_p (tree expr, tree args)
-{
-  return evaluate_constraint_expression (expr, args) == boolean_true_node;
+  if (check == error_mark_node)
+    return error_mark_node;
+
+  gcc_assert (concept_check_p (check));
+
+  /* Check for satisfaction without diagnostics.  */
+  subst_info quiet (tf_none, NULL_TREE);
+  tree result = satisfy_constraint_expression (check, NULL_TREE, quiet);
+  if (result == error_mark_node && (complain & tf_error))
+  {
+    /* Replay the error with re-normalized requirements.  */
+    subst_info noisy (tf_warning_or_error, NULL_TREE);
+    satisfy_constraint_expression (check, NULL_TREE, noisy);
+  }
+  return result;
 }
 
-} /* namespace */
-
 /*---------------------------------------------------------------------------
                 Semantic analysis of requires-expressions
 ---------------------------------------------------------------------------*/
 
 /* Finish a requires expression for the given PARMS (possibly
-   null) and the non-empty sequence of requirements. */
+   null) and the non-empty sequence of requirements.  */
+
 tree
-finish_requires_expr (tree parms, tree reqs)
+finish_requires_expr (location_t loc, tree parms, tree reqs)
 {
   /* Modify the declared parameters by removing their context
      so they don't refer to the enclosing scope and explicitly
@@ -2447,62 +2809,82 @@
   tree r = build_min (REQUIRES_EXPR, boolean_type_node, parms, reqs);
   TREE_SIDE_EFFECTS (r) = false;
   TREE_CONSTANT (r) = true;
+  SET_EXPR_LOCATION (r, loc);
   return r;
 }
 
-/* Construct a requirement for the validity of EXPR. */
+/* Construct a requirement for the validity of EXPR.   */
+
 tree
-finish_simple_requirement (tree expr)
+finish_simple_requirement (location_t loc, tree expr)
 {
-  return build_nt (SIMPLE_REQ, expr);
+  tree r = build_nt (SIMPLE_REQ, expr);
+  SET_EXPR_LOCATION (r, loc);
+  return r;
 }
 
-/* Construct a requirement for the validity of TYPE. */
+/* Construct a requirement for the validity of TYPE.  */
+
 tree
-finish_type_requirement (tree type)
+finish_type_requirement (location_t loc, tree type)
 {
-  return build_nt (TYPE_REQ, type);
+  tree r = build_nt (TYPE_REQ, type);
+  SET_EXPR_LOCATION (r, loc);
+  return r;
 }
 
 /* Construct a requirement for the validity of EXPR, along with
    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. */
+   NOEXCEPT_P is true iff the noexcept keyword was specified.  */
+
 tree
-finish_compound_requirement (tree expr, tree type, bool noexcept_p)
+finish_compound_requirement (location_t loc, tree expr, tree type, bool noexcept_p)
 {
   tree req = build_nt (COMPOUND_REQ, expr, type);
+  SET_EXPR_LOCATION (req, loc);
   COMPOUND_REQ_NOEXCEPT_P (req) = noexcept_p;
   return req;
 }
 
-/* Finish a nested requirement. */
+/* Finish a nested requirement.  */
+
 tree
-finish_nested_requirement (tree expr)
+finish_nested_requirement (location_t loc, tree expr)
 {
-  return build_nt (NESTED_REQ, expr);
+  /* Save the normalized constraint and complete set of normalization
+     arguments with the requirement.  We keep the complete set of arguments
+     around for re-normalization during diagnostics.  */
+  tree args = current_template_parms
+    ? template_parms_to_args (current_template_parms) : NULL_TREE;
+  tree norm = normalize_constraint_expression (expr, args, false);
+  tree info = build_tree_list (args, norm);
+
+  /* Build the constraint, saving its normalization as its type.  */
+  tree r = build1 (NESTED_REQ, info, expr);
+  SET_EXPR_LOCATION (r, loc);
+  return r;
 }
 
-// Check that FN satisfies the structural requirements of a
-// function concept definition.
+/* Check that FN satisfies the structural requirements of a
+   function concept definition.  */
 tree
 check_function_concept (tree fn)
 {
-  // Check that the function is comprised of only a single
-  // return statement.
+  /* Check that the function is comprised of only a return statement.  */
   tree body = DECL_SAVED_TREE (fn);
   if (TREE_CODE (body) == BIND_EXPR)
     body = BIND_EXPR_BODY (body);
 
-  // Sometimes a function call results in the creation of clean up
-  // points. Allow these to be preserved in the body of the
-  // constraint, as we might actually need them for some constexpr
-  // evaluations.
+  /* Sometimes a function call results in the creation of clean up
+     points. Allow these to be preserved in the body of the
+     constraint, as we might actually need them for some constexpr
+     evaluations.  */
   if (TREE_CODE (body) == CLEANUP_POINT_EXPR)
     body = TREE_OPERAND (body, 0);
 
-  /* Check that the definition is written correctly. */
+  /* Check that the definition is written correctly.  */
   if (TREE_CODE (body) != RETURN_EXPR)
     {
       location_t loc = DECL_SOURCE_LOCATION (fn);
@@ -2582,108 +2964,104 @@
   return subsumes (a, b);
 }
 
-/* Returns true when the the constraints in A subsume those in B, but
-   the constraints in B do not subsume the constraints in A.  */
+/* Returns true when the the constraints in CI (with arguments
+   ARGS) strictly subsume the associated constraints of TMPL.  */
 
 bool
-strictly_subsumes (tree a, tree b)
+strictly_subsumes (tree ci, tree args, tree tmpl)
 {
-  return subsumes (a, b) && !subsumes (b, a);
+  tree n1 = get_normalized_constraints_from_info (ci, args, NULL_TREE);
+  tree n2 = get_normalized_constraints_from_decl (tmpl);
+
+  return subsumes (n1, n2) && !subsumes (n2, n1);
+}
+
+/* REturns true when the constraints in CI (with arguments ARGS) subsume
+   the associated constraints of TMPL.  */
+
+bool
+weakly_subsumes (tree ci, tree args, tree tmpl)
+{
+  tree n1 = get_normalized_constraints_from_info (ci, args, NULL_TREE);
+  tree n2 = get_normalized_constraints_from_decl (tmpl);
+
+  return subsumes (n1, n2);
 }
 
 /* Determines which of the declarations, A or B, is more constrained.
    That is, which declaration's constraints subsume but are not subsumed
    by the other's?
 
-   Returns 1 if A is more constrained than B, -1 if B is more constrained
-   than A, and 0 otherwise. */
+   Returns 1 if D1 is more constrained than D2, -1 if D2 is more constrained
+   than D1, and 0 otherwise. */
 
 int
 more_constrained (tree d1, tree d2)
 {
-  tree c1 = get_constraints (d1);
-  tree c2 = get_constraints (d2);
+  tree n1 = get_normalized_constraints_from_decl (d1);
+  tree n2 = get_normalized_constraints_from_decl (d2);
+
   int winner = 0;
-  if (subsumes_constraints (c1, c2))
+  if (subsumes (n1, n2))
     ++winner;
-  if (subsumes_constraints (c2, c1))
+  if (subsumes (n2, n1))
     --winner;
   return winner;
 }
 
-/* Returns true if D1 is at least as constrained as D2. That is, the
-   associated constraints of D1 subsume those of D2, or both declarations
-   are unconstrained. */
+/* Return whether D1 is at least as constrained as D2.  */
 
 bool
 at_least_as_constrained (tree d1, tree d2)
 {
-  tree c1 = get_constraints (d1);
-  tree c2 = get_constraints (d2);
-  return subsumes_constraints (c1, c2);
+  tree n1 = get_normalized_constraints_from_decl (d1);
+  tree n2 = get_normalized_constraints_from_decl (d2);
+
+  return subsumes (n1, n2);
 }
 
-
 /*---------------------------------------------------------------------------
                         Constraint diagnostics
-
-FIXME: Normalize expressions into constraints before evaluating them.
-This should be the general pattern for all such diagnostics.
 ---------------------------------------------------------------------------*/
 
-/* The number of detailed constraint failures.  */
-
-int constraint_errors = 0;
-
-/* Do not generate errors after diagnosing this number of constraint
-   failures.
-
-   FIXME: This is a really arbitrary number. Provide better control of
-   constraint diagnostics with a command line option.  */
-
-int constraint_thresh = 20;
-
-
-/* Returns true if we should elide the diagnostic for a constraint failure.
-   This is the case when the number of errors has exceeded the pre-configured
-   threshold.  */
-
-inline bool
-elide_constraint_failure_p ()
+/* Returns the best location to diagnose a constraint error.  */
+
+static location_t
+get_constraint_error_location (tree t)
 {
-  bool ret = constraint_thresh <= constraint_errors;
-  ++constraint_errors;
-  return ret;
-}
-
-/* Returns the number of undiagnosed errors. */
-
-inline int
-undiagnosed_constraint_failures ()
-{
-  return constraint_errors - constraint_thresh;
+  /* If we have a specific location give it.  */
+  tree expr = CONSTR_EXPR (t);
+  if (location_t loc = cp_expr_location (expr))
+    return loc;
+
+  /* If the constraint is normalized from a requires-clause, give
+     the location as that of the constrained declaration.  */
+  tree cxt = CONSTR_CONTEXT (t);
+  tree src = TREE_VALUE (cxt);
+  if (!src)
+    /* TODO: This only happens for constrained non-template declarations.  */
+    return input_location;
+  if (DECL_P (src))
+    return DECL_SOURCE_LOCATION (src);
+
+  /* Otherwise, give the location as the defining concept.  */
+  gcc_assert (concept_check_p (src));
+  tree id = unpack_concept_check (src);
+  tree tmpl = TREE_OPERAND (id, 0);
+  if (OVL_P (tmpl))
+    tmpl = OVL_FIRST (tmpl);
+  return DECL_SOURCE_LOCATION (tmpl);
 }
 
-/* The diagnosis of constraints performs a combination of normalization
-   and satisfaction testing. We recursively walk through the conjunction or
-   disjunction of associated constraints, testing each sub-constraint in
-   turn.  */
-
-namespace {
-
-void diagnose_constraint (location_t, tree, tree, tree);
-
-/* Emit a specific diagnostics for a failed trait.  */
+/* Emit a diagnostic for a failed trait.  */
 
 void
-diagnose_trait_expression (location_t loc, tree, tree cur, tree args)
+diagnose_trait_expr (tree expr, tree args)
 {
-  if (constraint_expression_satisfied_p (cur, args))
-    return;
-  if (elide_constraint_failure_p())
-    return;
-
-  tree expr = PRED_CONSTR_EXPR (cur);
+  location_t loc = cp_expr_location (expr);
+
+  /* Build a "fake" version of the instantiated trait, so we can
+     get the instantiated types from result.  */
   ++processing_template_decl;
   expr = tsubst_expr (expr, args, tf_none, NULL_TREE, false);
   --processing_template_decl;
@@ -2693,13 +3071,13 @@
   switch (TRAIT_EXPR_KIND (expr))
     {
     case CPTK_HAS_NOTHROW_ASSIGN:
-      inform (loc, "  %qT is not nothrow copy assignable", t1);
+      inform (loc, "  %qT is not %<nothrow%> copy assignable", t1);
       break;
     case CPTK_HAS_NOTHROW_CONSTRUCTOR:
-      inform (loc, "  %qT is not nothrow default constructible", t1);
+      inform (loc, "  %qT is not %<nothrow%> default constructible", t1);
       break;
     case CPTK_HAS_NOTHROW_COPY:
-      inform (loc, "  %qT is not nothrow copy constructible", t1);
+      inform (loc, "  %qT is not %<nothrow%> copy constructible", t1);
       break;
     case CPTK_HAS_TRIVIAL_ASSIGN:
       inform (loc, "  %qT is not trivially copy assignable", t1);
@@ -2760,390 +3138,232 @@
     }
 }
 
-/* Diagnose the expression of a predicate constraint.  */
-
-void
-diagnose_other_expression (location_t loc, tree, tree cur, tree args)
+static tree
+diagnose_valid_expression (tree expr, tree args, tree in_decl)
 {
-  if (constraint_expression_satisfied_p (cur, args))
-    return;
-  if (elide_constraint_failure_p())
-    return;
-  inform (loc, "%qE evaluated to false", cur);
+  tree result = tsubst_expr (expr, args, tf_none, in_decl, false);
+  if (result != error_mark_node)
+    return result;
+
+  location_t loc = cp_expr_loc_or_input_loc (expr);
+  inform (loc, "the required expression %qE is invalid", expr);
+
+  /* TODO: Replay the substitution to diagnose the error?  */
+  // tsubst_expr (expr, args, tf_error, in_decl, false);
+
+  return error_mark_node;
 }
 
-/* Do our best to infer meaning from predicates.  */
-
-inline void
-diagnose_predicate_constraint (location_t loc, tree orig, tree cur, tree args)
+static tree
+diagnose_valid_type (tree type, tree args, tree in_decl)
 {
-  if (TREE_CODE (PRED_CONSTR_EXPR (cur)) == TRAIT_EXPR)
-    diagnose_trait_expression (loc, orig, cur, args);
-  else
-    diagnose_other_expression (loc, orig, cur, args);
+  tree result = tsubst (type, args, tf_none, in_decl);
+  if (result != error_mark_node)
+    return result;
+
+  location_t loc = cp_expr_loc_or_input_loc (type);
+  inform (loc, "the required type %qT is invalid", type);
+
+  /* TODO: Replay the substitution to diagnose the error?  */
+  // tsubst (type, args, tf_error, in_decl);
+
+  return error_mark_node;
 }
 
-/* Diagnose a failed pack expansion, possibly containing constraints.  */
-
-void
-diagnose_pack_expansion (location_t loc, tree, tree cur, tree args)
+static void
+diagnose_simple_requirement (tree req, tree args, tree in_decl)
 {
-  if (constraint_expression_satisfied_p (cur, args))
+  diagnose_valid_expression (TREE_OPERAND (req, 0), args, in_decl);
+}
+
+static void
+diagnose_compound_requirement (tree req, tree args, tree in_decl)
+{
+  tree expr = TREE_OPERAND (req, 0);
+  expr = diagnose_valid_expression (expr, args, in_decl);
+  if (expr == error_mark_node)
     return;
-  if (elide_constraint_failure_p())
+
+  location_t loc = cp_expr_loc_or_input_loc (expr);
+
+  /* Check the noexcept condition.  */
+  if (COMPOUND_REQ_NOEXCEPT_P (req) && !expr_noexcept_p (expr, tf_none))
+    inform (loc, "%qE is not %<noexcept%>", expr);
+
+  tree type = TREE_OPERAND (req, 1);
+  type = diagnose_valid_type (type, args, in_decl);
+  if (type == error_mark_node)
     return;
 
-  /* Make sure that we don't have naked packs that we don't expect. */
-  if (!same_type_p (TREE_TYPE (cur), boolean_type_node))
+  if (type)
     {
-      inform (loc, "invalid pack expansion in constraint %qE", cur);
-      return;
-    }
-
-  inform (loc, "in the expansion of %qE", cur);
-
-  /* Get the vector of expanded arguments. Note that n must not
-     be 0 since this constraint is not satisfied.  */
-  ++processing_template_decl;
-  tree exprs = tsubst_pack_expansion (cur, args, tf_none, NULL_TREE);
-  --processing_template_decl;
-  if (exprs == error_mark_node)
-    {
-      /* TODO: This error message could be better. */
-      inform (loc, "    substitution failure occurred during expansion");
-      return;
-    }
-
-  /* Check each expanded constraint separately. */
-  int n = TREE_VEC_LENGTH (exprs);
-  for (int i = 0; i < n; ++i)
-    {
-      tree expr = TREE_VEC_ELT (exprs, i);
-      if (!constraint_expression_satisfied_p (expr, args))
-        inform (loc, "    %qE was not satisfied", expr);
+      subst_info quiet (tf_none, in_decl);
+      subst_info noisy (tf_error, in_decl);
+
+      /* Check the expression against the result type.  */
+      if (tree placeholder = type_uses_auto (type))
+	{
+	  if (!type_deducible_p (expr, type, placeholder, args, quiet))
+	    {
+	      tree orig_expr = TREE_OPERAND (req, 0);
+	      inform (loc, "%qE does not satisfy return-type-requirement",
+		      orig_expr);
+
+	      /* Further explain the reason for the error.  */
+	      type_deducible_p (expr, type, placeholder, args, noisy);
+	    }
+	}
+      else if (!expression_convertible_p (expr, type, quiet))
+	{
+	  tree orig_expr = TREE_OPERAND (req, 0);
+	  inform (loc, "cannot convert %qE to %qT", orig_expr, type);
+
+	  /* Further explain the reason for the error.  */
+	  expression_convertible_p (expr, type, noisy);
+	}
     }
 }
 
-/* Diagnose a potentially unsatisfied concept check constraint DECL<CARGS>.
-   Parameters are as for diagnose_constraint.  */
-
-void
-diagnose_check_constraint (location_t loc, tree orig, tree cur, tree args)
+static void
+diagnose_type_requirement (tree req, tree args, tree in_decl)
 {
-  if (constraints_satisfied_p (cur, args))
+  tree type = TREE_OPERAND (req, 0);
+  diagnose_valid_type (type, args, in_decl);
+}
+
+static void
+diagnose_nested_requirement (tree req, tree args)
+{
+  /* Quietly check for satisfaction first. We can elaborate details
+     later if needed.  */
+  tree norm = TREE_VALUE (TREE_TYPE (req));
+  subst_info info (tf_none, NULL_TREE);
+  tree result = satisfy_constraint (norm, args, info);
+  if (result == boolean_true_node)
     return;
 
-  tree decl = CHECK_CONSTR_CONCEPT (cur);
-  tree cargs = CHECK_CONSTR_ARGS (cur);
-  tree tmpl = DECL_TI_TEMPLATE (decl);
-  tree check = build_nt (CHECK_CONSTR, decl, cargs);
-
-  /* Instantiate the concept check arguments.  */
-  tree targs = tsubst (cargs, args, tf_none, NULL_TREE);
-  if (targs == error_mark_node)
+  tree expr = TREE_OPERAND (req, 0);
+  location_t loc = cp_expr_location (expr);
+  inform (loc, "nested requirement %qE is not satisfied", expr);
+
+  /* TODO: Replay the substitution to diagnose the error?  */
+  // subst_info noisy (tf_warning_or_error, NULL_TREE);
+  // satisfy_constraint (norm, args, info);
+}
+
+static void
+diagnose_requirement (tree req, tree args, tree in_decl)
+{
+  iloc_sentinel loc_s (cp_expr_location (req));
+  switch (TREE_CODE (req))
     {
-      if (elide_constraint_failure_p ())
-        return;
-      inform (loc, "invalid use of the concept %qE", check);
-      tsubst (cargs, args, tf_warning_or_error, NULL_TREE);
-      return;
+    case SIMPLE_REQ:
+      return diagnose_simple_requirement (req, args, in_decl);
+    case COMPOUND_REQ:
+      return diagnose_compound_requirement (req, args, in_decl);
+    case TYPE_REQ:
+      return diagnose_type_requirement (req, args, in_decl);
+    case NESTED_REQ:
+      return diagnose_nested_requirement (req, args);
+    default:
+       gcc_unreachable ();
     }
-
-  tree sub = build_tree_list (tmpl, targs);
-  /* Update to the expanded definitions. */
-  cur = expand_concept (decl, targs);
-  if (cur == error_mark_node)
+}
+
+static void
+diagnose_requires_expr (tree expr, tree args, tree in_decl)
+{
+  local_specialization_stack stack (lss_copy);
+  tree parms = TREE_OPERAND (expr, 0);
+  tree body = TREE_OPERAND (expr, 1);
+
+  cp_unevaluated u;
+  subst_info info (tf_warning_or_error, NULL_TREE);
+  tree vars = tsubst_constraint_variables (parms, args, info);
+  if (vars == error_mark_node)
+    return;
+
+  tree p = body;
+  while (p)
     {
-      if (elide_constraint_failure_p ())
-        return;
-      inform (loc, "in the expansion of concept %<%E %S%>", check, sub);
-      cur = get_concept_definition (decl);
-      tsubst_expr (cur, targs, tf_warning_or_error, NULL_TREE, false);
+      tree req = TREE_VALUE (p);
+      diagnose_requirement (req, args, in_decl);
+      p = TREE_CHAIN (p);
+    }
+}
+
+/* Diagnose a substitution failure in the atomic constraint T. Note that
+   ARGS have been previously instantiated through the parameter map.  */
+
+static void
+diagnose_atomic_constraint (tree t, tree args, subst_info info)
+{
+  /* If the constraint is already ill-formed, we've previously diagnosed
+     the reason. We should still say why the constraints aren't satisfied.  */
+  if (t == error_mark_node)
+    {
+      location_t loc;
+      if (info.in_decl)
+        loc = DECL_SOURCE_LOCATION (info.in_decl);
+      else
+        loc = input_location;
+      inform (loc, "invalid constraints");
       return;
     }
 
-  orig = get_concept_definition (CHECK_CONSTR_CONCEPT (orig));
-  orig = normalize_expression (orig);
-
-  location_t dloc = DECL_SOURCE_LOCATION (decl);
-  inform (dloc, "within %qS", sub);
-  diagnose_constraint (dloc, orig, cur, targs);
-}
-
-/* Diagnose a potentially unsatisfied conjunction or disjunction.  Parameters
-   are as for diagnose_constraint.  */
-
-void
-diagnose_logical_constraint (location_t loc, tree orig, tree cur, tree args)
-{
-  tree t0 = TREE_OPERAND (cur, 0);
-  tree t1 = TREE_OPERAND (cur, 1);
-  if (!constraints_satisfied_p (t0, args))
-    diagnose_constraint (loc, TREE_OPERAND (orig, 0), t0, args);
-  else if (TREE_CODE (orig) == TRUTH_ORIF_EXPR)
-    return;
-  if (!constraints_satisfied_p (t1, args))
-    diagnose_constraint (loc, TREE_OPERAND (orig, 1), t1, args);
-}
-
-/* Diagnose a potential expression constraint failure. */
-
-void
-diagnose_expression_constraint (location_t loc, tree orig, tree cur, tree args)
-{
-  if (constraints_satisfied_p (cur, args))
-    return;
-  if (elide_constraint_failure_p())
-    return;
-
-  tree expr = EXPR_CONSTR_EXPR (orig);
-  inform (loc, "the required expression %qE would be ill-formed", expr);
-
-  // TODO: We should have a flag that controls this substitution.
-  // I'm finding it very useful for resolving concept check errors.
-
-  // inform (input_location, "==== BEGIN DUMP ====");
-  // tsubst_expr (EXPR_CONSTR_EXPR (orig), args, tf_warning_or_error, NULL_TREE, false);
-  // inform (input_location, "==== END DUMP ====");
-}
-
-/* Diagnose a potentially failed type constraint. */
-
-void
-diagnose_type_constraint (location_t loc, tree orig, tree cur, tree args)
-{
-  if (constraints_satisfied_p (cur, args))
-    return;
-  if (elide_constraint_failure_p())
-    return;
-
-  tree type = TYPE_CONSTR_TYPE (orig);
-  inform (loc, "the required type %qT would be ill-formed", type);
-}
-
-/* Diagnose a potentially unsatisfied conversion constraint. */
-
-void
-diagnose_implicit_conversion_constraint (location_t loc, tree orig, tree cur,
-					 tree args)
-{
-  if (constraints_satisfied_p (cur, args))
-    return;
-
-  /* The expression and type will previously have been substituted into,
-     and therefore may already be an error. Also, we will have already
-     diagnosed substitution failures into an expression since this must be
-     part of a compound requirement.  */
-  tree expr = ICONV_CONSTR_EXPR (cur);
-  if (error_operand_p (expr))
-    return;
-
-  /* Don't elide a previously diagnosed failure.  */
-  if (elide_constraint_failure_p())
-    return;
-
-  tree type = ICONV_CONSTR_TYPE (cur);
-  if (error_operand_p (type))
-    {
-      inform (loc, "substitution into type %qT failed",
-	      ICONV_CONSTR_TYPE (orig));
-      return;
-    }
-
-  inform(loc, "%qE is not implicitly convertible to %qT", expr, type);
-}
-
-/* Diagnose an argument deduction constraint. */
-
-void
-diagnose_argument_deduction_constraint (location_t loc, tree orig, tree cur,
-					tree args)
-{
-  if (constraints_satisfied_p (cur, args))
-    return;
-
-  /* The expression and type will previously have been substituted into,
-     and therefore may already be an error. Also, we will have already
-     diagnosed substution failures into an expression since this must be
-     part of a compound requirement.  */
-  tree expr = DEDUCT_CONSTR_EXPR (cur);
-  if (error_operand_p (expr))
-    return;
-
-  /* Don't elide a previously diagnosed failure.  */
-  if (elide_constraint_failure_p ())
-    return;
-
-  tree pattern = DEDUCT_CONSTR_PATTERN (cur);
-  if (error_operand_p (pattern))
+  location_t loc = get_constraint_error_location (t);
+  iloc_sentinel loc_s (loc);
+
+  /* Generate better diagnostics for certain kinds of expressions.  */
+  tree expr = ATOMIC_CONSTR_EXPR (t);
+  STRIP_ANY_LOCATION_WRAPPER (expr);
+  switch (TREE_CODE (expr))
     {
-      inform (loc, "substitution into type %qT failed",
-	      DEDUCT_CONSTR_PATTERN (orig));
-      return;
-    }
-
-  inform (loc, "unable to deduce placeholder type %qT from %qE",
-	  pattern, expr);
-}
-
-/* Diagnose an exception constraint. */
-
-void
-diagnose_exception_constraint (location_t loc, tree orig, tree cur, tree args)
-{
-  if (constraints_satisfied_p (cur, args))
-    return;
-  if (elide_constraint_failure_p ())
-    return;
-
-  /* Rebuild a noexcept expression. */
-  tree expr = EXCEPT_CONSTR_EXPR (cur);
-  if (error_operand_p (expr))
-    return;
-
-  inform (loc, "%qE evaluated to false", EXCEPT_CONSTR_EXPR (orig));
-}
-
-/* Diagnose a potentially unsatisfied parameterized constraint.  */
-
-void
-diagnose_parameterized_constraint (location_t loc, tree orig, tree cur,
-				   tree args)
-{
-  if (constraints_satisfied_p (cur, args))
-    return;
-
-  local_specialization_stack stack;
-  tree parms = PARM_CONSTR_PARMS (cur);
-  tree vars = tsubst_constraint_variables (parms, args, tf_warning_or_error,
-					   NULL_TREE);
-  if (vars == error_mark_node)
-    {
-      if (elide_constraint_failure_p ())
-        return;
-
-      /* TODO: Check which variable failed and use orig to diagnose
-         that substitution error.  */
-      inform (loc, "failed to instantiate constraint variables");
-      return;
-    }
-
-  /* TODO: It would be better write these in a list. */
-  while (vars)
-    {
-      inform (loc, "    with %q#D", vars);
-      vars = TREE_CHAIN (vars);
-    }
-  orig = PARM_CONSTR_OPERAND (orig);
-  cur = PARM_CONSTR_OPERAND (cur);
-  return diagnose_constraint (loc, orig, cur, args);
-}
-
-/* Diagnose the constraint CUR for the given ARGS. This is only ever invoked
-   on the associated constraints, so we can only have conjunctions of
-   predicate constraints.  The ORIGinal (dependent) constructs follow
-   the current constraints to enable better diagnostics.  Note that ORIG
-   and CUR must be the same kinds of node, except when CUR is an error.  */
-
-void
-diagnose_constraint (location_t loc, tree orig, tree cur, tree args)
-{
-  switch (TREE_CODE (cur))
-    {
-    case EXPR_CONSTR:
-      diagnose_expression_constraint (loc, orig, cur, args);
+    case TRAIT_EXPR:
+      diagnose_trait_expr (expr, args);
+      break;
+    case REQUIRES_EXPR:
+      diagnose_requires_expr (expr, args, info.in_decl);
       break;
-
-    case TYPE_CONSTR:
-      diagnose_type_constraint (loc, orig, cur, args);
-      break;
-
-    case ICONV_CONSTR:
-      diagnose_implicit_conversion_constraint (loc, orig, cur, args);
-      break;
-
-    case DEDUCT_CONSTR:
-      diagnose_argument_deduction_constraint (loc, orig, cur, args);
-      break;
-
-    case EXCEPT_CONSTR:
-      diagnose_exception_constraint (loc, orig, cur, args);
-      break;
-
-    case CONJ_CONSTR:
-    case DISJ_CONSTR:
-      diagnose_logical_constraint (loc, orig, cur, args);
+    case INTEGER_CST:
+      /* This must be either 0 or false.  */
+      inform (loc, "%qE is never satisfied", expr);
       break;
-
-    case PRED_CONSTR:
-      diagnose_predicate_constraint (loc, orig, cur, args);
-      break;
-
-    case PARM_CONSTR:
-      diagnose_parameterized_constraint (loc, orig, cur, args);
-      break;
-
-    case CHECK_CONSTR:
-      diagnose_check_constraint (loc, orig, cur, args);
-      break;
-
-    case EXPR_PACK_EXPANSION:
-      diagnose_pack_expansion (loc, orig, cur, args);
-      break;
-
-    case ERROR_MARK:
-      /* TODO: Can we improve the diagnostic with the original?  */
-      inform (input_location, "ill-formed constraint");
-      break;
-
     default:
-      gcc_unreachable ();
-      break;
+      inform (loc, "the expression %qE evaluated to %<false%>", expr);
     }
 }
 
-/* Diagnose the reason(s) why ARGS do not satisfy the constraints
-   of declaration DECL. */
-
-void
-diagnose_declaration_constraints (location_t loc, tree decl, tree args)
+GTY(()) tree current_failed_constraint;
+
+diagnosing_failed_constraint::
+diagnosing_failed_constraint (tree t, tree args, bool diag)
+  : diagnosing_error (diag)
 {
-  inform (loc, "  constraints not satisfied");
-
-  /* Constraints are attached to the template.  */
-  if (tree ti = DECL_TEMPLATE_INFO (decl))
-    {
-      decl = TI_TEMPLATE (ti);
-      if (!args)
-	args = TI_ARGS (ti);
-    }
-
-  /* Recursively diagnose the associated constraints.  */
-  tree ci = get_constraints (decl);
-  tree t = CI_ASSOCIATED_CONSTRAINTS (ci);
-  diagnose_constraint (loc, t, t, args);
+  if (diagnosing_error)
+    current_failed_constraint = tree_cons (args, t, current_failed_constraint);
 }
 
-} // namespace
-
-/* Emit diagnostics detailing the failure ARGS to satisfy the
-   constraints of T. Here, T can be either a constraint
-   or a declaration.  */
+diagnosing_failed_constraint::
+~diagnosing_failed_constraint ()
+{
+  if (diagnosing_error && current_failed_constraint)
+    current_failed_constraint = TREE_CHAIN (current_failed_constraint);
+}
+
+/* Emit diagnostics detailing the failure ARGS to satisfy the constraints
+   of T. Here, T can be either a constraint or a declaration.  */
 
 void
 diagnose_constraints (location_t loc, tree t, tree args)
 {
-  constraint_errors = 0;
-
-  if (constraint_p (t))
-    diagnose_constraint (loc, t, t, args);
-  else if (DECL_P (t))
-    diagnose_declaration_constraints (loc, t, args);
+  inform (loc, "constraints not satisfied");
+
+  /* Replay satisfaction, but diagnose errors.  */
+  if (!args)
+    constraint_satisfaction_value (t, tf_warning_or_error);
   else
-    gcc_unreachable ();
-
-  /* Note the number of elided failures. */
-  int n = undiagnosed_constraint_failures ();
-  if (n > 0)
-    inform (loc, "... and %d more constraint errors not shown", n);
+    constraint_satisfaction_value (t, args, tf_warning_or_error);
 }
+
+#include "gt-cp-constraint.h"