Index: call.c
===================================================================
--- call.c	(revision 202501)
+++ call.c	(working copy)
@@ -1820,6 +1820,13 @@ remaining_arguments (tree arg)
   return n;
 }
 
+// Returns true if fn is a non-template friend definition.
+static bool
+is_non_template_friend (tree fn)
+{
+  return DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION (fn);
+}
+
 // Returns true if fn is a non-template member function.
 static bool
 is_non_template_member_fn (tree fn)
@@ -1892,15 +1899,15 @@ add_function_candidate (struct z_candida
   // class template instantiation and setting a flag indicating whether
   // or not the declaration is viable. This could be set as a flag in
   // TEMPLATE_INFO (there should be a bunch of unused bits there).
-  if (is_non_template_member_fn (fn)) 
+  if (is_non_template_member_fn (fn) || is_non_template_friend (fn)) 
     {
       tree tmpl = DECL_TI_TEMPLATE (fn);
       tree args = DECL_TI_ARGS (fn);
-      if (!check_template_constraints (tmpl, args))
+      if (!check_template_constraints (tmpl, args) && (complain & tf_error))
         {
           reason = template_constraint_failure (tmpl, args);
           viable = false;
-          goto out;          
+          goto out;
         }
     }
 
@@ -2966,7 +2973,7 @@ add_template_candidate_real (struct z_ca
 			    args_without_in_chrg,
 			    nargs_without_in_chrg,
 			    return_type, strict, flags, false,
-			    complain & tf_decltype);
+			    complain & tf_decltype, true);
 
   if (fn == error_mark_node)
     {
@@ -3284,7 +3291,7 @@ print_z_candidate (location_t loc, const
 			       r->u.template_unification.return_type,
 			       r->u.template_unification.strict,
 			       r->u.template_unification.flags,
-			       true, false);
+			       true, false, true);
 	  break;
 	case rr_invalid_copy:
 	  inform (cloc,
Index: cp-tree.h
===================================================================
--- cp-tree.h	(revision 202501)
+++ cp-tree.h	(working copy)
@@ -5579,7 +5579,7 @@ extern tree instantiate_template		(tree,
 extern tree fn_type_unification			(tree, tree, tree,
 						 const tree *, unsigned int,
 						 tree, unification_kind_t, int,
-						 bool, bool);
+						 bool, bool, bool);
 extern void mark_decl_instantiated		(tree, int);
 extern int more_specialized_fn			(tree, tree, int);
 extern void do_decl_instantiation		(tree, tree);
@@ -6274,6 +6274,8 @@ extern tree finish_validexpr_expr
 extern tree finish_validtype_expr               (tree);
 extern tree finish_constexpr_expr               (tree);
 
+extern void check_constrained_friend            (tree, tree);
+
 extern tree tsubst_requires_expr                (tree, tree, tsubst_flags_t, tree);
 extern tree tsubst_validexpr_expr               (tree, tree, tree);
 extern tree tsubst_validtype_expr               (tree, tree, tree);
@@ -6283,8 +6285,6 @@ extern tree tsubst_type_req
 extern tree tsubst_nested_req                   (tree, tree, tree);
 extern tree instantiate_requirements            (tree, tree);
 
-extern bool check_constraints                   (tree);
-extern bool check_constraints                   (tree, tree);
 extern bool check_template_constraints          (tree, tree);
 extern tree subst_template_constraints          (tree, tree);
 extern bool equivalent_constraints              (tree, tree);
Index: typeck.c
===================================================================
--- typeck.c	(revision 202501)
+++ typeck.c	(working copy)
@@ -3430,6 +3430,26 @@ cp_build_function_call_vec (tree functio
 
   if (TREE_CODE (function) == FUNCTION_DECL)
     {
+      // If the function is a non-template member function or a
+      // non-template friend, then we need to check the constraints.
+      //
+      // NOTE: If overload resolution failed with a single candidate
+      // this function will be used to explicitly diagnose the failure
+      // for the single call expression. The check is technically 
+      // redundant since we would have failed in add_function_candidate.
+      if (tree ti = DECL_TEMPLATE_INFO (function))
+        {
+          tree tmpl = TI_TEMPLATE (ti);
+          tree args = TI_ARGS (ti);
+          if (!check_template_constraints (tmpl, args))
+            {
+              location_t loc = DECL_SOURCE_LOCATION (function);
+              error ("%qD is not a viable candidate", function);
+              diagnose_constraints (input_location, tmpl, args);
+              return error_mark_node;
+            }
+        }
+
       mark_used (function);
       fndecl = function;
 
Index: class.c
===================================================================
--- class.c	(revision 202501)
+++ class.c	(working copy)
@@ -7435,7 +7435,7 @@ resolve_address_of_overloaded_function (
 	  instantiation = fn_type_unification (fn, explicit_targs, targs, args,
 					       nargs, ret,
 					      DEDUCE_EXACT, LOOKUP_NORMAL,
-					       false, false);
+					       false, false, true);
 	  if (instantiation == error_mark_node)
 	    /* Instantiation failed.  */
 	    continue;
Index: pt.c
===================================================================
--- pt.c	(revision 202501)
+++ pt.c	(working copy)
@@ -176,6 +176,7 @@ static tree tsubst_friend_function (tree
 static tree tsubst_friend_class (tree, tree);
 static int can_complete_type_without_circularity (tree);
 static tree get_bindings (tree, tree, tree, bool);
+static tree get_bindings (tree, tree, tree, bool, bool);
 static int template_decl_level (tree);
 static int check_cv_quals_for_unify (int, tree, tree);
 static void template_parm_level_and_index (tree, int*, int*);
@@ -2053,9 +2054,15 @@ determine_specialization (tree template_
 	  /* See whether this function might be a specialization of this
 	     template.  Suppress access control because we might be trying
 	     to make this specialization a friend, and we have already done
-	     access control for the declaration of the specialization.  */
+	     access control for the declaration of the specialization.  
+
+             Do not check constraints when determining if DECL is a
+             specialization of FN. Defer that check until we know DECL is
+             the best specialization of FN, and DECL is not a friend. */
 	  push_deferring_access_checks (dk_no_check);
-	  targs = get_bindings (fn, decl, explicit_targs, /*check_ret=*/true);
+	  targs = get_bindings (fn, decl, explicit_targs, 
+                                /*check_rettype=*/true,
+                                /*check_constraints*/false);
 	  pop_deferring_access_checks ();
 
 	  if (!targs)
@@ -2063,21 +2070,13 @@ determine_specialization (tree template_
 	       specialize TMPL will produce DECL.  */
 	    continue;
 
-	  // Make sure that the deduced arguments actually work. First,
-          // check that any template constraints are satisfied.
-          //
-          // TODO: Make sure that we get reasonable diagnostics for these
-          // kinds of failures.
-          if (!check_template_constraints (fn, targs))
-            continue;
-
           // Then, try to form the new function type.
 	  insttype = tsubst (TREE_TYPE (fn), targs, tf_none, NULL_TREE);
 	  if (insttype == error_mark_node)
 	    continue;
 	  fn_arg_types
 	    = skip_artificial_parms_for (fn, TYPE_ARG_TYPES (insttype));
-	  if (!compparms (fn_arg_types, decl_arg_types))
+          if (!compparms (fn_arg_types, decl_arg_types))
 	    continue;
 
 	  /* Save this template, and the arguments deduced.  */
@@ -2212,8 +2211,28 @@ determine_specialization (tree template_
       return DECL_TI_TEMPLATE (fn);
     }
 
+  // If we're not instantiating a friend function, then we need to 
+  // ensure the specialization of the best template satisfies its 
+  // constraints.
+  //
+  // Friend function declarations are excluded. Those constraints 
+  // during overload resolution.
+  if (!DECL_FRIEND_P (decl)) 
+    {
+      tree tmpl = TREE_VALUE (templates);
+      tree args = TREE_PURPOSE (templates);
+      if (!check_template_constraints (tmpl, args))
+        {
+          error_at(DECL_SOURCE_LOCATION (decl), 
+                   "%q+D is not a valid specialization of %q+D", decl, tmpl);
+          diagnose_constraints (input_location, tmpl, args);
+        }
+    }
+
   /* It was a specialization of a template.  */
   targs = DECL_TI_ARGS (DECL_TEMPLATE_RESULT (TREE_VALUE (templates)));
+
+
   if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (targs))
     {
       *targs_out = copy_node (targs);
@@ -15408,7 +15427,8 @@ fn_type_unification (tree fn,
 		     unification_kind_t strict,
 		     int flags,
 		     bool explain_p,
-		     bool decltype_p)
+		     bool decltype_p,
+                     bool constraints_p)
 {
   tree parms;
   tree fntype;
@@ -15622,9 +15642,9 @@ fn_type_unification (tree fn,
       goto fail;
     }
 
-  // All is well so far. Now, check that the template constraints
-  // are satisfied.
-  if (!check_template_constraints (fn, targs)) 
+  // All is well so far. If we are required to check constraints,
+  // do so now.
+  if (constraints_p && !check_template_constraints (fn, targs)) 
     {
       if (explain_p)
         diagnose_constraints (DECL_SOURCE_LOCATION (fn), fn, targs);
@@ -18277,11 +18297,13 @@ more_specialized_class (tree main_tmpl,
 /* Return the template arguments that will produce the function signature
    DECL from the function template FN, with the explicit template
    arguments EXPLICIT_ARGS.  If CHECK_RETTYPE is true, the return type must
-   also match.  Return NULL_TREE if no satisfactory arguments could be
-   found.  */
+   also match.  If CHECK_CONSTRAINTS is true, then the deduced template 
+   arguments will be checked against any templates constraints of FN.
+   Return NULL_TREE if no satisfactory arguments could be found.  */
 
 static tree
-get_bindings (tree fn, tree decl, tree explicit_args, bool check_rettype)
+get_bindings (tree fn, tree decl, tree explicit_args, bool check_rettype,
+              bool check_constraints)
 {
   int ntparms = DECL_NTPARMS (fn);
   tree targs = make_tree_vec (ntparms);
@@ -18308,14 +18330,23 @@ get_bindings (tree fn, tree decl, tree e
 			   args, ix,
 			   (check_rettype || DECL_CONV_FN_P (fn)
 			    ? TREE_TYPE (decl_type) : NULL_TREE),
-			   DEDUCE_EXACT, LOOKUP_NORMAL, /*explain_p=*/false,
-			   /*decltype*/false)
+			   DEDUCE_EXACT, LOOKUP_NORMAL, 
+                           /*explain_p=*/false,
+			   /*decltype*/false,
+                           check_constraints)
       == error_mark_node)
     return NULL_TREE;
 
   return targs;
 }
 
+// Same arguments as get_bindings() above. CHECK_CONSTRAINTS is true.
+static tree
+get_bindings(tree fn, tree decl, tree explicit_args, bool check_rettype)
+{
+  return get_bindings(fn, decl, explicit_args, check_rettype, true);
+}
+
 /* Return the innermost template arguments that, when applied to a partial
    specialization of MAIN_TMPL whose innermost template parameters are
    TPARMS, and whose specialization arguments are SPEC_ARGS, yield the
Index: constraint.cc
===================================================================
--- constraint.cc	(revision 202501)
+++ constraint.cc	(working copy)
@@ -731,6 +731,76 @@ finish_constexpr_expr (tree expr)
   return NULL_TREE;
 }
 
+namespace {
+
+// Check that a constrained friend function declaration refers to a
+// previous declaration with the same type and constraints. This
+// function checks declarations of the following form.:
+// 
+//
+//    friend T f<>(T, T) requires P
+//
+// There must be a previous function template declaration of f:
+//
+//    template<typename T>
+//      requires P
+//        T f(T, T);
+void
+check_constrained_friend_function (tree fn, tree constr)
+{
+  // Constrained friend functions that don't depend on template
+  // arguments are effectively meaningless.
+  tree parms = DECL_ARGUMENTS (fn);
+  tree result = TREE_TYPE (TREE_TYPE (fn));
+  if (!(parms && uses_template_parms (parms)) && !uses_template_parms (result))
+    {
+      error("constrained friend does not depend on template parameters");
+      return;
+    }
+
+  // If the function is not a definition, make sure that one of the
+  // overloads has the same constraints.
+  if (!DECL_PENDING_INLINE_P (fn)) 
+    {
+      tree ovl = TREE_TYPE (DECL_TEMPLATE_INFO (fn));
+      if (TREE_CODE (ovl) != OVERLOAD)
+        return;
+
+      while (ovl) {
+        tree f = OVL_CURRENT (ovl);
+        if (TREE_CODE (f) == TEMPLATE_DECL)
+          f = DECL_TEMPLATE_RESULT (f);
+
+        // If there is an overload with the same type and
+        // constraints, then this is a good declaration.
+        if (same_type_p (TREE_TYPE (fn), TREE_TYPE (f))) 
+          if (equivalent_constraints (constr, get_constraints (f)))
+            return;
+
+        ovl = OVL_NEXT (ovl);
+      }
+
+      error ("constrained friend %qD does not match any "
+             "previous declarations", fn);
+    }
+}
+} // namespace
+
+// Check that a constrained friend declaration is admissable. This
+// is the case only when the declaration depends on template parameters.
+void
+check_constrained_friend (tree decl, tree constr)
+{
+  // If there are no constraints, then we will have previously
+  // matched a declaration.
+  if (!constr)
+    return;
+
+  // Check that friend function declarations match a prvious declaration.
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    return check_constrained_friend_function (decl, constr);
+}
+
 // -------------------------------------------------------------------------- //
 // Substitution Rules
 //
@@ -927,7 +997,6 @@ check_requirements (tree reqs, tree args
     return false;
   return check_requirements (reqs);
 }
-} // namespace
 
 // Check the instantiated declaration constraints.
 bool
@@ -954,6 +1023,7 @@ check_constraints (tree cinfo, tree args
 
   return check_requirements (CI_REQUIREMENTS (cinfo), args);
 }
+} // namespace
 
 // Check the constraints of the declaration or type T, against 
 // the specified arguments. Returns true if the constraints are 
Index: parser.c
===================================================================
--- parser.c	(revision 202501)
+++ parser.c	(working copy)
@@ -20142,6 +20142,11 @@ cp_parser_member_declaration (cp_parser*
 		  /* If the member was not a friend, declare it here.  */
 		  if (!friend_p)
 		    finish_member_declaration (decl);
+
+                  // Disallow allow non-dependent constrained friends.
+                  if (friend_p)
+                    check_constrained_friend (decl, current_template_reqs);
+
 		  /* Peek at the next token.  */
 		  token = cp_lexer_peek_token (parser->lexer);
 		  /* If the next token is a semicolon, consume it.  */
@@ -20162,6 +20167,11 @@ cp_parser_member_declaration (cp_parser*
 				  asm_specification,
 				  attributes);
 
+              // Disallow non-dependent constrained friends.
+              if (friend_p)
+                check_constrained_friend (decl, current_template_reqs);
+
+
               // Restore the current template requirments.
               current_template_reqs = saved_template_reqs;
 	    }
