Index: cp/class.c
===================================================================
--- cp/class.c	(revision 199411)
+++ cp/class.c	(working copy)
@@ -934,6 +934,20 @@ modify_vtable_entry (tree t,
     }
 }
 
+// Returns true if NEW_FN and OLD_FN are non-template member functions
+// of a class template with with different constraints. The types of the 
+// functions are assumed to be equivalent.
+static inline bool
+are_constrained_member_overloads (tree new_fn, tree old_fn) 
+{
+  // Non-temploids cannot be constrained.
+  if (!DECL_TEMPLOID_INSTANTIATION (new_fn) 
+      && !DECL_TEMPLOID_INSTANTIATION (old_fn))
+    return false;
+  else 
+    return !equivalently_constrained (new_fn, old_fn);
+}
+
 
 /* Add method METHOD to class TYPE.  If USING_DECL is non-null, it is
    the USING_DECL naming METHOD.  Returns true if the method could be
@@ -1140,6 +1154,8 @@ add_method (tree type, tree method, tree
 		/* Defer to the local function.  */
 		return false;
 	    }
+          else if (are_constrained_member_overloads (fn, method))
+            continue;
 	  else
 	    {
 	      error ("%q+#D cannot be overloaded", method);
Index: cp/call.c
===================================================================
--- cp/call.c	(revision 199411)
+++ cp/call.c	(working copy)
@@ -449,7 +449,8 @@ enum rejection_reason_code {
   rr_arg_conversion,
   rr_bad_arg_conversion,
   rr_template_unification,
-  rr_invalid_copy
+  rr_invalid_copy,
+  rr_constraint_failure
 };
 
 struct conversion_info {
@@ -709,6 +710,15 @@ invalid_copy_with_fn_template_rejection
   return r;
 }
 
+static struct rejection_reason *
+template_constraint_failure (tree tmpl, tree targs)
+{
+  struct rejection_reason *r = alloc_rejection (rr_constraint_failure);
+  r->u.template_instantiation.tmpl = tmpl;
+  r->u.template_instantiation.targs = targs;
+  return r;
+}
+
 /* Dynamically allocate a conversion.  */
 
 static conversion *
@@ -1858,6 +1868,25 @@ add_function_candidate (struct z_candida
   len = vec_safe_length (args) - skip + (first_arg != NULL_TREE ? 1 : 0);
   convs = alloc_conversions (len);
 
+  // Viable functions
+  //
+  // Functions whose constraints are not satisfied are non-viable.
+  //
+  // This only happens with constrained non-template members, which
+  // we've currently disabled.
+  if (DECL_USE_TEMPLATE (fn))
+    {
+      tree cons = DECL_TEMPLATE_CONSTRAINT (fn);
+      if (!check_constraints (cons))
+        {
+          tree tmpl = DECL_TI_TEMPLATE (fn);
+          tree args = DECL_TI_ARGS (fn);
+          reason = template_constraint_failure (tmpl, args);
+          viable = false;
+          goto out;          
+        }
+    }
+
   /* 13.3.2 - Viable functions [over.match.viable]
      First, to be a viable function, a candidate function shall have enough
      parameters to agree in number with the arguments in the list.
@@ -2924,8 +2953,8 @@ add_template_candidate_real (struct z_ca
 
   if (fn == error_mark_node)
     {
-      /* Don't repeat unification later if it already resulted in errors.  */
       if (errorcount+sorrycount == errs)
+        /* Don't repeat unification later if it already resulted in errors.  */
 	reason = template_unification_rejection (tmpl, explicit_targs,
 						 targs, args_without_in_chrg,
 						 nargs_without_in_chrg,
@@ -2977,6 +3006,7 @@ add_template_candidate_real (struct z_ca
 				   first_arg, arglist, access_path,
 				   conversion_path, flags, complain);
   if (DECL_TI_TEMPLATE (fn) != tmpl)
+    {
     /* This situation can occur if a member template of a template
        class is specialized.  Then, instantiate_template might return
        an instantiation of the specialization, in which case the
@@ -2994,7 +3024,9 @@ add_template_candidate_real (struct z_ca
        for this will point at template <class T> template <> S<T>::f(int),
        so that we can find the definition.  For the purposes of
        overload resolution, however, we want the original TMPL.  */
-    cand->template_decl = build_template_info (tmpl, targs);
+      tree cons = tsubst_constraint (DECL_TEMPLATE_CONSTRAINT (fn), targs);
+      cand->template_decl = build_template_info (tmpl, targs, cons);
+    }
   else
     cand->template_decl = DECL_TEMPLATE_INFO (fn);
   cand->explicit_targs = explicit_targs;
@@ -3243,6 +3275,13 @@ print_z_candidate (location_t loc, const
 		  "  a constructor taking a single argument of its own "
 		  "class type is invalid");
 	  break;
+        case rr_constraint_failure:
+          {
+            tree tmpl = r->u.template_instantiation.tmpl;
+            tree args = r->u.template_instantiation.targs;
+            diagnose_constraint_failure (cloc, tmpl, args);
+          }
+          break;
 	case rr_none:
 	default:
 	  /* This candidate didn't have any issues or we failed to
@@ -8353,6 +8392,22 @@ add_warning (struct z_candidate *winner,
   winner->warnings = cw;
 }
 
+// Returns the template declaration associated with the candidate
+// function. For actual templates, this is directly associated
+// with the candidate. For temploids, we return the template
+// associated with the specialization.
+static inline tree
+template_decl_for_candidate (struct z_candidate *cand)
+{
+ tree r = cand->template_decl;
+  tree d = cand->fn;
+  if (!r && DECL_P (d) && DECL_USE_TEMPLATE (d))
+    r = DECL_TI_TEMPLATE (d);
+  if (r && TREE_CODE (r) == TEMPLATE_INFO)
+    r = TI_TEMPLATE (r);
+  return r;
+}
+
 /* Compare two candidates for overloading as described in
    [over.match.best].  Return values:
 
@@ -8369,6 +8424,10 @@ joust (struct z_candidate *cand1, struct
   size_t i;
   size_t len;
 
+  // Get the actual template decls associated with the candidates.
+  tree tmpl1 = template_decl_for_candidate (cand1);
+  tree tmpl2 = template_decl_for_candidate (cand2);
+
   /* Candidates that involve bad conversions are always worse than those
      that don't.  */
   if (cand1->viable > cand2->viable)
@@ -8571,16 +8630,14 @@ joust (struct z_candidate *cand1, struct
      more specialized than the template for F2 according to the partial
      ordering rules.  */
 
-  if (cand1->template_decl && cand2->template_decl)
+  if (tmpl1 && tmpl2)
     {
-      winner = more_specialized_fn
-	(TI_TEMPLATE (cand1->template_decl),
-	 TI_TEMPLATE (cand2->template_decl),
 	 /* [temp.func.order]: The presence of unused ellipsis and default
 	    arguments has no effect on the partial ordering of function
 	    templates.   add_function_candidate() will not have
 	    counted the "this" argument for constructors.  */
-	 cand1->num_convs + DECL_CONSTRUCTOR_P (cand1->fn));
+      int nparms = cand1->num_convs + DECL_CONSTRUCTOR_P (cand1->fn);
+      winner = more_specialized_fn (tmpl1, tmpl2, nparms);
       if (winner)
 	return winner;
     }
Index: cp/ptree.c
===================================================================
--- cp/ptree.c	(revision 199411)
+++ cp/ptree.c	(working copy)
@@ -223,6 +223,14 @@ cxx_print_xnode (FILE *file, tree node,
 	  fprintf (file, "pending_template");
 	}
       break;
+    case CONSTRAINT_INFO:
+      {
+        tree_constraint_info *cinfo = (tree_constraint_info *)node;
+        print_node (file, "requirements", cinfo->requirements, indent+4);
+        if (cinfo->assumptions)
+          print_node_brief (file, "assumptions", cinfo->assumptions, indent+4);
+        break;
+      }    
     case ARGUMENT_PACK_SELECT:
       print_node (file, "pack", ARGUMENT_PACK_SELECT_FROM_PACK (node),
 		  indent+4);
Index: cp/semantics.c
===================================================================
--- cp/semantics.c	(revision 199581)
+++ cp/semantics.c	(working copy)
@@ -2567,12 +2567,18 @@ finish_template_type_parm (tree aggr, tr
 tree
 finish_template_template_parm (tree aggr, tree identifier)
 {
-  tree decl = build_decl (input_location,
+  tree decl = build_lang_decl_loc (input_location,
 			  TYPE_DECL, identifier, NULL_TREE);
   tree tmpl = build_lang_decl (TEMPLATE_DECL, identifier, NULL_TREE);
   DECL_TEMPLATE_PARMS (tmpl) = current_template_parms;
   DECL_TEMPLATE_RESULT (tmpl) = decl;
   DECL_ARTIFICIAL (decl) = 1;
+
+  // Build template info and associate it with the parameter.
+  DECL_TEMPLATE_INFO (decl) = build_template_info (tmpl, 
+                                                   current_template_args (), 
+                                                   current_template_reqs);
+
   end_template_decl ();
 
   gcc_assert (DECL_TEMPLATE_PARMS (tmpl));
@@ -5517,6 +5523,22 @@ classtype_has_nothrow_assign_or_copy_p (
   return true;
 }
 
+// Returns true if K denotes a unary type trait.
+inline bool
+is_unary_trait (cp_trait_kind k)
+{
+  if (k == CPTK_IS_CONVERTIBLE_TO || k == CPTK_IS_BASE_OF)
+    return false;
+  return true;
+}
+
+// Returns true if K denotes a binary type trait.
+inline bool
+is_binary_trait (cp_trait_kind k)
+{
+  return !is_unary_trait (k);
+}
+
 /* Actually evaluates the trait.  */
 
 static bool
@@ -5678,8 +5700,7 @@ finish_trait_expr (cp_trait_kind kind, t
     }
 
   if (type1 == error_mark_node
-      || ((kind == CPTK_IS_BASE_OF || kind == CPTK_IS_CONVERTIBLE_TO)
-	  && type2 == error_mark_node))
+      || (is_binary_trait (kind) && type2 == error_mark_node))
     return error_mark_node;
 
   if (processing_template_decl)
Index: cp/constraint.cc
===================================================================
--- cp/constraint.cc	(revision 199581)
+++ cp/constraint.cc	(working copy)
@@ -18,7 +18,7 @@ You should have received a copy of the G
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
-// Components for process constraints and evaluating constraints.
+// Components for processing constraints and evaluating constraints.
 
 #include "config.h"
 #include "system.h"
@@ -47,31 +47,34 @@ along with GCC; see the file COPYING3.
 //
 // Facilities for building and manipulating template requirements. 
 //
-// TODO: Simply assinging boolean_type_node to the result type of the expression
-// seems right thing for constraints, but in the long-term we might want to be
-// more flexible (i.e., allow some form of overload resolution?).
-
+// TODO: Simply assigning boolean_type_node to the result type of the 
+// expression seems right for constraints, but in the long-term we might want
+// to be more flexible (i.e., allow some form of overload resolution?).
+
+// Create a new logical node joining the subexpressions a and b.
+static inline tree
+join_requirements (tree_code c, tree a, tree b)
+{
+  gcc_assert (a != NULL_TREE && b != NULL_TREE);
+  gcc_assert (c == TRUTH_ANDIF_EXPR || c == TRUTH_ORIF_EXPR);
+  return build_min (c, boolean_type_node, a, b);
+}
 
 // Returns the conjunction of two requirements A and B, where A and B are
-// reduced terms in the constraints languaage. Returns NULL_TREE if either A or
-// B are NULL_TREE.
+// reduced terms in the constraints language. Note that conjoining with a
+// non-null expression with  NULL_TREE is an identity operation. That is, 
+// for some non-null A,
+//
+//    conjoin_requirements(a, NULL_TREE) == a
+//
+// If both A and B are NULL_TREE, the result is also NULL_TREE.
 tree
 conjoin_requirements (tree a, tree b)
 {
-  if (a && b)
-    return build_min (TRUTH_ANDIF_EXPR, boolean_type_node, a, b);
-  else
-    return NULL_TREE;
-}
-
-// Returns the disjunction of two requirements A and B, where A and B are
-// reduced terms in the constraints languaage. Returns NULL_TREE if either A or
-// B are NULL_TREE.
-tree
-disjoin_requirements (tree a, tree b)
-{
-  if (a && b)
-    return build_min (TRUTH_ORIF_EXPR, boolean_type_node, a, b);
+  if (a)
+    return b ? join_requirements (TRUTH_ANDIF_EXPR, a, b) : a;
+  else if (b)
+    return b;
   else
     return NULL_TREE;
 }
@@ -81,9 +84,8 @@ disjoin_requirements (tree a, tree b)
 // Constraint Resolution
 //
 // This facility is used to resolve constraint checks from requirement
-// expressions. A constraint check is a call to a constraint predicate:
-// a constexpr, nullary function teplate whose result can be converted
-// to bool.
+// expressions. A constraint check is a call to a function template, declared
+// concept.
 //
 // The result of resolution is a pair (a list node) whose value is the
 // matched declaration, and whose purpose contains the coerced template
@@ -91,37 +93,10 @@ disjoin_requirements (tree a, tree b)
 
 namespace {
 
-// Returns true if the function decl F is a constraint predicate.
-// It must be a constexpr, nullary function with a boolean result
-// type.
-static bool
-is_constraint (tree f)
-{
-  gcc_assert (TREE_CODE (f) == FUNCTION_DECL);
-
-  // A constraint is nullary.
-  if (DECL_ARGUMENTS (f))
-    return false;
-
-  // A constraint is declared constexpr
-  if (!DECL_DECLARED_CONSTEXPR_P (f))
-    return false;
-
-  // Whose result must be convertible to bool.
-  if (!can_convert (TREE_TYPE (TREE_TYPE (f)), boolean_type_node, tf_none))
-    return false;
-
-  // A constraint can only be checked if it is defined.
-  if (!DECL_SAVED_TREE (f))
-    return false;
-
-  return true;
-}
-
-// Given an OVL set of constraint candidates, try to find a unique definition
-// satisfying the requirements of a constraint.
+// Given an overload set, try to find a unique definition that can be
+// instantiated by the template arguments.
 //
-// This function is not called for abitrary call expressions. In particul,
+// 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:
 //
@@ -142,50 +117,53 @@ resolve_constraint_check (tree ovl, tree
       tree parms = TREE_VALUE (DECL_TEMPLATE_PARMS (tmpl));
 
       // Remember the candidate if we can deduce a substitution.
-      if (tree subst = substitute_template_parameters (parms, args))
+      if (tree subst = coerce_template_parms (parms, args, tmpl))
         if (subst != error_mark_node)
           cands = tree_cons (subst, DECL_TEMPLATE_RESULT (tmpl), cands);
     }
 
-  // If there are multiple candidates, then we have not found
-  // a unique definition.
-  if (TREE_CHAIN (cands))
+  // If we didn't find a unique candidate, then this is
+  // not a constraint check.
+  if (!cands || TREE_CHAIN (cands))
     return NULL_TREE;
 
-  if (!is_constraint (TREE_VALUE (cands)))
+  // Constraints must be declared concepts.
+  tree decl = TREE_VALUE (cands);
+  if (!DECL_DECLARED_CONCEPT_P (decl))
     return NULL_TREE;
 
+  // Concept declarations must have a corresponding definition.
+  //
+  // TODO: This should be part of the up-front checking for 
+  // a concept declaration.
+  if (!DECL_SAVED_TREE (decl))
+    {
+      error_at (DECL_SOURCE_LOCATION (decl),
+                "concept %q#D has no definition", decl);
+      return NULL;
+    }
+
   return cands;
 }
 
-// If the call express T is a check expression, return a singleton tree
-// list whose VALUE is the checked constraint predicate, and whose
-// PURPOSE contains substitution arguments for the constraint. If the 
-// call does not denote a check, return NULL_TREE.
-//
-// Note that a call expression is a check expression if it refers to a
-// unique, nullary function template via lightweight overload resolution.
+// 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
-maybe_constraint_check (tree call)
+resolve_constraint_check (tree call)
 {
   gcc_assert (TREE_CODE (call) == CALL_EXPR);
 
-  // A constraint check must be a call to a function template with 
-  // arguments given explicitly.
-  tree f = CALL_EXPR_FN (call);
-  if (TREE_CODE (f) != TEMPLATE_ID_EXPR)
-    return NULL_TREE;
-
-  // Also, make sure that there are no arguments to the call expression.
-  // If there are, then we are guaranteed that this is a regular call.
-  if (call_expr_nargs (call))
-    return NULL_TREE;
-
-  // Determine which constraint is actually referred to by the
-  // call expression.
-  tree tmpl = TREE_OPERAND (f, 0);
-  tree args = TREE_OPERAND (f, 1);
-  return resolve_constraint_check (tmpl, args);
+  // A constraint check must be only be a template-id expression.
+  tree target = CALL_EXPR_FN (call);
+  if (TREE_CODE (target) != TEMPLATE_ID_EXPR)
+    return NULL_TREE;
+
+  // Get the overload set and template arguments and try to
+  // resolve the target.
+  tree ovl = TREE_OPERAND (target, 0);
+  tree args = TREE_OPERAND (target, 1);
+  return resolve_constraint_check (ovl, args);
 }
   
 } // end namespace
@@ -360,13 +338,13 @@ reduce_logical (tree t)
 
 // Reduction rules for the call expression T.
 //
-// If T is a call to a constraint instantiate it's definition and
+// If T is a call to a constraint instantiate its definition and
 // recursively reduce its returned expression.
 tree
 reduce_call (tree t)
 {
   // Is the function call actually a constraint check?
-  tree check = maybe_constraint_check (t);
+  tree check = resolve_constraint_check (t);
   if (!check)
     return t;
 
@@ -406,8 +384,8 @@ reduce_template_id (tree t)
 {
   vec<tree, va_gc>* args = NULL;
   tree c = finish_call_expr (t, &args, true, false, 0);
-  error ("invalid requirement");
-  inform (input_location, "did you mean %qE", c);
+  error_at (EXPR_LOC_OR_HERE (t), "invalid requirement");
+  inform (EXPR_LOC_OR_HERE (t), "did you mean %qE", c);
   return NULL_TREE;
 }
 
@@ -441,7 +419,7 @@ reduce_stmt_list (tree stmts)
 } // end namespace
 
 
-// Reduce the requirement T into a logical formula written in terms of
+// Reduce the requirement REQS into a logical formula written in terms of
 // atomic propositions.
 tree
 reduce_requirements (tree reqs)
@@ -472,3 +450,155 @@ make_constraints (tree reqs)
     
   return (tree)cinfo;
 }
+
+namespace {
+
+inline tree
+get_type_constraints (tree t)
+{
+  // Template template arguments may not have template info.
+  if (!TYPE_TEMPLATE_INFO (t))
+    return NULL_TREE;
+  return TYPE_TEMPLATE_CONSTRAINT (t);
+}
+
+inline tree
+get_decl_constraints (tree t)
+{
+  if (TREE_CODE (t) == TEMPLATE_DECL)
+    {
+      tree d = DECL_TEMPLATE_RESULT (t);
+      if (TREE_CODE (d) == TYPE_DECL)
+        return get_type_constraints (TREE_TYPE (t));
+      else
+        return get_decl_constraints (d);
+    }
+  return DECL_TEMPLATE_CONSTRAINT (t);
+}
+
+} // end namespace
+
+// Return constraint info for the node T, regardless of the
+// kind of node.
+tree
+get_constraints (tree t)
+{
+  if (TYPE_P (t))
+    return get_type_constraints (t);
+  else if (DECL_P (t))
+    return get_decl_constraints (t);
+  else
+    gcc_unreachable ();
+  return false;
+}
+
+// Returns true if the requirements expression REQS is satisfied, 
+// and false otherwise. The requirements are checked by simply 
+// evaluating REQS as a constant expression.
+static inline bool
+check_requirements (tree reqs)
+{
+  // Simplify the expression before evaluating it. This will
+  // cause TRAIT_EXPR nodes to be reduced before constexpr
+  // evaluation.
+  reqs = fold_non_dependent_expr (reqs);
+  
+  // Requirements are satisfied when REQS evaluates to true.
+  return cxx_constant_value (reqs) == boolean_true_node;
+}
+
+// Check the instantiated declaration constraints.
+bool
+check_constraints (tree cinfo)
+{
+  if (!cinfo)
+    return true;
+  return check_requirements (CI_REQUIREMENTS (cinfo));
+}
+
+// Check the constraints in CINFO against the given ARGS, returning
+// true when the constraints are satisfied and false otherwise.
+bool 
+check_constraints (tree cinfo, tree args)
+{
+  // No constraints? Satisfied.
+  if (!cinfo)
+    return true;
+
+  // Instantiate the requirements before checking.
+  tree reqs = instantiate_requirements (CI_REQUIREMENTS (cinfo), args);
+  if (reqs == error_mark_node)
+    return false;
+  return check_requirements (reqs);
+}
+
+static inline bool
+check_type_constraints (tree t, tree args)
+{
+  return check_constraints (CLASSTYPE_TEMPLATE_CONSTRAINT (t), args);
+}
+
+static inline bool
+check_decl_constraints (tree t, tree args)
+{
+  if (TREE_CODE (t) == TEMPLATE_DECL)
+    return check_decl_constraints (DECL_TEMPLATE_RESULT (t), args);
+  else
+    return check_constraints (DECL_TEMPLATE_CONSTRAINT (t), args);
+}
+
+// Check the constraints of the declaration or type T, against 
+// the specified arguments. Returns true if the constraints are 
+// satisfied and false otherwise.
+bool
+check_template_constraints (tree t, tree args)
+{
+  return check_constraints (get_constraints (t), args);
+}
+
+// Returns true when A and B are equivlent constraints.
+bool
+equivalent_constraints (tree a, tree b)
+{
+  return subsumes (a, b) && subsumes (b, a);
+}
+
+// Returns true if the template declarations A and B have equivalent
+// constraints. This is the case when A's constraints subsume B's and
+// when B's also constrain A's.
+bool 
+equivalently_constrained (tree a, tree b)
+{
+  gcc_assert (TREE_CODE (a) == TREE_CODE (b));
+  return equivalent_constraints (get_constraints (a), get_constraints (b));
+}
+
+// Returns true when the A contains more atomic properties than B.
+bool
+more_constraints (tree a, tree b)
+{
+  return subsumes (a, b);
+}
+
+// Returns true when the template declaration A's constraints subsume
+// those of the template declaration B.
+bool 
+more_constrained (tree a, tree b)
+{
+  gcc_assert (TREE_CODE (a) == TREE_CODE (b));
+  return more_constraints (get_constraints (a), get_constraints (b));
+}
+
+
+// -------------------------------------------------------------------------- //
+// Constraint Diagnostics
+
+// Emit diagnostics detailing the failure ARGS to satisfy the constraints
+// of the template declaration, TMPL.
+//
+// TODO: Implement actual diagnostics.
+void
+diagnose_constraint_failure (location_t loc, tree tmpl, tree args)
+{
+  inform (loc, "  constraints not satisfied:");
+}
Index: cp/decl.c
===================================================================
--- cp/decl.c	(revision 199581)
+++ cp/decl.c	(working copy)
@@ -1077,6 +1077,12 @@ decls_match (tree newdecl, tree olddecl)
       else
 	types_match = decls_match (DECL_TEMPLATE_RESULT (olddecl),
 				   DECL_TEMPLATE_RESULT (newdecl));
+
+        // If the types of the underlying templates match, compare
+        // their constraints. The declarations could differ there.
+        if (types_match)
+          types_match = equivalent_constraints (get_constraints (olddecl), 
+                                                current_template_reqs);
     }
   else
     {
@@ -1104,6 +1110,7 @@ decls_match (tree newdecl, tree olddecl)
 				 COMPARE_REDECLARATION);
     }
 
+
   return types_match;
 }
 
@@ -1215,6 +1222,39 @@ validate_constexpr_redeclaration (tree o
   return false;
 }
 
+// If OLDDECL and NEWDECL are concept declarations with the same type
+// (i.e., and template parameters), but different requirements,
+// emit diagnostics and return true. Otherwise, return false.
+static inline bool
+check_concept_refinement (tree olddecl, tree newdecl) 
+{
+  if (!DECL_DECLARED_CONCEPT_P (olddecl) || !DECL_DECLARED_CONCEPT_P (newdecl))
+    return false;
+
+  // TODO: This isn't currently possible, but it will almost certainly
+  // change with variable templates.
+  tree d1 = DECL_TEMPLATE_RESULT (olddecl);
+  tree d2 = DECL_TEMPLATE_RESULT (newdecl);
+  if (TREE_CODE (d1) != TREE_CODE (d2))
+    return false;
+
+  tree t1 = TREE_TYPE (d1);
+  tree t2 = TREE_TYPE (d2);
+  if (TREE_CODE (d1) == FUNCTION_DECL)
+    {
+      if (compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2))
+          && comp_template_parms (DECL_TEMPLATE_PARMS (olddecl),
+                                  DECL_TEMPLATE_PARMS (newdecl))
+          && !equivalently_constrained (olddecl, newdecl))
+        {
+          error ("cannot specialize concept %q#D", olddecl);
+          return true;
+        }
+    }
+  return false;
+}
+
+
 #define GNU_INLINE_P(fn) (DECL_DECLARED_INLINE_P (fn)			\
 			  && lookup_attribute ("gnu_inline",		\
 					       DECL_ATTRIBUTES (fn)))
