diff mbox

[c++-concepts] Bring constraints in line with spec

Message ID 54D1871D.4020502@maniacsvault.net
State New
Headers show

Commit Message

Braden Obrzut Feb. 4, 2015, 2:42 a.m. UTC
This is a large patch mostly written by Andrew to change how constraints 
are stored.  It brings the implementation more in line with the 
specification and simplifies some parts.

I'm not entirely sure about the change to 
cp_parser_template_argument_list.  What happens here is when a template 
template parameter is created with terse notation on a function concept, 
a TEMPLATE_DECL appears instead.  This would manifest itself in 
producing a template that can't be forward declared (or mixed with a 
template that is defined using a trailing requires clause).  When I 
looked, it didn't seem like any earlier point was suitable for 
determining that the TEMPLATE_TEMPLATE_PARM should be unwrapped.

- Braden Obrzut

2015-02-03  Braden Obrzut  <admin@maniacsvault.net>

     * gcc/cp/class.c (build_clone): Clone constraints.
     * gcc/cp/constraint.cc (normalize_atom): Update diagnostic.
     (normalize_constraints): Return error_mark_node if normalization fails.
     (get_constraints): Access constraints through hash map.
     (set_constraints): Set constraints through hash map.
     (remove_constraints): Access constraints through hash map.
     (associate_classtype_constraints): New.
     (init_leading_requirements): Removed.
     (init_trailing_requirements): Removed.
     (update_leadng_requirements): Removed.
     (update_trailing_requirements): Removed.
     (save_leading_constraints): Removed.
     (save_trailing_constraints): Removed.
     (finish_template_constraints): Removed.
     (build_constraints): New. Builds CONSTRAINT_INFO from requirements.
     (finish_concept_introduction): Check generated parameters for errors.
     (tsubst_constraint_info): Update implementation.
     (equivalent_constraints): Check input types.
     (subsumes_constraints): Update implementation.
     (at_least_as_constrained): New. Check if a decl's constraints subsumes
     another.
     (diagnose_constraints): Temporarily simplify diagnostics.
     * gcc/cp/cp-tree.h (tree_constraint_info): Refactor the way constraints
     are stored.
     (CI_TEMPLATE_REQS): Renamed from CI_LEADING_REQS.
     (CI_DECLARATOR_REQS): Renamed from CI_TRAILING_REQS.
     (CI_ASSOCIATED_CONSTRAINTS): New.
     (CI_NORMALIZED_CONSTRAINTS): New.
     (CI_ASSOCIATED_REQS): Removed.
     (saved_scope): Save template requirements.
     (current_template_reqs): Removed.
     (lang_decl_min): Replace requires_clause (trailing requirements) with
     more generic constraint_info.
     * gcc/cp/cxx-pretty-print.c (cxx_pretty_printer::declarator): Print
     requires clause.
     (pp_cxx_function_definition): Moved requires clause printing to above.
     (pp_cxx_init_declarator): Likewise.
     (pp_cxx_template_declaration): Update implementation to get
     requirements from CONSTRAINT_INFO.
     * gcc/cp/decl.c (duplicate_decls): Remove constraints before reclaiming
     memory.
     (is_class_template_or_specialization): New.
     (get_leading_constraints): Removed.
     (adjust_fn_constraints): Removed.
     (grokfndecl): Update implementation to other changes.
     (get_trailing_requires_clause): New.
     (grokdeclarator): Pass trailing requires clause to grokfndecl.
     (xref_tag_1): Check overload constraints.
     * gcc/cp/error.c (dump_template_decl): Print requires clause.
     (dump_function_decl): Update implementation for accessing requirements.
     * gcc/cp/logic.cc (subsumes_constraints_nonnull): Update
     CI_ASSOCIATED_REQS usage.
     * gcc/cp/method.c (implicitly_declare_fn): Copy constraints of
     inherited constructors.
     * gcc/cp/parser.c (cp_parser_lambda_expression): Remove now unneeded
     template requirements saving.
     (cp_parser_type_parameter): Likewise.
     (cp_parser_template_argument_list): Unwrap template_template_parms when
     produced by short hand notation with function concepts.
     (cp_parser_alias_declaration): Attach constraints to aliases.
     (cp_manage_requirements): Removed.
     (cp_parser_trailing_requirements_clause): Renamed from
     cp_parser_trailing_requirements.
     (cp_parser_init_declarator): Removed now unneeded requirements saving.
     (cp_parser_basic_declarator): Separated from cp_parser_declarator.
     (cp_parser_declarator): Parses trailing requires clause if
     cp_parser_basic_declarator succeeds.
     (cp_parser_class_specifier_1): Associate constaints with type.
     (cp_parser_member_declaration): Remove unneeded template requirement
     saving.
     (cp_parser_template_declaration_after_export): Likewise.
     (cp_parser_single_declaration): Associate constraints.
     (cp_parser_late_parsing_for_member): Remove unneeded template
     requirement saving.
     (synthesize_implicit_template_parm): Likewise.
     * gcc/cp/pt.c (maybe_new_partial_specialization): Update
     implementation.
     (process_template_parm): Removed unneeded template requirement saving.
     (build_template_decl): Handle constraints.
     (process_partial_specialization): Update constraint access and check
     that specialization is more specialized.
     (push_template_decl_real): Update constraint access.
     (add_inherited_template_parms): Removed constraint handling.
     (tsubst_pack_conjuction): Update implemenation.
     (tsubst_decl): Changed constraint propagation.
     (more_specialized_fn): Update constraint access.
     (most_specialized_partial_spec): Update constraint access.
     * gcc/cp/ptree.c (cxx_print_xnode): Update constraint access.
     * gcc/cp/semantics.c (finish_call_expr): Remove constraints.
     (finish_template_template_parm): Update constraint access.
     * gcc/testsuite/g++.dg/concepts/alias4.C: Mark xfail.
     * gcc/testsuite/g++.dg/concepts/class.C: Check for escape hatch.
     * gcc/testsuite/g++.dg/concepts/class6.C: Added diagnostic.
     * gcc/testsuite/g++.dg/concepts/inherit-ctor1.C: Improved test case.
     * gcc/testsuite/g++.dg/concepts/inherit-ctor2.C: Updated diagnostic.
     * gcc/testsuite/g++.dg/concepts/inherit-ctor4.C: Updated diagnostic.
     * gcc/testsuite/g++.dg/concepts/intro4.C: Updated diagnostics.
     * gcc/testsuite/g++.dg/concepts/req4.C: Updated diagnostic.
     * gcc/testsuite/g++.dg/concepts/req5.C: Updated diagnostic.
diff mbox

Patch

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 5c5c287..ac2d444 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -4424,6 +4424,14 @@  build_clone (tree fn, tree name)
       TREE_TYPE (clone) = TREE_TYPE (result);
       return clone;
     }
+  else
+    {
+      // Clone constraints
+      if (flag_concepts)
+        if (tree ci = get_constraints (fn))
+          set_constraints (clone, copy_node (ci));
+    }
+
 
   SET_DECL_ASSEMBLER_NAME (clone, NULL_TREE);
   DECL_CLONED_FUNCTION (clone) = fn;
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 6550ec3..a69e717 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -238,7 +238,7 @@  deduce_concept_introduction (tree expr)
       tree var = DECL_TEMPLATE_RESULT (decl);
       tree parms = TREE_VALUE (DECL_TEMPLATE_PARMS (decl));
 
-      parms = coerce_template_parms (parms, args, var);
+      parms = coerce_template_parms (parms, args, var);      
       // Check that we are returned a proper set of arguments.
       if (parms == error_mark_node)
         return NULL_TREE;
@@ -248,7 +248,7 @@  deduce_concept_introduction (tree expr)
     {
       // Resolve the constraint check and return arguments.
       if (tree info = resolve_constraint_check (expr))
-	return TREE_PURPOSE (info);
+        return TREE_PURPOSE (info);
       return NULL_TREE;
     }
   else
@@ -664,7 +664,7 @@  normalize_atom (tree t)
   if (!type_dependent_expression_p (t))
     if (!can_convert (boolean_type_node, TREE_TYPE (t), tf_none))
       {
-        error ("atomic constraint %qE is not convertible to %<bool%>", t);
+        error ("predicate constraint %qE is not convertible to %<bool%>", t);
         return NULL_TREE;
       }
   return t;
@@ -682,6 +682,10 @@  normalize_constraints (tree reqs)
   tree expr = normalize_node (reqs);
   --processing_template_decl;
 
+  // If we couldn't normalize, then these constraints are ill-formed.
+  if (!expr)
+    return error_mark_node;
+
   return expr;
 }
 
@@ -694,13 +698,23 @@  normalize_constraints (tree reqs)
 // The following functions are called by the parser and substitution rules
 // to create and evaluate constraint-related nodes.
 
-// Returns the template constraints of declaration T. Note that
-// T must be non-null.
+// A mapping from declarations to constraint information. Note that 
+// both templates and their underlying declarations are mapped to the 
+// same constraint information.
+static hash_map<tree, tree> decl_constraints;
+
+// Returns the template constraints of declaration T. If T is not
+// constrained, return NULL_TREE. Note that T must be non-null.
 tree
 get_constraints (tree t)
 {
   gcc_assert (DECL_P (t));
-  return LANG_DECL_MIN_CHECK (t)->constraint_info;
+  if (TREE_CODE (t) == TEMPLATE_DECL)
+    t = DECL_TEMPLATE_RESULT (t);
+  if (tree *r = decl_constraints.get (t))
+    return *r;
+  else
+    return NULL_TREE;
 }
 
 // Associate the given constraint information with the declaration. Don't
@@ -708,8 +722,67 @@  get_constraints (tree t)
 void
 set_constraints (tree t, tree ci)
 {
+  gcc_assert (t && DECL_P (t) && TREE_CODE (t) != TEMPLATE_DECL);
+  if (!ci)
+    return;
+
+  gcc_assert (!decl_constraints.get (t));
+  gcc_assert (check_constraint_info (ci));
+  decl_constraints.put (t, ci);
+}
+
+// Remove the associated constraints of the declaration T. 
+//
+// FIXME: What if T is a template? What if it's a non-template? we
+// should remove both associations.
+void
+remove_constraints (tree t)
+{
   gcc_assert (DECL_P (t));
-  LANG_DECL_MIN_CHECK (t)->constraint_info = ci;
+  if (TREE_CODE (t) == TEMPLATE_DECL)
+    t = DECL_TEMPLATE_RESULT (t);
+
+  if (decl_constraints.get (t))
+    decl_constraints.remove (t);
+}
+
+// If the recently parsed TYPE declares or defines a template or template
+// specialization, get its corresponding constraints from the current
+// template parameters and bind them to TYPE's declaration.
+tree
+associate_classtype_constraints (tree type)
+{
+  if (!type || type == error_mark_node || TREE_CODE (type) != RECORD_TYPE)
+    return type;
+
+  // An explicit class template specialization has no template
+  // parameters.
+  if (!current_template_parms)
+    return type;
+
+  if (CLASSTYPE_IS_TEMPLATE (type) || CLASSTYPE_TEMPLATE_SPECIALIZATION (type))
+    {
+      tree decl = TYPE_STUB_DECL (type);
+      tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
+      tree ci = build_constraints (reqs, NULL_TREE);
+
+      // An implicitly instantiated member template declaration already
+      // has associated constraints. If it is defined outside of its
+      // class, then we need match these constraints against those of
+      // original declaration.
+      if (tree orig_ci = get_constraints (decl))
+        {
+          if (!equivalent_constraints (ci, orig_ci))
+            {
+              // FIXME: Improve diagnostics.
+              error ("%qT does not match any declaration", type);
+              return error_mark_node;
+            }
+          return type;
+        }
+      set_constraints (decl, ci);
+    }
+  return type;
 }
 
 // Returns a conjunction of shorthand requirements for the template
