Index: pt.c
===================================================================
--- pt.c	(revision 201431)
+++ pt.c	(working copy)
@@ -142,7 +142,7 @@ static int unify (tree, tree, tree, tree
 static void add_pending_template (tree);
 static tree reopen_tinst_level (struct tinst_level *);
 static tree tsubst_initializer_list (tree, tree);
-static tree get_class_bindings (tree, tree, tree, tree);
+static tree get_class_bindings (tree, tree, tree, tree, tree);
 static tree coerce_template_parms (tree, tree, tree, tsubst_flags_t,
 				   bool, bool);
 static tree coerce_innermost_template_parms (tree, tree, tree, tsubst_flags_t,
@@ -804,6 +804,102 @@ check_explicit_instantiation_namespace (
 	       spec, current_namespace, ns);
 }
 
+// Returns the TEMPLATE_DECL that defines the partial template specialization
+// TYPE. If TYPE is not found in the list of partial specializations, then
+// it must be an explicit specialization.
+static tree
+get_specializing_template_decl (tree type)
+{
+  tree tmpl = CLASSTYPE_TI_TEMPLATE (type);
+  tree decl = TYPE_MAIN_DECL (type);
+  tree specs = DECL_TEMPLATE_SPECIALIZATIONS (tmpl);
+  while (specs)
+    {
+      tree spec = TREE_VALUE (specs);
+      if (DECL_TEMPLATE_RESULT (spec) == decl)
+        return spec;
+      specs = TREE_CHAIN (specs);
+    }
+  return NULL_TREE;
+}
+
+// Return the template constraints for the template specialization TYPE.
+static inline tree
+get_specialization_constraints (tree type)
+{
+  // If TYPE is a partial specialization, return the constraints for
+  // that type. If it is an explicit specialization, return null since
+  // non-templates cannot be constrained.
+  if (tree d = get_specializing_template_decl (type))
+    return DECL_CONSTRAINTS (d);
+  else
+    return NULL_TREE;
+}
+
+// Returns the type of a template specialization only if that
+// specializaiton needs to defined. Otherwise (e.g., if the type has
+// already been defined), the function returns NULL_TREE.
+static tree
+maybe_new_partial_specialization (tree type)
+{
+  // An implicit instantiation of an incomplete type implies
+  // the definition of a new class template. 
+  //
+  //    template<typename T>
+  //      struct S;
+  //
+  //    template<typename T>
+  //      struct S<T*>;
+  //
+  // Here, S<T*> is an implicit instantiation of S whose type
+  // is incomplete.
+  if (CLASSTYPE_IMPLICIT_INSTANTIATION (type) && !COMPLETE_TYPE_P (type))
+    return type;
+  
+  // It can also be the case that is a completed specialization.
+  // Continuing the previous example, suppose we also declare:
+  //
+  //    template<typename T>
+  //      requires Integral<T>
+  //        struct S<T*>;
+  //
+  // Here, S<T*> refers to the specialization S<T*> defined 
+  // above. However, we need to differentiate definitions because
+  // we intend to define a new partial specialization. In this case,
+  // we rely on the fact that the constraints are different for
+  // this declaration than that above.
+  //
+  // Note that we also get here for injected class names and
+  // late-parsed template definitions. We must ensure that we
+  // do not create new type declarations for those cases.
+  if (CLASSTYPE_TEMPLATE_SPECIALIZATION (type))
+    {
+      tree constr = get_specialization_constraints (type);
+      if (!equivalent_constraints (current_template_reqs, constr))
+        {
+          tree tmpl = CLASSTYPE_TI_TEMPLATE (type);
+          tree args = CLASSTYPE_TI_ARGS (type);
+
+          // Create a new type node (and corresponding type decl) that 
+          // for the newly declared specialization.
+          tree t = make_class_type (TREE_CODE (type));
+          CLASSTYPE_DECLARED_CLASS (t) = CLASSTYPE_DECLARED_CLASS (type);
+          TYPE_FOR_JAVA (t) = TYPE_FOR_JAVA (type);
+          TYPE_CANONICAL (t) = t;
+          SET_CLASSTYPE_TEMPLATE_SPECIALIZATION (t);
+          SET_TYPE_TEMPLATE_INFO (t, build_template_info (tmpl, args));
+
+          // Build the corresponding type decl.
+          tree d = create_implicit_typedef (DECL_NAME (tmpl), t);
+          DECL_CONTEXT (d) = TYPE_CONTEXT (t);
+          DECL_SOURCE_LOCATION (d) = input_location;
+
+          return t;
+        }
+    }
+  return NULL;
+}
+
 /* The TYPE is being declared.  If it is a template type, that means it
    is a partial specialization.  Do appropriate error-checking.  */
 
@@ -852,17 +948,17 @@ maybe_process_partial_specialization (tr
 
 	 Make sure that `C<int>' and `C<T*>' are implicit instantiations.  */
 
-      if (CLASSTYPE_IMPLICIT_INSTANTIATION (type)
-	  && !COMPLETE_TYPE_P (type))
-	{
-	  check_specialization_namespace (CLASSTYPE_TI_TEMPLATE (type));
-	  SET_CLASSTYPE_TEMPLATE_SPECIALIZATION (type);
-	  DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (type)) = input_location;
+      if (tree t = maybe_new_partial_specialization (type))
+        {
+	  check_specialization_namespace (CLASSTYPE_TI_TEMPLATE (t));
+	  SET_CLASSTYPE_TEMPLATE_SPECIALIZATION (t);
+	  DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (t)) = input_location;
 	  if (processing_template_decl)
 	    {
-	      if (push_template_decl (TYPE_MAIN_DECL (type))
-		  == error_mark_node)
+              tree decl = push_template_decl (TYPE_MAIN_DECL (t));
+	      if (decl == error_mark_node)
 		return error_mark_node;
+              return TREE_TYPE (decl);
 	    }
 	}
       else if (CLASSTYPE_TEMPLATE_INSTANTIATION (type))
@@ -4056,9 +4152,25 @@ process_partial_specialization (tree dec
 
   gcc_assert (current_template_parms);
 
-  // TODO: Implement me!
+  // When defining a constrained partial specialization, DECL's type
+  // will have been assigned to the canonical type of the primary.
+  // That is:
+  //
+  //    template<typename T>
+  //      struct S; // Has canonical type S<T>
+  //
+  //    template<typename T>
+  //      requires C<T>
+  //        struct S<T>; // binds to the primary template.
+  //
+  // However, the the constraints differ, so we should be constructing
+  // a new type. We do this by making the DECL's type its own
+  // canonical type.
+  //
+  // TODO: Do we need to compare the current requirements to make 
+  // sure this isn't a redeclaration?
   if (current_template_reqs)
-    sorry("constrained partial specialization");
+    TYPE_CANONICAL (type) = type;
 
   inner_parms = INNERMOST_TEMPLATE_PARMS (current_template_parms);
   ntparms = TREE_VEC_LENGTH (inner_parms);
@@ -4128,12 +4240,17 @@ process_partial_specialization (tree dec
   /* [temp.class.spec]
 
      The argument list of the specialization shall not be identical to
-     the implicit argument list of the primary template.  */
-  if (comp_template_args
-      (inner_args,
-       INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (TREE_TYPE
-						   (maintmpl)))))
-    error ("partial specialization %qT does not specialize any template arguments", type);
+     the implicit argument list of the primary template.  
+
+     Note that concepts allow partial specializations with the same list of
+     arguments but different constraints. */
+  tree main_type = TREE_TYPE (maintmpl);
+  tree main_args = INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (main_type));
+  tree main_constr = DECL_CONSTRAINTS (maintmpl);
+  if (comp_template_args (inner_args, main_args)
+      && equivalent_constraints (current_template_reqs, main_constr))
+    error ("partial specialization %qT does not specialize any "
+           "template arguments", type);
 
   /* A partial specialization that replaces multiple parameters of the
      primary template with a pack expansion is less specialized for those
@@ -4273,10 +4390,10 @@ process_partial_specialization (tree dec
   /* We should only get here once.  */
   gcc_assert (!COMPLETE_TYPE_P (type));
 
-  // TODO: Implement constrained partial template specialization.
+  // Build the template decl.
   tree tmpl = build_template_decl (decl, 
                                    current_template_parms, 
-                                   NULL_TREE,
+                                   current_template_reqs,
                                    DECL_MEMBER_TEMPLATE_P (maintmpl));
   TREE_TYPE (tmpl) = type;
   DECL_TEMPLATE_RESULT (tmpl) = decl;
@@ -7436,7 +7553,11 @@ lookup_template_class_1 (tree d1, tree a
 	  /* comp_template_args is expensive, check it last.  */
 	  && comp_template_args (TYPE_TI_ARGS (template_type),
 				 arglist))
-	return template_type;
+        {
+          // TODO: We need to match against constrained specializations
+          // by searching for a matching declaration.
+	  return template_type;
+        }
 
       /* If we already have this specialization, return it.  */
       elt.tmpl = gen_tmpl;
@@ -7448,6 +7569,23 @@ lookup_template_class_1 (tree d1, tree a
       if (entry)
 	return entry->spec;
 
+      // If the the template's constraints are not satisfied, then we
+      // cannot form a valid type.
+      //
+      // Note that the check is deferred until after the hash-lookup. 
+      // This prevents redundant checks on specializations.
+      if (!check_template_constraints (gen_tmpl, arglist)) 
+        {
+          // Diaagnose constraints here since they are not diagnosed
+          // anywhere else.
+          if (complain & tf_error)
+            {
+              error ("template argument deduction failure");
+              diagnose_constraints (input_location, gen_tmpl, arglist);
+            }
+          return error_mark_node;
+        }
+
       is_dependent_type = uses_template_parms (arglist);
 
       /* If the deduced arguments are invalid, then the binding
@@ -7503,10 +7641,6 @@ 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.
 
@@ -8736,12 +8870,6 @@ 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 (templ, args))
-        return error_mark_node;
     }
 
   /* If the template we're instantiating is incomplete, then clearly
@@ -18003,26 +18131,28 @@ more_specialized_class (tree main_tmpl, 
   int winner = 0;
   bool any_deductions = false;
 
-  tree tmpl1 = TREE_TYPE (pat1);
-  tree tmpl2 = TREE_TYPE (pat2);
+  tree type1 = TREE_TYPE (pat1);
+  tree type2 = TREE_TYPE (pat2);
+  tree tmpl1 = get_specializing_template_decl (type1);
+  tree tmpl2 = get_specializing_template_decl (type2);
 
   /* Just like what happens for functions, if we are ordering between
      different class template specializations, we may encounter dependent
      types in the arguments, and we need our dependency check functions
      to behave correctly.  */
   ++processing_template_decl;
-  targs = get_class_bindings (main_tmpl, TREE_VALUE (pat1),
-			      CLASSTYPE_TI_ARGS (tmpl1),
-			      CLASSTYPE_TI_ARGS (tmpl2));
+  targs = get_class_bindings (main_tmpl, tmpl1, TREE_VALUE (pat1),
+			      CLASSTYPE_TI_ARGS (type1),
+			      CLASSTYPE_TI_ARGS (type2));
   if (targs)
     {
       --winner;
       any_deductions = true;
     }
 
-  targs = get_class_bindings (main_tmpl, TREE_VALUE (pat2),
-			      CLASSTYPE_TI_ARGS (tmpl2),
-			      CLASSTYPE_TI_ARGS (tmpl1));
+  targs = get_class_bindings (main_tmpl, tmpl2, TREE_VALUE (pat2),
+			      CLASSTYPE_TI_ARGS (type2),
+			      CLASSTYPE_TI_ARGS (type1));
   if (targs)
     {
       ++winner;
@@ -18055,6 +18185,11 @@ more_specialized_class (tree main_tmpl, 
         return -1;
     }
 
+  if (more_constrained (tmpl1, tmpl2))
+    ++winner;
+  if (more_constrained (tmpl2, tmpl1))
+    --winner;
+
   return winner;
 }
 
@@ -18116,7 +18251,8 @@ get_bindings (tree fn, tree decl, tree e
    is bound to `double'.  */
 
 static tree
-get_class_bindings (tree main_tmpl, tree tparms, tree spec_args, tree args)
+get_class_bindings (tree main_tmpl, tree spec_tmpl, tree tparms, 
+                    tree spec_args, tree args)
 {
   int i, ntparms = TREE_VEC_LENGTH (tparms);
   tree deduced_args;
@@ -18174,6 +18310,12 @@ get_class_bindings (tree main_tmpl, tree
   if (!template_template_parm_bindings_ok_p (tparms, deduced_args))
     return NULL_TREE;
 
+  // Having computed and checked the binding, make sure that the
+  // deduced arguments actually satisfy the template constraints.
+  // If not, it is equivalent to have failed to compute the binding.
+  if (!check_template_constraints (spec_tmpl, deduced_args))
+    return NULL_TREE;  
+
   return deduced_args;
 }
 
@@ -18377,7 +18519,7 @@ most_specialized_class (tree type, tree 
 	return error_mark_node;
 
       tree parms = DECL_INNERMOST_TEMPLATE_PARMS (spec_tmpl);
-      spec_args = get_class_bindings (tmpl, parms,
+      spec_args = get_class_bindings (tmpl, spec_tmpl, parms,
 				      partial_spec_args,
 				      args);
       if (spec_args)
Index: constraint.cc
===================================================================
--- constraint.cc	(revision 201434)
+++ constraint.cc	(working copy)
@@ -400,7 +400,7 @@ reduce_template_id (tree t)
   tree c = finish_call_expr (t, &args, true, false, 0);
   error_at (EXPR_LOC_OR_HERE (t), "invalid requirement");
   inform (EXPR_LOC_OR_HERE (t), "did you mean %qE", c);
-  return NULL_TREE;
+  return c;
 }
 
 
@@ -927,6 +927,7 @@ check_requirements (tree reqs, tree args
 bool
 check_constraints (tree cinfo)
 {
+  // No constraints? Satisfied.
   if (!cinfo)
     return true;
   return check_requirements (CI_REQUIREMENTS (cinfo));
@@ -940,6 +941,11 @@ check_constraints (tree cinfo, tree args
   // No constraints? Satisfied.
   if (!cinfo)
     return true;
+
+  // Dependent arguments? Satisfied. They won't reduce to true or false.
+  if (uses_template_parms (args))
+    return true;
+
   return check_requirements (CI_REQUIREMENTS (cinfo), args);
 }
 
@@ -961,7 +967,10 @@ check_template_constraints (tree t, tree
 bool
 equivalent_constraints (tree a, tree b)
 {
-  return subsumes (a, b) && subsumes (b, a);
+  if (a == b)
+    return true;
+  else
+    return subsumes (a, b) && subsumes (b, a);
 }
 
 // Returns true if the template declarations A and B have equivalent
Index: decl2.c
===================================================================
--- decl2.c	(revision 201431)
+++ decl2.c	(working copy)
@@ -655,6 +655,11 @@ check_classfn (tree ctype, tree function
       return error_mark_node;
     }
 
+  // Use the current template requirements as the constraints
+  // for function. Unfortunately, when this is called, FUNCTION
+  // does not have a TEMPLATE_DECL yet.
+  tree constr = current_template_reqs;
+
   /* We must enter the scope here, because conversion operators are
      named by target type, and type equivalence relies on typenames
      resolving within the scope of CTYPE.  */
@@ -707,6 +712,7 @@ check_classfn (tree ctype, tree function
 	      && (!is_template
 		  || comp_template_parms (template_parms,
 					  DECL_TEMPLATE_PARMS (fndecl)))
+              && equivalent_constraints (constr, get_constraints (fndecl))
 	      && (DECL_TEMPLATE_SPECIALIZATION (function)
 		  == DECL_TEMPLATE_SPECIALIZATION (fndecl))
 	      && (!DECL_TEMPLATE_SPECIALIZATION (function)
Index: parser.c
===================================================================
--- parser.c	(revision 201434)
+++ parser.c	(working copy)
@@ -16381,6 +16381,34 @@ cp_parser_init_declarator (cp_parser* pa
   attributes_start_token = cp_lexer_peek_token (parser->lexer);
   attributes = cp_parser_attributes_opt (parser);
 
+  // Save off the current template constraints. These will apply
+  // to the nested scope, not the declarator. Consider, an out-of-class
+  // member definition:
+  //
+  //    template<typename T>
+  //      requires C<T>()
+  //        void S<T>::f() requires D<T>() { ... }
+  //
+  // At the point we parse the 2nd requires clause, the previous the
+  // current constraints will have been used to resolve the enclosing
+  // class S<T>. The D<T>() requirement applies only to the definition
+  // of f and do not include C<T>().
+  tree saved_template_reqs = release (current_template_reqs);
+
+  // Parse an optional requires clause. Currently, requirements can
+  // be written for out-of-class member function definitions.
+  //
+  // TODO: It may be better to always parse and diagnose the error
+  // as a semantic one later on.
+  if (flag_concepts && scope && function_declarator_p (declarator))
+    {
+      if (tree r = cp_parser_requires_clause_opt (parser))
+        current_template_reqs = finish_template_requirements (r);
+    }
+  else
+    current_template_reqs = saved_template_reqs;
+
+
   /* Peek at the next token.  */
   token = cp_lexer_peek_token (parser->lexer);
   /* Check to see if the token indicates the start of a
@@ -16392,8 +16420,8 @@ cp_parser_init_declarator (cp_parser* pa
 	{
 	  /* If a function-definition should not appear here, issue an
 	     error message.  */
-	  cp_parser_error (parser,
-			   "a function-definition is not allowed here");
+	  cp_parser_error (parser, "a function-definition is not allowed here");
+    current_template_reqs = saved_template_reqs;
 	  return error_mark_node;
 	}
       else
@@ -16431,6 +16459,9 @@ cp_parser_init_declarator (cp_parser* pa
 		= func_brace_location;
 	    }
 
+          // Restore the current requirements before returing.
+          current_template_reqs = saved_template_reqs;
+
 	  return decl;
 	}
     }
@@ -20150,6 +20181,9 @@ cp_parser_member_declaration (cp_parser*
 				  initializer, /*init_const_expr_p=*/true,
 				  asm_specification,
 				  attributes);
+
+              // Restore the current template requirments.
+              current_template_reqs = saved_template_reqs;
 	    }
 
 	  /* Reset PREFIX_ATTRIBUTES.  */
@@ -22873,6 +22907,8 @@ cp_parser_template_declaration_after_exp
 
   /* Finish up.  */
   finish_template_decl (parameter_list);
+
+  // Restore the current template requirements.
   current_template_reqs = saved_template_reqs;
 
   /* Check the template arguments for a literal operator template.  */
@@ -23406,12 +23442,12 @@ cp_parser_late_parsing_for_member (cp_pa
       cp_parser_pop_lexer (parser);
     }
 
-  // Restore the template constraints.
-  current_template_reqs = saved_template_reqs;
-
   /* Remove any template parameters from the symbol table.  */
   maybe_end_member_template_processing ();
 
+  // Restore the template requirements.
+  current_template_reqs = saved_template_reqs;
+
   /* Restore the queue.  */
   pop_unparsed_function_queues (parser);
   timevar_pop (TV_PARSE_INMETH);