@@ -1512,11 +1552,19 @@ duplicate_decls (tree newdecl, tree oldd
 		   /* Template functions can be disambiguated by
 		      return type.  */
 		   && same_type_p (TREE_TYPE (TREE_TYPE (newdecl)),
-				   TREE_TYPE (TREE_TYPE (olddecl))))
+				   TREE_TYPE (TREE_TYPE (olddecl)))
+                   // Template functions can also be disambiguated by
+                   // constraints.
+                   && equivalent_constraints (get_constraints (olddecl), 
+                                              current_template_reqs))
 	    {
 	      error ("new declaration %q#D", newdecl);
 	      error ("ambiguates old declaration %q+#D", olddecl);
 	    }
+          else if (check_concept_refinement (olddecl, newdecl))
+            {
+              return error_mark_node;
+            }
 	  return NULL_TREE;
 	}
       if (TREE_CODE (newdecl) == FUNCTION_DECL)
@@ -7316,24 +7364,16 @@ check_static_quals (tree decl, cp_cv_qua
 }
 
 // Check that FN takes no arguments and returns bool.
-static bool
+static void
 check_concept_fn (tree fn)
 {
   // A constraint is nullary.
   if (DECL_ARGUMENTS (fn))
-    {
-      error ("concept %q#D declared with function arguments", fn);
-      return false;
-    }
+    error ("concept %q#D declared with function parameters", fn);
 
   // The result type must be convertible to bool.
-  if (!can_convert (TREE_TYPE (TREE_TYPE (fn)), boolean_type_node, tf_none))
-    {
-      error ("concept %q#D result must be convertible to bool", fn);
-      return false;
-    }
-
-  return true;
+  if (!same_type_p (TREE_TYPE (TREE_TYPE (fn)), boolean_type_node))
+    error ("concept %q#D result must be bool", fn);
 }
 
 /* CTYPE is class type, or null if non-class.
@@ -7467,7 +7507,7 @@ grokfndecl (tree ctype,
 	      fns = TREE_OPERAND (fns, 1);
 	    }
 	  gcc_assert (identifier_p (fns) || TREE_CODE (fns) == OVERLOAD);
-	  DECL_TEMPLATE_INFO (decl) = build_template_info (fns, args);
+	  DECL_TEMPLATE_INFO (decl) = build_template_info (fns, args, NULL_TREE);
 
 	  for (t = TYPE_ARG_TYPES (TREE_TYPE (decl)); t; t = TREE_CHAIN (t))
 	    if (TREE_PURPOSE (t)
@@ -7593,8 +7633,7 @@ grokfndecl (tree ctype,
   if (inlinep & 4)
     {
       DECL_DECLARED_CONCEPT_P (decl) = true;
-      if (!check_concept_fn (decl))
-        return NULL_TREE;
+      check_concept_fn (decl);
     }
 
   DECL_EXTERNAL (decl) = 1;
@@ -14394,6 +14433,7 @@ cp_tree_node_structure (union lang_tree_
     case TRAIT_EXPR:		return TS_CP_TRAIT_EXPR;
     case LAMBDA_EXPR:		return TS_CP_LAMBDA_EXPR;
     case TEMPLATE_INFO:		return TS_CP_TEMPLATE_INFO;
+    case CONSTRAINT_INFO:       return TS_CP_CONSTRAINT_INFO;
     case USERDEF_LITERAL:	return TS_CP_USERDEF_LITERAL;
     default:			return TS_CP_GENERIC;
     }
Index: cp/tree.c
===================================================================
--- cp/tree.c	(revision 199411)
+++ cp/tree.c	(working copy)
@@ -2026,7 +2026,8 @@ bind_template_template_parm (tree t, tre
   TEMPLATE_TYPE_PARM_INDEX (t2) = copy_node (TEMPLATE_TYPE_PARM_INDEX (t));
   TEMPLATE_PARM_DECL (TEMPLATE_TYPE_PARM_INDEX (t2)) = decl;
   TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (t2)
-    = build_template_info (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t), newargs);
+    = build_template_info (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t), 
+                           newargs, NULL_TREE);
 
   TREE_TYPE (decl) = t2;
   TYPE_NAME (t2) = decl;
Index: cp/logic.cc
===================================================================
--- cp/logic.cc	(revision 199581)
+++ cp/logic.cc	(working copy)
@@ -42,7 +42,6 @@ along with GCC; see the file COPYING3.
 #include "gimple.h"
 #include "bitmap.h"
 
-#include <algorithm>
 #include <list>
   
 namespace {
@@ -74,45 +73,81 @@ struct term_list : std::list<tree>
   term_list (const term_list &x);
   term_list& operator= (const term_list &x);
 
-  iterator cur;
+  tree       current_term ()       { return *current; }
+  const_tree current_term () const { return *current; }
+
+
+  void insert (tree t);
+  tree erase ();
+
+  void start ();
+  void next ();
+  bool done() const;
+
+  iterator current;
 };
 
 inline
 term_list::term_list ()
-  : std::list<tree> (), cur (end ())
+  : std::list<tree> (), current (end ())
 { }
 
 inline
 term_list::term_list (const term_list &x)
-  : std::list<tree> (x), cur (::next_by_distance (begin (), x.begin (), x.cur))
+  : std::list<tree> (x)
+  , current (next_by_distance (begin (), x.begin (), x.current))
 { }
 
 inline term_list&
 term_list::operator= (const term_list &x)
 {
   std::list<tree>::operator=(x);
-  cur = next_by_distance (begin (), x.begin (), x.cur);
+  current = next_by_distance (begin (), x.begin (), x.current);
   return *this;
 }
 
-// Insert the term t into the list at the current position, making
+// Insert the term T into the list before the current position, making
 // this term current.
 inline void
-insert_term (term_list& l, tree t)
+term_list::insert (tree t)
 {
-  l.cur = l.insert (l.cur, t);
+  current = std::list<tree>::insert (current, t);
 }
 
-// Remove the current term form the list, repositioning the current
-// position at the next term in the list.
+// Remove the current term form the list, repositioning to the term
+// following the removed term. Note that the new position could be past 
+// the end of the list.
+//
+// The removed term is returned.
 inline tree
-remove_term (term_list& l)
+term_list::erase ()
 {
-  tree t = *l.cur;
-  l.cur = l.erase (l.cur);
+  tree t = *current;
+  current = std::list<tree>::erase (current);
   return t;
 }
 
+// Initialize the current term to the first in the list.
+inline void
+term_list::start ()
+{
+  current = begin ();
+}
+
+// Advance to the next term in the list.
+inline void
+term_list::next ()
+{
+  ++current;
+}
+
+// Returns true when the current position is past the end.
+inline bool
+term_list::done () const
+{
+  return current == end ();
+}
+
 
 // -------------------------------------------------------------------------- //
 // Proof Goal
@@ -122,24 +157,10 @@ remove_term (term_list& l)
 // constraint language (i.e., lists of trees).
 struct proof_goal
 {
-  term_list as; // Assumptions
-  term_list cs; // Conclusions   
+  term_list assumptions;
+  term_list conclusions;
 };
 
-// Return the list of assumed terms for the goal g.
-inline term_list &
-assumptions (proof_goal &g) { return g.as; }
-
-inline const term_list &
-assumptions (const proof_goal &g) { return g.as; }
-
-// Return the list of concluded terms for the goal g.
-inline term_list &
-conclusions (proof_goal &g) { return g.cs; }
-
-inline const term_list &
-conclusions (const proof_goal &g) { return g.cs; }
-
 
 // -------------------------------------------------------------------------- //
 // Proof State
@@ -151,145 +172,26 @@ struct proof_state : std::list<proof_goa
 {
   proof_state ();
 
-  iterator cur;
+  iterator branch (iterator i);
 };
 
-// Initialize the state with a single empty goal, and set
-// that goal as the current subgoal.
+// An alias for proof state iterators.
+typedef proof_state::iterator goal_iterator;
+
+// Initialize the state with a single empty goal, and set that goal as the
+// current subgoal.
 inline
 proof_state::proof_state ()
-  : std::list<proof_goal> (1), cur (begin ())
+  : std::list<proof_goal> (1)
 { }
 
 
-// Return the current goal. Provided for notational symmetry
-inline proof_goal &
-current_goal (proof_state &s) { return *s.cur; }
-
-inline const proof_goal &
-current_goal (const proof_state &s) { return *s.cur; }
-
-// Return the current list of assumed terms.
-inline term_list &
-assumptions (proof_state &s) { return assumptions (current_goal (s)); }
-
-inline const term_list &
-assumptions (const proof_state &s) { return assumptions (current_goal (s)); }
-
-// Return the current list of concluded terms.
-inline term_list &
-conclusions (proof_state &s) { return conclusions (current_goal (s)); }
-
-inline const term_list &
-conclusions (const proof_state &s) { return conclusions (current_goal (s)); }
-
-// Return the current assumption.
-inline tree
-assumption (const proof_state &s) { return *assumptions (s).cur; }
-
-// Return the current conclision.
-inline tree
-conclusion (const proof_state &s) { return *conclusions (s).cur; }
-
-// Move to the next goal.
-inline void
-next_goal (proof_state &s) { ++s.cur; }
-
-// Move to the next assumption.
-inline void
-next_assumption (proof_state &s) { ++assumptions (s).cur; }
-
-// Move to the next conclusion.
-inline void
-next_conclusion (proof_state &s) { ++conclusions (s).cur; }
-
-
-// -------------------------------------------------------------------------- //
-// Term List Manipulation
-//
-// The following functions are used to manage the insertation and removal
-// goals and terms in the proof state.
-
-// Assume the term e in the current goal. The current assumption is set to the
-// new term.
-inline void
-assume_term (proof_goal &g, tree e) { insert_term (assumptions (g), e); }
-
-inline void 
-assume_term (proof_state &s, tree e) { assume_term (current_goal (s), e); }
-
-// Forget the current assumption, removing it from the context of the current
-// goal. Returns the forgotten assumption.
-inline tree
-forget_term (proof_goal &g) { return remove_term (assumptions (g)); }
-
-inline tree
-forget_term (proof_state &s) { return forget_term (current_goal (s)); }
-
-// Conclude the term e in the current goal. The current conclusion is set to 
-// the new term.
-inline void
-conclude_term (proof_goal &g, tree e) { insert_term (conclusions (g), e); }
-
-inline void
-conclude_term (proof_state &s, tree e) { conclude_term (current_goal (s), e); }
-
-// Ignore the current conclusion, removing it from the conclusions
-// of the current goal. Returns the ignored conclusion.
-inline tree
-ignore_term (proof_goal &g) { return remove_term (conclusions (g)); }
-
-inline tree
-ignore_term (proof_state &s) { return ignore_term (current_goal (s)); }
-
 // Branch the current goal by creating a new subgoal, returning a reference to
-// the new objet. This does not update the current goal.
-inline proof_goal &
-branch_goal (proof_state &s)
-{
-  proof_state::iterator p = s.cur;
-  p = s.insert (++p, *s.cur);
-  return *p;
-}
-
-
-// -------------------------------------------------------------------------- //
-// Debugging
-//
-// Helper functions for debugging the proof state.
-
-void
-debug (term_list &l)
+// the new object. This does not update the current goal.
+inline proof_state::iterator
+proof_state::branch (iterator i)
 {
-  term_list::iterator i = l.begin ();
-  term_list::iterator last = --l.end ();
-  term_list::iterator end = l.end ();
-  for ( ; i != end; ++i)
-    {
-      debug (*i);
-      if (i != last)
-        fprintf (stderr, " ");
-    }
-}
-
-void
-debug (proof_goal &g)
-{
-  debug (g.as);
-  fprintf (stderr, " |- ");
-  debug (g.cs);
-}
-
-void
-debug (proof_state& s)
-{
-  proof_state::iterator i = s.begin ();
-  proof_state::iterator end = s.end ();
-  for ( ; i != end; ++i)
-    {
-      debug (*i);
-      fprintf (stderr, "\n");
-    }
+  return insert (++i, *i);
 }
 
 
@@ -299,63 +201,82 @@ debug (proof_state& s)
 // These functions modify the current state and goal by decomposing
 // logical expressions using the logical rules of sequent calculus for
 // first order logic.
+//
+// Note that in each decomposition rule, the term T has been erased
+// from term list before the specific rule is applied.
 
-
-// And left logical rule.
+// Left-and logical rule.
+//
+//  Gamma, P, Q |- Delta
+//  -------------------------
+//  Gamma, P and Q |- Delta
 inline void 
-and_left (proof_state &s)
+left_and (proof_state &, goal_iterator i, tree t)
 {
-  gcc_assert (TREE_CODE (assumption (s)) == TRUTH_ANDIF_EXPR);
-  tree t = forget_term (s);
-  assume_term (s, TREE_OPERAND (t, 1));
-  assume_term (s, TREE_OPERAND (t, 0));
-}
+  gcc_assert (TREE_CODE (t) == TRUTH_ANDIF_EXPR);
 
-// And right logical rule.
-inline void
-and_right (proof_state &s)
-{
-  gcc_assert (TREE_CODE (conclusion (s)) == TRUTH_ANDIF_EXPR);
-  tree t = ignore_term (s);
-  conclude_term (branch_goal (s), TREE_OPERAND (t, 1));
-  conclude_term (current_goal (s), TREE_OPERAND (t, 0));
+  // Insert the operands into the current branch. Note that the
+  // final order of insertion is left-to-right.
+  term_list &l = i->assumptions;
+  l.insert (TREE_OPERAND (t, 1));
+  l.insert (TREE_OPERAND (t, 0));
 }
 
-// Or left logical rule.
+// Left-or logical rule.
+//
+//  Gamma, P |- Delta    Gamma, Q |- Delta
+//  -----------------------------------------
+//  Gamma, P or Q |- Delta
 inline void
-or_left (proof_state& s)
+left_or (proof_state &s, goal_iterator i, tree t)
 {
-  gcc_assert (TREE_CODE (assumption (s)) == TRUTH_ORIF_EXPR);
-  tree t = forget_term (s);
-  assume_term (branch_goal (s), TREE_OPERAND (t, 1));
-  assume_term (current_goal (s), TREE_OPERAND (t, 0));
+  gcc_assert (TREE_CODE (t) == TRUTH_ORIF_EXPR);
+
+  // Branch the current subgoal.
+  goal_iterator j = s.branch (i);
+  term_list &l1 = i->assumptions;
+  term_list &l2 = j->assumptions;
+
+  // Insert operands into the different branches.
+  l1.insert (TREE_OPERAND (t, 0));
+  l2.insert (TREE_OPERAND (t, 1));
 }
 
-// Or right logical rule.
+// Right-and logical rule.
+//
+//  Gamma |- P, Delta    Gamma |- Q, Delta
+//  -----------------------------------------
+//  Gamma |- P and Q, Delta
 inline void
-or_right (proof_state &s)
+right_and (proof_state &s, goal_iterator i, tree t)
 {
-  gcc_assert (TREE_CODE (conclusion (s)) == TRUTH_ORIF_EXPR);
-  tree t = ignore_term (s);
-  conclude_term (s, TREE_OPERAND (t, 1));
-  conclude_term (s, TREE_OPERAND (t, 0));
-}
+  gcc_assert (TREE_CODE (t) == TRUTH_ORIF_EXPR);
 
+  // Branch the current subgoal.
+  goal_iterator j = s.branch (i);
+  term_list &l1 = i->conclusions;
+  term_list &l2 = j->conclusions;
 
-// -------------------------------------------------------------------------- //
-// Algorithms
+  // Insert operands into the different branches.
+  l1.insert (TREE_OPERAND (t, 0));
+  l2.insert (TREE_OPERAND (t, 1));
+}
+
+// Right-or logical rule.
 //
-// Generic algorithms for querying or manipulating a proof state.
+//  Gamma |- P, Q, Delta
+//  ------------------------
+//  Gamma |- P or Q, Delta
+inline void
+right_or (proof_state &, goal_iterator i, tree t)
+{
+  gcc_assert (TREE_CODE (t) == TRUTH_ANDIF_EXPR);
 
-// Apply fn for each goal and returns fn. The current goal is set prior to
-// calling fn.
-template<typename F>
-  inline F
-  for_each_goal (proof_state &s, F fn)
-  {
-    for (s.cur = s.begin (); s.cur != s.end (); ++s.cur)
-      fn (s);
-    return fn;
+  // Insert the operands into the current branch. Note that the
+  // final order of insertion is left-to-right.
+  term_list &l = i->conclusions;
+  l.insert (TREE_OPERAND (t, 1));
+  l.insert (TREE_OPERAND (t, 0));
   }
 
 
@@ -375,60 +296,40 @@ template<typename F>
 // subgoal that can be further decomposed.
 
 void
-decompose_left_term (proof_state &s)
-{
-  tree e = assumption (s);
-  if (TREE_CODE (e) == TRUTH_ANDIF_EXPR)
-    and_left (s);
-  else if (TREE_CODE (e) == TRUTH_ORIF_EXPR)
-    or_left (s);
-  else
-    next_assumption (s);
-}
-
-void 
-decompose_left_goal (proof_state &s)
+decompose_left_term (proof_state &s, goal_iterator i)
 {
-  term_list& l = assumptions (s);
-  for (l.cur = l.begin (); l.cur != l.end (); )
-    decompose_left_term (s);
-}
-
-inline void
-decompose_left (proof_state& s)
+  term_list &l = i->assumptions;
+  tree t = l.current_term ();
+  switch (TREE_CODE (t))
 {
-  for_each_goal (s, decompose_left_goal);
+    case TRUTH_ANDIF_EXPR:
+      left_and (s, i, l.erase ());
+      break;
+    case TRUTH_ORIF_EXPR:
+      left_or (s, i, l.erase ());
+      break;
+    default:
+      l.next ();
+      break;
 }
-
-// Right decomposition.
-// Continually decompose conclusions until there are no terms in any
-// subgoal that can be further decomposed.
-
-void
-decompose_right_term (proof_state &s)
-{
-  tree e = conclusion (s);
-  if (TREE_CODE (e) == TRUTH_ANDIF_EXPR)
-    and_right (s);
-  else if (TREE_CODE (e) == TRUTH_ORIF_EXPR)
-    or_right (s);
-  else
-    next_conclusion (s);
 }
 
 void
-decompose_right_goal (proof_state &s)
+decompose_left_goal (proof_state &s, goal_iterator i)
 {
-  term_list& l = conclusions (s);
-  for (l.cur = l.begin (); l.cur != l.end (); )
-    decompose_right_term (s);
+  term_list& l = i->assumptions;
+  l.start ();
+  while (!l.done ())
+    decompose_left_term (s, i);
 }
 
-
 inline void
-decompose_right (proof_state& s)
+decompose_left (proof_state& s)
 {
-  for_each_goal (s, decompose_right_goal);
+  goal_iterator iter = s.begin ();
+  goal_iterator end = s.end ();
+  for ( ; iter != end; ++iter)
+    decompose_left_goal (s, iter);
 }
 
 
@@ -436,32 +337,17 @@ decompose_right (proof_state& s)
 // Term Extraction
 //
 // Extract a list of term lists from a proof state, and return it as a
-// a tree (a vetor of vectors).
+// a tree (a vector of vectors).
 
 // Returns a vector of terms from the given term list.
 tree
 extract_terms (term_list& l)
 {
   tree result = make_tree_vec (l.size());
-  term_list::iterator i = l.begin();
-  term_list::iterator e = l.end();
-  for (int n = 0; i != e; ++i, ++n)
-    TREE_VEC_ELT (result, n) = *i;
-  return result;
-}
-
-// Extract a vector of term vectors from s. The selected set of terms is given
-// by the projection function proj. This is generally either assumptions or
-// conclusions.
-template<typename F>
-  tree
-  extract_goals (proof_state& s, F proj)
-  {
-    tree result = make_tree_vec (s.size ());
-    proof_state::iterator i = s.begin ();
-    proof_state::iterator e = s.end ();
-    for (int n = 0; i != e; ++i, ++n)
-      TREE_VEC_ELT (result, n) = extract_terms (proj (*i));
+  term_list::iterator iter = l.begin();
+  term_list::iterator end = l.end();
+  for (int n = 0; iter != end; ++iter, ++n)
+    TREE_VEC_ELT (result, n) = *iter;
     return result;
   }
 
@@ -469,43 +355,33 @@ template<typename F>
 inline tree
 extract_assumptions (proof_state& s)
 {
-  term_list& (*proj)(proof_goal&) = assumptions;
-  return extract_goals (s, proj);
-}
-
-// Extract the conclusion vector from the proof state s.
-inline tree
-extract_conclusions (proof_state& s)
-{
-  term_list& (*proj)(proof_goal&) = conclusions;
-  return extract_goals (s, proj);
+  tree result = make_tree_vec (s.size ());
+  goal_iterator iter = s.begin ();
+  goal_iterator end = s.end ();
+  for (int n = 0; iter != end; ++iter, ++n)
+    TREE_VEC_ELT (result, n) = extract_terms (iter->assumptions);
+  return result;
 }
 
 } // namespace
 
 
-// Decompose the requirement R into a set of assumptions, returing a
-// vector of vectors containing atomic propositions.
+// Decompose the required expression T into a constraint set: a
+// vector of vectors containing only atomic propositions.
 tree
-decompose_assumptions (tree r)
+decompose_assumptions (tree t)
 {
+  // Create a proof state, and insert T as the sole assumption.
   proof_state s;
-  assume_term (s, r);
+  term_list &l = s.begin ()->assumptions;
+  l.insert (t);
+  
+  // Decompose the expression into a constraint set, and then
+  // extract the terms for the AST.
   decompose_left (s);
   return extract_assumptions (s);
 }
 
-// Decompose the requirement R into a set of conclusionss, returning a
-// vector of vectors containing atomic propositions.
-tree
-decompose_conclusions (tree r)
-{
-  proof_state s;
-  conclude_term (s, r);
-  decompose_right (s);
-  return extract_conclusions (s);
-}
-
 
 // -------------------------------------------------------------------------- //
 // Subsumption and Entailment
@@ -515,11 +391,20 @@ decompose_conclusions (tree r)
 
 namespace {
 
-// Returns true if the assumed proposition A entails the conclusion C.
-// In general, this is the case when A has equivalent spelling to C,
-// although there will be some special cases.
+bool subsumes_prop(tree, tree);
+bool subsumes_atom(tree, tree);
+bool subsumes_and(tree, tree);
+bool subsumes_or(tree, tree);
+
+// Returns true if the assumption A matches the conclusion C. This
+// is generally the case when A and C have the same syntax.
+//
+// TODO: Implement special cases for:
+//    * __is_same_as |- __is_convertible_to
+//    * __is_same_as |- __is_derived_from
+//    * Any other built-in predicates?
 bool
-entails_atom (tree a, tree c)
+match_terms (tree a, tree c)
 {
   // TODO: Add special cases for __is_same, __is_convertible, 
   // and __is_base_of.
@@ -528,16 +413,33 @@ entails_atom (tree a, tree c)
 
 // Returns true if the list of assumptions AS subsume the atomic 
 // proposition C. This is the case when we can find a proposition in
-// HS that entails the conclusion C.
+// AS that entails the conclusion C.
 bool
 subsumes_atom (tree as, tree c)
 {
   for (int i = 0; i < TREE_VEC_LENGTH (as); ++i)
-    if (entails_atom (TREE_VEC_ELT (as, i), c))
+    if (match_terms (TREE_VEC_ELT (as, i), c))
       return true;
   return false;
 }
 
+// Returns true when both operands of C are subsumed by the assumptions AS.
+inline bool 
+subsumes_and (tree as, tree c)
+{
+  tree l = TREE_OPERAND (c, 0);
+  tree r = TREE_OPERAND (c, 1);
+  return subsumes_prop (as, l) && subsumes_prop (as, r);
+}
+
+// Returns true when either operand of C is subsumed by the assumptions AS.
+inline bool
+subsumes_or (tree as, tree c)
+{
+  tree l = TREE_OPERAND (c, 0);
+  tree r = TREE_OPERAND (c, 1);
+  return subsumes_prop (as, l) || subsumes_prop (as, r);
+}
 
 // Returns true when the list of assumptions AS subsumes the 
 // concluded proposition C.
@@ -550,11 +452,9 @@ subsumes_prop (tree as, tree c)
   switch (TREE_CODE (c))
     {
     case TRUTH_ANDIF_EXPR:
-      return subsumes_prop (as, TREE_OPERAND (c, 0)) 
-          && subsumes_prop (as, TREE_OPERAND (c, 1));
+      return subsumes_and (as, c);
     case TRUTH_ORIF_EXPR:
-      return subsumes_prop (as, TREE_OPERAND (c, 0)) 
-          || subsumes_prop (as, TREE_OPERAND (c, 1));
+      return subsumes_or (as, c);
     default:
       return subsumes_atom (as, c);
     }
@@ -566,11 +466,11 @@ subsumes_prop (tree as, tree c)
 bool
 subsumes_constraints (tree left, tree right)
 {
-  gcc_assert (constraint_info_p (left));
-  gcc_assert (constraint_info_p (right));
+  gcc_assert (check_constraint_info (left));
+  gcc_assert (check_constraint_info (right));
 
-  // Check that c is subsumed by each subproblem in h.
-  // If it is not, then h does not subsume c.
+  // Check that the required expression in RIGHT is subsumed by each
+  // subgoal in the assumptions of LEFT.
   tree as = CI_ASSUMPTIONS (left);
   tree c = reduce_requirements (CI_REQUIREMENTS (right));
   for (int i = 0; i < TREE_VEC_LENGTH (as); ++i)
@@ -583,7 +483,7 @@ subsumes_constraints (tree left, tree ri
 
 
 // Returns true the LEFT constraints subsume the RIGHT constraints. Note
-// that subsumption is a reflexive relation.
+// that subsumption is a reflexive relation (e.g., <=)
 bool
 subsumes (tree left, tree right)
 {
@@ -596,3 +496,4 @@ subsumes (tree left, tree right)
   return subsumes_constraints (left, right);
 }
 
+
Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h	(revision 199581)
+++ cp/cp-tree.h	(working copy)
@@ -800,7 +800,7 @@ struct GTY(()) tree_constraint_info {
 
 // Returns true iff T is non-null and represents constraint info.
 inline tree_constraint_info *
-constraint_info_p (tree t)
+check_constraint_info (tree t)
 {
   if (t && TREE_CODE (t) == CONSTRAINT_INFO)
     return (tree_constraint_info *)t;
@@ -809,7 +809,7 @@ constraint_info_p (tree t)
 
 // Returns true iff T is non-null and is a template info object.
 inline tree_template_info *
-template_info_p (tree t)
+check_template_info (tree t)
 {
   if (t && TREE_CODE (t) == TEMPLATE_INFO)
     return (tree_template_info *)t;
@@ -818,34 +818,34 @@ template_info_p (tree t)
 
 // Get the spelling of the requirements
 #define CI_SPELLING(NODE) \
-  check_nonnull (constraint_info_p (NODE))->spelling
+  check_nonnull (check_constraint_info (NODE))->spelling
 
 // Get the reduced requirements associated with the constraint info node
 #define CI_REQUIREMENTS(NODE) \
-  check_nonnull (constraint_info_p (NODE))->requirements
+  check_nonnull (check_constraint_info (NODE))->requirements
 
 // Get the set of assumptions associated with the constraint info node
 #define CI_ASSUMPTIONS(NODE) \
-  check_nonnull (constraint_info_p (NODE))->assumptions
+  check_nonnull (check_constraint_info (NODE))->assumptions
 
 // Get the constraint associated with the template info NODE.
 #define TI_CONSTRAINT(NODE) \
-  check_nonnull (template_info_p (NODE))->constraint
+  check_nonnull (check_template_info (NODE))->constraint
 
 // Get the spelling of constraints associated
 #define TI_SPELLING(NODE) \
-  check_nonnull (constraint_info_p (TI_CONSTRAINT (NODE)))->spelling
+  check_nonnull (check_constraint_info (TI_CONSTRAINT (NODE)))->spelling
 
 // Get requirements associated with the template info NODE.
 #define TI_REQUIREMENTS(NODE) \
-  check_nonnull (constraint_info_p (TI_CONSTRAINT (NODE)))->requirements
+  check_nonnull (check_constraint_info (TI_CONSTRAINT (NODE)))->requirements
 
 // Get assumptions associated with the template info NODE.
 #define TI_ASSUMPTIONS(NODE) \
-  check_nonnull (constraint_info_p (TI_CONSTRAINT (NODE)))->assumptions
+  check_nonnull (check_constraint_info (TI_CONSTRAINT (NODE)))->assumptions
 
 // Access constraint information for C++ declarations. Note that
-// NODE must be a lang-decl.
+// NODE must have DECL_LANG_SPECIFIC.
 #define DECL_TEMPLATE_CONSTRAINT(NODE) \
   TI_CONSTRAINT (DECL_TEMPLATE_INFO (NODE))
 
@@ -4409,6 +4409,15 @@ extern int cp_unevaluated_operand;
 extern tree cp_convert_range_for (tree, tree, tree);
 extern bool parsing_nsdmi (void);
 
+// An RAII class used to inhibit the evaluation of operands during parsing
+// and template instantiation. Evaluation warnings are also inhibited.
+class cp_unevaluated
+{
+public:
+  cp_unevaluated ();
+  ~cp_unevaluated ();
+};
+
 /* in pt.c  */
 
 /* These values are used for the `STRICT' parameter to type_unification and
@@ -4421,6 +4430,18 @@ typedef enum unification_kind_t {
   DEDUCE_EXACT
 } unification_kind_t;
 
+// An RAII class used to create a new pointer map for local
+// specializations. When the stack goes out of scope, the
+// previous pointer map is restored.
+class local_specialization_stack
+{
+public:
+  local_specialization_stack ();
+  ~local_specialization_stack ();
+
+  struct pointer_map_t *saved;
+};
+
 /* in class.c */
 
 extern int current_class_depth;