@@ -737,110 +810,26 @@  build_constraint_info ()
   return (tree_constraint_info *)make_node (CONSTRAINT_INFO);
 }
 
-// Create a constraint info object, initialized with the given template
-// requirements.
-inline tree
-init_leading_constraints (tree reqs)
-{
-  tree_constraint_info* ci = build_constraint_info ();
-  ci->leading_reqs = reqs;
-  return (tree)ci;
-}
-
-// Initialize a constraint info object, initialized with the given
-// trailing requirements.
-inline tree
-init_trailing_constraints (tree reqs)
-{
-  tree_constraint_info* ci = build_constraint_info ();
-  ci->trailing_reqs = reqs;
-  return (tree)ci;
-}
-
-// Update the template requirements.
-inline tree
-update_leading_constraints (tree ci, tree reqs)
-{
-  tree& current = CI_LEADING_REQS (ci);
-  current = conjoin_constraints (current, reqs);
-  return ci;
-}
-
-// Set the trailing requirements to the given expression. Note that
-// trailing requirements cannot be updated once set: no other requirements
-// can be found after parsing a trailing requires-clause.
-inline tree
-update_trailing_constraints (tree ci, tree reqs)
-{
-  gcc_assert (CI_TRAILING_REQS (ci) == NULL_TREE);
-  CI_TRAILING_REQS (ci) = reqs;
-  return ci;
-}
-
 } // namespace
 
-// Return a constraint-info object containing the current template
-// requirements. If constraints have already been assigned, then these
-// are appended to the current constraints.
+// Build a constraint-info object that contains the associated requirements
+// of a declaration. This also includes the declaration's template
+// requirements TR (if any) and declaration requirements DR (if any).
 //
-// Note that template constraints can be updated by the appearance of
-// constrained type specifiers in a parameter list. These update the
-// template requirements after the template header has been parsed.
-tree
-save_leading_constraints (tree reqs)
-{
-  if (!reqs || reqs == error_mark_node)
-    return NULL_TREE;
-  else if (!current_template_reqs)
-    return init_leading_constraints (reqs);
-  else
-    return update_leading_constraints (current_template_reqs, reqs);
-}
-
-// Return a constraint info object containing saved trailing requirements.
-// If there are already template requirements, these are added to the
-// existing requirements. Otherwise, a new constraint-info object
-// holding only these trailing requirements is returned.
+// If the declaration has neither template nor declaration requirements
+// this returns NULL_TREE, indicating an unconstrained declaration.
 tree
-save_trailing_constraints (tree reqs)
+build_constraints (tree tr, tree dr)
 {
-  if (!reqs || reqs == error_mark_node)
+  if (!tr && !dr)
     return NULL_TREE;
-  else if (!current_template_reqs)
-    return init_trailing_constraints (reqs);
-  else
-    return update_trailing_constraints (current_template_reqs, reqs);
-}
-
-// Finish the template requirements, by computing the associated
-// constraints (the conjunction of leading and trailing requirements),
-// and then decomposing that into sets of atomic propositions.
-tree
-finish_template_constraints (tree ci)
-{
-  if (!ci || ci == error_mark_node)
-    return NULL_TREE;
-
-  // If these constraints have already been analyzed, don't do it
-  // a second time. This happens when grokking a function decl
-  // before creating its corresponding template.
-  if (CI_ASSUMPTIONS (ci))
-    return ci;
-
-  // Build and normalize the associated constraints. If any constraints
-  // are ill-formed, this is a hard error.
-  tree r1 = CI_LEADING_REQS (ci);
-  tree r2 = CI_TRAILING_REQS (ci);
-  tree reqs = normalize_constraints (conjoin_constraints (r1, r2));
-  CI_ASSOCIATED_REQS (ci) = reqs;
-
-  // If normalization succeeds, decompose those expressions into sets
-  // of atomic constraints. Otherwise, mark this as an error.
-  if (reqs)
-    CI_ASSUMPTIONS (ci) = decompose_assumptions (reqs);
-  else
-    CI_ASSUMPTIONS (ci) = error_mark_node;
-  return ci;
+  tree_constraint_info* ci = build_constraint_info ();
+  ci->template_reqs = tr;
+  ci->declarator_reqs = dr;
+  ci->associated_constr = conjoin_constraints (tr, dr);
+  ci->normalized_constr = normalize_constraints (ci->associated_constr);
+  ci->assumptions = decompose_assumptions (ci->normalized_constr);
+  return (tree)ci;
 }
 
 // Returns true iff cinfo contains a valid constraint expression.
@@ -1223,7 +1212,7 @@  finish_shorthand_constraint (tree decl, tree constr)
     }
 
   return check;
- }
+}
 
 // Returns and chains a new parameter for PARAMETER_LIST which will conform
 // to the prototype given by SRC_PARM.  The new parameter will have its
@@ -1320,6 +1309,12 @@  finish_concept_introduction (tree tmpl_decl, tree intro_list)
     parm_list = process_introduction_parm (parm_list, TREE_VEC_ELT (parms, n));
 
   parm_list = end_template_parm_list (parm_list);
+  for (int i = 0; i < TREE_VEC_LENGTH (parm_list); ++i)
+    if (TREE_VALUE (TREE_VEC_ELT (parm_list, i)) == error_mark_node)
+      {
+        end_template_decl ();
+        return error_mark_node;
+      }
 
   // Build a concept check for our constraint.
   tree check_args = make_tree_vec (TREE_VEC_LENGTH (parms));
@@ -1331,6 +1326,7 @@  finish_concept_introduction (tree tmpl_decl, tree intro_list)
       tree parm = TREE_VEC_ELT (parm_list, n);
       TREE_VEC_ELT (check_args, n) = template_parm_to_arg (parm);
     }
+
   // If the template expects more parameters we should be able to use the
   // defaults from our deduced form.
   for (; n < TREE_VEC_LENGTH (parms); ++n)
@@ -1338,8 +1334,7 @@  finish_concept_introduction (tree tmpl_decl, tree intro_list)
 
   // Associate the constraint.
   tree reqs = build_concept_check (tmpl_decl, NULL_TREE, check_args);
-  current_template_reqs = save_leading_constraints (reqs);
-  TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = current_template_reqs;
+  TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = reqs;
 
   return parm_list;
 }
@@ -1525,32 +1520,20 @@  tsubst_constraint_expr (tree reqs, tree args, bool do_not_fold)
 tree
 tsubst_constraint_info (tree ci, tree args)
 {
-  if (!ci || ci == error_mark_node)
+  if (!ci || ci == error_mark_node || !check_constraint_info (ci))
     return NULL_TREE;
 
-  // Substitute into the various constraint fields.
-  tree_constraint_info* result = build_constraint_info ();
-  if (tree r = CI_LEADING_REQS (ci))
-    result->leading_reqs = tsubst_constraint_expr (r, args, true);
-  if (tree r = CI_TRAILING_REQS (ci))
-    result->trailing_reqs = tsubst_constraint_expr (r, args, true);
-  if (tree r = CI_ASSOCIATED_REQS (ci))
-      result->associated_reqs = tsubst_constraint_expr (r, args, true);
-
-  // Re-normalize the constraints to ensure that we haven't picked
-  // any fatal errors when substituting.
-  if (!normalize_constraints (result->associated_reqs))
-    {
-      result->associated_reqs = error_mark_node;
-      result->assumptions = error_mark_node;
-    }
-  else
-    {
-      // Analyze the resulting constraints.
-      result->assumptions = decompose_assumptions (result->associated_reqs);
-    }
+  tree tr = NULL_TREE;
+  if (tree r = CI_TEMPLATE_REQS (ci))
+    tr = tsubst_constraint_expr (r, args, true);
+
+  tree dr = NULL_TREE;
+  if (tree r = CI_DECLARATOR_REQS (ci))
+    dr = tsubst_constraint_expr (r, args, true);
 
-  return (tree)result;
+  // TODO: This is re-normalizing and re-decomposing. We probably
+  // don't need to do this.
+  return build_constraints (tr, dr);
 }
 
 // -------------------------------------------------------------------------- //
@@ -1601,7 +1584,7 @@  check_constraints (tree cinfo)
   // all remaining expressions that are not constant expressions
   // (e.g., template-id expressions).
   else
-    return check_satisfied (CI_ASSOCIATED_REQS (cinfo), NULL_TREE);
+    return check_satisfied (CI_NORMALIZED_CONSTRAINTS (cinfo), NULL_TREE);
 }
 
 // Check the constraints in CINFO against the given ARGS, returning
@@ -1616,7 +1599,7 @@  check_constraints (tree cinfo, tree args)
   else if (!valid_requirements_p (cinfo))
     return false;
   else {
-    return check_satisfied (CI_ASSOCIATED_REQS (cinfo), args);
+    return check_satisfied (CI_NORMALIZED_CONSTRAINTS (cinfo), args);
   }
 }
 
@@ -1638,6 +1621,8 @@  check_template_constraints (tree t, tree args)
 bool
 equivalent_constraints (tree a, tree b)
 {
+  gcc_assert (!a || TREE_CODE (a) == CONSTRAINT_INFO);
+  gcc_assert (!b || TREE_CODE (b) == CONSTRAINT_INFO);
   return cp_tree_equal (a, b);
 }
 
@@ -1645,38 +1630,51 @@  equivalent_constraints (tree a, tree b)
 // 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)
+equivalently_constrained (tree d1, tree d2)
 {
-  gcc_assert (TREE_CODE (a) == TREE_CODE (b));
-  return equivalent_constraints (get_constraints (a), get_constraints (b));
+  gcc_assert (TREE_CODE (d1) == TREE_CODE (d2));
+  return equivalent_constraints (get_constraints (d1), get_constraints (d2));
 }
 