@@ -5652,8 +5673,7 @@ extern tree get_template_argument_pack_e
 extern tree get_function_template_decl		(const_tree);
 extern tree resolve_nondeduced_context		(tree);
 extern hashval_t iterative_hash_template_arg (tree arg, hashval_t val);
-extern tree substitute_template_parameters      (tree, tree);
-extern tree substitute_requirements             (tree, tree);
+extern tree coerce_template_parms               (tree, tree, tree);
 extern tree instantiate_requirements            (tree, tree);
 extern tree tsubst_constraint                   (tree, tree);
 extern tree current_template_args               ();
@@ -5807,6 +5827,8 @@ extern bool is_sub_constant_expr (tree);
 extern bool reduced_constant_expression_p (tree);
 extern void explain_invalid_constexpr_fn (tree);
 extern vec<tree> cx_error_context (void);
+extern bool is_unary_trait                      (cp_trait_kind);
+extern bool is_binary_trait                     (cp_trait_kind);
 
 enum {
   BCS_NO_SCOPE = 1,
@@ -6250,6 +6272,16 @@ extern tree conjoin_requirements
 extern tree disjoin_requirements                (tree, tree);
 extern tree reduce_requirements                 (tree);
 extern tree make_constraints                    (tree);
+extern tree get_constraints                     (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);
+extern bool equivalently_constrained            (tree, tree);
+extern bool more_constraints                    (tree, tree);
+extern bool more_constrained                    (tree, tree);
+extern void diagnose_constraint_failure         (location_t, tree, tree);
 
 /* in logic.cc */
 extern tree decompose_assumptions               (tree);
Index: cp/cxx-pretty-print.c
===================================================================
--- cp/cxx-pretty-print.c	(revision 199411)
+++ cp/cxx-pretty-print.c	(working copy)
@@ -2182,6 +2182,14 @@ pp_cxx_template_declaration (cxx_pretty_
       pp_cxx_end_template_argument_list (pp);
       pp_newline_and_indent (pp, 3);
     }
+
+  if (tree c = get_constraints (t))
+    {
+      pp_cxx_ws_string (pp, "requires");
+      pp_cxx_expression (pp, CI_REQUIREMENTS (c));
+      pp_newline_and_indent (pp, 6);
+    }
+
   if (TREE_CODE (t) == FUNCTION_DECL && DECL_SAVED_TREE (t))
     pp_cxx_function_definition (pp, t);
   else
Index: cp/pt.c
===================================================================
--- cp/pt.c	(revision 199581)
+++ cp/pt.c	(working copy)
@@ -77,6 +77,23 @@ static tree cur_stmt_expr;
    local variables.  */
 static struct pointer_map_t *local_specializations;
 
+// -------------------------------------------------------------------------- //
+// Local Specialization Stack
+//
+// Implementation of the RAII helper for creating new local
+// specializations.
+local_specialization_stack::local_specialization_stack ()
+  : saved (local_specializations)
+{
+  local_specializations = pointer_map_create ();
+}
+
+local_specialization_stack::~local_specialization_stack ()
+{
+  pointer_map_destroy (local_specializations);
+  local_specializations = saved;
+}
+
 /* True if we've recursed into fn_type_unification too many times.  */
 static bool excessive_deduction_depth;
 
@@ -301,9 +318,16 @@ finish_member_template_decl (tree decl)
 tree
 build_template_info (tree template_decl, tree template_args)
 {
+  return build_template_info (template_decl, template_args, NULL_TREE);
+}
+
+tree
+build_template_info (tree template_decl, tree template_args, tree template_reqs)
+{
   tree result = make_node (TEMPLATE_INFO);
   TI_TEMPLATE (result) = template_decl;
   TI_ARGS (result) = template_args;
+  TI_CONSTRAINT (result) = template_reqs;
   return result;
 }
 
@@ -1952,7 +1976,15 @@ determine_specialization (tree template_
 	       specialize TMPL will produce DECL.  */
 	    continue;
 
-	  /* Make sure that the deduced arguments actually work.  */
+	  // 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;
@@ -2683,6 +2715,8 @@ check_explicit_specialization (tree decl
 	    }
 
 	  /* Set up the DECL_TEMPLATE_INFO for DECL.  */
+          tree fn = DECL_TEMPLATE_RESULT (tmpl);
+          tree cons = tsubst_constraint (DECL_TEMPLATE_CONSTRAINT (fn), targs);
 	  DECL_TEMPLATE_INFO (decl) = build_template_info (tmpl, targs);
 
 	  /* Inherit default function arguments from the template
@@ -4878,7 +4912,7 @@ template arguments to %qD do not match o
   if (DECL_TEMPLATE_INFO (tmpl))
     args = add_outermost_template_args (DECL_TI_ARGS (tmpl), args);
 
-  info = build_template_info (tmpl, args);
+  info = build_template_info (tmpl, args, current_template_reqs);
 
   if (DECL_IMPLICIT_TYPEDEF_P (decl))
     SET_TYPE_TEMPLATE_INFO (TREE_TYPE (tmpl), info);
@@ -5029,6 +5063,17 @@ redeclare_class_template (tree type, tre
 	TREE_PURPOSE (TREE_VEC_ELT (parms, i)) = tmpl_default;
     }
 
+  // Cannot redeclare a class template with a different set of constraints. 
+  tree tmpl_type = TREE_TYPE (tmpl);
+  if (!equivalent_constraints (TYPE_TEMPLATE_CONSTRAINT (tmpl_type), cons))
+    {
+      // FIXME: This points to the wrong line.
+      error_at (input_location, "redeclaration %q#D with different "
+                                "constraints", tmpl);
+      inform (DECL_SOURCE_LOCATION (tmpl), 
+              "original declaration appeared here");
+    }
+
     return true;
 }
 
@@ -6160,6 +6205,47 @@ canonicalize_type_argument (tree arg, ts
   return arg;
 }
 
+// A template declaration can be substituted for a constrained
+// template template parameter only when the argument is more 
+// constrained than the parameter.
+static bool
+is_compatible_template_arg (tree parm, tree arg)
+{
+  // TODO: The argument may not have a decl result. This seems to
+  // happen in some classes with nested template template
+  // parameters (e.g., a rebind struct in a class taking a template
+  // template parameter. If this is the case, just return true and
+  // allow things to happen as they always did.
+  if (TREE_CODE (arg) == TEMPLATE_DECL)
+    {
+      if (!DECL_TEMPLATE_RESULT (arg))
+        return true;
+    }
+
+  // If the template parameter is constrained, we need to rewrite its
+  // constraints in terms of the ARG's template parameters. This ensures
+  // that all of the template parameter types will have the same depth.
+  //
+  // Note that this is only valid when coerce_template_template_parm is
+  // true for the innermost template parameters of PARM and ARG. In other
+  // words, because coercion is successful, conversion will be valid.
+  tree parmcons = DECL_TEMPLATE_CONSTRAINT (DECL_TEMPLATE_RESULT (parm));
+  if (parmcons)
+    {
+      tree args = template_parms_to_args (DECL_TEMPLATE_PARMS (arg));
+      ++processing_template_decl;
+      tree reqs = instantiate_requirements (CI_REQUIREMENTS (parmcons), args);
+      --processing_template_decl;
+      if (reqs == error_mark_node)
+        return false;
+      parmcons = make_constraints (reqs);
+    }
+
+  tree argtype = TREE_TYPE (arg);
+  tree argcons = get_constraints (argtype);
+  return more_constraints (argcons, parmcons);
+}
+
 /* Convert the indicated template ARG as necessary to match the
    indicated template PARM.  Returns the converted ARG, or
    error_mark_node if the conversion was unsuccessful.  Error and
@@ -6304,9 +6390,7 @@ convert_template_argument (tree parm,
 	  else
 	    {
 	      tree parmparm = DECL_INNERMOST_TEMPLATE_PARMS (parm);
-	      tree argparm;
-
-              argparm = DECL_INNERMOST_TEMPLATE_PARMS (arg);
+	      tree argparm = DECL_INNERMOST_TEMPLATE_PARMS (arg);
 
 	      if (coerce_template_template_parms (parmparm, argparm,
 						  complain, in_decl,
@@ -6337,6 +6421,22 @@ convert_template_argument (tree parm,
 
 		  val = error_mark_node;
 		}
+
+              // Check that the constraints are compatible before allowing the
+              // substitution.
+              if (val != error_mark_node)
+                if (!is_compatible_template_arg (parm, arg))
+                  {
+                      if (in_decl && (complain & tf_error))
+                      {
+                        error ("constraint mismatch at argument %d in "
+                               "template parameter list for %qD",
+                               i + 1, in_decl);
+                        inform (input_location, "  expected %qD but got %qD",
+                                parm, arg);
+                      }                      
+                      val = error_mark_node;
+                  }
 	    }
 	}
       else
@@ -6543,7 +6643,6 @@ any_pack_expanson_args_p (tree args)
   return false;
 }
 
-
 /* Convert all template arguments to their appropriate types, and
    return a vector containing the innermost resulting template
    arguments.  If any error occurs, return error_mark_node. Error and
@@ -6741,6 +6840,19 @@ coerce_template_parms (tree parms,
   return new_inner_args;
 }
 
+// Convert all template arguments to their appropriate types, and
+// return a vector containing the innermost resulting template
+// arguments.  If any error occurs, return error_mark_node. Error and
+// warning messages are not issued.
+//
+// Note that no function argument deduction is performed, and default 
+// arguments are used to fill in unspecified arguments.
+tree
+coerce_template_parms (tree parms, tree args, tree in_decl)
+{
+  return coerce_template_parms (parms, args, in_decl, tf_none, true, true);
+}
+
 /* Like coerce_template_parms.  If PARMS represents all template
    parameters levels, this function returns a vector of vectors
    representing all the resulting argument levels.  Note that in this
@@ -7371,6 +7483,10 @@ lookup_template_class_1 (tree d1, tree a
 	}
       else if (DECL_ALIAS_TEMPLATE_P (gen_tmpl))
 	{
+          // Check the alias declaration's args. 
+          if (!check_template_constraints (gen_tmpl, arglist))
+            return error_mark_node;
+
 	  /* The user referred to a specialization of an alias
 	    template represented by GEN_TMPL.
 
@@ -7534,7 +7650,10 @@ lookup_template_class_1 (tree d1, tree a
 	    : CLASSTYPE_TI_TEMPLATE (found);
 	}
 
-      SET_TYPE_TEMPLATE_INFO (t, build_template_info (found, arglist));
+      // Build the constraints for this type. 
+      tree type = TREE_TYPE (found);
+      tree cons = tsubst_constraint (TYPE_TEMPLATE_CONSTRAINT (type), arglist);
+       SET_TYPE_TEMPLATE_INFO (t, build_template_info (found, arglist, cons));
 
       elt.spec = t;
       slot = htab_find_slot_with_hash (type_specializations,
@@ -8600,6 +8719,12 @@ instantiate_class_template_1 (tree type)
     {
       pattern = TREE_TYPE (templ);
       args = CLASSTYPE_TI_ARGS (type);
+
+      // Check class template requirements. Note that constraints will 
+      // already have been checked when trying to find a most specialized 
+      // class among multiple specializations.
+      if (!check_template_constraints (pattern, args))
+        return error_mark_node;
     }
 
   /* If the template we're instantiating is incomplete, then clearly
@@ -9981,6 +10106,7 @@ tsubst_decl (tree t, tree args, tsubst_f
 	/* We can get here when processing a member function template,
 	   member class template, or template template parameter.  */
 	tree decl = DECL_TEMPLATE_RESULT (t);
+  tree type = TREE_TYPE (t);
 	tree spec;
 	tree tmpl_args;
 	tree full_args;
@@ -9988,7 +10114,7 @@ tsubst_decl (tree t, tree args, tsubst_f
 	if (DECL_TEMPLATE_TEMPLATE_PARM_P (t))
 	  {
 	    /* Template template parameter is treated here.  */
-	    tree new_type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+	    tree new_type = tsubst (type, args, complain, in_decl);
 	    if (new_type == error_mark_node)
 	      RETURN (error_mark_node);
 	    /* If we get a real template back, return it.  This can happen in
@@ -10049,7 +10175,13 @@ tsubst_decl (tree t, tree args, tsubst_f
 	gcc_assert (DECL_LANG_SPECIFIC (r) != 0);
 	DECL_CHAIN (r) = NULL_TREE;
 
-	DECL_TEMPLATE_INFO (r) = build_template_info (t, args);
+        // Rebuild the constraints on the original template.
+        tree cons = get_constraints (t);
+        cons = tsubst_constraint (cons, args);
+ 
+        // Build new template info linking to the original template
+        // decl, but having these args and constraints.
+        DECL_TEMPLATE_INFO (r) = build_template_info (t, args, cons);	
 
 	if (TREE_CODE (decl) == TYPE_DECL
 	    && !TYPE_DECL_ALIAS_P (decl))
@@ -10286,8 +10418,11 @@ tsubst_decl (tree t, tree args, tsubst_f
 	   GEN_TMPL is NULL.  */
 	if (gen_tmpl)
 	  {
+            // Rebuild the template constraint.
+            tree cons = tsubst_constraint (DECL_TEMPLATE_CONSTRAINT (t), args);
+	    
 	    DECL_TEMPLATE_INFO (r)
-	      = build_template_info (gen_tmpl, argvec);
+	      = build_template_info (gen_tmpl, argvec, cons);
 	    SET_DECL_IMPLICIT_INSTANTIATION (r);
 
 	    tree new_r
@@ -10426,13 +10561,15 @@ tsubst_decl (tree t, tree args, tsubst_f
               /* We're on the Ith parameter of the function parameter
                  pack.  */
               {
-		/* An argument of a function parameter pack is not a parameter
-		   pack.  */
-		FUNCTION_PARAMETER_PACK_P (r) = false;
-
                 /* Get the Ith type.  */
                 type = TREE_VEC_ELT (expanded_types, i);
 
+                // An argument of a function parameter pack is a function
+                // parameter pack if its type is also a pack. This can
+                // happen when instantiating templates with other template
+                // parameters.
+                FUNCTION_PARAMETER_PACK_P (r) = PACK_EXPANSION_P (type);
+
 		/* Rename the parameter to include the index.  */
 		DECL_NAME (r)
 		  = make_ith_pack_parameter_name (DECL_NAME (r), i);
@@ -10512,7 +10649,7 @@ tsubst_decl (tree t, tree args, tsubst_f
 	    DECL_INITIAL (r) = void_zero_node;
 	    gcc_assert (DECL_LANG_SPECIFIC (r) == NULL);
 	    retrofit_lang_decl (r);
-	    DECL_TEMPLATE_INFO (r) = build_template_info (t, args);
+	    DECL_TEMPLATE_INFO (r) = build_template_info (t, args, NULL_TREE);
 	  }
 	/* We don't have to set DECL_CONTEXT here; it is set by
 	   finish_member_declaration.  */
@@ -10743,7 +10880,9 @@ tsubst_decl (tree t, tree args, tsubst_f
 	    DECL_EXTERNAL (r) = 1;
 
 	    register_specialization (r, gen_tmpl, argvec, false, hash);
-	    DECL_TEMPLATE_INFO (r) = build_template_info (tmpl, argvec);
+
+	    DECL_TEMPLATE_INFO (r) = 
+                build_template_info (tmpl, argvec, NULL_TREE);
 	    SET_DECL_IMPLICIT_INSTANTIATION (r);
 	  }
 	else if (cp_unevaluated_operand)
@@ -12526,6 +12665,8 @@ tsubst_copy (tree t, tree args, tsubst_f
     case UNION_TYPE:
     case ENUMERAL_TYPE:
     case INTEGER_TYPE:
+    case REAL_TYPE:
+    case BOOLEAN_TYPE:
     case TEMPLATE_TYPE_PARM:
     case TEMPLATE_TEMPLATE_PARM:
     case BOUND_TEMPLATE_TEMPLATE_PARM:
@@ -14493,6 +14634,12 @@ tsubst_copy_and_build (tree t,
 	  /* If the original type was a reference, we'll be wrapped in
 	     the appropriate INDIRECT_REF.  */
 	  r = convert_from_reference (r);
+
+        // If the type of the argument is a pack expansion, then
+        // the parameter must also be expanded.
+        if (PACK_EXPANSION_P (TREE_TYPE (r)))
+          r = make_pack_expansion (r);
+
 	RETURN (r);
       }
 
@@ -15204,6 +15351,15 @@ 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)) 
+    {
+      if (explain_p)
+        diagnose_constraint_failure (DECL_SOURCE_LOCATION (fn), fn, targs);
+      return error_mark_node;
+    }
+
   /* All is well so far.  Now, check:
 
      [temp.deduct]
@@ -17709,6 +17865,13 @@ more_specialized_fn (tree pat1, tree pat
       lose2 = TREE_CODE (TREE_VALUE (args2)) == TYPE_PACK_EXPANSION;
     }
 
+  // All things still being equal, determine if one is more constrained.
+  if (lose1 == lose2)
+    {
+      lose1 = !more_constrained (pat1, pat2);
+      lose2 = !more_constrained (pat2, pat1);
+    }
+
   if (lose1 == lose2)
     return 0;
   else if (!lose1)
@@ -17736,12 +17899,11 @@ static int
 more_specialized_class (tree main_tmpl, tree pat1, tree pat2)
 {
   tree targs;
-  tree tmpl1, tmpl2;
   int winner = 0;
   bool any_deductions = false;
 
-  tmpl1 = TREE_TYPE (pat1);
-  tmpl2 = TREE_TYPE (pat2);
+  tree tmpl1 = TREE_TYPE (pat1);
+  tree tmpl2 = TREE_TYPE (pat2);
 
   /* Just like what happens for functions, if we are ordering between
      different class template specializations, we may encounter dependent
@@ -20179,11 +20341,15 @@ instantiation_dependent_r (tree *tp, int
       }
 
     case TRAIT_EXPR:
-      if (dependent_type_p (TRAIT_EXPR_TYPE1 (*tp))
-	  || dependent_type_p (TRAIT_EXPR_TYPE2 (*tp)))
+      {
+        bool l = dependent_type_p (TRAIT_EXPR_TYPE1 (*tp));
+        bool r = is_binary_trait (TRAIT_EXPR_KIND (*tp))
+                   ? dependent_type_p (TRAIT_EXPR_TYPE1 (*tp)) : false;
+        if (l || r)
 	return *tp;
       *walk_subtrees = false;
       return NULL_TREE;
+      }
 
     case COMPONENT_REF:
       if (identifier_p (TREE_OPERAND (*tp, 1)))
@@ -21101,16 +21267,6 @@ print_template_statistics (void)
 	   htab_collisions (type_specializations));
 }
 
-
-// Try to substitute ARGS into PARMS, returning the actual list of
-// arguments that have been substituted. If ARGS cannot be substituted,
-// return error_mark_node.
-tree
-substitute_template_parameters (tree parms, tree args)
-{
-  return coerce_template_parms (parms, args, NULL_TREE, tf_none, true, true);
-}
-
 // Substitute the template arguments ARGS into the requirement
 // expression REQS. Errors resulting from substitution are not
 // diagnosed.
@@ -21120,5 +21276,17 @@ instantiate_requirements (tree reqs, tre
   return tsubst_expr (reqs, args, tf_none, NULL_TREE, true);
 }
 
+// Create a new constraint info block by substituting ARGS into
+// the requirements of CONS.
+//
+// Note that this does not require evaluation.
+tree
+tsubst_constraint (tree cons, tree args)
+{
+  if (!cons)
+    return NULL_TREE;
+  tree reqs = instantiate_requirements (CI_REQUIREMENTS (cons), args);
+  return make_constraints (reqs);
+}
 
 #include "gt-cp-pt.h"
Index: cp/parser.c
===================================================================
--- cp/parser.c	(revision 199581)
+++ cp/parser.c	(working copy)
@@ -2210,8 +2210,6 @@ static void cp_parser_label_declaration
 
 /* Concept Extensions */
 
-static tree cp_parser_requires_clause
-  (cp_parser *);
 static tree cp_parser_requires_clause_opt
   (cp_parser *);
 
@@ -2418,52 +2416,21 @@ static cp_declarator * cp_parser_make_in
  (enum tree_code, tree, cp_cv_quals, cp_declarator *, tree);
 
 
-// A helper type for declaring rule pointers.
-typedef tree (*cp_rule)(cp_parser *);
-
 
 // -------------------------------------------------------------------------- //
-// Optional Parsing
+// Unevaluated Operand Guard
 //
-// The following functions will optionally parse a rule if the corresponding
-// criteria is satisfied. If not, the parser returns NULL indicating that
-// the optional parse taken.
-//
-// Note that an optional parse returning error_mark_node means that the
-// optional parse was taken, but failed due to some error in the following
-// token stream. 
-
-// Optionally parse RULE if the next token type matches TYPE.
-template<typename Rule>
-static inline tree
-cp_parser_optional_if_token (cp_parser *parser, Rule rule, cpp_ttype type)
-{
-  if (cp_lexer_next_token_is (parser->lexer, type))
-    return rule (parser);
-  else
-    return NULL_TREE;
-}
-
-// Optionally parse RULE if the next token type does not match TYPE.
-template<typename Rule>
-static inline tree
-cp_parser_optional_if_not_token (cp_parser *parser, Rule rule, cpp_ttype type)
+// Implementation of an RAII helper for unevaluated operand parsing.
+cp_unevaluated::cp_unevaluated ()
 {
-  if (cp_lexer_next_token_is_not (parser->lexer, type))
-    return rule (parser);
-  else
-    return NULL_TREE;
+  ++cp_unevaluated_operand;
+  ++c_inhibit_evaluation_warnings;
 }
 
-// Optionally parse RULE if the next token is the keyword KW.
-template<typename Rule>
-static inline tree
-cp_parser_optional_if_keyword (cp_parser *parser, Rule rule, rid kw)
+cp_unevaluated::~cp_unevaluated ()
 {
-  if (cp_lexer_next_token_is_keyword (parser->lexer, kw))
-    return rule (parser);
-  else
-    return NULL_TREE;
+  --c_inhibit_evaluation_warnings;
+  --cp_unevaluated_operand;
 }
 
 // -------------------------------------------------------------------------- //
@@ -12816,6 +12783,7 @@ cp_parser_type_parameter (cp_parser* par
 	/* Look for the `>'.  */
 	cp_parser_require (parser, CPP_GREATER, RT_GREATER);
 	
+
         // If template requirements are present, parse them.
         if (flag_concepts)
           {
@@ -19885,11 +19853,11 @@ cp_parser_member_declaration (cp_parser*
 
               // If we're looking at a function declaration, then a requires
               // clause may follow the declaration.
-              tree saved_template_reqs = current_template_reqs;
-              if (flag_concepts 
-                  && function_declarator_p (declarator)
-                  && cp_lexer_next_token_is_keyword (parser->lexer, RID_REQUIRES))
+              tree saved_template_reqs = release (current_template_reqs);
+              if (flag_concepts && function_declarator_p (declarator))
                 {
+                  // Because this is a non-template member, there are no
+                  // template requirements to conjoin.
                   if (tree r = cp_parser_requires_clause_opt (parser))
                     current_template_reqs = finish_template_requirements (r);
                 }
@@ -21423,39 +21391,27 @@ cp_parser_label_declaration (cp_parser*
   cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
 }
 
-// Parse a requires clause:
+// Optionally parse a requires clause:
 //
 //   requires-clause:
 //     'requires' constant-expression
 //
 // The constant expression is a logical-or-expression.
 static tree
-cp_parser_requires_clause (cp_parser *parser)
+cp_parser_requires_clause_opt (cp_parser *parser)
 {
-  gcc_assert (cp_lexer_next_token_is_keyword (parser->lexer, RID_REQUIRES));
+  if (!cp_lexer_next_token_is_keyword (parser->lexer, RID_REQUIRES))
+    return NULL_TREE;
   cp_lexer_consume_token (parser->lexer);
 
   // Parse a logical-or-expression as a constant expression.
   tree expr = 
     cp_parser_binary_expression (parser, false, false, PREC_NOT_OPERATOR, NULL);
-  if (!potential_rvalue_constant_expression (expr))
-    {
-      require_potential_rvalue_constant_expression (expr);
+  if (!require_potential_rvalue_constant_expression (expr))
       return error_mark_node;
-    }
   return expr;
 }
 
-// Parse an optional template requirement, returning NULL_TREE if no
-// 'requires' clause is found. The template requirement is required to
-// be a constant expression.
-static tree
-cp_parser_requires_clause_opt (cp_parser* parser)
-{
-  cp_rule p = cp_parser_requires_clause;
-  return cp_parser_optional_if_keyword (parser, p, RID_REQUIRES);
-}
-
 /* Support Functions */
 
 /* Looks up NAME in the current scope, as given by PARSER->SCOPE.
Index: system.h
===================================================================
--- system.h	(revision 199581)
+++ system.h	(working copy)
@@ -222,10 +222,6 @@ extern int errno;
 # endif
 #endif
 
-#ifdef __cplusplus
-# include <cstdlib>
-#endif
-
 #ifdef HAVE_STDLIB_H
 # include <stdlib.h>
 #endif
Index: c-family/c-common.h
===================================================================
--- c-family/c-common.h	(revision 199581)
+++ c-family/c-common.h	(working copy)
@@ -368,6 +368,9 @@ struct c_common_resword
 #define D_OBJC		0x080	/* In Objective C and neither C nor C++.  */
 #define D_CXX_OBJC	0x100	/* In Objective C, and C++, but not C.  */
 #define D_CXXWARN	0x200	/* In C warn with -Wcxx-compat.  */
+#define D_CXX_CONCEPTS  0x400   /* In C++, only with concepts. */
+
+#define D_CXX_CONCEPTS_FLAGS D_CXXONLY | D_CXX0X | D_CXX_CONCEPTS
 
 /* The reserved keyword table.  */
 extern const struct c_common_resword c_common_reswords[];
Index: c-family/c.opt
===================================================================
--- c-family/c.opt	(revision 199411)
+++ c-family/c.opt	(working copy)
@@ -21,10 +21,6 @@
 
 ; Please try to keep this file in ASCII collating order.
 
-; Activate C++ concepts support.
-Variable
-bool flag_concepts
-
 Language
 C
 
Index: c-family/c-common.c
===================================================================
--- c-family/c-common.c	(revision 199581)
+++ c-family/c-common.c	(working copy)
@@ -555,11 +555,11 @@ const struct c_common_resword c_common_r
   { "while",		RID_WHILE,	0 },
 
   /* Concepts-related keywords */
-  { "assume",		RID_ASSUME,	D_CXXONLY | D_CXX0X | D_CXXWARN },
-  { "axiom",		RID_AXIOM,	D_CXXONLY | D_CXX0X | D_CXXWARN },
-  { "concept",		RID_CONCEPT,	D_CXXONLY | D_CXX0X | D_CXXWARN },
-  { "forall", 		RID_FORALL,	D_CXXONLY | D_CXX0X | D_CXXWARN },
-  { "requires", 	RID_REQUIRES,	D_CXXONLY | D_CXX0X | D_CXXWARN },
+  { "assume",		RID_ASSUME,	D_CXX_CONCEPTS_FLAGS | D_CXXWARN },
+  { "axiom",		RID_AXIOM,	D_CXX_CONCEPTS_FLAGS | D_CXXWARN },
+  { "concept",		RID_CONCEPT,	D_CXX_CONCEPTS_FLAGS | D_CXXWARN },
+  { "forall", 		RID_FORALL,	D_CXX_CONCEPTS_FLAGS | D_CXXWARN },
+  { "requires", 	RID_REQUIRES,	D_CXX_CONCEPTS_FLAGS | D_CXXWARN },
 
   /* These Objective-C keywords are recognized only immediately after
      an '@'.  */