-// Returns true when the template declaration A's constraints subsume
-// those of the template declaration B.
+// Returns true when the the constraints in A subsume those in B.
 bool
 subsumes_constraints (tree a, tree b)
 {
-  gcc_assert (TREE_CODE (a) == TREE_CODE (b));
-  return subsumes (get_constraints (a), get_constraints (b));
+  gcc_assert (!a || TREE_CODE (a) == CONSTRAINT_INFO);
+  gcc_assert (!b || TREE_CODE (b) == CONSTRAINT_INFO);
+  return subsumes (a, b);
 }
 
-// Determines which of the templates, A or B, is more constrained.
-// That is, which template's constraints subsume but are not subsumed
+// Determines which of the declarations, A or B, is more constrained.
+// That is, which declaration's constraints subsume but are not subsumed
 // by the other's?
 //
 // Returns 1 if A is more constrained than B, -1 if B is more constrained
 // than A, and 0 otherwise.
 int
-more_constrained (tree a, tree b)
+more_constrained (tree d1, tree d2)
 {
+  tree c1 = get_constraints (d1);
+  tree c2 = get_constraints (d2);
   int winner = 0;
-  if (subsumes_constraints (a, b))
+  if (subsumes_constraints (c1, c2))
     ++winner;
-  if (subsumes_constraints (b, a))
+  if (subsumes_constraints (c2, c1))
     --winner;
   return winner;
 }
 
+// Returns true if d1 is at least as constrained as d2. That is, the
+// associated constraints of d1 subsume those of d2, or both declarations
+// are unconstrained.
+bool
+at_least_as_constrained (tree d1, tree d2)
+{
+  tree c1 = get_constraints (d1);
+  tree c2 = get_constraints (d2);
+  return subsumes_constraints (c1, c2);
+}
+
 
 // -------------------------------------------------------------------------- //
 // Constraint Diagnostics
@@ -2018,22 +2016,27 @@  diagnose_constraints (location_t loc, tree decl, tree args)
       return;
     }
 
+  // FIXME: Re-think how we recurse through the expression to emit
+  // diagnostics.
+
   // If this is a specialization of a template, we want to diagnose
   // the dependent constraints. Also update the template arguments.
-  if (DECL_USE_TEMPLATE (decl))
-    {
-      args = DECL_TI_ARGS (decl);
-      decl = DECL_TI_TEMPLATE (decl);
-    }
+  // if (DECL_USE_TEMPLATE (decl))
+  //   {
+  //     args = DECL_TI_ARGS (decl);
+  //     decl = DECL_TI_TEMPLATE (decl);
+  //   }
 
-  // Otherwise, diagnose the actual failed constraints.
-  if (TREE_CODE (decl) == TEMPLATE_DECL)
-    inform (loc, "  constraints not satisfied %S", make_subst (decl, args));
-  else
-    inform (loc, "  constraints not satisfied");
+  // // Otherwise, diagnose the actual failed constraints.
+  // if (TREE_CODE (decl) == TEMPLATE_DECL)
+  //   inform (loc, "  constraints not satisfied %S", make_subst (decl, args));
+  // else
+  //   inform (loc, "  constraints not satisfied");
+
+  inform (loc, "  constraints not satisfied");
 
   // Diagnose the constraints by recursively decomposing and
   // evaluating the template requirements.
-  tree reqs = CI_ASSOCIATED_REQS (get_constraints (decl));
+  tree reqs = CI_ASSOCIATED_CONSTRAINTS (get_constraints (decl));
   diagnose_requirements (loc, reqs, args);
 }
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index e99368f..a091be6 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -825,26 +825,23 @@  struct GTY(()) tree_template_info {
 // Constraint information for a C++ declaration. Constraint information is
 // comprised of:
 //
-// - leading requirements (possibly null), which are introduced by the
-//   template header and constrained-type-specifiers in a parameter
-//   declaration clause
-// - trailing requirements (possibly null), which are introduced by the
-//   a requires-clause following a declarator in a function declaration,
-//   member declaration, or function definition.
-// - associated requirements (should never be null), which is the conjunction
-//   of leading and trailing requirements (in that order), and
-// - assumptions which is the result of analyzed and decomposed template
-//   requirements.
+// - a constraint expression introduced by the template header
+// - a constraint expression introduced by a function declarator
+// - the associated constraints, which are the conjunction of those,
+//   and used for declaration matching
+// - the cached normalized associated constraints which are used
+//   to support satisfaction and subsumption.
+// - assumptions which is the result of decomposing the normalized
+//   constraints.
 //
-// The leading and trailing requirements are kept to support pretty printing
-// constrained declarations. The associated requirements are used for
-// declaration matching, and the assumptions are computed to support
-// partial ordering of constraints.
+// The template and declarator requirements are kept to support pretty 
+// printing constrained declarations.
 struct GTY(()) tree_constraint_info {
   struct tree_base base;
-  tree leading_reqs;
-  tree trailing_reqs;
-  tree associated_reqs;
+  tree template_reqs;
+  tree declarator_reqs;
+  tree associated_constr;
+  tree normalized_constr;
   tree assumptions;
 };
 
@@ -861,21 +858,23 @@  check_constraint_info (tree t)
 // null if no constraints were introduced in the template parameter list,
 // a requirements clause after the template parameter list, or constraints
 // through a constrained-type-specifier.
-#define CI_LEADING_REQS(NODE) \
-  check_constraint_info (check_nonnull(NODE))->leading_reqs
+#define CI_TEMPLATE_REQS(NODE) \
+  check_constraint_info (check_nonnull(NODE))->template_reqs
 
 // Access the expression describing the trailing constraints. This is non-null
 // for any implicit instantiation of a constrained declaration. For a
 // templated declaration it is non-null only when a trailing requires-clause
 // was specified.
-#define CI_TRAILING_REQS(NODE) \
-  check_constraint_info (check_nonnull(NODE))->trailing_reqs
+#define CI_DECLARATOR_REQS(NODE) \
+  check_constraint_info (check_nonnull(NODE))->declarator_reqs
+
+// The computed associated constraint expression for a declaration.
+#define CI_ASSOCIATED_CONSTRAINTS(NODE) \
+  check_constraint_info (check_nonnull(NODE))->associated_constr
 
-// Access the expression describing the associated constraints of a
-// declaration. This is the conjunction of leading and trailing
-// requirements.
-#define CI_ASSOCIATED_REQS(NODE) \
-  check_constraint_info (check_nonnull(NODE))->associated_reqs
+// The normalized associated constraints.
+#define CI_NORMALIZED_CONSTRAINTS(NODE) \
+  check_constraint_info (check_nonnull(NODE))->normalized_constr
 
 // Get the set of assumptions associated with the constraint info node.
 #define CI_ASSUMPTIONS(NODE) \
@@ -1141,7 +1140,6 @@  struct GTY(()) saved_scope {
   vec<tree, va_gc> *lang_base;
   tree lang_name;
   tree template_parms;
-  tree template_reqs;
   cp_binding_level *x_previous_class_level;
   tree x_saved_tree;
 
@@ -1208,11 +1206,6 @@  struct GTY(()) saved_scope {
 
 #define current_template_parms scope_chain->template_parms
 
-// When parsing a template declaration this node represents the
-// active template requirements. This includes the lists of
-// actual assumptions in the current scope.
-#define current_template_reqs scope_chain->template_reqs
-
 #define processing_template_decl scope_chain->x_processing_template_decl
 #define processing_specialization scope_chain->x_processing_specialization
 #define processing_explicit_instantiation scope_chain->x_processing_explicit_instantiation
@@ -2104,10 +2097,6 @@  struct GTY(()) lang_decl_min {
      DECL_TEMPLATE_INFO.  */
   tree template_info;
 
-  // The constraint info maintains information about constraints
-  // associated with the declaration.
-  tree constraint_info;
-
   union lang_decl_u2 {
     /* In a FUNCTION_DECL for which DECL_THUNK_P holds, this is
        THUNK_VIRTUAL_OFFSET.
@@ -5152,6 +5141,8 @@  struct cp_declarator {
       tree exception_specification;
       /* The late-specified return type, if any.  */
       tree late_return_type;
+      /* The trailing requires-clause, if any. */
+      tree requires_clause;
     } function;
     /* For arrays.  */
     struct {
@@ -6473,6 +6464,9 @@  extern tree conjoin_constraints                 (tree, tree);
 extern tree conjoin_constraints                 (tree);
 extern tree get_constraints                     (tree);
 extern void set_constraints                     (tree, tree);
+extern void remove_constraints                  (tree);
+extern tree associate_classtype_constraints     (tree);
+extern tree build_constraints                   (tree, tree);
 extern tree get_shorthand_constraints           (tree);
 
 extern tree build_concept_check                 (tree, tree, tree = NULL_TREE);
diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c
index 8ba9683..4000eab 100644
--- a/gcc/cp/cxx-pretty-print.c
+++ b/gcc/cp/cxx-pretty-print.c
@@ -24,6 +24,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "tm.h"
 #include "intl.h"
 #include "cp-tree.h"
+#include "print-tree.h"
 #include "cxx-pretty-print.h"
 #include "tree-pretty-print.h"
 
@@ -1615,12 +1616,28 @@  cxx_pretty_printer::direct_declarator (tree t)
 
 /* declarator:
    direct-declarator
-   ptr-operator declarator  */
+   ptr-operator declarator  
+
+   Concepts:
+
+   declarator:
+     basic-declarator requires-clause(opt)
+
+   basic-declarator:
+     direct-declarator
+     ptr-operator declarator
+   */
 
 void
 cxx_pretty_printer::declarator (tree t)
 {
   direct_declarator (t);
+
+  // Print a requires clause.
+  if (flag_concepts)
+    if (tree ci = get_constraints (t))
+      if (tree reqs = CI_DECLARATOR_REQS (ci))
+        pp_cxx_requires_clause (this, reqs);
 }
 
 /* ctor-initializer:
@@ -1671,12 +1688,6 @@  pp_cxx_function_definition (cxx_pretty_printer *pp, tree t)
   tree saved_scope = pp->enclosing_scope;
   pp->declaration_specifiers (t);
   pp->declarator (t);
-
-  // Print a requires clause.
-  if (flag_concepts)
-    if (tree ci = get_constraints (t))
-      pp_cxx_requires_clause (pp, CI_TRAILING_REQS (ci));
-
   pp_needs_newline (pp) = true;
   pp->enclosing_scope = DECL_CONTEXT (t);
   if (DECL_SAVED_TREE (t))
@@ -2128,12 +2139,6 @@  pp_cxx_init_declarator (cxx_pretty_printer *pp, tree t)
 {
   pp->declarator (t);
 
-  // If there's a trailing requires clause, print it here.
-  if (flag_concepts) {
-    if (tree ci = get_constraints (t))
-      pp_cxx_requires_clause (pp, CI_TRAILING_REQS (ci));
-  }
-
   /* We don't want to output function definitions here.  There are handled
      elsewhere (and the syntactic form is bogus anyway).  */
   if (TREE_CODE (t) != FUNCTION_DECL && DECL_INITIAL (t))
@@ -2278,10 +2283,11 @@  pp_cxx_template_declaration (cxx_pretty_printer *pp, tree t)
 
   if (flag_concepts)
     if (tree ci = get_constraints (t))
-       {
-          pp_cxx_requires_clause (pp, CI_LEADING_REQS (ci));
-          pp_newline_and_indent (pp, 6);
-       }
+      if (tree reqs = CI_TEMPLATE_REQS (ci))
+         {
+            pp_cxx_requires_clause (pp, reqs);
+            pp_newline_and_indent (pp, 6);
+         }
 
   if (TREE_CODE (t) == FUNCTION_DECL && DECL_SAVED_TREE (t))
     pp_cxx_function_definition (pp, t);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 757a451..4686ab4 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -31,6 +31,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tm.h"
 #include "tree.h"
+#include "print-tree.h"
 #include "tree-hasher.h"
 #include "stringpool.h"
 #include "stor-layout.h"
@@ -2603,6 +2604,10 @@  duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
 	snode->remove ();
     }
 
+  // Remove the associated constraints for newdecl, if any, before
+  // explicitly reclaiming memory.
+  remove_constraints (newdecl);
+
   ggc_free (newdecl);
 
   return olddecl;
@@ -4522,6 +4527,17 @@  check_tag_decl (cp_decl_specifier_seq *declspecs,
   return declared_type;
 }
 
+// True if the type T is a class template or a class template 
+// specialization (either explicit or partial).
+static inline bool
+is_class_template_or_specialization (tree t)
+{
+  if (CLASS_TYPE_P (t) 
+      && (CLASSTYPE_IS_TEMPLATE (t) || CLASSTYPE_TEMPLATE_SPECIALIZATION (t)))
+    return true;
+  return false;
+}
+
 /* Called when a declaration is seen that contains no names to declare.
    If its type is a reference to a structure, union or enum inherited
    from a containing scope, shadow that tag name for the current scope
@@ -7600,88 +7616,6 @@  declare_simd_adjust_this (tree *tp, int *walk_subtrees, void *data)
   return NULL_TREE;
 }
 
-// Returns the leading template requirements if they exist.
-static inline tree
-get_leading_constraints ()
-{
-  return current_template_reqs ?
-    CI_LEADING_REQS (current_template_reqs) : NULL_TREE;
-}
-
-// When defining an out-of-class template, we want to adjust the
-// current template requirements by adding any template requirements
-// declared by the innermost template parameter list. For example:
-//
-//    template<typename T>
-//    struct S { template<C U> void f(); };
-//
-//    template<typename T>
-//    template<C U>
-//    void S<T>::f() { }  // #2
-//
-// When grokking #2, the constraints introduced by C are not
-// in the current_template_reqs; they are attached to the innermost
-// parameter list. The adjustment makes them part of the current
-// template requirements.
-static void
-adjust_fn_constraints (tree ctype)
-{
-  // When grokking a member function template, we are processing
-  // template decl at a depth greater than that of the member's
-  // enclosing class. That is, this case corresponds to the
-  // following declarations:
-  //
-  //    template<C T>
-  //    struct S {
-  //      template<D U> void f(U);
-  //    };
-  //
-  //    template<C T> template <D U> void S<T>::f(U) { }
-  //
-  // In both decls, the constraint D<U> is not the current leading
-  // constraint. Make it so.
-  //
-  // Note that for normal member functions, there are no leading
-  // requirements we need to gather.
-  if (ctype && processing_template_decl > template_class_depth (ctype))
-    {
-      if (tree ci = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms))
-        {
-          // TODO: When do I ever have leading requirements for a
-          // member function template?
-          tree reqs = CI_LEADING_REQS (ci);
-          if (reqs && !get_leading_constraints ())
-            current_template_reqs = save_leading_constraints (reqs);
-        }
-    }
-
-  // Otherwise, this is just a regular function template. Like so:
-  //
-  //    template<C T> void f();
-  //
-  // Note that the constraint C<T> is not the current leading requirement
-  // at this point; it was stashed before the declarator was parsed.
-  // Make it the leading constraint.
-  else if (!ctype && current_template_parms)
-  {
-    if (tree ci = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms))
-      {
-        tree r1 = CI_LEADING_REQS (ci);
-        if (current_template_reqs)
-          {
-            // TODO: As with above, when do I ever have leading
-            // requirements that aren't part of the template
-            // constraint.
-            tree r2 = CI_LEADING_REQS (current_template_reqs);
-            CI_LEADING_REQS (current_template_reqs) =
-                conjoin_constraints (r1, r2);
-          }
-        else
-          current_template_reqs = save_leading_constraints (r1);
-      }
-  }
-}
-
 /* CTYPE is class type, or null if non-class.
    TYPE is type this FUNCTION_DECL should have, either FUNCTION_TYPE
    or METHOD_TYPE.
@@ -7706,6 +7640,7 @@  grokfndecl (tree ctype,
 	    tree declarator,
 	    tree parms,
 	    tree orig_declarator,
+	    tree decl_reqs,
 	    int virtualp,
 	    enum overload_flags flags,
 	    cp_cv_quals quals,
@@ -7743,24 +7678,14 @@  grokfndecl (tree ctype,
 
   decl = build_lang_decl (FUNCTION_DECL, declarator, type);
 
-  // Possibly adjust the template requirements for out-of-class
-  // function definitions. This guarantees that current_template_reqs
-  // will be fully completed before calling finish_template_constraints.
+  // Set the constraints on the declaration.
   if (flag_concepts)
-    adjust_fn_constraints (ctype);
-
-  // Check and normalize the template requirements for the declared
-  // function. Note that these constraints are multiply associated
-  // with both the template-decl and the function-decl.
-  if (current_template_reqs)
     {
-      current_template_reqs
-        = finish_template_constraints (current_template_reqs);
-      set_constraints (decl, current_template_reqs);
-
-      // TODO: Disallow these until we resolve the linking issue.
-      if (current_template_reqs && !current_template_parms)
-        sorry("constrained regular function");
+      tree temp_reqs = NULL_TREE;
+      if (processing_template_decl > template_class_depth (ctype))
+        temp_reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
+      tree ci = build_constraints (temp_reqs, decl_reqs);
+      set_constraints (decl, ci);
     }
 
   /* If we have an explicit location, use it, otherwise use whatever
@@ -7830,12 +7755,16 @@  grokfndecl (tree ctype,
           // specializations. They cannot be instantiated since they
           // must match a fully instantiated function, and non-dependent
           // functions cannot be constrained.
-          if (current_template_reqs)
-            {
-              error ("constraints are not allowed in declaration "
-                     "of friend template specialization %qD", decl);
-              return NULL_TREE;
-            }
+          //
+          // FIXME [concepts] This is no longer correct. We do disallow
+          // constraints on friend function template specializations.
+          //             
+          // if (current_template_reqs)
+          //   {
+          //     error ("constraints are not allowed in declaration "
+          //            "of friend template specialization %qD", decl);
+          //     return NULL_TREE;
+          //   }
 
 	  /* A friend declaration of the form friend void f<>().  Record
 	     the information in the TEMPLATE_ID_EXPR.  */
@@ -9002,6 +8931,18 @@  check_var_type (tree identifier, tree type)
   return type;
 }
 
+// Return a trailing requires clause for a function declarator, or
+// NULL_TREE if there is no trailing requires clause or the declarator
+// is some other kind.
+static inline tree
+get_trailing_requires_clause (const cp_declarator *declarator)
+{
+  if (declarator && declarator->kind == cdk_function)
+    return declarator->u.function.requires_clause;
+  else
+    return NULL_TREE;
+}
+
 /* Given declspecs and a declarator (abstract or otherwise), determine
    the name and type of the object declared and construct a DECL node
    for it.
@@ -9132,6 +9073,9 @@  grokdeclarator (const cp_declarator *declarator,
   explicit_intN = declspecs->explicit_intN_p;
   thread_p = decl_spec_seq_has_spec_p (declspecs, ds_thread);
 
+  // Get a requires-clause attached to the declarator.
+  tree reqs = get_trailing_requires_clause (declarator);
+
   // Was concept_p specified? Note that ds_concept
   // implies ds_constexpr!
   bool concept_p = decl_spec_seq_has_spec_p (declspecs, ds_concept);
@@ -10960,6 +10904,7 @@  grokdeclarator (const cp_declarator *declarator,
 			       ? unqualified_id : dname,
 			       parms,
 			       unqualified_id,
+			       reqs,
 			       virtualp, flags, memfn_quals, rqual, raises,
 			       friendp ? -1 : 0, friendp, publicp,
                                inlinep | (2 * constexpr_p) | (4 * concept_p),
@@ -11188,7 +11133,7 @@  grokdeclarator (const cp_declarator *declarator,
 	  TYPE_HAS_LATE_RETURN_TYPE (type) = 1;
 
 	decl = grokfndecl (ctype, type, original_name, parms, unqualified_id,
-			   virtualp, flags, memfn_quals, rqual, raises,
+                           reqs, virtualp, flags, memfn_quals, rqual, raises,
 			   1, friendp,
 			   publicp,
                            inlinep | (2 * constexpr_p) | (4 * concept_p),
@@ -12578,13 +12523,11 @@  xref_tag_1 (enum tag_types tag_code, tree name,
     {
       if (template_header_p && MAYBE_CLASS_TYPE_P (t))
         {
-	  // It's safe to finish the current template requirements here
-	  // since a class doesn't have trailing requirements.
-	  if (current_template_reqs)
-	    current_template_reqs =
-		finish_template_constraints (current_template_reqs);
-	  if (!redeclare_class_template (t, current_template_parms,
-					 current_template_reqs))
+          // Check that we aren't trying to overload a class with
+          // different constraints.
+          tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
+          tree constr = build_constraints (reqs, NULL_TREE);
+	  if (!redeclare_class_template (t, current_template_parms, constr))
 	    return error_mark_node;
         }
       else if (!processing_template_decl
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index e4eefc1..3779f14 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -1320,9 +1320,6 @@  dump_template_decl (cxx_pretty_printer *pp, tree t, int flags)
 	    }
 	  pp_cxx_end_template_argument_list (pp);
 
-	  if (flag_concepts)
-	    if (tree ci = get_constraints (t))
-	      pp_cxx_requires_clause (pp, CI_LEADING_REQS (ci));
 
 	  pp_cxx_whitespace (pp);
 	}
@@ -1339,6 +1336,15 @@  dump_template_decl (cxx_pretty_printer *pp, tree t, int flags)
 	}
     }
 
+  if (flag_concepts)
+    if (tree ci = get_constraints (t))
+      if (check_constraint_info (ci))
+        if (tree reqs = CI_TEMPLATE_REQS (ci))
+	  {
+	    pp_cxx_requires_clause (pp, reqs);
+	    pp_cxx_whitespace (pp);
+	  }
+
   if (DECL_CLASS_TEMPLATE_P (t))
     dump_type (pp, TREE_TYPE (t),
 	       ((flags & ~TFF_CLASS_KEY_OR_ENUM) | TFF_TEMPLATE_NAME
@@ -1572,7 +1578,8 @@  dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
 
       if (flag_concepts)
         if (tree ci = get_constraints (t))
-          pp_cxx_requires_clause (pp, CI_TRAILING_REQS (ci));
+          if (tree reqs = CI_DECLARATOR_REQS (ci))
+            pp_cxx_requires_clause (pp, reqs);
 
       dump_substitution (pp, t, template_parms, template_args, flags);
     }
diff --git a/gcc/cp/logic.cc b/gcc/cp/logic.cc
index d8fb818..389df02 100644
--- a/gcc/cp/logic.cc
+++ b/gcc/cp/logic.cc
@@ -503,7 +503,7 @@  subsumes_constraints_nonnull (tree left, tree right)
   // Check that the required expression in RIGHT is subsumed by each
   // subgoal in the assumptions of LEFT.
   tree as = CI_ASSUMPTIONS (left);
-  tree c = CI_ASSOCIATED_REQS (right);
+  tree c = CI_NORMALIZED_CONSTRAINTS (right);
   for (int i = 0; i < TREE_VEC_LENGTH (as); ++i)
     if (!subsumes_prop (TREE_VEC_ELT (as, i), c))
       return false;
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 10751ed..a786d60 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -1939,6 +1939,15 @@  implicitly_declare_fn (special_function_kind kind, tree type,
   rest_of_decl_compilation (fn, toplevel_bindings_p (), at_eof);
   gcc_assert (!TREE_USED (fn));
 
+  // If the inherited constructor was constrained, copy the
+  // constraints. 
+  if (flag_concepts && inherited_ctor)
+  {
+    tree orig_ci = get_constraints (inherited_ctor);
+    tree new_ci = copy_node (orig_ci);
+    set_constraints (fn, new_ci);
+  }
+
   /* Restore PROCESSING_TEMPLATE_DECL.  */
   processing_template_decl = saved_processing_template_decl;
 
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 2a1a5e8..2752436 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -9077,9 +9077,6 @@  cp_parser_lambda_expression (cp_parser* parser)
     parser->implicit_template_scope = 0;
     parser->auto_is_implicit_function_template_parm_p = false;
 
-    // Reset the current requirements also.
-    tree saved_template_reqs = release (current_template_reqs);
-
     /* By virtue of defining a local class, a lambda expression has access to
        the private variables of enclosing classes.  */
 
@@ -9117,9 +9114,6 @@  cp_parser_lambda_expression (cp_parser* parser)
     parser->implicit_template_scope = implicit_template_scope;
     parser->auto_is_implicit_function_template_parm_p
 	= auto_is_implicit_function_template_parm_p;
-
-    // Restore requirements.
-    current_template_reqs = saved_template_reqs;
   }
 
   pop_deferring_access_checks ();
@@ -13443,7 +13437,7 @@  cp_parser_check_constrained_type_parm (cp_parser *parser,
   return true;
 }
 
-// Finish parsing/processing a template type parameter and chekcing
+// Finish parsing/processing a template type parameter and checking
 // various restrictions.
 static inline tree
 cp_parser_constrained_type_template_parm (cp_parser *parser,
@@ -13476,6 +13470,7 @@  cp_parser_constrained_template_template_parm (cp_parser *parser,
 
   tree parm = finish_template_template_parm (class_type_node, id);
   current_template_parms = saved_parms;
+
   return parm;
 }
 
@@ -13905,10 +13900,6 @@  cp_parser_type_parameter (cp_parser* parser, bool *is_parameter_pack)
 	tree identifier;
 	tree default_argument;
 
-        // Save the current requirements before parsing the
-        // template parameter list.
-        tree saved_template_reqs = release (current_template_reqs);
-
 	/* Look for the `<'.  */
 	cp_parser_require (parser, CPP_LESS, RT_LESS);
 	/* Parse the template-parameter-list.  */
@@ -13922,11 +13913,7 @@  cp_parser_type_parameter (cp_parser* parser, bool *is_parameter_pack)
             tree reqs = get_shorthand_constraints (current_template_parms);
             if (tree r = cp_parser_requires_clause_opt (parser))
               reqs = conjoin_constraints (reqs, r);
-            current_template_reqs = save_leading_constraints (reqs);
-
-            // Attach the constraints to the parameter list.
-            TEMPLATE_PARMS_CONSTRAINTS (current_template_parms)
-              = current_template_reqs;
+            TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = reqs;
           }
 
 	/* Look for the `class' or 'typename' keywords.  */
@@ -13961,9 +13948,6 @@  cp_parser_type_parameter (cp_parser* parser, bool *is_parameter_pack)
 	parameter = finish_template_template_parm (class_type_node,
 						   identifier);
 
-        // Restore the saved constraints.
-        current_template_reqs = saved_template_reqs;
-
 	/* If the next token is an `=', then there is a
 	   default-argument.  */
 	if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
@@ -14222,6 +14206,7 @@  cp_parser_template_id (cp_parser *parser,
     }
 
   pop_to_parent_deferring_access_checks ();
+
   return template_id;
 }
 
@@ -14479,6 +14464,11 @@  cp_parser_template_argument_list (cp_parser* parser)
           argument = make_pack_expansion (argument);
         }
 
+      // If we end up with a template decl argument, check if this is actually
+      // a template template parameter and drop the outer wrapping.
+      if (DECL_TEMPLATE_TEMPLATE_PARM_P (argument))
+	argument = TREE_TYPE (argument);
+
       if (n_args == alloced)
 	{
 	  alloced *= 2;
@@ -17057,6 +17047,14 @@  cp_parser_alias_declaration (cp_parser* parser)
   if (decl == error_mark_node)
     return decl;
 
+  // Attach constraints to the alias declaration.
+  if (flag_concepts)
+    {
+      tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
+      tree constr = build_constraints (reqs, NULL_TREE);
+      set_constraints (decl, constr);
+    }
+
   cp_finish_decl (decl, NULL_TREE, 0, NULL_TREE, 0);
 
   if (pushed_scope)
@@ -17310,51 +17308,6 @@  cp_parser_asm_definition (cp_parser* parser)
     }
 }
 
-// An RAII guard that manages the current template requirements. The
-// constructor takes a boolean value, SAVE that, when true, resets
-// the current template requirements on construction. Otherwise, no change
-// is made. When the destructor is invoked, the current template requirements
-// are reset (made null) preventing subsequent parsing routines from using
-// them.
-struct cp_manage_requirements {
-  bool save;
-  tree reqs;
-
-  // Construct the guard. If SAVE is true, the current requirements
-  // saved and reset. Otherwise, no action is taken.
-  cp_manage_requirements (bool save)
-    : save (save), reqs (save ? release (current_template_reqs) : NULL_TREE)
-  { }
-
-  ~cp_manage_requirements ()
-  {
-    current_template_reqs = reqs;
-  }
-};
-
-// A DECLARATOR may have a trailing requires clause; it may also have
-// requirements introduced through the use of terse notation in the
-// declaration of function parameters. Returns the parsed and analyzed
-// template requirements.
-static tree
-cp_parser_trailing_requirements (cp_parser *parser, cp_declarator *decl)
-{
-  if (function_declarator_p (decl))
-    {
-      if (cp_lexer_next_token_is_keyword (parser->lexer, RID_REQUIRES))
-        {
-          ++cp_unevaluated_operand;
-          push_function_parms (decl);
-          cp_lexer_consume_token (parser->lexer);
-          tree reqs = cp_parser_requires_clause (parser);
-          current_template_reqs = save_trailing_constraints (reqs);
-          finish_scope();
-          --cp_unevaluated_operand;
-        }
-    }
-  return current_template_reqs;
-}
-
 /* Declarators [gram.dcl.decl] */
 
 /* Parse an init-declarator.
@@ -17456,23 +17409,6 @@  cp_parser_init_declarator (cp_parser* parser,
      declared.  */
   resume_deferring_access_checks ();
 
-  // If scope is non-null, then we're parsing a declarator with
-  // a nested-name specifier. It's possible that some component of
-  // that specifier is bringing template constraints with it, which
-  // we need to suppress for for the time being. For example:
-  //
-  //    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>().
-  //
-  // Save requirements, resetting them if the scope was established.
-  cp_manage_requirements saved_requirements (true);
-
   /* Parse the declarator.  */
   token = cp_lexer_peek_token (parser->lexer);
   declarator
@@ -17526,8 +17462,6 @@  cp_parser_init_declarator (cp_parser* parser,
   attributes = cp_parser_attributes_opt (parser);
 
   // Parse an optional trailing requires clause for the parsed declarator.
-  if (flag_concepts)
-    cp_parser_trailing_requirements (parser, declarator);
 
   /* Peek at the next token.  */
   token = cp_lexer_peek_token (parser->lexer);
@@ -17866,7 +17800,7 @@  cp_parser_init_declarator (cp_parser* parser,
    FRIEND_P is true iff this declarator is a friend.  */
 
 static cp_declarator *
-cp_parser_declarator (cp_parser* parser,
+cp_parser_basic_declarator (cp_parser* parser,
 		      cp_parser_declarator_kind dcl_kind,
 		      int* ctor_dtor_or_conv_p,
 		      bool* parenthesized_p,
@@ -17907,7 +17841,7 @@  cp_parser_declarator (cp_parser* parser,
 	cp_parser_parse_tentatively (parser);
 
       /* Parse the dependent declarator.  */
-      declarator = cp_parser_declarator (parser, dcl_kind,
+      declarator = cp_parser_basic_declarator (parser, dcl_kind,
 					 /*ctor_dtor_or_conv_p=*/NULL,
 					 /*parenthesized_p=*/NULL,
 					 /*member_p=*/false,
@@ -17939,6 +17873,75 @@  cp_parser_declarator (cp_parser* parser,
   return declarator;
 }
 
+
+// A declarator may have a trailing requires clause. Because the
+// requires clause is part of the declarator the function parameters
+// are visibile in that expression.
+static tree
+cp_parser_trailing_requires_clause (cp_parser *parser, cp_declarator *decl)
+{
+  tree reqs = NULL_TREE;
+  if (cp_lexer_next_token_is_keyword (parser->lexer, RID_REQUIRES))
+    {
+      cp_lexer_consume_token (parser->lexer);
+      push_function_parms (decl);
+      ++cp_unevaluated_operand;
+      reqs = cp_parser_requires_clause (parser);
+      --cp_unevaluated_operand;
+      finish_scope();
+    }
+  return reqs;
+}
+
+/* Parse a declarator. See cp_parser_basic_declarator for details.
+
+   In concepts, we allow a requires-clause to be parsed at
+   after a function declarator. The program is ill-formed for
+   any other kind of declarator.
+
+     declarator:
+       basic-declarator requires-clause [opt]   
+
+     basic-declarator:
+       direct-declarator
+       ptr-operator-declarator */
+
+static cp_declarator *
+cp_parser_declarator (cp_parser* parser,
+          cp_parser_declarator_kind dcl_kind,
+          int* ctor_dtor_or_conv_p,
+          bool* parenthesized_p,
+          bool member_p, bool friend_p)
+{
+  cp_declarator *declarator = 
+    cp_parser_basic_declarator (parser, dcl_kind, 
+                            ctor_dtor_or_conv_p, 
+                            parenthesized_p,
+                            member_p,
+                            friend_p);
+  if (!declarator)
+    return declarator;
+
+  // Parse the optional trailing requires clause. Note that
+  // the requires clause is only valid for function declarators.
+  if (flag_concepts)
+    {
+      if (declarator->kind == cdk_function)
+        {
+          declarator->u.function.requires_clause
+            = cp_parser_trailing_requires_clause (parser, declarator);
+        }
+      else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_REQUIRES))
+        {
+          error ("requires clause after non-function declaration");
+          cp_parser_skip_to_end_of_statement (parser);
+        }
+    }    
+  return declarator;
+}
+
+
+
 /* Parse a direct-declarator or direct-abstract-declarator.
 
    direct-declarator:
@@ -20308,6 +20311,7 @@  cp_parser_class_specifier_1 (cp_parser* parser)
   /* Parse the class-head.  */
   type = cp_parser_class_head (parser,
 			       &nested_name_specifier_p);
+
   /* If the class-head was a semantic disaster, skip the entire body
      of the class.  */
   if (!type)
@@ -20349,6 +20353,10 @@  cp_parser_class_specifier_1 (cp_parser* parser)
     = parser->in_unbraced_linkage_specification_p;
   parser->in_unbraced_linkage_specification_p = false;
 
+  // Associate constraints with the type.
+  if (flag_concepts)
+    type = associate_classtype_constraints (type);
+
   /* Start the class.  */
   if (nested_name_specifier_p)
     {
@@ -21489,10 +21497,6 @@  cp_parser_member_declaration (cp_parser* parser)
 	      tree asm_specification;
 	      int ctor_dtor_or_conv_p;
 
-              // Save off the requirements, creating a new context
-              // for constraints.
-              cp_manage_requirements saved_requirements (true);
-
 	      /* Parse the declarator.  */
 	      declarator
 		= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
@@ -21593,11 +21597,6 @@  cp_parser_member_declaration (cp_parser* parser)
 	      else
 		initializer = NULL_TREE;
 
-              // Save and reset the current template requirements. Handle
-              // the trailing requirements, if there are any.
-              if (flag_concepts)
-                cp_parser_trailing_requirements (parser, declarator);
-
 	      /* See if we are probably looking at a function
 		 definition.  We are certainly not looking at a
 		 member-declarator.  Calling `grokfield' has
@@ -21624,9 +21623,6 @@  cp_parser_member_declaration (cp_parser* parser)
 		  if (!friend_p)
 		    finish_member_declaration (decl);
 
-                  if (friend_p)
-                     check_constrained_friend (decl, current_template_reqs);
-
 		  /* Peek at the next token.  */
 		  token = cp_lexer_peek_token (parser->lexer);
 		  /* If the next token is a semicolon, consume it.  */
@@ -24432,8 +24428,9 @@  cp_parser_template_introduction (cp_parser* parser)
     }
 
   // Build and associate the constraint.
-  if (tree p = finish_concept_introduction (tmpl_decl, introduction_list))
-    return p;
+  tree parms = finish_concept_introduction (tmpl_decl, introduction_list);
+  if (parms)
+    return parms;
 
   error_at (token->location, "no matching concept for introduction-list");
   return error_mark_node;
@@ -24452,7 +24449,6 @@  cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p)
   bool friend_p = false;
   bool need_lang_pop;
   cp_token *token;
-  tree saved_template_reqs;
 
   /* Look for the `template' keyword.  */
   token = cp_lexer_peek_token (parser->lexer);
@@ -24495,9 +24491,6 @@  cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p)
 	 cannot check the decl-specifier list.  */
       push_deferring_access_checks (dk_deferred);
 
-      // Save the current template requirements.
-      saved_template_reqs = release (current_template_reqs);
-
       /* If the next token is `>', then we have an invalid
          specialization.  Rather than complain about an invalid template
          parameter, issue an error message here.  */
@@ -24528,20 +24521,13 @@  cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p)
 	  tree reqs = get_shorthand_constraints (current_template_parms);
 	  if (tree r = cp_parser_requires_clause_opt (parser))
 	    reqs = conjoin_constraints (reqs, r);
-	  current_template_reqs = save_leading_constraints (reqs);
-
-	  // Attach the constraints to the template parameter list.
-	  // This is used to pass template requirements to out-of-class
-	  // member definitions.
-	  TEMPLATE_PARMS_CONSTRAINTS (current_template_parms)
-	    = current_template_reqs;
+          TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = reqs;
 	}
     }
   else if (flag_concepts)
     {
       need_lang_pop = false;
       checks = NULL;
-      saved_template_reqs = release (current_template_reqs);
 
       // Scope may be changed by a nested-name-specifier.
       tree saved_scope = parser->scope;
@@ -24552,14 +24538,15 @@  cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p)
       parameter_list = cp_parser_template_introduction (parser);
       if (parameter_list == error_mark_node)
         {
-	  current_template_reqs = saved_template_reqs;
           pop_deferring_access_checks ();
-	  return;
+          cp_parser_skip_to_end_of_statement (parser);
+          return;
         }
 
       parser->scope = saved_scope;
       parser->qualifying_scope = saved_qualifying_scope;
       parser->object_scope = saved_object_scope;
+
     }
   else
     {
@@ -24615,9 +24602,6 @@  cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p)
   /* 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.  */
   if (decl
       && DECL_DECLARES_FUNCTION_P (decl)
@@ -24663,6 +24647,7 @@  cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p)
 		   decl);
 	}
     }
+
   /* Register member declarations.  */
   if (member_p && !friend_p && decl && !DECL_CLASS_TEMPLATE_P (decl))
     finish_member_declaration (decl);
@@ -24745,7 +24730,13 @@  cp_parser_single_declaration (cp_parser* parser,
     {
       if (cp_parser_declares_only_class_p (parser))
 	{
-	  decl = shadow_tag (&decl_specifiers);
+          // If this is a declaration, but not a definition, associate
+          // any constraints with the type declaration. Constraints
+          // are associated with definitions in cp_parser_class_specifier.
+          if (declares_class_or_enum == 1)
+            associate_classtype_constraints (decl_specifiers.type);
+
+          decl = shadow_tag (&decl_specifiers);
 
 	  /* In this case:
 
@@ -25112,11 +25103,6 @@  cp_parser_late_parsing_for_member (cp_parser* parser, tree member_function)
   /* Make sure that any template parameters are in scope.  */
   maybe_begin_member_template_processing (member_function);
 
-  // Restore the declaration's requirements for the parsing of
-  // the definition.
-  tree saved_template_reqs = release (current_template_reqs);
-  current_template_reqs = get_constraints (member_function);
-
   /* If the body of the function has not yet been parsed, parse it
      now.  */
   if (DECL_PENDING_INLINE_P (member_function))
@@ -25172,9 +25158,6 @@  cp_parser_late_parsing_for_member (cp_parser* parser, tree member_function)
   /* 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);
@@ -33802,10 +33785,6 @@  synthesize_implicit_template_parm  (cp_parser *parser, tree constr)
 			     /*non_type=*/false,
 			     /*param_pack=*/false);
 
-  // If the invented parameter was constrained, save the constraint.
-  if (tree reqs = TEMPLATE_PARM_CONSTRAINTS (tree_last (new_parm)))
-    current_template_reqs = save_leading_constraints (reqs);
-
   // Chain the new parameter to the list of implicit parameters.
   if (parser->implicit_template_parms)
     parser->implicit_template_parms
@@ -33836,6 +33815,15 @@  synthesize_implicit_template_parm  (cp_parser *parser, tree constr)
       TREE_VEC_ELT (new_parms, new_parm_idx) = parser->implicit_template_parms;
     }
 
+  // If the new parameter was constrained, we need to add that to the
+  // constraints in the tmeplate parameter list.
+  if (tree req = TEMPLATE_PARM_CONSTRAINTS (tree_last (new_parm)))
+    {
+      tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
+      reqs = conjoin_constraints (reqs, req);
+      TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = reqs;
+    }
+
   current_binding_level = entry_scope;
 
   return new_type;
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 2ceff1d..58d5223 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -889,32 +889,68 @@  maybe_new_partial_specialization (tree type)
   // 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)
-          // 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;
+  //
+  // FIXME: This may allow multiple partial specializations to have
+  // equivalent constraints. We need to check this against all
+  // partial specializations with euqivalent type. For exmaple:
+  //
+  //    template<typename T> struct S;
+  //    template<typename T> struct S<T*>; // #1
+  //    template<C T> struct S<T*>;        // #2
+  //    template<C T> struct S<T*>;        // differs from #1 but not #2
+  if (flag_concepts && CLASSTYPE_TEMPLATE_SPECIALIZATION (type))
+    {
+      tree tmpl = CLASSTYPE_TI_TEMPLATE (type);
+      tree args = CLASSTYPE_TI_ARGS (type);
+
+      // If TYPE is the same as the template's type, this is clearly
+      // not a specialization. This happens when you define a member
+      // template outside of its enclosing class.
+      if (type == DECL_TEMPLATE_RESULT (tmpl))
+        return NULL_TREE;
 
-          return t;
+      // If there are no template parameters, this cannot be a new
+      // partial template specializtion?
+      if (!current_template_parms)
+        return NULL_TREE;
+
+      // If the constraints are not the same as those of the primary
+      // then, we can probably create a new specialization.
+      tree type_reqs = TEMPLATE_PARM_CONSTRAINTS (current_template_parms);
+      tree type_constr = build_constraints (type_reqs, NULL_TREE);
+      tree main_constr = get_constraints (DECL_TEMPLATE_RESULT (tmpl));
+      if (equivalent_constraints (type_constr, main_constr))
+        return NULL_TREE;
+
+      // Also, if there's a pre-existing specialization with matching
+      // constraints, then this also isn't new.
+      tree specs = DECL_TEMPLATE_SPECIALIZATIONS (tmpl);
+      while (specs)
+        {
+          tree spec_tmpl = TREE_VALUE (specs);
+          tree spec_constr = get_constraints (DECL_TEMPLATE_RESULT (spec_tmpl));
+          if (equivalent_constraints (type_constr, spec_constr))
+            return NULL_TREE;
+          specs = TREE_CHAIN (specs);
         }
+
+      // Create a new type node (and corresponding type decl)
+      // 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_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;
+  
+  return NULL_TREE;
 }
 
 /* The TYPE is being declared.  If it is a template type, that means it
@@ -924,7 +960,6 @@  tree
 maybe_process_partial_specialization (tree type)
 {
   tree context;
-
   if (type == error_mark_node)
     return error_mark_node;
 
@@ -2330,8 +2365,9 @@  determine_specialization (tree template_id,
   else
     *targs_out = TREE_PURPOSE (templates);
 
-  // Associate the deduced constraints with the declaration.
-  if (tree ci = get_constraints (TREE_VALUE (templates)))
+  // Associate the deduced constraints with the new declaration.
+  tree tmpl = TREE_VALUE (templates);
+  if (tree ci = get_constraints (DECL_TEMPLATE_RESULT (tmpl)))
     set_constraints (decl, tsubst_constraint_info (ci, *targs_out));
 
   return TREE_VALUE (templates);
@@ -3974,9 +4010,6 @@  process_template_parm (tree list, location_t parm_loc, tree parm,
 
       TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm)) 
 	= is_parameter_pack;
-
-      // Build requirements for the parameter.
-      reqs = finish_shorthand_constraint (parm, constr);
     }
   else
     {
@@ -4009,12 +4042,14 @@  process_template_parm (tree list, location_t parm_loc, tree parm,
 				     decl, TREE_TYPE (parm));
       TEMPLATE_TYPE_PARAMETER_PACK (t) = is_parameter_pack;
       TYPE_CANONICAL (t) = canonical_type_parameter (t);
-
-      // Build requirements for the type/template parameter.
-      reqs = finish_shorthand_constraint (parm, constr);
     }
   DECL_ARTIFICIAL (decl) = 1;
   SET_DECL_TEMPLATE_PARM_P (decl);
+
+  // Build requirements for the type/template parameter.  This must be done
+  // after SET_DECL_TEMPLATE_PARM_P or process_template_parm could fail.
+  reqs = finish_shorthand_constraint (parm, constr);
+
   pushdecl (decl);
 
   // Build the parameter node linking the parameter declaration, its
@@ -4265,14 +4300,13 @@  maybe_update_decl_type (tree orig_type, tree scope)
    the new  template is a member template. */
 
 tree
-build_template_decl (tree decl, tree parms, tree constr, bool member_template_p)
+build_template_decl (tree decl, tree parms, bool member_template_p)
 {
   tree tmpl = build_lang_decl (TEMPLATE_DECL, DECL_NAME (decl), NULL_TREE);
   DECL_TEMPLATE_PARMS (tmpl) = parms;
   DECL_CONTEXT (tmpl) = DECL_CONTEXT (decl);
   DECL_SOURCE_LOCATION (tmpl) = DECL_SOURCE_LOCATION (decl);
   DECL_MEMBER_TEMPLATE_P (tmpl) = member_template_p;
-  set_constraints (tmpl, finish_template_constraints (constr));
 
   return tmpl;
 }
@@ -4363,7 +4397,7 @@  process_partial_specialization (tree decl)
   //
   // TODO: Do we need to compare the current requirements to make
   // sure this isn't a redeclaration?
-  if (current_template_reqs)
+  if (TEMPLATE_PARM_CONSTRAINTS (current_template_parms))
     TYPE_CANONICAL (type) = type;
 
   inner_parms = INNERMOST_TEMPLATE_PARMS (current_template_parms);
@@ -4438,13 +4472,20 @@  process_partial_specialization (tree decl)
      The argument list of the specialization shall not be identical to
      the implicit argument list of the primary template.
 
+     FIXME: This is redundant with the requirement that a specialization
+     shall be more specialized than the primary. H
+
      Note that concepts allow partial specializations with the same list of
      arguments but different constraints. */
   tree main_args
     = TI_ARGS (get_template_info (DECL_TEMPLATE_RESULT (maintmpl)));
+  
+  tree temp_reqs = TEMPLATE_PARM_CONSTRAINTS (current_template_parms);
+  // FIXME: Why can't I get tmpl_constr from decl.
+  tree tmpl_constr = build_constraints (temp_reqs, NULL_TREE);
   tree main_constr = get_constraints (maintmpl);
   if (comp_template_args (inner_args, INNERMOST_TEMPLATE_ARGS (main_args))
-      && equivalent_constraints (current_template_reqs, main_constr))
+      && equivalent_constraints (tmpl_constr, main_constr))
     error ("partial specialization %qT does not specialize any "
            "template arguments", type);
 
@@ -4460,6 +4501,16 @@  process_partial_specialization (tree decl)
       return decl;
     }
 
+  // All things not being equal, we still need to check that the
+  // constraints are more specialized than those of the primary.
+  if (flag_concepts && !subsumes_constraints (tmpl_constr, main_constr))
+    {
+      error ("partial specialization is not more specialized than the "
+             "primary template because it is not more constrained");
+      inform (DECL_SOURCE_LOCATION (maintmpl), "primary template here");
+      return error_mark_node;
+    }
+
   /* [temp.class.spec]
 
      A partially specialized non-type argument expression shall not
@@ -4592,7 +4643,6 @@  process_partial_specialization (tree decl)
   // Build the template decl.
   tree tmpl = build_template_decl (decl,
                                    current_template_parms,
-                                   current_template_reqs,
                                    DECL_MEMBER_TEMPLATE_P (maintmpl));
   TREE_TYPE (tmpl) = type;
   DECL_TEMPLATE_RESULT (tmpl) = decl;
@@ -5149,9 +5199,11 @@  push_template_decl_real (tree decl, bool is_friend)
 	  /* Since a template declaration already existed for this
 	     class-type, we must be redeclaring it here.  Make sure
 	     that the redeclaration is valid.  */
+          tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
+          tree constr = build_constraints (reqs, NULL_TREE);
 	  redeclare_class_template (TREE_TYPE (decl),
                                     current_template_parms,
-                                    current_template_reqs);
+                                    constr);
 	  /* We don't need to create a new TEMPLATE_DECL; just use the
 	     one we already had.  */
 	  tmpl = TYPE_TI_TEMPLATE (TREE_TYPE (decl));
@@ -5160,7 +5212,6 @@  push_template_decl_real (tree decl, bool is_friend)
 	{
 	  tmpl = build_template_decl (decl,
                                       current_template_parms,
-                                      current_template_reqs,
                                       member_template_p);
 	  new_template_p = 1;
 
@@ -5205,7 +5256,6 @@  push_template_decl_real (tree decl, bool is_friend)
 
 	  new_tmpl = build_template_decl (decl,
                                     current_template_parms,
-                                    current_template_reqs,
                                     member_template_p);
 	  DECL_TEMPLATE_RESULT (new_tmpl) = decl;
 	  TREE_TYPE (new_tmpl) = TREE_TYPE (decl);
@@ -5378,15 +5428,9 @@  add_inherited_template_parms (tree fn, tree inherited)
   tree parms
     = tree_cons (size_int (processing_template_decl + 1),
 		 inner_parms, current_template_parms);
-  tree tmpl = build_template_decl (fn, parms, NULL_TREE, /*member*/true);
+  tree tmpl = build_template_decl (fn, parms, /*member*/true);
   tree args = template_parms_to_args (parms);
 
-  // If the inherited constructor was constrained, then also
-  // propagate the constraints to the new declaration by
-  // rewriting them in terms of the local template parameters.
-  if (tree ci = get_constraints (inherited))
-    set_constraints (tmpl, tsubst_constraint_info (ci, args));
-
   DECL_TEMPLATE_INFO (fn) = build_template_info (tmpl, args);
   TREE_TYPE (tmpl) = TREE_TYPE (fn);
   DECL_TEMPLATE_RESULT (tmpl) = fn;
@@ -6765,9 +6809,6 @@  is_compatible_template_arg (tree parm, tree arg)
   // 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, this conversion will be valid.
-  //
-  // BUG: This substitution seems to have broken during an update and no
-  // longer works. The resulting expression seems to be the same.
   if (parm_cons)
     {
       tree args = template_parms_to_args (DECL_TEMPLATE_PARMS (arg));
@@ -10249,12 +10290,12 @@  tsubst_pack_conjunction (tree t, tree args, tsubst_flags_t complain,
 
   // If the resulting expression is type- or value-dependent, then
   // return it after setting the result type to bool (so it can be
-  // expanded as a conjunction).
-  //
-  // This happens when instantiating constrained variadic
-  // member function templates.
+  // expanded as a conjunction). This happens when instantiating 
+  // constrained variadic member function templates. Just rebuild
+  // the dependent pack expansion.
   if (instantiation_dependent_expression_p (terms))
     {
+      terms = TREE_VEC_ELT (terms, 0);
       TREE_TYPE (terms) = boolean_type_node;
       return terms;
     }
@@ -11053,10 +11094,6 @@  tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 	  = tsubst_template_parms (DECL_TEMPLATE_PARMS (t), args,
 				   complain);
 
-        // If constrained, also instantiate the constraints.
-        if (tree ci = get_constraints (t))
-          set_constraints (r, tsubst_constraint_info (ci, args));
-
 	if (PRIMARY_TEMPLATE_P (t))
 	  DECL_PRIMARY_TEMPLATE (r) = r;
 
@@ -11262,15 +11299,24 @@  tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 	    && !grok_op_properties (r, /*complain=*/false))
 	  RETURN (error_mark_node);
 
+        // Propagate constraints to the new declaration.
+        if (tree ci = get_constraints (t)) {
+          if (!uses_template_parms (argvec))
+            {
+              tree tr = CI_TEMPLATE_REQS (ci);
+              tree dr = CI_DECLARATOR_REQS (ci);
+              ci = build_constraints (NULL_TREE, conjoin_constraints (tr, dr));
+            }
+          tree new_ci = tsubst_constraint_info (ci, argvec);
+          set_constraints (r, new_ci);
+        }
+
 	/* Set up the DECL_TEMPLATE_INFO for R.  There's no need to do
 	   this in the special friend case mentioned above where
 	   GEN_TMPL is NULL.  */
 	if (gen_tmpl)
 	  {
-            if (tree ci = get_constraints (gen_tmpl))
-              set_constraints (r, tsubst_constraint_info (ci, argvec));
-
-            DECL_TEMPLATE_INFO (r) = build_template_info (gen_tmpl, argvec);
+           DECL_TEMPLATE_INFO (r) = build_template_info (gen_tmpl, argvec);
 	    SET_DECL_IMPLICIT_INSTANTIATION (r);
 
 	    tree new_r
@@ -19386,8 +19432,10 @@  more_specialized_fn (tree pat1, tree pat2, int len)
   // All things still being equal, determine if one is more constrained.
   if (lose1 == lose2)
     {
-      lose1 = !subsumes_constraints (pat1, pat2);
-      lose2 = !subsumes_constraints (pat2, pat1);
+      tree c1 = get_constraints (DECL_TEMPLATE_RESULT (pat1));
+      tree c2 = get_constraints (DECL_TEMPLATE_RESULT (pat2));
+      lose1 = !subsumes_constraints (c1, c2);
+      lose2 = !subsumes_constraints (c2, c1);
     }
 
   if (lose1 == lose2)
@@ -19834,7 +19882,9 @@  most_specialized_partial_spec (tree target, tsubst_flags_t complain)
 	    spec_args = add_to_template_args (outer_args, spec_args);
 
           // Keep the candidate only if the constraints are satisfied.
-          if (check_template_constraints (spec_tmpl, spec_args))
+          tree spec_decl = DECL_TEMPLATE_RESULT (spec_tmpl);
+          tree spec_constr = get_constraints (spec_decl);
+          if (check_constraints (spec_constr, spec_args))
             {
 	      list = tree_cons (spec_args, TREE_VALUE (t), list);
 	      TREE_TYPE (list) = TREE_TYPE (t);
diff --git a/gcc/cp/ptree.c b/gcc/cp/ptree.c
index c877f17..9fac29c 100644
--- a/gcc/cp/ptree.c
+++ b/gcc/cp/ptree.c
@@ -227,12 +227,13 @@  cxx_print_xnode (FILE *file, tree node, int indent)
     case CONSTRAINT_INFO:
       {
         tree_constraint_info *cinfo = (tree_constraint_info *)node;
-        if (cinfo->leading_reqs)
-          print_node (file, "leading_reqs", cinfo->leading_reqs, indent+4);
-        if (cinfo->trailing_reqs)
-          print_node (file, "trailing_reqs", cinfo->trailing_reqs, indent+4);
-        if (cinfo->assumptions)
-          print_node_brief (file, "assumptions", cinfo->assumptions, indent+4);
+        if (cinfo->template_reqs)
+          print_node (file, "template_reqs", cinfo->template_reqs, indent+4);
+        if (cinfo->declarator_reqs)
+          print_node (file, "declarator_reqs", cinfo->declarator_reqs, indent+4);
+        print_node (file, "associated_constr", 
+                          cinfo->associated_constr, indent+4);
+        print_node_brief (file, "assumptions", cinfo->assumptions, indent+4);
         break;
       }
     case ARGUMENT_PACK_SELECT:
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index e9c6ce5..62c6d0b 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2439,6 +2439,8 @@  finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual,
 	  else
 	    {
 	      next = OVL_CHAIN (fn);
+              if (flag_concepts)
+                remove_constraints (fn);
 	      ggc_free (fn);
 	    }
 	}
@@ -2730,7 +2732,12 @@  finish_template_template_parm (tree aggr, tree identifier)
   DECL_TEMPLATE_PARMS (tmpl) = current_template_parms;
   DECL_TEMPLATE_RESULT (tmpl) = decl;
   DECL_ARTIFICIAL (decl) = 1;
-  set_constraints (tmpl, finish_template_constraints (current_template_reqs));
+  
+  // Associate the constraints with the underlying declaration,
+  // not the template.
+  tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
+  tree constr = build_constraints (reqs, NULL_TREE);
+  set_constraints (decl, constr);
 
   end_template_decl ();
 
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index a9928c5..ff8fe7a 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -2948,7 +2948,8 @@  cp_tree_equal (tree t1, tree t2)
 	      && cp_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1)));
 
     case CONSTRAINT_INFO:
-      return cp_tree_equal (CI_ASSOCIATED_REQS (t1), CI_ASSOCIATED_REQS (t2));
+      return cp_tree_equal (CI_ASSOCIATED_CONSTRAINTS (t1), 
+                            CI_ASSOCIATED_CONSTRAINTS (t2));
 
     case TREE_VEC:
       {
diff --git a/gcc/testsuite/g++.dg/concepts/alias4.C b/gcc/testsuite/g++.dg/concepts/alias4.C
index cdc980c..4227a44 100644
--- a/gcc/testsuite/g++.dg/concepts/alias4.C
+++ b/gcc/testsuite/g++.dg/concepts/alias4.C
@@ -11,9 +11,9 @@  template<typename T>
 // of whether or not they are dependent. This causes T* to be substituted
 // without acutally checking the constraints.
 template<typename T>
-  using Y = X<T>; // { dg-error "constraints"}
+  using Y = X<T>;
 
 int main()
 {
-  Y<int> y1; // { dg-error "invalid" }
+  Y<int> y1; // { dg-error "" "" { xfail *-*-* } }
 }
diff --git a/gcc/testsuite/g++.dg/concepts/class.C b/gcc/testsuite/g++.dg/concepts/class.C
index f3bf042..ea74a54 100644
--- a/gcc/testsuite/g++.dg/concepts/class.C
+++ b/gcc/testsuite/g++.dg/concepts/class.C
@@ -49,12 +49,4 @@  static_assert(S2<char>::value == 0, "");
 static_assert(S2<one_type>::value == 1, "");
 static_assert(S2<two_type>::value == 2, "");
 
-// Check that there is no ecsacpe hatch
-template<Two T> struct S4 { };
-template<One T> struct S4<T> { }; // Should never be usable.
-
-S4<two_type>* x4a;
-// S4<one_type>* x4b; // Not suficiently strict
-
-
 int main() { }
diff --git a/gcc/testsuite/g++.dg/concepts/class6.C b/gcc/testsuite/g++.dg/concepts/class6.C
index 74f2a0c..aa6934d 100644
--- a/gcc/testsuite/g++.dg/concepts/class6.C
+++ b/gcc/testsuite/g++.dg/concepts/class6.C
@@ -8,7 +8,7 @@  template<typename T>
 
 // Check that there is no ecsacpe hatch
 template<Two T> struct S4 { };
-template<One T> struct S4<T> { }; // Should never be usable.
+template<One T> struct S4<T> { }; // { dg-error "not more specialized" }
 
 struct one_type { char x[4]; };
 
diff --git a/gcc/testsuite/g++.dg/concepts/inherit-ctor1.C b/gcc/testsuite/g++.dg/concepts/inherit-ctor1.C
index 031a0af..29433ad 100644
--- a/gcc/testsuite/g++.dg/concepts/inherit-ctor1.C
+++ b/gcc/testsuite/g++.dg/concepts/inherit-ctor1.C
@@ -4,17 +4,19 @@  template<typename T>
   concept bool C() { return __is_class(T); }
 
 template<typename T>
-  struct S1 {
-    S1() requires C<T>() { }
-  };
+  struct S1 { S1(double) requires C<T>() { } };
+
+struct S2 : S1<int> {
+  using S1<int>::S1;
+};
 
 template<typename T>
-  struct S2 : S1<T> {
+  struct S3 : S1<T> {
     using S1<T>::S1;
   };
 
 struct X { };
 
 int main() {
-  S2<X> s;
+  S3<X> s(0.0);
 }
diff --git a/gcc/testsuite/g++.dg/concepts/inherit-ctor2.C b/gcc/testsuite/g++.dg/concepts/inherit-ctor2.C
index 74ad602..4f39203 100644
--- a/gcc/testsuite/g++.dg/concepts/inherit-ctor2.C
+++ b/gcc/testsuite/g++.dg/concepts/inherit-ctor2.C
@@ -5,7 +5,7 @@  template<typename T>
 
 template<typename T>
   struct S1 {
-    S1() requires C<T>() { }
+    S1(double) requires C<T>() { }
   };
 
 template<typename T>
@@ -14,5 +14,5 @@  template<typename T>
   };
 
 int main() {
-  S2<int> s; // { dg-error "deleted" }
+  S2<int> s; // { dg-error "deleted function" }
 }
diff --git a/gcc/testsuite/g++.dg/concepts/inherit-ctor4.C b/gcc/testsuite/g++.dg/concepts/inherit-ctor4.C
index cbcf875..cd9565f 100644
--- a/gcc/testsuite/g++.dg/concepts/inherit-ctor4.C
+++ b/gcc/testsuite/g++.dg/concepts/inherit-ctor4.C
@@ -14,5 +14,5 @@  template<typename T>
   };
 
 int main() {
-  S2<int> s(0); // { dg-error "matching" }
+  S2<int> s(0); // { dg-error "no matching function" }
 }
diff --git a/gcc/testsuite/g++.dg/concepts/intro4.C b/gcc/testsuite/g++.dg/concepts/intro4.C
index 9d57c2f..f821c1c 100644
--- a/gcc/testsuite/g++.dg/concepts/intro4.C
+++ b/gcc/testsuite/g++.dg/concepts/intro4.C
@@ -1,7 +1,7 @@ 
 // { dg-options "-std=c++1z" }
 
 template<typename ... T>
-  concept bool C1 = true;
+  concept bool C1 = true; // { dg-message "provided" }
 
 template<int ... N>
   concept bool C2 = true;
@@ -17,7 +17,7 @@  template<int N>
 template<typename T, typename U = int>
   concept bool C5() { return __is_class(U); }
 
-C1{...A, B} void f1() {}; // { dg-error "no matching concept" }
+C1{...A, B} void f1() {}; // { dg-error "no matching|wrong number" }
 C1{A} void f2() {} // { dg-error "match pack" }
 C2{A, B} void f3() {}; // { dg-error "match pack" }
 C3{...A} void f4() {}; // { dg-error "match pack" }
diff --git a/gcc/testsuite/g++.dg/concepts/req4.C b/gcc/testsuite/g++.dg/concepts/req4.C
index 7f46976..927e4e5 100644
--- a/gcc/testsuite/g++.dg/concepts/req4.C
+++ b/gcc/testsuite/g++.dg/concepts/req4.C
@@ -11,8 +11,8 @@  template<typename T> constexpr fool p2() { return {}; }
 template<typename T>
   concept bool C() { return p1<T>() && p2<T>(); }
 
-template<C T> void f(T x) { } // { dg-error "user-defined" }
+template<C T> void f(T x) { }
 
 int main() {
-  f(0); // { dg-error "cannot call" }
+  f(0); // { dg-error "cannot call|predicate constraint" }
 }
diff --git a/gcc/testsuite/g++.dg/concepts/req5.C b/gcc/testsuite/g++.dg/concepts/req5.C
index ce98d4d..c566d31 100644
--- a/gcc/testsuite/g++.dg/concepts/req5.C
+++ b/gcc/testsuite/g++.dg/concepts/req5.C
@@ -11,8 +11,8 @@  template<typename T> constexpr fool p2() { return {}; }
 template<typename T>
   concept bool C() { return p1<T>() && p2<T>(); }
 
-template<C T> void f(T x) { } // { dg-error "user-defined" }
+template<C T> void f(T x) { }
 
 int main() {
-  f(0); // { dg-error "cannot call" }
+  f(0); // { dg-error "cannot call|predicate constraint" }
 }