This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[c++-concepts] Constraint processing updates


Now that the concepts PDTS has shipped, I've had time to finish a very
large backlog of changes to the implementation. The attached patch
(probably non-conforming since it's a git patch) brings constraint
processing much more into line with the current specification.

Sorry for the big patch, but doing it in small patches would have left
the branch broken for about a month. Here is a high-level summary of
changes:

- Move constraints out of declaration nodes and into a separate hash
table (and actually make that work with the GC so nodes don't
magically change when compiling -- I hate you, GC).

- Define constraints as a completely separate set of nodes that do not
interoperate with the usual expression processing (these nodes end in
_CONSTR). Making constraints completely separate from expressions
brings a much greater clarity to the constraint processing rules.

- Redefine constraint normalization in terms of constraints instead of
expressions. Implement concept lifting (inlining of concept
definitions to make things SFINAE friendly) and the transformation of
expressions and constraints as subroutines of normalization.

- Define associated constraints as constraints and not expressions.

- Define reqiurements (the things in a requires-expr) separately from
expressions (these nodes end in _REQ). This also makes processing
requires-expressions much more clear with respect to the usual rules
for expression processing.

- Clean up the value/type dependence characterization of requires
expressions, and make sure that constexpr evaluation doesn't try to
fold them.

- Only ask to satisfy/instantiate constraints when actually needed.
Don't conflate substitution and instantiation (this clears up some
long-standing ambiguities in the implementation).

- Tentatively rewrite diagnostics so they don't fully recurse and
enumerate all possible constraint failures. We probably want a flag to
control this. And the actual output of constraints is not ideal (a bit
hacky for now). Needs work.

- Extend the TS to allow the use of concepts in non-SFNINAE contexts
such as static_assertions and if statements.

This will probably introduce some new regressions, but thus far,
compiler stability seems to have improved significantly.

Below are the ChangeLog entries from a series of git commits that have
gone into this patch.

2015-03-03  Andrew Sutton  <andrew.n.sutton@gmail.com>

        Rewrite to use new constraint model.
        * gcc/cp/call.c (add_function_candidate): Use new constraint
        checking interface.
        (build_new_function_call): Evaluate concepts when selected
        by overload resolution.
        * gcc/cp/class.c (resolve_address_of_overloaded_function):
        Use new constraint interface.
        * gcc/cp/constexpr.c (cxx_eval_constant_expression): Don't
        try to constexpr evaluate a requires-expression.
        (potential_constant_expression_1): Stop using old
        requires/constraint features.
        gcc/cp/constraint.cc: Much rewriting, reorganization, refactoring
        to support new constraint/requirement terms.
        (lift_function_definition): New. Factor lifting code out of
        lift_call for reuse in evaluate_function_concept.
        (lift_variable_intializer): New. Factor lifting code out of
        lift_var for reuse in evaluate_variable_concept.
        (lift_template_id): Restore checking code for mis-written
        variable concepts.
        (lift_requires_expr): Handle these separately.
        (xform_*_requirement): New. Transform requires-expressions
        into constraints.
        (get/set/remove_constraints, decl_constraints): Move to
        pt.c to allow for garbage collection.
        (processing_constraint): Kill this global.
        (diagnose_*): Update diagnostics to use the new constraint
        interface.
        * gcc/cp/cp-objcp-common.c (cp_common_init_ts): Remove typing
        of old nodes.
        * gcc/cp/cp-tree.def: Add new nodes for requirements and
        constraints. Remove previous constraint/req nodes.
        gcc/cp/cp-tree.h (COMPOUND_REQ_NOEXCEPT_P): New.
        (ICONV_CONSTR_EXPR, ICONV_CONSTR_TYPE): Fix operands.
        (constraint_p, make_predicate_constraint_p, valid_constraints_p): New.
        (misc): Remove unused declarations.
        gcc/cp/cxx-pretty-print.c: Reorganize/rewrite for new constraint
        model.
        (primary_expression, expression): Remove unused nodes, add options
        for constraints
        gcc/cp/cxx-pretty-print.h: Declare new functions for pretty
        printing.
        gcc/cp/decl.c (duplicate_decls): Only reclaim when flag_concepts
        is on.
        (grokfndecl): Associate predicate constraints.
        gcc/cp/decl2.c (mark_used): Don't instantiate concepts.
        gcc/cp/error.c (dump_expr): Handle new constraints.
        gcc/cp/method.c (implicitly_declare_fn): Use new constraint
        interface.
        gcc/cp/parser.c (make_call_declarator): Pass a requires-clause for
        call declarators.
        (cp_parser_type_name): Take a flag to indicate the presence of
        a pre-parsed 'typename'.
        (cp_parser_requires_expression): Move sentinel into function.
        (cp_parser_type_requirement): Parse type requirements in accordance
        with Concepts TS.
        (cp_parser_compound_requirement): Parse compound requirements in
        accordance with Concepts TS. Remove constexpr requirements.
        (cp_parser_template_declaration_after_export): Associate
        predicate constraints.
        gcc/cp/pt.c (get_template_for_ordering): New. Extract a template
        decl from a list of candidates.
        (lookup_template_class_1): Use new constraint interface.
        (tsubst_pack_conjunction): Build an expression, not constraints.
        (tsubst_decl): Only associate constraints when substituting
        through members.
        (tsubst): Kill subst rules for old nodes.
        (most_specialized_partial_spec): Save candidates correctly
        in the presence of constraints.
        (always_instantiate_p): Never always instantiate a concept.
        (type_dependent_expression_p): Requires expressions have type bool.
        (decl_constraints): Moved from constraint.cc, use hash_table
        instead of hash_map.
        gcc/cp/semantics.c (finish_call_expr): Remove constraints from
        functions, not overload sets.
        (finish_template_variable): Evaluate variable concepts by
        determining satisfaction.
        gcc/cp/typeck.c (cp_build_function_call_vec): Use new concept
        interface.
        gcc/cp/testsuite/g++.dg/concepts/*: Update tests to match syntax,
        diagnostics.
        gcc/cp/testsuite/g++.dg/concepts/req1.C: Test requires-expression
        with no parens.

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

        * gcc/cp/constraint.cc (lift_operands): New.
        (lift_call): Lift operands on function calls and don't use
        tsubst_constraint_expr.
        (lift_var): Don't use tsubst_constraint_expr.
        (lift_constraints): Use the returned number of operands for most nodes
        and also lift from TREE_LISTs.

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

        * gcc/cp/constraint.cc (lift_call): Converted from normalize_call.
        (lift_var): Converted from normalize_var.
        (lift_template_id): Converted from normalize_template_id.
        (lift_constraints): Implemented.

2015-02-16  Andrew Sutton  <andrew.n.sutton@gmail.com>

        * gcc/cp/cp-tree.h: (EXPR_CONSTR_EXPR, TYPE_CONSTR_TYPE): Fix
        typos in macro names.
        * gcc/cp/constraint.cc: (check_constraint*): New. Rewrite the
        constraint checking implementation so that it matches the
        wording and rules in n4377.

2015-02-10  Andrew Sutton  <andrew.n.sutton@gmail.com>

        * gcc/cp/logic.cc: Rewrite to use new constraint model and
        update formatting.
        * gcc/cp/constraint.cc: Documentation and organization.

2015-02-10  Andrew Sutton  <andrew.n.sutton@gmail.com>

        * gcc/cp/cp-tree.h (is_constraint): Make static.

2015-02-09  Andrew Sutton  <andrew.n.sutton@gmail.com>

        Rewrite normalization in terms of constraints.
        * gcc/cp/cp-tree.h (is_constraint): New.
        * gcc/cp/constraint.cc (normalize_*): Rewrite the previous normalization
        model so that it conforms with the specification. Normalization applies
        to constraints. Transformation of expressions into constraints now
        happens in two phases: lifting concept definitions, and the actual
        transformation.
        (tranform_expression, xform_*): New. Define transformation of
        expressions into constraints.
        (lift_constraints): New. Stubbed out inlining function.

2015-02-09  Andrew Sutton  <andrew.n.sutton@gmail.com>

        Start refactoring constraints to match the specification.
        * gcc/cp/cp-tree.def: Add new TREECODEs for constraints.
        * gcc/cp/cp-tree.h: Add accessor macros for constraint operands.

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

        * gcc/cp/constexpr.c (potential_constant_expression_1): Readded missing
        cases from previous merge from trunk.
        * gcc/cp/cxx-pretty-print.c (pp_cxx_trait_expression): Restored
        CPTK_IS_CONVERTIBLE_TO for the time being since the constraint code
        relies on it.
        * gcc/cp/semantics.c (finish_trait_expr): Likewise.
        * gcc/testsuite/g++.dg/concepts/req9.C: New test.

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.


Andrew Sutton
diff --git a/ChangeLog.concepts b/ChangeLog.concepts
index 4e04aad..bfd4002 100644
--- a/ChangeLog.concepts
+++ b/ChangeLog.concepts
@@ -1,3 +1,141 @@
+2015-03-03  Andrew Sutton  <andrew.n.sutton@gmail.com>
+
+	Rewrite to use new constraint model.
+	* gcc/cp/call.c (add_function_candidate): Use new constraint
+	checking interface.
+	(build_new_function_call): Evaluate concepts when selected
+	by overload resolution.
+	* gcc/cp/class.c (resolve_address_of_overloaded_function):
+	Use new constraint interface.
+	* gcc/cp/constexpr.c (cxx_eval_constant_expression): Don't 
+	try to constexpr evaluate a requires-expression.
+	(potential_constant_expression_1): Stop using old
+	requires/constraint features.
+	gcc/cp/constraint.cc: Much rewriting, reorganization, refactoring
+	to support new constraint/requirement terms.
+	(lift_function_definition): New. Factor lifting code out of
+	lift_call for reuse in evaluate_function_concept.
+	(lift_variable_intializer): New. Factor lifting code out of
+	lift_var for reuse in evaluate_variable_concept.
+	(lift_template_id): Restore checking code for mis-written
+	variable concepts.
+	(lift_requires_expr): Handle these separately.
+	(xform_*_requirement): New. Transform requires-expressions
+	into constraints.
+	(get/set/remove_constraints, decl_constraints): Move to
+	pt.c to allow for garbage collection.
+	(processing_constraint): Kill this global.
+	(diagnose_*): Update diagnostics to use the new constraint
+	interface.
+	* gcc/cp/cp-objcp-common.c (cp_common_init_ts): Remove typing
+	of old nodes.
+	* gcc/cp/cp-tree.def: Add new nodes for requirements and
+	constraints. Remove previous constraint/req nodes.
+	gcc/cp/cp-tree.h (COMPOUND_REQ_NOEXCEPT_P): New.
+	(ICONV_CONSTR_EXPR, ICONV_CONSTR_TYPE): Fix operands.
+	(constraint_p, make_predicate_constraint_p, valid_constraints_p): New.
+	(misc): Remove unused declarations.
+	gcc/cp/cxx-pretty-print.c: Reorganize/rewrite for new constraint
+	model.
+	(primary_expression, expression): Remove unused nodes, add options 
+	for constraints
+	gcc/cp/cxx-pretty-print.h: Declare new functions for pretty
+	printing.
+	gcc/cp/decl.c (duplicate_decls): Only reclaim when flag_concepts
+	is on.
+	(grokfndecl): Associate predicate constraints.
+	gcc/cp/decl2.c (mark_used): Don't instantiate concepts.
+	gcc/cp/error.c (dump_expr): Handle new constraints.
+	gcc/cp/method.c (implicitly_declare_fn): Use new constraint
+	interface.
+	gcc/cp/parser.c (make_call_declarator): Pass a requires-clause for
+	call declarators.
+	(cp_parser_type_name): Take a flag to indicate the presence of
+	a pre-parsed 'typename'.
+	(cp_parser_requires_expression): Move sentinel into function.
+	(cp_parser_type_requirement): Parse type requirements in accordance
+	with Concepts TS.
+	(cp_parser_compound_requirement): Parse compound requirements in
+	accordance with Concepts TS. Remove constexpr requirements.
+	(cp_parser_template_declaration_after_export): Associate
+	predicate constraints.
+	gcc/cp/pt.c (get_template_for_ordering): New. Extract a template
+	decl from a list of candidates.
+	(lookup_template_class_1): Use new constraint interface.
+	(tsubst_pack_conjunction): Build an expression, not constraints.
+	(tsubst_decl): Only associate constraints when substituting
+	through members.
+	(tsubst): Kill subst rules for old nodes.
+	(most_specialized_partial_spec): Save candidates correctly
+	in the presence of constraints.
+	(always_instantiate_p): Never always instantiate a concept.
+	(type_dependent_expression_p): Requires expressions have type bool.
+	(decl_constraints): Moved from constraint.cc, use hash_table
+	instead of hash_map.
+	gcc/cp/semantics.c (finish_call_expr): Remove constraints from
+	functions, not overload sets.
+	(finish_template_variable): Evaluate variable concepts by
+	determining satisfaction.
+	gcc/cp/typeck.c (cp_build_function_call_vec): Use new concept 
+	interface.
+	gcc/cp/testsuite/g++.dg/concepts/*: Update tests to match syntax,
+	diagnostics.
+	gcc/cp/testsuite/g++.dg/concepts/req1.C: Test requires-expression
+	with no parens.
+
+2015-02-25  Braden Obrzut  <admin@maniacsvault.net>
+
+	* gcc/cp/constraint.cc (lift_operands): New.
+	(lift_call): Lift operands on function calls and don't use
+	tsubst_constraint_expr.
+	(lift_var): Don't use tsubst_constraint_expr.
+	(lift_constraints): Use the returned number of operands for most nodes
+	and also lift from TREE_LISTs.
+
+2015-02-17  Braden Obrzut  <admin@maniacsvault.net>
+
+	* gcc/cp/constraint.cc (lift_call): Converted from normalize_call.
+	(lift_var): Converted from normalize_var.
+	(lift_template_id): Converted from normalize_template_id.
+	(lift_constraints): Implemented.
+
+2015-02-16  Andrew Sutton  <andrew.n.sutton@gmail.com>
+
+	* gcc/cp/cp-tree.h: (EXPR_CONSTR_EXPR, TYPE_CONSTR_TYPE): Fix 
+	typos in macro names.
+	* gcc/cp/constraint.cc: (check_constraint*): New. Rewrite the
+	constraint checking implementation so that it matches the
+	wording and rules in n4377.
+
+2015-02-10  Andrew Sutton  <andrew.n.sutton@gmail.com>
+
+	* gcc/cp/logic.cc: Rewrite to use new constraint model and
+	update formatting.
+	* gcc/cp/constraint.cc: Documentation and organization.
+
+2015-02-10  Andrew Sutton  <andrew.n.sutton@gmail.com>
+
+	* gcc/cp/cp-tree.h (is_constraint): Make static.
+
+2015-02-09  Andrew Sutton  <andrew.n.sutton@gmail.com>
+
+	Rewrite normalization in terms of constraints.
+	* gcc/cp/cp-tree.h (is_constraint): New.
+	* gcc/cp/constraint.cc (normalize_*): Rewrite the previous normalization
+	model so that it conforms with the specification. Normalization applies
+	to constraints. Transformation of expressions into constraints now
+	happens in two phases: lifting concept definitions, and the actual
+	transformation.
+	(tranform_expression, xform_*): New. Define transformation of 
+	expressions into constraints.
+	(lift_constraints): New. Stubbed out inlining function.
+
+2015-02-09  Andrew Sutton  <andrew.n.sutton@gmail.com>
+
+	Start refactoring constraints to match the specification.
+	* gcc/cp/cp-tree.def: Add new TREECODEs for constraints.
+	* gcc/cp/cp-tree.h: Add accessor macros for constraint operands.
+
 2015-02-05  Braden Obrzut  <admin@maniacsvault.net>
 
 	* gcc/cp/constexpr.c (potential_constant_expression_1): Readded missing
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 576d31e..bf564e3 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -1994,17 +1994,16 @@ add_function_candidate (struct z_candidate **candidates,
       reason = arity_rejection (first_arg, i + remaining, len);
     }
 
-  // Second, a constrained function is not viable if its constraints are not
-  // satisfied.
-  if (viable && flag_concepts) {
-    if (tree ci = get_constraints (fn)) {
-      if (!check_constraints (ci))
+  /* Second, for a function to be viable, it's constraints must be
+     satisfied. */
+  if (flag_concepts && viable) 
+    {
+      if (!constraints_satisfied_p (fn))
         {
           reason = constraint_failure (fn);
           viable = false;
         }
     }
-  }
 
   /* When looking for a function from a subobject from an implicit
      copy/move constructor/operator=, don't consider anything that takes (a
@@ -4124,7 +4123,29 @@ build_new_function_call (tree fn, vec<tree, va_gc> **args, bool koenig_p,
          through flags so that later we can use it to decide whether to warn
          about peculiar null pointer conversion.  */
       if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
-        flags |= LOOKUP_EXPLICIT_TMPL_ARGS;
+        {
+          /* If overload resolution selects a specialization of a
+             function concept, the expression is true if the
+             constraints are satisfied and false otherwise. 
+
+             NOTE: This is an extension of Concepts Lite TS that
+             allows constraints to be used in expressions. */
+          if (flag_concepts)
+            {
+              tree tmpl = DECL_TI_TEMPLATE (cand->fn);
+              tree decl = DECL_TEMPLATE_RESULT (tmpl);
+              if (DECL_DECLARED_CONCEPT_P (decl))
+                {
+                  tree targs = DECL_TI_ARGS (cand->fn);
+                  tree eval = evaluate_function_concept (decl, targs);
+                  return eval;
+                }
+            }
+
+
+          flags |= LOOKUP_EXPLICIT_TMPL_ARGS;
+        }
+
       result = build_over_call (cand, flags, complain);
     }
 
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index ac2d444..27cd8da 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -7483,11 +7483,11 @@ resolve_address_of_overloaded_function (tree target_type,
 	    /* Instantiation failed.  */
 	    continue;
 
-          // Constraints must be satisfied. Note that this is done
-          // before return type deduction.
-          if (tree ci = get_constraints (instantiation))
-            if (!check_constraints (ci))
-                continue;
+          /* Constraints must be satisfied. This is done before
+             return type deduction since that instantiates the
+             declaration. */
+          if (flag_concepts && !constraints_satisfied_p (instantiation))
+            continue;
 
 	  /* And now force instantiation to do return type deduction.  */
 	  if (undeduced_auto_decl (instantiation))
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 606379a..1880879 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -2730,6 +2730,15 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	}
       break;
 
+    case REQUIRES_EXPR:
+      /* A requires-expression appearing as the initializer of
+         variable concept is evaluated as a constant expression.
+         We can't actually evaluate it because we've defined
+         those to be instantiation dependent. */
+      gcc_assert (processing_template_decl);
+      *non_constant_p = true;
+      return t;
+
     default:
       internal_error ("unexpected expression %qE of kind %s", t,
 		      get_tree_code_name (TREE_CODE (t)));
@@ -3022,12 +3031,6 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags)
     case USING_DECL:
     case PLACEHOLDER_EXPR:
     case REQUIRES_EXPR:
-    case EXPR_REQ:
-    case TYPE_REQ:
-    case NESTED_REQ:
-    case VALIDEXPR_EXPR:
-    case VALIDTYPE_EXPR:
-    case CONSTEXPR_EXPR:
       return true;
 
     case AGGR_INIT_EXPR:
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index a69e717..1d758de 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -36,48 +36,69 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-iterator.h"
 #include "vec.h"
 #include "target.h"
-#include "bitmap.h"
-#include "hash-map.h"
+#include "hash-table.h"
 
-// -------------------------------------------------------------------------- //
-// Requirement Construction
-//
-// Facilities for building and manipulating template requirements.
-//
-// TODO: Simply assigning boolean_type_node to the result type of the
-// expression seems right for constraints, but in the long-term we might want
-// to be more flexible (i.e., allow some form of overload resolution?).
+/*---------------------------------------------------------------------------
+                       Operations on constraints
+---------------------------------------------------------------------------*/
 
-// Create a new logical node joining the subexpressions a and b.
-static inline tree
-join_requirements (tree_code c, tree a, tree b)
+/* Returns true if C is a constraint tree code. */
+static inline bool
+constraint_p (tree_code c)
 {
-  gcc_assert (a != NULL_TREE && b != NULL_TREE);
-  gcc_assert (c == TRUTH_ANDIF_EXPR || c == TRUTH_ORIF_EXPR);
-  return build_min (c, boolean_type_node, a, b);
+  return PRED_CONSTR <= c && c <= DISJ_CONSTR;
 }
 
-// Returns the conjunction of two requirements A and B, where A and B are
-// reduced terms in the constraints language. Note that conjoining a non-null
-// expression with  NULL_TREE is an identity operation. That is, for
-// non-null A,
-//
-//    conjoin_constraints(a, NULL_TREE) == a
-//
-// If both A and B are NULL_TREE, the result is also NULL_TREE.
+/* Returns true if T is a constraint. */
+bool
+constraint_p (tree t)
+{
+  return constraint_p (TREE_CODE (t));
+}
+
+/* Returns true if T can be used as  a predicate constraint. */
+static inline bool
+valid_predicate_p (tree t)
+{
+  return CONSTANT_CLASS_P (t) || EXPR_P (t) || t == error_mark_node;
+}
+
+/* Make a predicate constraint from the given expression. */
+tree
+make_predicate_constraint (tree expr)
+{
+  if (!valid_predicate_p (expr))
+    debug_tree (expr);
+  gcc_assert(valid_predicate_p (expr));
+  return build_nt (PRED_CONSTR, expr);
+}
+
+/* Returns the conjunction of two constraints A and B. Note that 
+   conjoining a non-null constraint with NULL_TREE is an identity 
+   operation. That is, for non-null A,
+
+      conjoin_constraints(a, NULL_TREE) == a
+
+   and
+
+      conjoin_constraints (NULL_TREE, a) == a
+
+   If both A and B are NULL_TREE, the result is also NULL_TREE. */
 tree
 conjoin_constraints (tree a, tree b)
 {
+  gcc_assert (a ? constraint_p (a) : true);
+  gcc_assert (b ? constraint_p (b) : true);
   if (a)
-    return b ? join_requirements (TRUTH_ANDIF_EXPR, a, b) : a;
+    return b ? build_nt (CONJ_CONSTR, a, b) : a;
   else if (b)
     return b;
   else
     return NULL_TREE;
 }
 
-// Transform the list of expressions in the T into a conjunction
-// of requirements. T must be a TREE_VEC.
+/* Transform the vector of expressions in the T into a conjunction
+   of requirements. T must be a TREE_VEC. */
 tree
 conjoin_constraints (tree t)
 {
@@ -88,18 +109,18 @@ conjoin_constraints (tree t)
   return r;
 }
 
+/*---------------------------------------------------------------------------
+                    Resolution of qualified concept names
+---------------------------------------------------------------------------*/
 
-// -------------------------------------------------------------------------- //
-// Constraint Resolution
-//
-// This facility is used to resolve constraint checks from requirement
-// expressions. A constraint check is a call to a function template declared
-// with the keyword 'concept'.
-//
-// The result of resolution is a pair (a TREE_LIST) whose value is the
-// matched declaration, and whose purpose contains the coerced template
-// arguments that can be substituted into the call.
+/* This facility is used to resolve constraint checks from 
+   requirement expressions. A constraint check is a call to 
+   a function template declared with the keyword 'concept'.
 
+   The result of resolution is a pair (a TREE_LIST) whose value 
+   is the matched declaration, and whose purpose contains the 
+   coerced template arguments that can be substituted into the 
+   call.  */
 
 // Given an overload set OVL, try to find a unique definition that can be
 // instantiated by the template arguments ARGS.
@@ -169,7 +190,7 @@ resolve_constraint_check (tree call)
 
   // A constraint check must be only a template-id expression. If
   // it's a call to a base-link, its function(s) should be a
-  // template-id expressson. If this is not a template-id, then it
+  // template-id expression. If this is not a template-id, then it
   // cannot be a concept-check.
   tree target = CALL_EXPR_FN (call);
   if (BASELINK_P (target))
@@ -180,13 +201,21 @@ resolve_constraint_check (tree call)
   // Get the overload set and template arguments and try to
   // resolve the target.
   tree ovl = TREE_OPERAND (target, 0);
+  
+  /* This is a function call of a variable concept... ill-formed. */
+  if (TREE_CODE (ovl) == TEMPLATE_DECL)
+    {
+      error ("function call of variable concept %qE", call);
+      return error_mark_node;
+    }
+
   tree args = TREE_OPERAND (target, 1);
   return resolve_constraint_check (ovl, args);
 }
 
 // Given a call expression or template-id expression to a concept, EXPR,
 // possibly including a placeholder argument, deduce the concept being checked
-// and the prototype paraemter.  Returns true if the constraint and prototype
+// and the prototype parameter.  Returns true if the constraint and prototype
 // can be deduced and false otherwise. Note that the CHECK and PROTO arguments
 // are set to NULL_TREE if this returns false.
 bool
@@ -205,7 +234,8 @@ deduce_constrained_parameter (tree expr, tree& check, tree& proto)
   else if (TREE_CODE (expr) == CALL_EXPR)
     {
       // Resolve the constraint check to deduce the prototype parameter.
-      if (tree info = resolve_constraint_check (expr))
+      tree info = resolve_constraint_check (expr);
+      if (info && info != error_mark_node)
         {
           // Get function and argument from the resolved check expression and
           // the prototype parameter. Note that if the first argument was a
@@ -247,7 +277,8 @@ deduce_concept_introduction (tree expr)
   else if (TREE_CODE (expr) == CALL_EXPR)
     {
       // Resolve the constraint check and return arguments.
-      if (tree info = resolve_constraint_check (expr))
+      tree info = resolve_constraint_check (expr);
+      if (info && info != error_mark_node)
         return TREE_PURPOSE (info);
       return NULL_TREE;
     }
@@ -255,496 +286,565 @@ deduce_concept_introduction (tree expr)
     gcc_unreachable ();
 }
 
+namespace {
+
+/*---------------------------------------------------------------------------
+                       Lifting of concept definitions
+---------------------------------------------------------------------------*/
 
-// -------------------------------------------------------------------------- //
-// Declarations
+tree lift_constraints (tree);
 
-// Check that FN satisfies the structural requirements of a
-// function concept definition.
+/* If the tree T has operands, then lift any concepts out of them.  */
 tree
-check_function_concept (tree fn)
+lift_operands (tree t)
 {
-  location_t loc = DECL_SOURCE_LOCATION (fn);
+  if (int n = tree_operand_length (t))
+    {
+      t = copy_node (t);
+      for (int i = 0; i < n; ++i)
+        TREE_OPERAND (t, i) = lift_constraints (TREE_OPERAND (t, i));
+    }
+  return t;
+}
 
-  // Check that the function is comprised of only a single
-  // return statement.
+/* Inline a function (concept) definition by substituting
+   ARGS into its body. */
+tree
+lift_function_definition (tree fn, tree args)
+{
+  /* Extract the body of the function minus the return expression.  */
   tree body = DECL_SAVED_TREE (fn);
+  if (!body)
+    return error_mark_node;
   if (TREE_CODE (body) == BIND_EXPR)
     body = BIND_EXPR_BODY (body);
-
-  // Sometimes a function call results in the creation of clean up
-  // points. Allow these to be preserved in the body of the
-  // constraint, as we might actually need them for some constexpr
-  // evaluations.
-  if (TREE_CODE (body) == CLEANUP_POINT_EXPR)
-    body = TREE_OPERAND (body, 0);
-
+  
+  /* FIXME: Why isn't this being checked at the point of definition? */
   if (TREE_CODE (body) != RETURN_EXPR)
-    error_at (loc, "function concept definition %qD has multiple statements",
-              fn);
-
-  return NULL_TREE;
-}
+    {
+      error_at (DECL_SOURCE_LOCATION (fn),
+                "concept definition %qD has multiple statements", fn);
+      return error_mark_node;
+    }
 
+  gcc_assert (TREE_CODE (body) == RETURN_EXPR);
+  body = TREE_OPERAND (body, 0);
 
-// -------------------------------------------------------------------------- //
-// Normalization
-//
-// Normalize a template requirement to a logical formula written in terms of
-// atomic propositions, returing the new expression.  If the expression cannot
-// be normalized, a NULL_TREE is returned.
+  /* Substitute template arguments to produce our inline expression.  */
+  tree result = tsubst_expr (body, args, tf_none, NULL_TREE, false);
+  if (result == error_mark_node)
+    return error_mark_node;
 
-namespace {
+  return lift_constraints (result);
+}
 
-// Helper functions
-tree normalize_constraints (tree);
-tree normalize_node (tree);
-tree normalize_expr (tree);
-tree normalize_stmt (tree);
-tree normalize_decl (tree);
-tree normalize_misc (tree);
-tree normalize_logical (tree);
-tree normalize_call (tree);
-tree normalize_requires (tree);
-tree normalize_expr_req (tree);
-tree normalize_type_req (tree);
-tree normalize_nested_req (tree);
-tree normalize_var (tree);
-tree normalize_cleanup_point (tree);
-tree normalize_template_id (tree);
-tree normalize_atom (tree);
-
-// Reduce the requirement T into a logical formula written in terms of
-// atomic propositions.
+/* Inline a reference to a function concept.  */
 tree
-normalize_node (tree t)
+lift_call (tree t)
 {
-  switch (TREE_CODE_CLASS (TREE_CODE (t)))
-    {
-    case tcc_unary:
-    case tcc_binary:
-    case tcc_expression:
-    case tcc_vl_exp:
-      return normalize_expr (t);
-
-    case tcc_statement:
-      return normalize_stmt (t);
-
-    case tcc_declaration:
-      return normalize_decl (t);
-
-    case tcc_exceptional:
-      return normalize_misc (t);
-
-    // These kinds of expressions are atomic.
-    case tcc_constant:
-    case tcc_reference:
-    case tcc_comparison:
-      return t;
+  /* Try to resolve this function call as a concept.  If not, then 
+     it can be returned as-is.  */
+  tree check = resolve_constraint_check (t);
+  if (!check)
+      return lift_operands (t);
+  if (check == error_mark_node)
+    return error_mark_node;
 
-    default:
-      gcc_unreachable ();
-    }
-  return NULL_TREE;
+  tree fn = TREE_VALUE (check);
+  tree args = TREE_PURPOSE (check);
+  return lift_function_definition (fn, args);
 }
 
-// Reduction rules for the expression node T.
 tree
-normalize_expr (tree t)
+lift_variable_initializer (tree var, tree args)
 {
-  switch (TREE_CODE (t))
-    {
-    case TRUTH_ANDIF_EXPR:
-    case TRUTH_ORIF_EXPR:
-      return normalize_logical (t);
-
-    case CALL_EXPR:
-      return normalize_call (t);
-
-    case REQUIRES_EXPR:
-      return normalize_requires (t);
-
-    case EXPR_REQ:
-      return normalize_expr_req (t);
-
-    case TYPE_REQ:
-      return normalize_type_req (t);
-
-    case NESTED_REQ:
-      return normalize_nested_req (t);
-
-    case TEMPLATE_ID_EXPR:
-      return normalize_template_id (t);
-
-    case BIND_EXPR:
-      return normalize_node (BIND_EXPR_BODY (t));
+  /* Extract the body from the variable initializer.  */
+  tree init = DECL_INITIAL (var);
+  if (!init)
+    return error_mark_node;
 
-    case CLEANUP_POINT_EXPR:
-      return normalize_cleanup_point (t);
+  /* Substitute the arguments to form our new inline expression.  */
+  tree result = tsubst_expr (init, args, tf_none, NULL_TREE, false);
+  if (result == error_mark_node)
+    return error_mark_node;
 
-    // Do not recurse.
-    case TAG_DEFN:
-      return NULL_TREE;
+  return lift_constraints (result);
+}
 
-    // Everything else is atomic.
-    default:
-      return normalize_atom (t);
-    }
+/* Inline a reference to a variable concept.  */
+tree
+lift_var (tree t)
+{
+  tree tmpl = TREE_OPERAND (t, 0);
+  tree args = TREE_OPERAND (t, 1);
+  tree decl = DECL_TEMPLATE_RESULT (tmpl);
+  if (!DECL_DECLARED_CONCEPT_P (decl))
+    return t;
+  return lift_variable_initializer (decl, args);
 }
 
-// Reduction rules for the statement T.
+/* Determine if a template-id is a variable concept and inline.  */
 tree
-normalize_stmt (tree t)
+lift_template_id (tree t)
 {
-  switch (TREE_CODE (t))
-    {
-    // Reduce the returned expression.
-    case RETURN_EXPR:
-      return normalize_node (TREE_OPERAND (t, 0));
+  if (variable_concept_p (TREE_OPERAND (t, 0)))
+    return lift_var (t);
 
-    // These statements do not introduce propositions
-    // in the constraints language. Do not recurse.
-    case DECL_EXPR:
-    case USING_STMT:
-      return NULL_TREE;
+  /* Check that we didn't refer to a function concept like
+      a variable.
 
-    default:
-      gcc_unreachable ();
+     TODO: Add a note on how to fix this.  */
+  tree tmpl = TREE_OPERAND (t, 0);
+  if (TREE_CODE (tmpl) == OVERLOAD)
+    {
+      tree fn = OVL_FUNCTION (tmpl);
+      if (TREE_CODE (fn) == TEMPLATE_DECL 
+          && DECL_DECLARED_CONCEPT_P (DECL_TEMPLATE_RESULT (fn)))
+        {
+          error ("invalid reference to function concept %qD", fn);
+          return error_mark_node;
+        }
     }
-  return NULL_TREE;
+
+  return t;
 }
 
-// Reduction rules for the declaration T.
+/* Lift any constraints appearing in a nested requirement of
+   a requires-expression. */
 tree
-normalize_decl (tree t)
+lift_requires_expr (tree t)
 {
-  switch (TREE_CODE (t))
+  tree parms = TREE_OPERAND (t, 0);
+  tree reqs = TREE_OPERAND (t, 1);
+  tree result = NULL_TREE;
+  for (; reqs != NULL_TREE; reqs = TREE_CHAIN (reqs))
     {
-    // References to var decls are atomic.
-    case VAR_DECL:
-      return t;
-
-    default:
-      gcc_unreachable ();
+      tree req = TREE_VALUE (reqs);
+      if (TREE_CODE (req) == NESTED_REQ)
+        {
+          tree expr = lift_constraints (TREE_OPERAND (req, 0));
+          req = finish_nested_requirement (expr);
+        }
+      result = tree_cons (NULL_TREE, req, result);
     }
-  return NULL_TREE;
+  return finish_requires_expr (parms, result);
 }
 
-// Reduction rules for the node T.
-tree
-normalize_misc (tree t)
+/* Inline references to specializations of concepts.  */
+tree 
+lift_constraints (tree t)
 {
+  if (t == NULL_TREE)
+    return NULL_TREE;
+  
+  if (t == error_mark_node)
+    return error_mark_node;
+
+  /* Concepts can be referred to by call or variable. All other
+     nodes are preserved.  */
   switch (TREE_CODE (t))
     {
-    // All of these are atomic.
-    case ERROR_MARK:
-    case TRAIT_EXPR:
-    case CONSTRUCTOR:
-      return t;
+    case CALL_EXPR:
+      return lift_call (t);
+    
+    case TEMPLATE_ID_EXPR:
+      return lift_template_id (t);
+    
+    case REQUIRES_EXPR:
+      return lift_requires_expr (t);
 
-    // This should have been caught as an error.
-    case STATEMENT_LIST:
-      return NULL_TREE;
+    case TREE_LIST:
+      {
+        t = copy_node (t);
+        TREE_VALUE (t) = lift_constraints (TREE_VALUE (t));
+        TREE_CHAIN (t) = lift_constraints (TREE_CHAIN (t));
+        return t;
+      }
 
     default:
-      gcc_unreachable ();
+      return lift_operands (t);
     }
-  return NULL_TREE;
 }
 
-// Check that the logical expression is not a user-defined operator.
+/*---------------------------------------------------------------------------
+                        Constraint normalization
+---------------------------------------------------------------------------*/
+
+tree transform_expression (tree);
+
+/* Check that the logical-or or logical-and expression does
+   not result in a call to a user-defined user-defined operator 
+   (temp.constr.op). Returns true if the logical operator is 
+   admissible and false otherwise. */
 bool
-check_logical (tree t)
+check_logical_expr (tree t) 
 {
-  // We can't do much for type dependent expressions.
-  if (type_dependent_expression_p (t) || value_dependent_expression_p (t))
+  /* We can't do much for type dependent expressions. */
+  if (type_dependent_expression_p (t))
     return true;
 
-  // Resolve the logical operator. Note that template processing is
-  // disabled so we get the actual call or target expression back.
-  // not_processing_template_sentinel sentinel;
+  /* Resolve the logical operator. Note that template processing is
+     disabled so we get the actual call or target expression back.
+     not_processing_template_sentinel sentinel. */
   tree arg1 = TREE_OPERAND (t, 0);
   tree arg2 = TREE_OPERAND (t, 1);
-
   tree ovl = NULL_TREE;
-  tree expr = build_new_op (input_location, TREE_CODE (t), LOOKUP_NORMAL,
-                            arg1, arg2, /*arg3*/NULL_TREE,
+  tree expr = build_new_op (input_location, TREE_CODE (t), LOOKUP_NORMAL, 
+                            arg1, arg2, /*arg3*/NULL_TREE, 
                             &ovl, tf_none);
   if (TREE_CODE (expr) != TREE_CODE (t))
     {
       error ("user-defined operator %qs in constraint %qE",
              operator_name_info[TREE_CODE (t)].name, t);
-      ;
       return false;
     }
   return true;
 }
 
-// Reduction rules for the binary logical expression T (&& and ||).
-//
-// Generate a new expression from the reduced operands. If either operand
-// cannot be reduced, then the resulting expression is null.
+/* Transform a logical-or or logical-and expression into either
+   a conjunction or disjunction. */
 tree
-normalize_logical (tree t)
+xform_logical (tree t, tree_code c)
 {
-  if (!check_logical (t))
-    return NULL_TREE;
+  if (!check_logical_expr (t))
+    return error_mark_node;
+  tree t0 = transform_expression (TREE_OPERAND (t, 0));
+  tree t1 = transform_expression (TREE_OPERAND (t, 1));
+  return build_nt (c, t0, t1);
+}
 
-  tree l = normalize_expr (TREE_OPERAND (t, 0));
-  tree r = normalize_expr (TREE_OPERAND (t, 1));
-  if (l && r)
-    {
-      tree result = copy_node (t);
-      SET_EXPR_LOCATION (result, EXPR_LOCATION (t));
-      TREE_OPERAND (result, 0) = l;
-      TREE_OPERAND (result, 1) = r;
-      return result;
-    }
-  else
-    return NULL_TREE;
+/* A simple requirement T introduces an expression constraint
+   for its expression. */
+inline tree
+xform_simple_requirement (tree t)
+{
+  return build_nt (EXPR_CONSTR, TREE_OPERAND (t, 0));
 }
 
-// Do a cursory investigation of the target in the call expression
-// with the aim of early diagnosis of ill-formed constraints.
-inline bool
-check_call (tree t)
+/* A type requirement T introduce a type constraint for its
+   type. */
+inline tree
+xform_type_requirement (tree t)
 {
-  tree target = CALL_EXPR_FN (t);
-  if (TREE_CODE (target) != TEMPLATE_ID_EXPR)
-    return true;
-  tree tmpl = TREE_OPERAND (target, 0);
-  if (TREE_CODE (tmpl) != TEMPLATE_DECL)
-    return true;
-  tree decl = DECL_TEMPLATE_RESULT (tmpl);
-  if (TREE_CODE (decl) == VAR_DECL && DECL_DECLARED_CONCEPT_P (decl))
-    {
-      error ("invalid constraint %qE", t);
-      inform (input_location, "did you mean %qE", target);
-      return false;
-    }
-  return true;
+  return build_nt (TYPE_CONSTR, TREE_OPERAND (t, 0));
 }
 
-// Reduction rules for the call expression T.
-//
-// If T is a call to a constraint instantiate its definition and
-// recursively reduce its returned expression.
+/* A compound requirement T introduces a conjunction of constraints
+   depending on its form. The conjunction always includes
+   an expression constraint for the expression of the requirement.
+   If a trailing return type was specified, the conjunction includes
+   either an implicit conversion constraint or an argument
+   deduction constraint. If the noexcept specifier is present, the
+   conjunction includes an exception constraint. */
 tree
-normalize_call (tree t)
+xform_compound_requirement (tree t)
 {
-  if (!check_call (t))
-    return NULL_TREE;
+  tree expr = TREE_OPERAND (t, 0);
+  tree constr = build_nt (EXPR_CONSTR, TREE_OPERAND (t, 0));
 
-  // Is the function call actually a constraint check? If not, then it's
-  // an atom, and needs to be treated as such.
-  tree check = resolve_constraint_check (t);
-  if (!check)
-    return normalize_atom (t);
-
-  tree fn = TREE_VALUE (check);
-  tree args = TREE_PURPOSE (check);
+  /* If a type is given, append an implicit conversion or
+     argument deduction constraint. 
 
-  // Normalize the body of the function into the constraints language.
-  tree body = normalize_constraints (DECL_SAVED_TREE (fn));
-  if (!body)
-    return error_mark_node;
+     FIXME: Handle argument deduction constraints. */
+  if (tree type = TREE_OPERAND (t, 1)) 
+    {
+      tree iconv = build_nt (ICONV_CONSTR, expr, type);
+      constr = conjoin_constraints (constr, iconv);
+    }
 
-  // Instantiate the reduced results using the deduced args.
-  tree result = tsubst_constraint_expr (body, args, true);
-  if (result == error_mark_node)
-    return error_mark_node;
+  /* If noexcept is present, append an exception constraint. */
+  if (COMPOUND_REQ_NOEXCEPT_P (t))
+    {
+      tree except = build_nt (EXCEPT_CONSTR, expr);
+      constr = conjoin_constraints (constr, except);
+    }
 
-  return result;
+  return constr;
 }
 
-// Reduction rules for a variable template-id T.
-//
-// If T is a constraint, instantiate its initializer and recursively reduce its
-// expression.
-tree
-normalize_var (tree t)
+/* A nested requirement T introduces a conjunction of constraints
+   corresponding to its constraint-expression. */
+inline tree
+xform_nested_requirement (tree t)
 {
-  tree decl = DECL_TEMPLATE_RESULT (TREE_OPERAND (t, 0));
-  if (!DECL_DECLARED_CONCEPT_P (decl))
-    return t;
-
-  // Reduce the initializer of the variable into the constraints language.
-  tree body = normalize_constraints (DECL_INITIAL (decl));
-  if (!body)
-    return error_mark_node;
+  return transform_expression (TREE_OPERAND (t, 0));
+}
 
-  // Instantiate the reduced results.
-  tree result = tsubst_constraint_expr (body, TREE_OPERAND (t, 1), false);
-  if (result == error_mark_node)
-    return error_mark_node;
+/* Transform a requirement T into one or more constraints. */
+tree 
+xform_requirement (tree t)
+{
+  switch (TREE_CODE (t))
+  {
+  case SIMPLE_REQ:
+    return xform_simple_requirement (t);
+  
+  case TYPE_REQ:
+    return xform_type_requirement (t);
+  
+  case COMPOUND_REQ:
+    return xform_compound_requirement (t);
+  
+  case NESTED_REQ:
+    return xform_nested_requirement (t);
+
+  default:
+    gcc_unreachable ();
+  }
+  return error_mark_node;
+}
 
+/* Transform a sequence of requirements into a conjunction of
+   constraints. */
+tree
+xform_requirements (tree t)
+{
+  tree result = NULL_TREE;
+  for (; t; t = TREE_CHAIN (t)) {
+    tree constr = xform_requirement (TREE_VALUE (t));
+    result = conjoin_constraints (result, constr);
+  }
   return result;
 }
 
-// Reduction rules for the template-id T.
-//
-// It turns out that we often get requirements being written like this:
-//
-//    template<typename T>
-//      requires Foo<T>
-//    void f()
-//
-// Where Foo<T> should actually be written as Foo<T>(). Generate an
-// error and suggest the improved writing.
+/* Transform a requires-expression into a parameterized constraint. */
 tree
-normalize_template_id (tree t)
+xform_requires_expr (tree t)
 {
-  tree tmpl = TREE_OPERAND (t, 0);
-  if (variable_concept_p (tmpl))
-    return normalize_var (t);
+  tree operand = xform_requirements (TREE_OPERAND (t, 1));
+  if (tree parms = TREE_OPERAND (t, 0))
+    return build_nt (PARM_CONSTR, parms, operand);
   else
-    {
-      location_t locus = EXPR_LOC_OR_LOC (t, input_location);
-      error_at (locus, "invalid constraint %qE", t);
-
-      vec<tree, va_gc>* args = NULL;
-      tree c = finish_call_expr (t, &args, true, false, 0);
-      inform (locus, "did you mean %qE", c);
-
-      return error_mark_node;
-    }
+    return operand;
 }
 
-// Reduce an expression requirement as a conjunction of its
-// individual constraints.
+/* Transform an expression into an atomic predicate constraint. 
+    After substitution, the expression of a predicate constraint shall 
+    have type bool (temp.constr.pred). For non-type- dependent 
+    expressions, we can check that now. */
 tree
-normalize_expr_req (tree t)
+xform_atomic (tree t) 
 {
-  tree r = NULL_TREE;
-  for (tree l = TREE_OPERAND (t, 0); l; l = TREE_CHAIN (l))
-    r = conjoin_constraints (r, normalize_expr (TREE_VALUE (l)));
-  return r;
+  if (!type_dependent_expression_p (t)) 
+  {
+    tree type = cv_unqualified (TREE_TYPE (t));
+    if (!same_type_p (type, boolean_type_node))
+      {
+        error ("predicate constraint %qE does not have type %<bool%>", t);
+        return error_mark_node;
+      }
+  }
+  return build_nt (PRED_CONSTR, t);
 }
 
-// Reduce a type requirement by returning its underlying
-// constraint.
+/* Transform an expression into a constraint. */
 tree
-normalize_type_req (tree t)
+xform_expr (tree t)
 {
-  return TREE_OPERAND (t, 0);
+  switch (TREE_CODE (t))
+    {
+    case TRUTH_ANDIF_EXPR:
+      return xform_logical (t, CONJ_CONSTR);
+    
+    case TRUTH_ORIF_EXPR:
+      return xform_logical (t, DISJ_CONSTR);
+    
+    case REQUIRES_EXPR:
+      return xform_requires_expr (t);
+    
+    case BIND_EXPR:        
+      return transform_expression (BIND_EXPR_BODY (t));
+    
+    default:
+      /* All other constraints are atomic. */ 
+      return xform_atomic (t);
+    }
 }
 
-// Reduce a nested requirement by returning its only operand.
+/* Transform a statement into an expression. */
 tree
-normalize_nested_req (tree t)
+xform_stmt (tree t)
 {
-  return TREE_OPERAND (t, 0);
+  switch (TREE_CODE (t))
+    {
+    case RETURN_EXPR:
+      return transform_expression (TREE_OPERAND (t, 0));
+    default:
+      gcc_unreachable ();
+    }
+  return error_mark_node;
 }
 
-// Reduce a requires expr by reducing each requirement in turn,
-// rewriting the list of requirements so that we end up with a
-// list of expressions, some of which may be conjunctions.
+// Reduction rules for the declaration T.
 tree
-normalize_requires (tree t)
+xform_decl (tree t)
 {
-  for (tree l = TREE_OPERAND (t, 1); l; l = TREE_CHAIN (l))
-    TREE_VALUE (l) = normalize_expr (TREE_VALUE (l));
-  return t;
+  switch (TREE_CODE (t))
+    {
+    case VAR_DECL:
+      return xform_atomic (t);
+    default:
+      gcc_unreachable ();
+    }
+  return error_mark_node;
 }
 
-// Normalize a cleanup point by normalizing the underlying
-// expression.
+/* Transform an exceptional node into a constraint. */
 tree
-normalize_cleanup_point (tree t)
+xform_misc (tree t)
 {
-  return normalize_node (TREE_OPERAND (t, 0));
+  switch (TREE_CODE (t))
+    {
+    case TRAIT_EXPR:
+      return xform_atomic (t);
+    case CONSTRUCTOR:
+      return xform_atomic (t);
+    default:
+      gcc_unreachable ();
+    }
+  return error_mark_node;
 }
 
-// Normalize an atomic expression by performing some basic checks.
-// In particular, if the type is known, it must be convertible to
-// bool.
+
+/* Transform a lifted expression into a constraint. This either
+   returns a constraint, or it returns error_mark_node when
+   a constraint cannot be formed. */
 tree
-normalize_atom (tree t)
+transform_expression (tree t)
 {
-  if (!type_dependent_expression_p (t))
-    if (!can_convert (boolean_type_node, TREE_TYPE (t), tf_none))
-      {
-        error ("predicate constraint %qE is not convertible to %<bool%>", t);
-        return NULL_TREE;
-      }
-  return t;
-}
-
-// Reduce the requirement REQS into a logical formula written in terms of
-// atomic propositions.
-tree
-normalize_constraints (tree reqs)
-{
-  if (!reqs)
+  if (!t) 
     return NULL_TREE;
-
-  ++processing_template_decl;
-  tree expr = normalize_node (reqs);
-  --processing_template_decl;
-
-  // If we couldn't normalize, then these constraints are ill-formed.
-  if (!expr)
+ 
+  if (t == error_mark_node)
     return error_mark_node;
 
-  return expr;
+  switch (TREE_CODE_CLASS (TREE_CODE (t))) 
+    {
+    case tcc_unary:
+    case tcc_binary:
+    case tcc_expression:
+    case tcc_vl_exp:
+      return xform_expr (t);
+    
+    case tcc_statement:   
+      return xform_stmt (t);
+    
+    case tcc_declaration: 
+      return xform_decl (t);
+    
+    case tcc_exceptional: 
+      return xform_misc (t);
+    
+    case tcc_constant:
+    case tcc_reference:
+    case tcc_comparison:
+      /* These are atomic predicate constraints. */
+      return xform_atomic (t);
+
+    default:
+      /* Unhandled node kind. */
+      gcc_unreachable ();
+    }
+  return error_mark_node;
 }
 
-} // end namespace
+/*---------------------------------------------------------------------------
+                        Constraint normalization
+---------------------------------------------------------------------------*/
 
+tree normalize_constraint (tree);
 
-// -------------------------------------------------------------------------- //
-// Constraint Semantic Processing
-//
-// The following functions are called by the parser and substitution rules
-// to create and evaluate constraint-related nodes.
+/* The normal form of the disjunction T0 /\ T1 is the conjunction
+   of the normal form of T0 and the normal form of T1 */
+inline tree
+normalize_conjunction (tree t)
+{
+  tree t0 = normalize_constraint (TREE_OPERAND (t, 0));
+  tree t1 = normalize_constraint (TREE_OPERAND (t, 1));
+  return build_nt (CONJ_CONSTR, t0, t1);
+}
+
+/* The normal form of the disjunction T0 \/ T1 is the disjunction 
+   of the normal form of T0 and the normal form of T1 */
+inline tree
+normalize_disjunction (tree t)
+{
+  tree t0 = normalize_constraint (TREE_OPERAND (t, 0));
+  tree t1 = normalize_constraint (TREE_OPERAND (t, 1));
+  return build_nt (DISJ_CONSTR, t0, t1);
+}
 
-// A 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;
+/* A predicate constraint is normalized in two stages. First all
+   references specializations of concepts are replaced by their
+   substituted definitions. Then, the resulting expression is
+   transformed into a constraint by transforming && expressions
+   into conjunctions and || into disjunctions. */
+tree 
+normalize_predicate_constraint (tree t)
+{
+  tree expr = PRED_CONSTR_EXPR (t);
+  tree lifted = lift_constraints (expr);
+  tree constr = transform_expression (lifted);
+  return constr;
+}
 
-// Returns the template constraints of declaration T. If T is not
-// constrained, return NULL_TREE. Note that T must be non-null.
+/* The normal form of a parameterized constraint is the normal
+   form of its operand. */
 tree
-get_constraints (tree t)
+normalize_parameterized_constraint (tree t)
 {
-  gcc_assert (DECL_P (t));
-  if (TREE_CODE (t) == TEMPLATE_DECL)
-    t = DECL_TEMPLATE_RESULT (t);
-  if (tree *r = decl_constraints.get (t))
-    return *r;
-  else
-    return NULL_TREE;
+  tree parms = PARM_CONSTR_PARMS (t);
+  tree operand = normalize_constraint (PARM_CONSTR_OPERAND (t));
+  return build_nt (PARM_CONSTR, parms, operand);
 }
 
-// Associate the given constraint information with the declaration. Don't
-// build associations if ci is NULL_TREE.
-void
-set_constraints (tree t, tree ci)
+/* Normalize the constraint T by reducing it so that it is
+   comprised of only conjunctions and disjunctions of atomic
+   constraints. */
+tree
+normalize_constraint (tree t)
 {
-  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);
+  if (!t)
+    return NULL_TREE;
+  
+  switch (TREE_CODE (t))
+    {
+      case CONJ_CONSTR:
+        return normalize_conjunction (t);
+      
+      case DISJ_CONSTR:
+        return normalize_disjunction (t);
+      
+      case PRED_CONSTR:
+        return normalize_predicate_constraint (t);
+      
+      case PARM_CONSTR:
+        return normalize_parameterized_constraint (t);
+      
+      case EXPR_CONSTR:
+      case TYPE_CONSTR:
+      case ICONV_CONSTR:
+      case DEDUCT_CONSTR:
+      case EXCEPT_CONSTR:
+        /* These constraints are defined to be atomic. */
+        return t;
+      
+      default:
+        /* CONSTR was not a constraint. */
+        gcc_unreachable();
+    }
+  return error_mark_node;
 }
 
-// Remove the associated constraints of the declaration T. 
+} /* namespace */
+
+
+// -------------------------------------------------------------------------- //
+// Constraint Semantic Processing
 //
-// 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));
-  if (TREE_CODE (t) == TEMPLATE_DECL)
-    t = DECL_TEMPLATE_RESULT (t);
+// The following functions are called by the parser and substitution rules
+// to create and evaluate constraint-related nodes.
 
-  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
@@ -785,22 +885,6 @@ associate_classtype_constraints (tree type)
   return type;
 }
 
-// Returns a conjunction of shorthand requirements for the template
-// parameter list PARMS. Note that the requirements are stored in
-// the TYPE of each tree node.
-tree
-get_shorthand_constraints (tree parms)
-{
-  tree reqs = NULL_TREE;
-  parms = INNERMOST_TEMPLATE_PARMS (parms);
-  for (int i = 0; i < TREE_VEC_LENGTH (parms); ++i)
-    {
-      tree parm = TREE_VEC_ELT (parms, i);
-      reqs = conjoin_constraints (reqs, TEMPLATE_PARM_CONSTRAINTS (parm));
-    }
-  return reqs;
-}
-
 namespace {
 
 // Create an empty constraint info block.
@@ -812,274 +896,35 @@ build_constraint_info ()
 
 } // namespace
 
-// 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).
-//
-// If the declaration has neither template nor declaration requirements
-// this returns NULL_TREE, indicating an unconstrained declaration.
-tree
-build_constraints (tree tr, tree dr)
-{
-  if (!tr && !dr)
-    return NULL_TREE;
-  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.
-// This is the case when the associated requirements can be successfully
-// decomposed into lists of atomic constraints.
-bool
-valid_requirements_p (tree cinfo)
-{
-  gcc_assert (cinfo);
-  return CI_ASSUMPTIONS (cinfo) != error_mark_node;
-}
-
-// Constructs a REQUIRES_EXPR with parameters, PARMS, and requirements, REQS,
-// that can be evaluated as a constant expression.
-tree
-build_requires_expr (tree parms, tree reqs)
-{
-  // Modify the declared parameters by removing their context (so they
-  // don't refer to the enclosing scope), and marking them constant (so
-  // we can actually check constexpr properties).
-  for (tree p = parms; p && !VOID_TYPE_P (TREE_VALUE (p)); p = TREE_CHAIN (p))
-    {
-      tree parm = TREE_VALUE (p);
-      DECL_CONTEXT (parm) = NULL_TREE;
-      TREE_CONSTANT (parm) = true;
-    }
-
-  // Build the node.
-  tree r = build_min (REQUIRES_EXPR, boolean_type_node, parms, reqs);
-  TREE_SIDE_EFFECTS (r) = false;
-  TREE_CONSTANT (r) = true;
-  return r;
-}
-
-// Evaluate an instantiated requires expr, returning the true node
-// only when all sub-requirements have evaluated to true.
-tree
-eval_requires_expr (tree reqs)
-{
-  for (tree t = reqs ; t; t = TREE_CHAIN (t))
-    {
-      tree r = TREE_VALUE (t);
-      r = fold_non_dependent_expr (r);
-      r = maybe_constant_value (r);
-      if (r != boolean_true_node)
-	return boolean_false_node;
-    }
-  return boolean_true_node;
-}
-
-// Finish a requires expression, returning a node wrapping the parameters,
-// PARMS, and the list of requirements REQS.
-tree
-finish_requires_expr (tree parms, tree reqs)
-{
-  if (processing_template_decl)
-    return build_requires_expr (parms, reqs);
-  else
-    return eval_requires_expr (reqs);
-}
-
-// Construct a unary expression that evaluates properties of the
-// expression or type T, and has a boolean result type.
-static inline tree
-build_check_expr (tree_code c, tree t)
-{
-  tree r = build_min (c, boolean_type_node, t);
-  TREE_SIDE_EFFECTS (r) = false;
-  TREE_READONLY (r) = true;
-  TREE_CONSTANT (r) = true;
-  return r;
-}
-
-// Finish a syntax requirement, constructing a list embodying a sequence
-// of checks for the validity of EXPR and TYPE, the convertibility of
-// EXPR to TYPE, and the expression properties specified in SPECS.
-tree
-finish_expr_requirement (tree expr, tree type, tree specs)
-{
-  gcc_assert (processing_template_decl);
-
-  // Build a list of checks, starting with the valid expression.
-  tree result = tree_cons (NULL_TREE, finish_validexpr_expr (expr), NULL_TREE);
-
-  // If a type requirement was provided, build the result type checks.
-  if (type)
-    {
-      // If the type is dependent, ensure that it can be validly
-      // instantiated.
-      //
-      // NOTE: We can also disregard checks that result in the template
-      // parameter.
-      if (dependent_type_p (type))
-        {
-          tree treq = finish_type_requirement (type);
-          result = tree_cons (NULL_TREE, treq, result);
-        }
-
-      // Ensure that the result of the expression can be converted to
-      // the result type.
-      tree decl_type = finish_decltype_type (expr, false, tf_none);
-      tree creq = finish_trait_expr (CPTK_IS_CONVERTIBLE_TO, decl_type, type);
-      result = tree_cons (NULL_TREE, creq, result);
-    }
-
-  // If constraint specifiers are present, make them part of the
-  // list of constraints.
-  if (specs)
-    {
-      TREE_CHAIN (tree_last (specs)) = result;
-      result = specs;
-    }
-
-  // Finally, construct the syntactic requirement.
-  return build_check_expr (EXPR_REQ, nreverse (result));
-}
-
-// Finish a simple syntax requirement, returning a node representing
-// a check that EXPR is a valid expression.
-tree
-finish_expr_requirement (tree expr)
-{
-  gcc_assert (processing_template_decl);
-  tree req = finish_validexpr_expr (expr);
-  tree reqs = tree_cons (NULL_TREE, req, NULL_TREE);
-  return build_check_expr (EXPR_REQ, reqs);
-}
-
-// Finish a type requirement, returning a node representing a check
-// that TYPE will result in a valid type when instantiated.
-tree
-finish_type_requirement (tree type)
-{
-  gcc_assert (processing_template_decl);
-  tree req = finish_validtype_expr (type);
-  return build_check_expr (TYPE_REQ, req);
-}
-
-tree
-finish_nested_requirement (tree expr)
-{
-  gcc_assert (processing_template_decl);
-  return build_check_expr (NESTED_REQ, expr);
-}
-
-// Finish a constexpr requirement, returning a node representing a
-// check that EXPR, when instantiated, may be evaluated at compile time.
-tree
-finish_constexpr_requirement (tree expr)
-{
-  gcc_assert (processing_template_decl);
-  return finish_constexpr_expr (expr);
-}
-
-// Finish the noexcept requirement by constructing a noexcept
-// expression evaluating EXPR.
-tree
-finish_noexcept_requirement (tree expr)
-{
-  gcc_assert (processing_template_decl);
-  return finish_noexcept_expr (expr, tf_none);
-}
-
-// Returns the true or false node depending on the truth value of B.
-static inline tree
-truth_node (bool b)
-{
-  return b ? boolean_true_node : boolean_false_node;
-}
-
-// Returns a finished validexpr-expr. Returns the true or false node
-// depending on whether EXPR denotes a valid expression. This is the case
-// when the expression has been successfully type checked.
-//
-// When processing a template declaration, the result is an expression
-// representing the check.
-tree
-finish_validexpr_expr (tree expr)
-{
-  if (processing_template_decl)
-    return build_check_expr (VALIDEXPR_EXPR, expr);
-  return truth_node (expr && expr != error_mark_node);
-}
-
-// Returns a finished validtype-expr. Returns the true or false node
-// depending on whether T denotes a valid type name.
-//
-// When processing a template declaration, the result is an expression
-// representing the check.
-//
-// FIXME: Semantics need to be aligned with the new version of the
-// specification (i.e., we must be able to invent a function and
-// perform argument deduction against it).
-tree
-finish_validtype_expr (tree type)
-{
-  if (is_auto (type))
-    {
-      sorry ("%<auto%> not supported in result type constraints");
-      return error_mark_node;
-    }
-
-  if (processing_template_decl)
-    return build_check_expr (VALIDTYPE_EXPR, type);
-  return truth_node (type && TYPE_P (type));
-}
+/* Build a constraint-info object that contains the 
+   associated condstraints of a declaration. This also 
+   includes the declaration's template requirements (TREQS)
+   and any trailing requirements for a function declarator
+   (DREQS). Note that both TREQS and DREQS must be constraints.
 
-// Returns a finished constexpr-expr. Returns the true or false node
-// depending on whether the expression T may be evaluated at compile
-// time.
-//
-// When processing a template declaration, the result is an expression
-// representing the check.
+   If the declaration has neither template nor declaration 
+   requirements this returns NULL_TREE, indicating an 
+   unconstrained declaration. */
 tree
-finish_constexpr_expr (tree expr)
+build_constraints (tree tmpl_reqs, tree decl_reqs)
 {
-  if (processing_template_decl)
-    return build_check_expr (CONSTEXPR_EXPR, expr);
-
-  // TODO: Actually check that the expression can be constexpr
-  // evaluated.
-  //
-  // return truth_node (potential_constant_expression (expr));
-  sorry ("constexpr requirement");
-  return NULL_TREE;
-}
+  gcc_assert (tmpl_reqs ? constraint_p (tmpl_reqs) : true);
+  gcc_assert (decl_reqs ? constraint_p (decl_reqs) : true);
 
-// Check that a constrained friend declaration function declaration,
-// FN, is admissable. This is the case only when the declaration depends
-// on template parameters and does not declare a specialization.
-void
-check_constrained_friend (tree fn, tree reqs)
-{
-  if (fn == error_mark_node)
-    return;
-  gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
+  if (!tmpl_reqs && !decl_reqs)
+    return NULL_TREE;
 
-  // If there are not constraints, this cannot be an error.
-  if (!reqs)
-    return;
+  tree_constraint_info* ci = build_constraint_info ();
+  ci->template_reqs = tmpl_reqs;
+  ci->declarator_reqs = decl_reqs;
+  ci->associated_constr = conjoin_constraints (tmpl_reqs, decl_reqs);
 
-  // Constrained friend functions that don't depend on template
-  // arguments are effectively meaningless.
-  tree parms = DECL_ARGUMENTS (fn);
-  tree result = TREE_TYPE (TREE_TYPE (fn));
-  if (!(parms && uses_template_parms (parms)) && !uses_template_parms (result))
-    {
-      error ("constrained friend does not depend on template parameters");
-      return;
-    }
+  ++processing_template_decl;
+  ci->normalized_constr = normalize_constraint (ci->associated_constr);
+  --processing_template_decl;
+  
+  ci->assumptions = decompose_assumptions (ci->normalized_constr);
+  return (tree)ci;
 }
 
 namespace {
@@ -1099,7 +944,7 @@ build_call_check (tree id)
 // Construct a concept check for the given TARGET. The target may be
 // an overload set or a baselink referring to an overload set. Template
 // arguments to the target are given by ARG and REST. If the target is
-// a function (overload set or baselink reffering to an overload set),
+// a function (overload set or baselink referring to an overload set),
 // then this builds the call expression  TARGET<ARG, REST>(). If REST is
 // NULL_TREE, then the resulting check is just TARGET<ARG>(). If ARG is
 // NULL_TREE, then the resulting check is TARGET<REST>().
@@ -1153,13 +998,15 @@ build_constrained_parameter (tree fn, tree proto, tree args)
   return decl;
 }
 
-// Create a constraint expression for the given DECL that evaluates the
-// requirements specified by CONSTR, a TYPE_DECL that contains all the
-// information necessary to build the requirements (see finish_concept_name
-// for the layout of that TYPE_DECL).
-//
-// Note that the constraints are neither reduced nor decomposed. That is
-// done only after the requires clause has been parsed (or not).
+/* Create a constraint expression for the given DECL that 
+   evaluates the requirements specified by CONSTR, a TYPE_DECL 
+   that contains all the information necessary to build the 
+   requirements (see finish_concept_name for the layout of 
+   that TYPE_DECL).
+
+   Note that the constraints are neither reduced nor decomposed. 
+   That is done only after the requires clause has been parsed 
+   (or not). */
 tree
 finish_shorthand_constraint (tree decl, tree constr)
 {
@@ -1211,7 +1058,24 @@ finish_shorthand_constraint (tree decl, tree constr)
       TREE_TYPE (check) = boolean_type_node;
     }
 
-  return check;
+  return make_predicate_constraint (check);
+}
+
+/* Returns a conjunction of shorthand requirements for the template
+   parameter list PARMS. Note that the requirements are stored in
+   the TYPE of each tree node. */
+tree
+get_shorthand_constraints (tree parms)
+{
+  tree result = NULL_TREE;
+  parms = INNERMOST_TEMPLATE_PARMS (parms);
+  for (int i = 0; i < TREE_VEC_LENGTH (parms); ++i)
+    {
+      tree parm = TREE_VEC_ELT (parms, i);
+      tree constr = TEMPLATE_PARM_CONSTRAINTS (parm);
+      result = conjoin_constraints (result, constr);
+    }
+  return result;
 }
 
 // Returns and chains a new parameter for PARAMETER_LIST which will conform
@@ -1224,7 +1088,7 @@ process_introduction_parm (tree parameter_list, tree src_parm)
   // placeholder we want to look at.
   bool is_parameter_pack = ARGUMENT_PACK_P (src_parm);
   if (is_parameter_pack)
-      src_parm = TREE_VEC_ELT (ARGUMENT_PACK_ARGS (src_parm), 0);
+    src_parm = TREE_VEC_ELT (ARGUMENT_PACK_ARGS (src_parm), 0);
 
   // At this point we should have a INTRODUCED_PARM_DECL, but we want to grab
   // the associated decl from it.  Also grab the stored identifier and location
@@ -1238,7 +1102,7 @@ process_introduction_parm (tree parameter_list, tree src_parm)
   // template is using a pack and we didn't declare a pack, throw an error.
   if (is_parameter_pack != INTRODUCED_PACK_P (src_parm))
     {
-      error_at (parm_loc, "can not match pack for introduced parameter");
+      error_at (parm_loc, "cannot match pack for introduced parameter");
       tree err_parm = build_tree_list (error_mark_node, error_mark_node);
       return chainon (parameter_list, err_parm);
     }
@@ -1276,20 +1140,22 @@ process_introduction_parm (tree parameter_list, tree src_parm)
                                 is_non_type, is_parameter_pack);
 }
 
-// Associates a constraint check to the current template based on the
-// introduction parameters.  INTRO_LIST should be a TREE_VEC of
-// INTRODUCED_PARM_DECLs containing a chained PARM_DECL which contains the
-// identifier as well as the source location.  TMPL_DECL is the decl for the
-// concept being used.  If we take some concept, C, this will form a check in
-// the form of C<INTRO_LIST> filling in any extra arguments needed by the
-// defaults deduced.
-//
-// Returns the template parameters as given from end_template_parm_list or
-// NULL_TREE if the process fails.
+/* Associates a constraint check to the current template based 
+   on the introduction parameters.  INTRO_LIST should be a TREE_VEC 
+   of INTRODUCED_PARM_DECLs containing a chained PARM_DECL which 
+   contains the identifier as well as the source location.  
+   TMPL_DECL is the decl for the concept being used.  If we take 
+   some concept, C, this will form a check in the form of 
+   C<INTRO_LIST> filling in any extra arguments needed by the
+   defaults deduced.
+
+   Returns NULL_TREE if no concept could be matched and 
+   error_mark_node if an error occurred when matching.
+*/
 tree
-finish_concept_introduction (tree tmpl_decl, tree intro_list)
+finish_template_introduction (tree tmpl_decl, tree intro_list)
 {
-  // Deduce the concept check.
+  /* Deduce the concept check.  */
   tree expr = build_concept_check (tmpl_decl, NULL_TREE, intro_list);
   if (expr == error_mark_node)
     return NULL_TREE;
@@ -1298,16 +1164,12 @@ finish_concept_introduction (tree tmpl_decl, tree intro_list)
   if (!parms)
     return NULL_TREE;
 
-  // Build template parameter scope for introduction.
+  /* Build template parameter scope for introduction.  */
   tree parm_list = NULL_TREE;
   begin_template_parm_list ();
-
-  // Produce a parameter for each introduction argument according to the
-  // deduced form.
   int nargs = MIN (TREE_VEC_LENGTH (parms), TREE_VEC_LENGTH (intro_list));
   for (int n = 0; n < nargs; ++n)
     parm_list = process_introduction_parm (parm_list, TREE_VEC_ELT (parms, n));
-
   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)
@@ -1316,10 +1178,8 @@ finish_concept_introduction (tree tmpl_decl, tree intro_list)
         return error_mark_node;
       }
 
-  // Build a concept check for our constraint.
+  /* Build a concept check for our constraint.  */
   tree check_args = make_tree_vec (TREE_VEC_LENGTH (parms));
-
-  // Start with introduction parameters.
   int n = 0;
   for (; n < TREE_VEC_LENGTH (parm_list); ++n)
     {
@@ -1327,50 +1187,116 @@ finish_concept_introduction (tree tmpl_decl, tree intro_list)
       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.
+  /* If the template expects more parameters we should be able 
+     to use the defaults from our deduced concept.  */
   for (; n < TREE_VEC_LENGTH (parms); ++n)
     TREE_VEC_ELT (check_args, n) = TREE_VEC_ELT (parms, n);
 
-  // Associate the constraint.
-  tree reqs = build_concept_check (tmpl_decl, NULL_TREE, check_args);
-  TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = reqs;
+  /* Associate the constraint. */
+  tree check = build_concept_check (tmpl_decl, NULL_TREE, check_args);
+  tree constr = make_predicate_constraint (check);
+  TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = constr;
 
   return parm_list;
 }
 
-// -------------------------------------------------------------------------- //
-// Substitution Rules
-//
-// The following functions implement substitution rules for constraints.
+/*---------------------------------------------------------------------------
+                        Constraint substitution
+---------------------------------------------------------------------------*/
+
+tree tsubst_constraint (tree, tree, tsubst_flags_t, tree);
+
+/* The following functions implement substitution rules for constraints. 
+   Substitution without checking constraints happens only in the 
+   instantiation of class templates. For example:
+
+      template<C1 T> struct S {
+        void f(T) requires C2<T>;
+        void g(T) requires T::value;
+      };
+
+      S<int> s; // error instantiating S<int>::g(T)
+   
+   When we instantiate S, we substitute into its member declarations,
+   including their constraints. However, those constraints are not
+   checked. Substituting int into C2<T> yields C2<int>, and substituting
+   into T::value yields a substitution failure, making the program
+   ill-formed. 
+
+   Note that we only ever substitute into the associated constraints
+   of a declaration. That is, substitute is defined only for predicate 
+   constraints and conjunctions. */
+
+/* Substitute into the predicate constraints. Returns error_mark_node 
+   if the substitution into the expression fails. */
+tree
+tsubst_predicate_constraint (tree t, tree args, 
+                             tsubst_flags_t complain, tree in_decl)
+{
+  tree expr = PRED_CONSTR_EXPR (t);
+  ++processing_template_decl;
+  tree result = tsubst_expr (expr, args, complain, in_decl, false);
+  --processing_template_decl;
+  return build_nt (PRED_CONSTR, result);
+}
+
+/* Substitute into the conjunction of constraints. Returns 
+   error_mark_node if substitution into either operand fails. */
+tree
+tsubst_conjunction (tree t, tree args, 
+                    tsubst_flags_t complain, tree in_decl)
+{
+  tree t0 = TREE_OPERAND (t, 0);
+  tree r0 = tsubst_constraint (t0, args, complain, in_decl);
+  tree t1 = TREE_OPERAND (t, 1);
+  tree r1 = tsubst_constraint (t1, args, complain, in_decl);
+  return build_nt (CONJ_CONSTR, r0, r1);
+}
+
+/* Substitute ARGS into the constraint T. */
+tree
+tsubst_constraint (tree t, tree args, tsubst_flags_t complain, tree in_decl)
+{
+  if (TREE_CODE (t) == CONJ_CONSTR)
+    return tsubst_conjunction (t, args, complain, in_decl);
+  else if (TREE_CODE (t) == PRED_CONSTR)
+    return tsubst_predicate_constraint (t, args, complain, in_decl);
+  else
+    gcc_unreachable ();
+  return error_mark_node;
+}
 
 namespace {
-// In an unevaluated context, the substitution of parm decls are not
-// properly chained during substitution. Do that here.
+
+/* A subroutine of tsubst_constraint_variables. In an unevaluated 
+   context, the substitution of PARM_DECLs are not properly chained 
+   during substitution. Do that here. */
 tree
-fix_local_parms (tree sparms)
+fixup_constraint_vars (tree parms)
 {
-  if (!sparms)
-    return sparms;
+  if (!parms)
+    return parms;
 
-  tree p = TREE_CHAIN (sparms);
-  tree q = sparms;
+  tree p = TREE_CHAIN (parms);
+  tree q = parms;
   while (p && TREE_VALUE (p) != void_type_node)
     {
       DECL_CHAIN (TREE_VALUE (q)) = TREE_VALUE (p);
       q = p;
       p = TREE_CHAIN (p);
     }
-  return sparms;
+  return parms;
 }
 
-// Register local specializations for each of tparm and the corresponding
-// sparm. This is a helper function for tsubst_requires_expr.
-void
-declare_local_parms (tree tparms, tree sparms)
+/* A subroutine of tsubst_constraint_variables. Register local 
+   specializations for each of parameter in PARMS and its 
+   corresponding substituted constraint variable in VARS. 
+   Returns VARS. */
+tree
+declare_constraint_vars (tree parms, tree vars)
 {
-  tree s = TREE_VALUE (sparms);
-  for (tree p = tparms; p && !VOID_TYPE_P (TREE_VALUE (p)); p = TREE_CHAIN (p))
+  tree s = TREE_VALUE (vars);
+  for (tree p = parms; p && !VOID_TYPE_P (TREE_VALUE (p)); p = TREE_CHAIN (p))
     {
       tree t = TREE_VALUE (p);
       if (DECL_PACK_P (t))
@@ -1384,240 +1310,613 @@ declare_local_parms (tree tparms, tree sparms)
           s = TREE_CHAIN (s);
         }
     }
+  return vars;
 }
 
-// Substitute ARGS into the parameter list T, producing a sequence of
-// local parameters (variables) in the current scope.
+/* A subroutine of tsubst_parameterized_constraint. Substitute ARGS 
+   into the parameter list T, producing a sequence of constraint 
+   variables, declared in the current scope. 
+
+   Note that the caller must establish a local specialization stack
+   prior to calling this function since this substitution will 
+   declare the substituted parameters. */
 tree
-tsubst_local_parms (tree t,
-                    tree args,
-                    tsubst_flags_t complain,
-                    tree in_decl)
+tsubst_constraint_variables (tree t, tree args,
+                             tsubst_flags_t complain, tree in_decl)
 {
-  tree r = fix_local_parms (tsubst (t, args, complain, in_decl));
-  if (r == error_mark_node)
+  tree vars = tsubst (t, args, complain, in_decl);
+  if (vars == error_mark_node)
     return error_mark_node;
+  return declare_constraint_vars (t, fixup_constraint_vars (vars));
+}
 
-  // Register the instantiated args as local parameters.
-  if (t)
-    declare_local_parms (t, r);
+/* Substitute ARGS into the simple requirement T. Note that
+   substitution may result in an ill-formed expression without
+   causing the program to be ill-formed. In such cases, the
+   requirement wraps an error_mark_node. */
+inline tree
+tsubst_simple_requirement (tree t, tree args, 
+                           tsubst_flags_t complain, tree in_decl)
+{
+  tree expr = tsubst_expr (TREE_OPERAND (t, 0), args, complain, in_decl, false);
+  return finish_simple_requirement (expr);
+}
 
-  return r;
+/* Substitute ARGS into the type requirement T. Note that
+   substitution may result in an ill-formed type without
+   causing the program to be ill-formed. In such cases, the
+   requirement wraps an error_mark_node. */
+inline tree
+tsubst_type_requirement (tree t, tree args, 
+                         tsubst_flags_t complain, tree in_decl)
+{
+  tree type = tsubst (TREE_OPERAND (t, 0), args, complain, in_decl);
+  return finish_type_requirement (type);
 }
 
-// Substitute ARGS into the requirement body (list of requirements), T.
-// Note that if any substitutions fail, then this is equivalent to
-// returning false.
+/* Substitute args into the compound requirement T. If substituting
+   into either the expression or the type fails, the corresponding
+   operands in the resulting node will be error_mark_node. This
+   preserves a requirement for the purpose of partial ordering, but
+   it will never be satisfied. */
 tree
-tsubst_requirement_body (tree t, tree args, tree in_decl)
+tsubst_compound_requirement (tree t, tree args,
+                             tsubst_flags_t complain, tree in_decl)
 {
-  tree r = NULL_TREE;
-  while (t)
-    {
-      tree e = tsubst_expr (TREE_VALUE (t), args, tf_none, in_decl, false);
-      if (e == error_mark_node)
-        e = boolean_false_node;
-      r = tree_cons (NULL_TREE, e, r);
-      t = TREE_CHAIN (t);
-    }
-  return r;
+  tree expr = tsubst_expr (TREE_OPERAND (t, 0), args, complain, in_decl, false);
+  tree type = tsubst (TREE_OPERAND (t, 1), args, complain, in_decl);
+  bool noexcept_p = COMPOUND_REQ_NOEXCEPT_P (t);
+  return finish_compound_requirement (expr, type, noexcept_p);
 }
-} // namespace
 
-// Substitute ARGS into the requires expression T.
+/* Substitute ARGS into the nested requirement T. */
 tree
-tsubst_requires_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
+tsubst_nested_requirement (tree t, tree args, 
+                           tsubst_flags_t complain, tree in_decl)
 {
-  local_specialization_stack stack;
-  tree p = tsubst_local_parms (TREE_OPERAND (t, 0), args, complain, in_decl);
-  tree r = tsubst_requirement_body (TREE_OPERAND (t, 1), args, in_decl);
-  return finish_requires_expr (p, r);
+  tree expr = tsubst_expr (TREE_OPERAND (t, 0), args, complain, in_decl, false);
+  return finish_nested_requirement (expr);
 }
 
-// Substitute ARGS into the valid-expr expression T.
+inline tree
+tsubst_requirement (tree t, tree args, tsubst_flags_t complain, tree in_decl)
+{
+  switch (TREE_CODE (t))
+    {
+    case SIMPLE_REQ:
+      return tsubst_simple_requirement (t, args, complain, in_decl);
+    case TYPE_REQ:
+      return tsubst_type_requirement (t, args, complain, in_decl);
+    case COMPOUND_REQ:
+      return tsubst_compound_requirement (t, args, complain, in_decl);
+    case NESTED_REQ:
+      return tsubst_nested_requirement (t, args, complain, in_decl);
+    default:
+      gcc_unreachable ();
+    }
+  return error_mark_node;
+}
+
+/* Substitute ARGS into the list of requirements T. Note that
+   substitution failures here result in ill-formed programs. */
 tree
-tsubst_validexpr_expr (tree t, tree args, tree in_decl)
+tsubst_requirement_body (tree t, tree args, 
+                         tsubst_flags_t complain, tree in_decl)
 {
-  tree r = tsubst_expr (TREE_OPERAND (t, 0), args, tf_none, in_decl, false);
-  return finish_validexpr_expr (r);
+  tree r = NULL_TREE;
+  while (t)
+    {
+      tree e = tsubst_requirement (TREE_VALUE (t), args, complain, in_decl);
+      if (e == error_mark_node)
+        return error_mark_node;
+      r = tree_cons (NULL_TREE, e, r);
+      t = TREE_CHAIN (t);
+    }
+  return r;
 }
 
-// Substitute ARGS into the valid-type expression T.
+} /* namespace */
+
+/* Substitute ARGS into the requires expression T. Note that this
+   results in the re-declaration of local parameters when
+   substituting through the parameter list. If either substitution
+   fails, the program is ill-formed. */
 tree
-tsubst_validtype_expr (tree t, tree args, tree in_decl)
+tsubst_requires_expr (tree t, tree args, 
+                      tsubst_flags_t complain, tree in_decl)
 {
-  tree r = tsubst (TREE_OPERAND (t, 0), args, tf_none, in_decl);
-  return finish_validtype_expr (r);
+  local_specialization_stack stack;
+
+  tree parms = TREE_OPERAND (t, 0);
+  if (parms)
+    {
+      parms = tsubst_constraint_variables (parms, args, complain, in_decl);
+      if (parms == error_mark_node)
+        return error_mark_node;
+    }
+  
+  tree reqs = TREE_OPERAND (t, 1);
+  reqs = tsubst_requirement_body (reqs, args, complain, in_decl);
+  if (reqs == error_mark_node)
+    return error_mark_node;
+
+  return finish_requires_expr (parms, reqs);
 }
 
-// Substitute ARGS into the constexpr expression T.
+/* Substitute ARGS into the constraint information CI, producing a new 
+   constraint record. */
 tree
-tsubst_constexpr_expr (tree t, tree args, tree in_decl)
+tsubst_constraint_info (tree t, tree args, 
+                        tsubst_flags_t complain, tree in_decl)
 {
-  tree r = tsubst_expr (TREE_OPERAND (t, 0), args, tf_none, in_decl, false);
-  return finish_constexpr_expr (r);
+  if (!t || t == error_mark_node || !check_constraint_info (t))
+    return NULL_TREE;
+
+  tree tmpl_constr = NULL_TREE;
+  if (tree r = CI_TEMPLATE_REQS (t))
+    tmpl_constr = tsubst_constraint (r, args, complain, in_decl);
+
+  tree decl_constr = NULL_TREE;
+  if (tree r = CI_DECLARATOR_REQS (t))
+    decl_constr = tsubst_constraint (r, args, complain, in_decl);
+
+  return build_constraints (tmpl_constr, decl_constr);
 }
 
-// Substitute ARGS into the expr requirement T. Note that a requirement
-// node is instantiated from a non-reduced context (e.g., static_assert).
+
+/*---------------------------------------------------------------------------
+                        Constraint satisfaction 
+---------------------------------------------------------------------------*/
+
+/* The following functions determine if a constraint, when
+   substituting template arguments, is satisfied. For convenience,
+   satisfaction reduces a constraint to either true or false (and
+   nothing else). */
+
+namespace {
+
+tree check_constraint (tree, tree, tsubst_flags_t, tree);
+
+/* A predicate constraint is satisfied if its expression evaluates
+   to true. If substitution into that node fails, the constraint
+   is not satisfied ([temp.constr.pred]).
+
+   Note that a predicate constraint is a constraint expression
+   of type bool. If neither of those are true, the program is
+   ill-formed; they are not SFINAE'able errors. */
 tree
-tsubst_expr_req (tree t, tree args, tree in_decl)
+check_predicate_constraint (tree t, tree args, 
+                            tsubst_flags_t complain, tree in_decl)
 {
-  tree r = NULL_TREE;
-  for (tree l = TREE_OPERAND (t, 0); l; l = TREE_CHAIN (l))
+  tree expr = tsubst_expr (TREE_OPERAND (t, 0), args, complain, in_decl, false);
+  if (expr == error_mark_node)
+    return boolean_false_node;
+
+  tree result = fold_non_dependent_expr (expr);
+  if (result == error_mark_node)
+    return boolean_false_node;
+
+  /* A predicate constraint shall have type bool. In some
+     cases, substitution gives us const-qualified bool, which
+     is also acceptable.  */
+  tree type = cv_unqualified (TREE_TYPE (result));
+  if (!same_type_p (type, boolean_type_node))
     {
-      tree e = tsubst_expr (TREE_VALUE (l), args, tf_none, in_decl, false);
-      r = conjoin_constraints (r, e);
+      error_at (EXPR_LOC_OR_LOC (t, input_location),
+                "constraint %qE does not have type %qT", 
+                result, boolean_type_node);
+      return boolean_false_node;
     }
-  return r;
+
+  return cxx_constant_value (result);
 }
 
-// Substitute ARGS into the type requirement T. Note that a requirement
-// node is instantiated from a non-reduced context (e.g., static_assert).
+/* Check an expression constraint. The constraint is satisfied if
+   substitution succeeds ([temp.constr.expr]). 
+
+   Note that the expression is unevaluated. */
 tree
-tsubst_type_req (tree t, tree args, tree in_decl)
+check_expression_constraint (tree t, tree args, 
+                             tsubst_flags_t complain, tree in_decl)
 {
-  return tsubst_expr (TREE_OPERAND (t, 0), args, tf_none, in_decl, false);
+  cp_unevaluated guard;
+  tree expr = EXPR_CONSTR_EXPR (t);
+  tree check = tsubst_expr (expr, args, complain, in_decl, false);
+  if (check == error_mark_node)
+    return boolean_false_node;
+  return boolean_true_node;
+}
+
+/* Check a type constraint. The constraint is satisfied if
+   substitution succeeds. */
+inline tree
+check_type_constraint (tree t, tree args, 
+                       tsubst_flags_t complain, tree in_decl)
+{
+  tree type = TYPE_CONSTR_TYPE (t);
+  tree check = tsubst (type, args, complain, in_decl);
+  if (check == error_mark_node)
+    return boolean_false_node;
+  return boolean_true_node;
+}
+
+/* Check an implicit conversion constraint. */
+tree
+check_implicit_conversion_constraint (tree t, tree args, 
+                                      tsubst_flags_t complain, tree in_decl)
+{
+  tree expr = ICONV_CONSTR_EXPR (t);
+
+  /* Don't tsubst as if we're processing a template. If we try 
+     to we can end up generating template-like expressions
+     (e.g., modop-exprs) that aren't properly typed. */
+  int saved_template_decl = processing_template_decl;
+  processing_template_decl = 0;
+  tree arg = tsubst_expr (expr, args, complain, in_decl, false);
+  processing_template_decl = saved_template_decl;
+
+  if (arg == error_mark_node)
+    return boolean_false_node;
+  tree from = TREE_TYPE (arg);
+
+  tree type = ICONV_CONSTR_TYPE (t);
+  tree to = tsubst (type, args, complain, in_decl);
+  if (to == error_mark_node)
+    return boolean_false_node;
+
+  if (can_convert_arg (to, from, arg, LOOKUP_IMPLICIT, complain))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
 }
 
-// Substitute ARGS into the nested requirement T. Note that a requirement
-// node is instantiated from a non-reduced context (e.g., static_assert).
+/* Check an argument deduction constraint.
+
+   TODO: Implement me. We need generalized auto for this to work. */
 tree
-tsubst_nested_req (tree t, tree args, tree in_decl)
+check_argument_deduction_constraint (tree /*t*/, tree /*args*/, 
+                                     tsubst_flags_t /*complain*/, 
+                                     tree /*in_decl*/)
 {
-  return tsubst_expr (TREE_OPERAND (t, 0), args, tf_none, in_decl, false);
+  gcc_unreachable ();
+  return boolean_false_node;
 }
 
-// Used in various contexts to control substitution. In particular, when
-// non-zero, the substitution of NULL arguments into a type will still
-// process the type as if passing non-NULL arguments, allowing type
-// expressions to be fully elaborated during substitution.
-int processing_constraint;
+/* Check an exception constraint. An exception constraint for an
+   expression e is satisfied when noexcept(e) is true. */
+tree
+check_exception_constraint (tree t, tree args, 
+                             tsubst_flags_t complain, tree in_decl)
+{
+  tree expr = EXCEPT_CONSTR_EXPR (t);
+  tree check = tsubst_expr (expr, args, complain, in_decl, false);
+  if (check == error_mark_node)
+    return boolean_false_node;
 
-// Substitute the template arguments ARGS into the requirement
-// expression REQS. Errors resulting from substitution are not
-// diagnosed.
-//
-// If DO_NOT_FOLD is true, then the requirements are substituted as
-// if parsing a template declaration, which causes the resulting expression
-// to not be folded.
+  if (expr_noexcept_p (check, complain))
+    return boolean_true_node;
+  else
+    return boolean_false_node;
+}
+
+/* Check a parameterized constraint. */
 tree
-tsubst_constraint_expr (tree reqs, tree args, bool do_not_fold)
+check_parameterized_constraint (tree t, tree args, 
+                                tsubst_flags_t complain, tree in_decl)
 {
-  cp_unevaluated guard;
-  ++processing_constraint;
-  if (do_not_fold)
-    ++processing_template_decl;
-  tree r = tsubst_expr (reqs, args, tf_none, NULL_TREE, false);
-  if (do_not_fold)
-    --processing_template_decl;
-  --processing_constraint;
-  return r;
+  local_specialization_stack stack;
+  tree parms = PARM_CONSTR_PARMS (t);
+  tree vars = tsubst_constraint_variables (parms, args, complain, in_decl);
+  if (vars == error_mark_node)
+    return boolean_false_node;
+  tree constr = PARM_CONSTR_OPERAND (t);
+  return check_constraint (constr, args, complain, in_decl);
+}
+
+/* Check that the conjunction of constraints is satisfied. Note
+   that if left operand is not satisfied, the right operand
+   is not checked. 
+
+   FIXME: Check that this wouldn't result in a user-defined
+   operator. Note that this error is partially diagnosed in
+   check_predicate_constriant. It would be nice to diagnose
+   the overload, but I don't think it's strictly necessary.  */
+tree
+check_conjunction (tree t, tree args, tsubst_flags_t complain, tree in_decl)
+{
+  tree t0 = check_constraint (TREE_OPERAND (t, 0), args, complain, in_decl);
+  if (t0 == boolean_false_node)
+    return t0;
+  tree t1 = check_constraint (TREE_OPERAND (t, 1), args, complain, in_decl);
+  if (t1 == boolean_false_node)
+    return t1;
+  return boolean_true_node;
 }
 
-// Substitute into the constraint information, producing a new constraint
-// record.
+/* Check that the disjunction of constraints is satisfied. Note
+   that if the left operand is satisfied, the right operand is not
+   checked.  */
 tree
-tsubst_constraint_info (tree ci, tree args)
+check_disjunction (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 {
-  if (!ci || ci == error_mark_node || !check_constraint_info (ci))
-    return NULL_TREE;
+  tree t0 = check_constraint (TREE_OPERAND (t, 0), args, complain, in_decl);
+  if (t0 == boolean_true_node)
+    return t0;
+  tree t1 = check_constraint (TREE_OPERAND (t, 1), args, complain, in_decl);
+  if (t1 == boolean_true_node)
+    return t0;
+  return boolean_false_node;
+}
 
-  tree tr = NULL_TREE;
-  if (tree r = CI_TEMPLATE_REQS (ci))
-    tr = tsubst_constraint_expr (r, args, true);
+/* Check that the constraint is satisfied, according to the rules 
+   for that constraint. Note that each check_* function returns
+   true or false, depending on whether it is satisfied or not.  */
+tree 
+check_constraint (tree t, tree args, tsubst_flags_t complain, tree in_decl)
+{
+  if (!t)
+    return boolean_false_node;
 
-  tree dr = NULL_TREE;
-  if (tree r = CI_DECLARATOR_REQS (ci))
-    dr = tsubst_constraint_expr (r, args, true);
+  if (t == error_mark_node)
+    return boolean_false_node;
 
-  // TODO: This is re-normalizing and re-decomposing. We probably
-  // don't need to do this.
-  return build_constraints (tr, dr);
+  switch (TREE_CODE (t))
+  {
+  case PRED_CONSTR:
+    return check_predicate_constraint (t, args, complain, in_decl);
+  
+  case EXPR_CONSTR:
+    return check_expression_constraint (t, args, complain, in_decl);
+  
+  case TYPE_CONSTR:
+    return check_type_constraint (t, args, complain, in_decl);
+  
+  case ICONV_CONSTR:
+    return check_implicit_conversion_constraint (t, args, complain, in_decl);
+  
+  case DEDUCT_CONSTR:
+    return check_argument_deduction_constraint (t, args, complain, in_decl);
+  
+  case EXCEPT_CONSTR:
+    return check_exception_constraint (t, args, complain, in_decl);
+  
+  case PARM_CONSTR:
+    return check_parameterized_constraint (t, args, complain, in_decl);
+  
+  case CONJ_CONSTR:
+    return check_conjunction (t, args, complain, in_decl);
+  
+  case DISJ_CONSTR:
+    return check_disjunction (t, args, complain, in_decl);
+  
+  default:
+    gcc_unreachable ();
+  }
+  return boolean_false_node;
 }
 
-// -------------------------------------------------------------------------- //
-// Constraint Satisfaction
-//
-// The following functions are responsible for the instantiation and
-// evaluation of constraints.
+} /* namespace */
 
-namespace {
-// Returns true iff the atomic constraint, REQ, is satisfied. This
-// is the case when substitution succeeds and the resulting expression
-// evaluates to true.
-static bool
-check_satisfied (tree req, tree args)
-{
-  // If any arguments are dependent, then we can't check the
-  // requirements. Just return true.
-  if (args && uses_template_parms (args))
+/* Check the constraints in CI against the given ARGS, returning
+   true when the constraints are satisfied and false otherwise. 
+
+   Note that this is the only place that we instantiate the
+   constraints. */
+bool
+check_constraints (tree ci, tree args)
+{
+  /* If there are no constraints then this is trivially satisfied. */
+  if (!ci)
     return true;
 
-  // Instantiate and evaluate the requirements.
-  req = tsubst_constraint_expr (req, args, false);
-  if (req == error_mark_node)
+  /* If any arguments depend on template parameters, we can't
+     check constraints. */
+  if (args && uses_template_parms (args))
+    return true;
+  
+  /* Invalid requirements cannot be satisfied. */
+  if (!valid_constraints_p (ci))
     return false;
 
-  // Reduce any remaining TRAIT_EXPR nodes before evaluating.
-  req = fold_non_dependent_expr (req);
-
-  // Requirements are satisfied when REQS evaluates to true.
-  tree result = cxx_constant_value (req);
+  tree constr = CI_NORMALIZED_CONSTRAINTS (ci);
+  tree result = check_constraint (constr, args, tf_none, NULL_TREE);
   return result == boolean_true_node;
 }
 
-} // namespace
-
-// Check the instantiated declaration constraints.
+/* Returns true if the declaration's constraints are satisfied. 
+   This is used in cases where a declaration is formed but
+   before it is used (e.g., overload resolution). */
 bool
-check_constraints (tree cinfo)
+constraints_satisfied_p (tree decl)
 {
-  // No constraints? Satisfied.
-  if (!cinfo)
-    return true;
-  // Invalid constraints, not satisfied.
-  else if (!valid_requirements_p (cinfo))
-    return false;
-  // Funnel back into the dependent checking branch. This forces
-  // one more substitution through the constraints, which removes
-  // all remaining expressions that are not constant expressions
-  // (e.g., template-id expressions).
+  /* Get the constraints to check for satisfaction. This depends
+     on whether we're looking at a template specialization or not. */
+  tree ci = NULL_TREE;
+  tree args = NULL_TREE;
+  if (tree ti = DECL_TEMPLATE_INFO (decl))
+    {
+      ci = get_constraints (TI_TEMPLATE (ti));
+      args = INNERMOST_TEMPLATE_ARGS (TI_ARGS (ti));
+    }
   else
-    return check_satisfied (CI_NORMALIZED_CONSTRAINTS (cinfo), NULL_TREE);
+    {
+      ci = get_constraints (decl);
+    }
+
+  return check_constraints (ci, args);
 }
 
-// Check the constraints in CINFO against the given ARGS, returning
-// true when the constraints are satisfied and false otherwise.
+/* Returns true if the template's constrains are satisfied
+   by the given arguments. This is used in cases where a
+   declaration cannot be formed unless the constraints are
+   checked (e.g., the use of a template-id that names a
+   class). */
 bool
-check_constraints (tree cinfo, tree args)
+constraints_satisfied_p (tree tmpl, tree args)
 {
-  // If there are no constraints then this is trivally satisfied.
-  if (!cinfo)
-    return true;
-  // Invlaid requirements cannot be satisfied.
-  else if (!valid_requirements_p (cinfo))
-    return false;
-  else {
-    return check_satisfied (CI_NORMALIZED_CONSTRAINTS (cinfo), args);
-  }
+  return check_constraints (get_constraints (tmpl), args);
+}
+
+/* Evaluate the function concept FN by substituting ARGS into its
+   definition and evaluating that as the result. Returns
+   boolean_true_node if the constraints are satisfied and
+   boolean_false_node otherwise.  */
+tree
+evaluate_function_concept (tree fn, tree args)
+{
+  ++processing_template_decl;
+  tree constr = transform_expression (lift_function_definition (fn, args));
+  --processing_template_decl;
+  return check_constraint (constr, args, tf_none, NULL_TREE);
+}
+
+/* Evaluate the variable concept VAR by substituting ARGS into
+   its initializer and checking the resulting constraint. Returns
+   boolean_true_node if the constraints are satisfied and
+   boolean_false_node otherwise.  */
+tree
+evaluate_variable_concept (tree decl, tree args)
+{
+  ++processing_template_decl;
+  tree constr = transform_expression (lift_variable_initializer (decl, args));
+  --processing_template_decl;
+  return check_constraint (constr, args, tf_none, NULL_TREE);
 }
 
-// Check the constraints of the declaration or type T, against
-// the specified arguments. Returns true if the constraints are
-// satisfied and false otherwise.
+/* Evaluate the given expression as if it were a predicate
+   constraint. Returns boolean_true_node if the constraint
+   is satisfied and boolean_false_node otherwise. */
+tree
+evaluate_constraint_expression (tree expr, tree args)
+{
+  ++processing_template_decl;
+  tree constr = transform_expression (lift_constraints (expr));
+  --processing_template_decl;
+  return check_constraint (constr, args, tf_none, NULL_TREE);
+}
+
+/* Normalize EXPR and determine if the resulting constraint is
+   satisfied by ARGS. Returns true if and only if the constraint
+   is satisfied. */
 bool
-check_template_constraints (tree t, tree args)
+check_constraint_expression (tree expr, tree args)
 {
-  return check_constraints (get_constraints (t), args);
+  return evaluate_constraint_expression (expr, args) == boolean_true_node;
 }
 
-// -------------------------------------------------------------------------- //
-// Constraint Relations
-//
-// Interfaces for determining equivalency and ordering of constraints.
+/*---------------------------------------------------------------------------
+                Semantic analysis of requires-expressions
+---------------------------------------------------------------------------*/
 
-// Returns true when A and B are equivalent constraints.
+/* Finish a requires expression for the given PARMS (possibly
+   null) and the non-empty sequence of requirements. */
+tree
+finish_requires_expr (tree parms, tree reqs)
+{
+  /* Modify the declared parameters by removing their context 
+     so they don't refer to the enclosing scope. */
+  for (tree p = parms; p && !VOID_TYPE_P (TREE_VALUE (p)); p = TREE_CHAIN (p))
+    DECL_CONTEXT (TREE_VALUE (p)) = NULL_TREE;
+
+  /* Build the node. */
+  tree r = build_min (REQUIRES_EXPR, boolean_type_node, parms, reqs);
+  TREE_SIDE_EFFECTS (r) = false;
+  TREE_CONSTANT (r) = true;
+  return r;
+}
+
+/* Construct a requirement for the validity of EXPR. */
+tree
+finish_simple_requirement (tree expr)
+{
+  return build_nt (SIMPLE_REQ, expr);
+}
+
+/* Construct a requirement for the validity of TYPE. */
+tree
+finish_type_requirement (tree type)
+{
+  return build_nt (TYPE_REQ, type);
+}
+
+/* Construct a requirement for the validity of EXPR, along with
+   its properties. if TYPE is non-null, then it specifies either 
+   an implicit conversion or argument deduction constraint, 
+   depending on whether any placeholders occur in the type name. 
+   NOEXCEPT_P is true iff the noexcept keyword was specified. */
+tree
+finish_compound_requirement (tree expr, tree type, bool noexcept_p)
+{
+  tree req = build_nt (COMPOUND_REQ, expr, type);
+  COMPOUND_REQ_NOEXCEPT_P (req) = noexcept_p;
+  return req;
+}
+
+/* Finish a nested requirement. */
+tree
+finish_nested_requirement (tree expr)
+{
+  return build_nt (NESTED_REQ, expr);
+}
+
+// Check that FN satisfies the structural requirements of a
+// function concept definition.
+tree
+check_function_concept (tree fn)
+{
+  location_t loc = DECL_SOURCE_LOCATION (fn);
+
+  // Check that the function is comprised of only a single
+  // return statement.
+  tree body = DECL_SAVED_TREE (fn);
+  if (TREE_CODE (body) == BIND_EXPR)
+    body = BIND_EXPR_BODY (body);
+
+  // Sometimes a function call results in the creation of clean up
+  // points. Allow these to be preserved in the body of the
+  // constraint, as we might actually need them for some constexpr
+  // evaluations.
+  if (TREE_CODE (body) == CLEANUP_POINT_EXPR)
+    body = TREE_OPERAND (body, 0);
+
+  if (TREE_CODE (body) != RETURN_EXPR)
+    error_at (loc, "function concept definition %qD has multiple statements",
+              fn);
+
+  return NULL_TREE;
+}
+
+
+// Check that a constrained friend declaration function declaration,
+// FN, is admissible. This is the case only when the declaration depends
+// on template parameters and does not declare a specialization.
+void
+check_constrained_friend (tree fn, tree reqs)
+{
+  if (fn == error_mark_node)
+    return;
+  gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
+
+  // If there are not constraints, this cannot be an error.
+  if (!reqs)
+    return;
+
+  // Constrained friend functions that don't depend on template
+  // arguments are effectively meaningless.
+  tree parms = DECL_ARGUMENTS (fn);
+  tree result = TREE_TYPE (TREE_TYPE (fn));
+  if (!(parms && uses_template_parms (parms)) && !uses_template_parms (result))
+    {
+      error ("constrained friend does not depend on template parameters");
+      return;
+    }
+}
+
+/*---------------------------------------------------------------------------
+                        Equivalence of constraints
+---------------------------------------------------------------------------*/
+
+/* Returns true when A and B are equivalent constraints.  */
 bool
 equivalent_constraints (tree a, tree b)
 {
@@ -1626,9 +1925,9 @@ equivalent_constraints (tree a, tree b)
   return cp_tree_equal (a, b);
 }
 
-// Returns true if the template declarations A and B have equivalent
-// constraints. This is the case when A's constraints subsume B's and
-// when B's also constrain A's.
+/* Returns true if the template declarations A and B have equivalent
+   constraints. This is the case when A's constraints subsume B's and
+   when B's also constrain A's.  */
 bool
 equivalently_constrained (tree d1, tree d2)
 {
@@ -1636,7 +1935,11 @@ equivalently_constrained (tree d1, tree d2)
   return equivalent_constraints (get_constraints (d1), get_constraints (d2));
 }
 
-// Returns true when the the constraints in A subsume those in B.
+/*---------------------------------------------------------------------------
+                     Partial ordering of constraints
+---------------------------------------------------------------------------*/
+
+/* Returns true when the the constraints in A subsume those in B.  */
 bool
 subsumes_constraints (tree a, tree b)
 {
@@ -1645,12 +1948,12 @@ subsumes_constraints (tree a, tree b)
   return subsumes (a, b);
 }
 
-// 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.
+/* 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 d1, tree d2)
 {
@@ -1664,9 +1967,9 @@ more_constrained (tree d1, tree d2)
   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.
+/* 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)
 {
@@ -1676,367 +1979,295 @@ at_least_as_constrained (tree d1, tree d2)
 }
 
 
-// -------------------------------------------------------------------------- //
-// Constraint Diagnostics
+/*---------------------------------------------------------------------------
+                        Constraint diagnostics
+---------------------------------------------------------------------------*/
+
+/* The diagnosis of constraints performs a combination of
+   normalization and satisfaction testing. We recursively
+   walk through the conjunction (or disjunctions) of associated 
+   constraints, testing each sub-expression in turn.
+
+   We currently restrict diagnostics to just the top-level
+   conjunctions within the associated constraints. A fully
+   recursive walk is possible, but it can generate a lot
+   of errors. */
+
 
 namespace {
 
-// Given an arbitrary constraint expression, normalize it and
-// then check it. We have to normalize so we don't accidentally
-// instantiate concept declarations.
-inline bool
-check_diagnostic_constraints (tree reqs, tree args)
+void diagnose_expression (location_t, tree, tree);
+void diagnose_constraint (location_t, tree, tree);
+
+/* Diagnose a conjunction of constraints. */
+void
+diagnose_logical_operation (location_t loc, tree t, tree args)
 {
-  return check_satisfied (normalize_constraints (reqs), args);
+  diagnose_expression (loc, TREE_OPERAND (t, 0), args);
+  diagnose_expression (loc, TREE_OPERAND (t, 0), args);
 }
 
-void diagnose_node (location_t, tree, tree);
-
-// Diagnose a constraint failure for type trait expressions.
+/* Determine if the trait expression T is satisfied by ARGS.
+   Emit a precise diagnostic if it is not. */
 void
-diagnose_trait (location_t loc, tree t, tree args)
+diagnose_trait_expression (location_t loc, tree t, tree args)
 {
-  if (check_diagnostic_constraints (t, args))
+  if (check_constraint_expression (t, args))
     return;
 
-  tree subst = tsubst_constraint_expr (t, args, true);
-
-  if (subst == error_mark_node)
-    {
-      inform (input_location, "  substitution failure in %qE", t);
-      return;
-    }
+  /* Rebuild the trait expression so we can diagnose the
+     specific failure. */
+  ++processing_template_decl;
+  tree expr = tsubst_expr (t, args, tf_none, NULL_TREE, false);
+  --processing_template_decl;
 
-  tree t1 = TRAIT_EXPR_TYPE1 (subst);
-  tree t2 = TRAIT_EXPR_TYPE2 (subst);
+  tree t1 = TRAIT_EXPR_TYPE1 (expr);
+  tree t2 = TRAIT_EXPR_TYPE2 (expr);
   switch (TRAIT_EXPR_KIND (t))
     {
-      case CPTK_HAS_NOTHROW_ASSIGN:
-        inform (loc, "  %qT is not nothrow copy assignable", t1);
-        break;
-      case CPTK_HAS_NOTHROW_CONSTRUCTOR:
-        inform (loc, "  %qT is not nothrow default constructible", t1);
-        break;
-      case CPTK_HAS_NOTHROW_COPY:
-        inform (loc, "  %qT is not nothrow copy constructible", t1);
-        break;
-      case CPTK_HAS_TRIVIAL_ASSIGN:
-        inform (loc, "  %qT is not trivially copy assignable", t1);
-        break;
-      case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
-        inform (loc, "  %qT is not trivially default constructible", t1);
-        break;
-      case CPTK_HAS_TRIVIAL_COPY:
-        inform (loc, "  %qT is not trivially copy constructible", t1);
-        break;
-      case CPTK_HAS_TRIVIAL_DESTRUCTOR:
-        inform (loc, "  %qT is not trivially destructible", t1);
-        break;
-      case CPTK_HAS_VIRTUAL_DESTRUCTOR:
-        inform (loc, "  %qT does not have a virtual destructor", t1);
-        break;
-      case CPTK_IS_ABSTRACT:
-        inform (loc, "  %qT is not an abstract class", t1);
-        break;
-      case CPTK_IS_BASE_OF:
-        inform (loc, "  %qT is not a base of %qT", t1, t2);
-        break;
-      case CPTK_IS_CLASS:
-        inform (loc, "  %qT is not a class", t1);
-        break;
-      case CPTK_IS_CONVERTIBLE_TO:
-        inform (loc, "  %qT is not convertible to %qT", t1, t2);
-        break;
-      case CPTK_IS_EMPTY:
-        inform (loc, "  %qT is not an empty class", t1);
-        break;
-      case CPTK_IS_ENUM:
-        inform (loc, "  %qT is not an enum", t1);
-        break;
-      case CPTK_IS_FINAL:
-        inform (loc, "  %qT is not a final class", t1);
-        break;
-      case CPTK_IS_LITERAL_TYPE:
-        inform (loc, "  %qT is not a literal type", t1);
-        break;
-      case CPTK_IS_POD:
-        inform (loc, "  %qT is not a POD type", t1);
-        break;
-      case CPTK_IS_POLYMORPHIC:
-        inform (loc, "  %qT is not a polymorphic type", t1);
-        break;
-      case CPTK_IS_SAME_AS:
-        inform (loc, "  %qT is not the same as %qT", t1, t2);
-        break;
-      case CPTK_IS_STD_LAYOUT:
-        inform (loc, "  %qT is not an standard layout type", t1);
-        break;
-      case CPTK_IS_TRIVIAL:
-        inform (loc, "  %qT is not a trivial type", t1);
-        break;
-      case CPTK_IS_UNION:
-        inform (loc, "  %qT is not a union", t1);
-        break;
-      default:
-        gcc_unreachable ();
+    case CPTK_HAS_NOTHROW_ASSIGN:
+      inform (loc, "  %qT is not nothrow copy assignable", t1);
+      break;
+    case CPTK_HAS_NOTHROW_CONSTRUCTOR:
+      inform (loc, "  %qT is not nothrow default constructible", t1);
+      break;
+    case CPTK_HAS_NOTHROW_COPY:
+      inform (loc, "  %qT is not nothrow copy constructible", t1);
+      break;
+    case CPTK_HAS_TRIVIAL_ASSIGN:
+      inform (loc, "  %qT is not trivially copy assignable", t1);
+      break;
+    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
+      inform (loc, "  %qT is not trivially default constructible", t1);
+      break;
+    case CPTK_HAS_TRIVIAL_COPY:
+      inform (loc, "  %qT is not trivially copy constructible", t1);
+      break;
+    case CPTK_HAS_TRIVIAL_DESTRUCTOR:
+      inform (loc, "  %qT is not trivially destructible", t1);
+      break;
+    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
+      inform (loc, "  %qT does not have a virtual destructor", t1);
+      break;
+    case CPTK_IS_ABSTRACT:
+      inform (loc, "  %qT is not an abstract class", t1);
+      break;
+    case CPTK_IS_BASE_OF:
+      inform (loc, "  %qT is not a base of %qT", t1, t2);
+      break;
+    case CPTK_IS_CLASS:
+      inform (loc, "  %qT is not a class", t1);
+      break;
+    case CPTK_IS_CONVERTIBLE_TO:
+      inform (loc, "  %qT is not convertible to %qT", t1, t2);
+      break;
+    case CPTK_IS_EMPTY:
+      inform (loc, "  %qT is not an empty class", t1);
+      break;
+    case CPTK_IS_ENUM:
+      inform (loc, "  %qT is not an enum", t1);
+      break;
+    case CPTK_IS_FINAL:
+      inform (loc, "  %qT is not a final class", t1);
+      break;
+    case CPTK_IS_LITERAL_TYPE:
+      inform (loc, "  %qT is not a literal type", t1);
+      break;
+    case CPTK_IS_POD:
+      inform (loc, "  %qT is not a POD type", t1);
+      break;
+    case CPTK_IS_POLYMORPHIC:
+      inform (loc, "  %qT is not a polymorphic type", t1);
+      break;
+    case CPTK_IS_SAME_AS:
+      inform (loc, "  %qT is not the same as %qT", t1, t2);
+      break;
+    case CPTK_IS_STD_LAYOUT:
+      inform (loc, "  %qT is not an standard layout type", t1);
+      break;
+    case CPTK_IS_TRIVIAL:
+      inform (loc, "  %qT is not a trivial type", t1);
+      break;
+    case CPTK_IS_UNION:
+      inform (loc, "  %qT is not a union", t1);
+      break;
+    default:
+      gcc_unreachable ();
     }
 }
 
-// Diagnose a failed concept check in concept indicated by T, where
-// T is the result of resolve_constraint_check. Recursively analyze
-// the nested requiremets for details.
-void
-diagnose_check (location_t loc, tree t, tree args)
-{
-  tree fn = TREE_VALUE (t);
-  tree targs = TREE_PURPOSE (t);
-  tree body = DECL_SAVED_TREE (fn);
-  if (!body)
-    return;
-
-  inform (loc, "  failure in constraint %q#D", DECL_TI_TEMPLATE (fn));
+/* Determine if the call expression T, when normalized as a constraint,
+   is satisfied by ARGS. 
 
-  // Perform a mini-reduction on the constraint.
-  if (TREE_CODE (body) == BIND_EXPR)
-    body = BIND_EXPR_BODY (body);
-  if (TREE_CODE (body) == RETURN_EXPR)
-    body = TREE_OPERAND (body, 0);
-
-  // Locally instantiate the body with the call's template args,
-  // and recursively diagnose.
-  body = tsubst_constraint_expr (body, targs, true);
-
-  diagnose_node (loc, body, args);
-}
-
-// Diagnose constraint failures from the call expression T.
+   TODO: If T is refers to a concept, We could recursively analyze 
+   its definition to identify the exact failure, but that could 
+   emit a *lot* of error messages (defeating the purpose of 
+   improved diagnostics). Consider adding a flag to control the 
+   depth of diagnostics. */
 void
-diagnose_call (location_t loc, tree t, tree args)
+diagnose_call_expression (location_t loc, tree t, tree args)
 {
-  if (check_diagnostic_constraints (t, args))
+  if (check_constraint_expression (t, args))
     return;
 
-  // If this is a concept, we're going to recurse.
-  // If it's just a call, then we can emit a simple message.
-  if (tree check = resolve_constraint_check (t))
-    diagnose_check (loc, check, args);
+  /* Rebuild the expression for the purpose of diagnostics. */
+  ++processing_template_decl;
+  tree expr = tsubst_expr (t, args, tf_none, NULL_TREE, false);
+  --processing_template_decl;
+
+  /* If the function call is known to be a concept check, then
+     diagnose it differently (i.e., we may recurse). */
+  if (resolve_constraint_check (t))
+    inform (loc, "  concept %qE was not satisfied", expr);
   else
-    inform (loc, "  %qE evaluated to false", t);
+    inform (loc, "  %qE evaluated to false", expr);
 }
 
-// Diagnose constraint failures in a variable template-id T.
+/* Determine if the template-id T, when normalized as a constraint
+   is satisfied by ARGS. */
 void
-diagnose_var (location_t loc, tree t, tree args)
+diagnose_template_id (location_t loc, tree t, tree args)
 {
-  // If the template-id isn't a variable template, it can't be a
-  // valid constraint.
+  /* Check for invalid template-ids. */
   if (!variable_template_p (TREE_OPERAND (t, 0)))
     {
       inform (loc, "  invalid constraint %qE", t);
       return;
     }
 
-  if (check_diagnostic_constraints (t, args))
-    return;
-
-  tree var = DECL_TEMPLATE_RESULT (TREE_OPERAND (t, 0));
-  tree body = DECL_INITIAL (var);
-  tree targs = TREE_OPERAND (t, 1);
-  tree subst = tsubst_constraint_expr (body, targs, true);
-
-  inform (loc, "  failure in constraint %q#D", DECL_TI_TEMPLATE (var));
-
-  diagnose_node (loc, subst, args);
-}
-
-// Diagnose specific constraint failures.
-void
-diagnose_requires (location_t loc, tree t, tree args)
-{
-  if (check_diagnostic_constraints (t, args))
-    return;
-
-  tree subst = tsubst_constraint_expr (t, args, true);
-
-  // Print the header for the requires expression.
-  tree parms = TREE_OPERAND (subst, 0);
-  if (!VOID_TYPE_P (TREE_VALUE (parms)))
-    inform (loc, "  requiring syntax with values %Z", TREE_OPERAND (subst, 0));
-
-  // Create a new local specialization binding for the arguments.
-  // This lets us instantiate sub-expressions separately from the
-  // requires clause.
-  local_specialization_stack locals;
-  declare_local_parms (TREE_OPERAND (t, 0), TREE_OPERAND (subst, 0));
-
-  // Iterate over the sub-requirements and try instantiating each.
-  for (tree l = TREE_OPERAND (t, 1); l; l = TREE_CHAIN (l))
-    diagnose_node (loc, TREE_VALUE (l), args);
-}
-
-static void
-diagnose_validexpr (location_t loc, tree t, tree args)
-{
-  if (check_diagnostic_constraints (t, args))
+  if (check_constraint_expression (t, args))
     return;
-  inform (loc, "    %qE is not a valid expression", TREE_OPERAND (t, 0));
-}
 
-static void
-diagnose_validtype (location_t loc, tree t, tree args)
-{
-  if (check_diagnostic_constraints (t, args))
-    return;
+  /* Rebuild the expression for the purpose of diagnostics. */
+  ++processing_template_decl;
+  tree expr = tsubst_expr (t, args, tf_none, NULL_TREE, false);
+  --processing_template_decl;
 
-  // Substitute into the qualified name.
-  tree name = TREE_OPERAND (t, 0);
-  if (tree cxt = TYPE_CONTEXT (name))
-    {
-      tree id = TYPE_IDENTIFIER (name);
-      cxt = tsubst (cxt, args, tf_none, NULL_TREE);
-      name = build_qualified_name (NULL_TREE, cxt, id, false);
-      inform (loc, "    %qE does not name a valid type", name);
-    }
+  tree var = DECL_TEMPLATE_RESULT (TREE_OPERAND (t, 0));
+  if (DECL_DECLARED_CONCEPT_P (var))
+    inform (loc, "  concept %qE was not satisfied", expr);
   else
-    {
-      inform (loc, "    %qT does not name a valid type", name);
-    }
+    inform (loc, "  %qE evaluated to false", expr);
 }
 
-static void
-diagnose_constexpr (location_t loc, tree t, tree args)
-{
-  if (check_diagnostic_constraints (t, args))
-    return;
-  inform (loc, "    %qE is not a constant expression", TREE_OPERAND (t, 0));
-}
+/* Determine if the requires-expression, when normalized as a
+   constraint is satisfied by ARGS. 
 
-static void
-diagnose_noexcept (location_t loc, tree t, tree args)
+   TODO: Build sets of expressions, types, and constraints
+   based on the requirements in T and emit specific diagnostics
+   for those. */
+void
+diagnose_requires_expression (location_t loc, tree t, tree args)
 {
-  if (check_diagnostic_constraints (t, args))
+  if (check_constraint_expression (t, args))
     return;
-  inform (loc, "    %qE propagates exceptions", TREE_OPERAND (t, 0));
+  inform (loc, "requirements not satisfied");
 }
 
-// Diagnose a constraint failure in the expression T.
+/* Diagnose an expression that would be characterized as
+   a predicate constraint. */
 void
-diagnose_other (location_t loc, tree t, tree args)
+diagnose_other_expression (location_t loc, tree t, tree args)
 {
-  if (check_diagnostic_constraints (t, args))
+  if (check_constraint_expression (t, args))
     return;
   inform (loc, "  %qE evaluated to false", t);
 }
 
-// Diagnose a constraint failure in the subtree T.
 void
-diagnose_node (location_t loc, tree t, tree args)
+diagnose_expression (location_t loc, tree t, tree args)
 {
   switch (TREE_CODE (t))
     {
     case TRUTH_ANDIF_EXPR:
-      diagnose_node (loc, TREE_OPERAND (t, 0), args);
-      diagnose_node (loc, TREE_OPERAND (t, 1), args);
+      diagnose_logical_operation (loc, t, args);
       break;
 
     case TRUTH_ORIF_EXPR:
-      // TODO: Design better diagnostics for dijunctions.
-      diagnose_other (loc, t, args);
-      break;
-
-    case TRAIT_EXPR:
-      diagnose_trait (loc, t, args);
+      diagnose_logical_operation (loc, t, args);
       break;
 
     case CALL_EXPR:
-      diagnose_call (loc, t, args);
+      diagnose_call_expression (loc, t, args);
       break;
 
-    case REQUIRES_EXPR:
-      diagnose_requires (loc, t, args);
-      break;
-
-    case VALIDEXPR_EXPR:
-      diagnose_validexpr (loc, t, args);
-      break;
-
-    case VALIDTYPE_EXPR:
-      diagnose_validtype (loc, t, args);
-      break;
-
-    case CONSTEXPR_EXPR:
-      diagnose_constexpr (loc, t, args);
+    case TEMPLATE_ID_EXPR:
+      diagnose_template_id (loc, t, args);
       break;
 
-    case NOEXCEPT_EXPR:
-      diagnose_noexcept (loc, t, args);
+    case REQUIRES_EXPR:
+      diagnose_requires_expression (loc, t, args);
       break;
 
-    case TEMPLATE_ID_EXPR:
-      diagnose_var (loc, t, args);
+    case TRAIT_EXPR:
+      diagnose_trait_expression (loc, t, args);
       break;
 
     default:
-      diagnose_other (loc, t, args);
+      diagnose_other_expression (loc, t, args);
       break;
     }
 }
 
-// Diagnose a constraint failure in the requirements expression REQS.
 inline void
-diagnose_requirements (location_t loc, tree reqs, tree args)
+diagnose_predicate_constraint (location_t loc, tree t, tree args)
 {
-  diagnose_node (loc, reqs, args);
+  diagnose_expression (loc, PRED_CONSTR_EXPR (t), args);
 }
 
-// Create a tree node representing the substitution of ARGS into
-// the parameters of TMPL. The resulting structure is passed as an
-// for diagnosing substitutions.
-inline tree
-make_subst (tree tmpl, tree args)
+inline void
+diagnose_conjunction (location_t loc, tree t, tree args)
 {
-  tree subst = tree_cons (NULL_TREE, args, NULL_TREE);
-  TREE_TYPE (subst) = DECL_TEMPLATE_PARMS (tmpl);
-  return subst;
+  diagnose_constraint (loc, TREE_OPERAND (t, 0), args);
+  diagnose_constraint (loc, TREE_OPERAND (t, 1), args);
+}
+
+/* Diagnose the constraint T for the given ARGS. This is only
+   ever invoked on the associated constraints, so we can
+   only have conjunctions of predicate constraints. */
+void
+diagnose_constraint (location_t loc, tree t, tree args)
+{
+  switch (TREE_CODE (t))
+    {
+    case CONJ_CONSTR:
+      diagnose_conjunction (loc, t, args);
+      break;
+
+    case PRED_CONSTR:
+      diagnose_predicate_constraint (loc, t, args);
+      break;
+
+    default:
+      gcc_unreachable ();
+      break;
+    }
 }
 
 } // namespace
 
-// Emit diagnostics detailing the failure ARGS to satisfy the constraints
-// of the template declaration, TMPL.
+/* Emit diagnostics detailing the failure ARGS to satisfy the constraints
+   of the template declaration, DECL.  */
 void
 diagnose_constraints (location_t loc, tree decl, tree args)
 {
-  tree ci = get_constraints (decl);
+  inform (loc, "  constraints not satisfied");
 
-  // If the constraints could not be reduced, then we can't diagnose them.
-  if (!valid_requirements_p (ci))
+  /* Constraints are attached to the template.  */
+  if (tree ti = DECL_TEMPLATE_INFO (decl)) {
+    decl = TI_TEMPLATE (ti);
+    args = TI_ARGS (ti);
+  }
+  
+  /* Check that the constraints are actually valid.  */
+  tree ci = get_constraints (decl);
+  if (!valid_constraints_p (ci))
     {
-      inform (loc, "  invalid constraints");
+      inform (loc, "    invalid constraints");
       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);
-  //   }
-
-  // // 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_CONSTRAINTS (get_constraints (decl));
-  diagnose_requirements (loc, reqs, args);
+  /* Recursively diagnose the associated constraints.  */
+  tree assoc = CI_ASSOCIATED_CONSTRAINTS (ci);
+  diagnose_constraint (loc, assoc, args);
 }
diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c
index 21f7a19..7e5b64e 100644
--- a/gcc/cp/cp-objcp-common.c
+++ b/gcc/cp/cp-objcp-common.c
@@ -318,13 +318,6 @@ cp_common_init_ts (void)
   MARK_TS_TYPED (CTOR_INITIALIZER);
   MARK_TS_TYPED (ARRAY_NOTATION_REF);
   MARK_TS_TYPED (REQUIRES_EXPR);
-  MARK_TS_TYPED (EXPR_REQ);
-  MARK_TS_TYPED (TYPE_REQ);
-  MARK_TS_TYPED (NESTED_REQ);
-  MARK_TS_TYPED (VALIDEXPR_EXPR);
-  MARK_TS_TYPED (VALIDTYPE_EXPR);
-  MARK_TS_TYPED (CONSTEXPR_EXPR);
-
 }
 
 #include "gt-cp-cp-objcp-common.h"
diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
index 12799ce..4e5b640 100644
--- a/gcc/cp/cp-tree.def
+++ b/gcc/cp/cp-tree.def
@@ -475,20 +475,35 @@ DEFTREECODE (BASES, "bases", tcc_type, 0)
    instantiation time.  */
 DEFTREECODE (TEMPLATE_INFO, "template_info", tcc_exceptional, 0)
 
-/* Concepts. */
+/* Extensions for Concepts. */
 
 /* Used to represent information associated with constrained declarations. */
 DEFTREECODE (CONSTRAINT_INFO, "constraint_info", tcc_exceptional, 0)
 
-/* A requires-expr is a binary expression. The first operand is its
-   parameter list. The second is a list of requirements. */
+/* Alternative PLACEHOLDER_EXPR which is used for concept introductions.  This
+   is a temporary type which is used to produce normal template parameters.  */
+DEFTREECODE (INTRODUCED_PARM_DECL, "introduced_parm_decl", tcc_declaration, 0)
+
+/* A requires-expr is a binary expression. The first operand is 
+   its parameter list (possibly NULL). The second is a list of 
+   requirements, which are denoted by the _REQ* tree codes
+   below. */
 DEFTREECODE (REQUIRES_EXPR,   "requires_expr", tcc_expression, 2)
 
-/* The REQ expressions are unary expressions that specify individual
-   statements in a requires clause. */
-DEFTREECODE (EXPR_REQ, "expr-req", tcc_expression, 1)
-DEFTREECODE (TYPE_REQ, "type-req", tcc_expression, 1)
-DEFTREECODE (NESTED_REQ, "nested-req", tcc_expression, 1)
+/* A requirement for an expression. */
+DEFTREECODE (SIMPLE_REQ, "simple_req", tcc_expression, 1)
+
+/* A requirement for a type. */
+DEFTREECODE (TYPE_REQ, "type_req", tcc_expression, 1)
+
+/* A requirement for an expression and its properties. The
+   first operand is the expression, and the 2nd is its type.
+   The accessor COMPOUND_REQ_NOEXCEPT determines whether
+   the noexcept keyword was present. */
+DEFTREECODE (COMPOUND_REQ, "compound_req", tcc_expression, 2)
+
+/* A requires clause within a requires expression. */
+DEFTREECODE (NESTED_REQ, "nested_req", tcc_expression, 1)
 
 /* A unary expression representing a requirement for a valid expression. */
 DEFTREECODE (VALIDEXPR_EXPR, "validexpr_expr", tcc_expression, 1)
@@ -500,9 +515,61 @@ DEFTREECODE (VALIDTYPE_EXPR, "validtype_expr", tcc_expression, 1)
    can be evaluated at compile time. */
 DEFTREECODE (CONSTEXPR_EXPR, "contexpr_expr", tcc_expression, 1)
 
-/* Alternative PLACEHOLDER_EXPR which is used for concept introductions.  This
-   is a temporary type which is used to produce normal template parameters.  */
-DEFTREECODE (INTRODUCED_PARM_DECL, "introduced_parm_decl", tcc_declaration, 0)
+
+/* Constraints are modeled as kinds of expressions.
+   The operands of a constraint can be either types or expressions.
+   Unlike expressions, constraints do not have a type. */
+
+/* A predicate constraint evaluates an expression E. 
+
+   PRED_CONSTR_EXPR has the expression to be evaluated. */
+DEFTREECODE (PRED_CONSTR, "pred_constr", tcc_expression, 1)
+
+/* An expression constraint determines the validity of a expression E.
+
+   EXPR_CONST_EXPR has the expression being validated. */
+DEFTREECODE (EXPR_CONSTR, "expr_constr", tcc_expression, 1)
+
+/* A type constraint determines the validity of a type T. Note that
+
+   TYPE_CONST_TYPE has the type being validated */
+DEFTREECODE (TYPE_CONSTR, "type_constr", tcc_expression, 1)
+
+/* An implicit conversion constraint determines if an expression
+   E is implicitly convertible to a type T. Note that T may
+   be dependent but does not contain any placeholders.
+   
+   ICONV_CONSTR_EXPR has the expression E.
+   ICONV_CONSTR_TYPE has the type T. 
+   */
+DEFTREECODE (ICONV_CONSTR, "iconv_constr", tcc_expression, 2)
+
+/* An argument deduction constraint determines if the type of an
+   expression E can be deduced from a type pattern T. Note that
+   T must contain at least one place holder.
+
+   DEDUCT_CONSTR_EXPR has the expression E
+   DEDUCT_CONSTR_PATTERN has the type patter T. */
+DEFTREECODE (DEDUCT_CONSTR, "deduct_constr", tcc_expression, 2)
+
+/* An exception constraint determines if, for an expression E,
+   noexcept(E) is true. 
+
+   EXCEPT_CONSTR_EXPR has the expression E. */
+DEFTREECODE (EXCEPT_CONSTR, "except_constr", tcc_expression, 1)
+
+/* A parameterized constraint declares constraint variables, which
+   are used in expression, type, and exception constraints. 
+
+   PARM_CONSTR_PARMS has a TREE_LIST of parameter declarations.
+   PARM_CONSTR_OPERAND has the nested constraint. */
+DEFTREECODE (PARM_CONSTR, "parm_constr", tcc_expression, 2)
+
+/* The conjunction and disjunction of two constraints, respectively.
+   Operands are accessed using TREE_OPERAND. */
+DEFTREECODE (CONJ_CONSTR, "conj_constr", tcc_expression, 2)
+DEFTREECODE (DISJ_CONSTR, "disj_constr", tcc_expression, 2)
+
 
 /*
 Local variables:
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index a091be6..e427baa 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -93,6 +93,7 @@ c-common.h, not after.
       PACK_EXPANSION_LOCAL_P (in *_PACK_EXPANSION)
       TINFO_RECHECK_ACCESS_P (in TEMPLATE_INFO)
       SIZEOF_EXPR_TYPE_P (in SIZEOF_EXPR)
+      COMPOUND_REQ_NOEXCEPT_P (in COMPOUND_REQ)
       INTRODUCED_PACK_P (in INTRODUCED_PARM_DECL)
    1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE)
       TI_PENDING_TEMPLATE_FLAG.
@@ -890,6 +891,50 @@ check_constraint_info (tree t)
 #define TEMPLATE_PARM_CONSTRAINTS(NODE) \
   TREE_TYPE (TREE_LIST_CHECK (NODE))
 
+/* Non-zero if the noexcept is present in a compound requirement. */
+#define COMPOUND_REQ_NOEXCEPT_P(NODE) \
+  TREE_LANG_FLAG_0 (TREE_CHECK (NODE, COMPOUND_REQ))
+
+/* The expression evaluated by the predicate constraint. */
+#define PRED_CONSTR_EXPR(NODE) \
+  TREE_OPERAND (TREE_CHECK (NODE, PRED_CONSTR), 0)
+
+/* The expression validated by the predicate constraint. */
+#define EXPR_CONSTR_EXPR(NODE) \
+  TREE_OPERAND (TREE_CHECK (NODE, EXPR_CONSTR), 0)
+
+/* The type validated by the predicate constraint. */
+#define TYPE_CONSTR_TYPE(NODE) \
+  TREE_OPERAND (TREE_CHECK (NODE, TYPE_CONSTR), 0)
+
+/* In an implicit conversion constraint, the source expression. */
+#define ICONV_CONSTR_EXPR(NODE) \
+  TREE_OPERAND (TREE_CHECK (NODE, ICONV_CONSTR), 0)
+
+/* In an implicit conversion constraint, the target type. */
+#define ICONV_CONSTR_TYPE(NODE) \
+  TREE_OPERAND (TREE_CHECK (NODE, ICONV_CONSTR), 1)
+
+/* In an argument deduction constraint, the source expression. */
+#define DEDUCT_CONSTR_EXPR(NODE) \
+  TREE_OPERAND (TREE_CHECK (NODE, DEDUCT_CONSTR), 0)
+
+/* In an argument deduction constraint, the target type pattern. */
+#define DEDUCT_CONSTR_PATTERN(NODE) \
+  TREE_OPERAND (TREE_CHECK (NODE, DEDUCT_CONSTR), 1)
+
+/* The expression of an exception constraint. */
+#define EXCEPT_CONSTR_EXPR(NODE) \
+  TREE_OPERAND (TREE_CHECK (NODE, EXCEPT_CONSTR), 0)
+
+/* In a parameterized constraint, the local parameters. */
+#define PARM_CONSTR_PARMS(NODE) \
+  TREE_OPERAND (TREE_CHECK (NODE, PARM_CONSTR), 0)
+
+/* In a parameterized constraint, the operand. */
+#define PARM_CONSTR_OPERAND(NODE) \
+  TREE_OPERAND (TREE_CHECK (NODE, PARM_CONSTR), 1)
+
 enum cp_tree_node_structure_enum {
   TS_CP_GENERIC,
   TS_CP_IDENTIFIER,
@@ -6460,56 +6505,43 @@ extern void suggest_alternatives_for            (location_t, tree);
 extern tree strip_using_decl                    (tree);
 
 /* in constraint.cc */
+
+extern bool constraint_p                        (tree);
+extern tree make_predicate_constraint           (tree);
 extern tree conjoin_constraints                 (tree, tree);
 extern tree conjoin_constraints                 (tree);
+extern bool valid_constraints_p                 (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);
 extern tree build_constrained_parameter         (tree, tree, tree = NULL_TREE);
 extern bool deduce_constrained_parameter        (tree, tree&, tree&);
 extern tree resolve_constraint_check            (tree);
 extern tree check_function_concept              (tree);
-
-extern tree finish_concept_introduction         (tree, tree);
-extern tree finish_template_constraints         (tree);
-extern tree save_leading_constraints            (tree);
-extern tree save_trailing_constraints           (tree);
+extern tree finish_template_introduction        (tree, tree);
 extern bool valid_requirements_p                (tree);
 extern tree finish_concept_name                 (tree);
 extern tree finish_shorthand_constraint         (tree, tree);
 extern tree finish_requires_expr                (tree, tree);
-extern tree finish_expr_requirement             (tree, tree, tree);
-extern tree finish_expr_requirement             (tree);
+extern tree finish_simple_requirement           (tree);
 extern tree finish_type_requirement             (tree);
+extern tree finish_compound_requirement         (tree, tree, bool);
 extern tree finish_nested_requirement           (tree);
-extern tree finish_constexpr_requirement        (tree);
-extern tree finish_noexcept_requirement         (tree);
-extern tree finish_validexpr_expr               (tree);
-extern tree finish_validtype_expr               (tree);
-extern tree finish_constexpr_expr               (tree);
-
 extern void check_constrained_friend            (tree, tree);
-
 extern tree tsubst_requires_expr                (tree, tree, tsubst_flags_t, tree);
-extern tree tsubst_validexpr_expr               (tree, tree, tree);
-extern tree tsubst_validtype_expr               (tree, tree, tree);
-extern tree tsubst_constexpr_expr               (tree, tree, tree);
-extern tree tsubst_expr_req                     (tree, tree, tree);
-extern tree tsubst_type_req                     (tree, tree, tree);
-extern tree tsubst_nested_req                   (tree, tree, tree);
-
-extern tree tsubst_constraint_info              (tree, tree);
-extern tree tsubst_constraint_expr              (tree, tree, bool);
-
-extern bool check_constraints                   (tree);
-extern bool check_constraints                   (tree, tree);
-extern bool check_template_constraints          (tree, tree);
-extern tree subst_template_constraints          (tree, tree);
+extern tree tsubst_constraint_info              (tree, tree, tsubst_flags_t, tree);
+
+extern bool constraints_satisfied_p             (tree);
+extern bool constraints_satisfied_p             (tree, tree);
+extern tree evaluate_function_concept           (tree, tree);
+extern tree evaluate_variable_concept           (tree, tree);
+extern tree evaluate_constraint_expression      (tree, tree);
+extern bool check_constraint_expression         (tree, tree);
+
 extern bool equivalent_constraints              (tree, tree);
 extern bool equivalently_constrained            (tree, tree);
 extern bool subsumes_constraints                (tree, tree);
diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c
index 2e52f09..21f3fc4 100644
--- a/gcc/cp/cxx-pretty-print.c
+++ b/gcc/cp/cxx-pretty-print.c
@@ -453,30 +453,6 @@ cxx_pretty_printer::primary_expression (tree t)
       pp_cxx_requires_expr (this, t);
       break;
 
-    case EXPR_REQ:
-      pp_cxx_expr_requirement (this, t);
-      break;
-
-    case TYPE_REQ:
-      pp_cxx_type_requirement (this, t);
-      break;
-
-    case NESTED_REQ:
-      pp_cxx_nested_requirement (this, t);
-      break;
-
-    case VALIDEXPR_EXPR:
-      pp_cxx_validexpr_expr (this, t);
-      break;
-
-    case VALIDTYPE_EXPR:
-      pp_cxx_validtype_expr (this, t);
-      break;
-
-    case CONSTEXPR_EXPR:
-      pp_cxx_constexpr_expr (this, t);
-      break;
-
     default:
       c_pretty_printer::primary_expression (t);
       break;
@@ -1091,9 +1067,6 @@ cxx_pretty_printer::expression (tree t)
     case TEMPLATE_TEMPLATE_PARM:
     case STMT_EXPR:
     case REQUIRES_EXPR:
-    case EXPR_REQ:
-    case TYPE_REQ:
-    case NESTED_REQ:
       primary_expression (t);
       break;
 
@@ -1188,6 +1161,18 @@ cxx_pretty_printer::expression (tree t)
       pp_cxx_ws_string (this, "<lambda>");
       break;
 
+    case PRED_CONSTR:
+    case EXPR_CONSTR:
+    case TYPE_CONSTR:
+    case ICONV_CONSTR:
+    case DEDUCT_CONSTR:
+    case EXCEPT_CONSTR:
+    case PARM_CONSTR:
+    case CONJ_CONSTR:
+    case DISJ_CONSTR:
+      pp_cxx_constraint (this, t);
+      break;
+
     case PAREN_EXPR:
       pp_cxx_left_paren (this);
       expression (TREE_OPERAND (t, 0));
@@ -2549,24 +2534,60 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t)
   pp_cxx_right_paren (pp);
 }
 
+// requires-clause:
+//    'requires' logical-or-expression
+void
+pp_cxx_requires_clause (cxx_pretty_printer *pp, tree t)
+{
+  if (!t)
+    return;
+  pp->padding = pp_before;
+  pp_cxx_ws_string (pp, "requires");
+  pp_space (pp);
+  pp->expression (t);
+}
+
+/* requirement:
+     simple-requirement
+     compound-requirement
+     type-requirement
+     nested-requirement */
+static void
+pp_cxx_requirement (cxx_pretty_printer *pp, tree t)
+{
+  switch (TREE_CODE (t))
+    {
+    case SIMPLE_REQ:
+      pp_cxx_simple_requirement (pp, t);
+      break;
+
+    case TYPE_REQ:
+      pp_cxx_type_requirement (pp, t);
+      break;
+
+    case COMPOUND_REQ:
+      pp_cxx_compound_requirement (pp, t);
+
+    case NESTED_REQ:
+      pp_cxx_nested_requirement (pp, t);
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
 // requirement-list:
 //    requirement
 //    requirement-list ';' requirement[opt]
 //
-// requirement:
-//    simple-requirement
-//    compound-requirement
-//    type-requirement
-//    nested-requirement
 static void
 pp_cxx_requirement_list (cxx_pretty_printer *pp, tree t)
 {
-  int n = 3;
   for (; t; t = TREE_CHAIN (t))
     {
-      pp_newline_and_indent (pp, n);
-      pp->expression (TREE_VALUE (t));
-      n = 0;
+      pp_newline_and_indent (pp, 3);
+      pp_cxx_requirement (pp, TREE_VALUE (t));
     }
   pp_newline_and_indent (pp, -3);
 }
@@ -2581,19 +2602,6 @@ pp_cxx_requirement_body (cxx_pretty_printer *pp, tree t)
   pp_cxx_right_brace (pp);
 }
 
-// requires-clause:
-//    'requires' logical-or-expression
-void
-pp_cxx_requires_clause (cxx_pretty_printer *pp, tree t)
-{
-  if (!t)
-    return;
-  pp->padding = pp_before;
-  pp_cxx_ws_string (pp, "requires");
-  pp_space (pp);
-  pp->expression (t);
-}
-
 // requires-expression:
 //    'requires' requirement-parameter-list requirement-body
 void
@@ -2601,143 +2609,187 @@ pp_cxx_requires_expr (cxx_pretty_printer *pp, tree t)
 {
   pp_cxx_ws_string (pp, "requires");
   pp_space (pp);
-  pp_cxx_parameter_declaration_clause (pp, TREE_OPERAND (t, 0));
+  if (TREE_OPERAND (t, 0))
+    pp_cxx_parameter_declaration_clause (pp, TREE_OPERAND (t, 0));
   pp_space (pp);
   pp_cxx_requirement_body (pp, TREE_OPERAND (t, 1));
 }
 
-// constraint-specifier:
-//    noexcept
-//    constexpr
-static void
-pp_cxx_constraint_specifier (cxx_pretty_printer *pp, tree t)
+/* simple-requirement:
+     expression ';' */
+void
+pp_cxx_simple_requirement (cxx_pretty_printer *pp, tree t)
 {
-  if (TREE_CODE (t) == NOEXCEPT_EXPR)
-    pp_cxx_ws_string (pp, "noexcept");
-  else if (TREE_CODE (t) == CONSTEXPR_EXPR)
-    pp_cxx_ws_string (pp, "constexpr");
-  else
-    gcc_unreachable ();
+  pp->expression (TREE_OPERAND (t, 0));
+  pp_cxx_semicolon (pp);
 }
 
-// compound-requirement:
-//    '{' expression '}' trailing-constraint-specifiers
-//
-// trailing-constraint-specifiers:
-//    constraint-specifiers-seq[opt] result-type-requirement[opt]
-//
-// result-type-requirement:
-//    '->' type-id
-static void
-pp_cxx_compound_requirement (cxx_pretty_printer *pp, tree t)
+/* type-requirement:
+     typename type-name ';' */
+void
+pp_cxx_type_requirement (cxx_pretty_printer *pp, tree t)
 {
-  // Get the expression requirement.
-  tree ereq = TREE_OPERAND (t, 0);
-
-  // Find the tree node containing the result type requirement.
-  // Note that validtype requirements are implicit.
-  tree treq = TREE_CHAIN (ereq);
-  if (TREE_CODE (TREE_VALUE (treq)) == VALIDTYPE_EXPR)
-    treq = TREE_CHAIN (treq);
-
-  // Find tree nodes for any additional constraint specifiers.
-  tree spec1 = TREE_CHAIN (treq);
-  tree spec2 = spec1 ? TREE_CHAIN (spec1) : NULL_TREE;
+  pp->type_id (TREE_OPERAND (t, 0));
+  pp_cxx_semicolon (pp);
+}
 
-  // Pretty print the {expr} requirement
-  tree expr = TREE_OPERAND (TREE_VALUE (ereq), 0);
+/* compound-requirement:
+     '{' expression '}' 'noexcept' [opt] trailing-return-type [opt] */
+void
+pp_cxx_compound_requirement (cxx_pretty_printer *pp, tree t)
+{
   pp_cxx_left_brace (pp);
-  pp->expression (expr);
+  pp->expression (TREE_OPERAND (t, 0));
   pp_cxx_right_brace (pp);
 
-  // Pretty constraint specifiers, if any.
-  if (spec1)
-    {
-      pp_space (pp);
-      pp_cxx_constraint_specifier (pp, TREE_VALUE (spec1));
-      if (spec2)
-        pp_cxx_constraint_specifier (pp, TREE_VALUE (spec2));
-    }
+  if (COMPOUND_REQ_NOEXCEPT_P (t))
+    pp_cxx_ws_string (pp, "noexcept");
 
-  // Pretty print the '-> type-id' part of the expression.
-  // Note that treq will contain a TRAIT_EXPR.
-  if (treq)
+  if (tree type = TREE_OPERAND (t, 1))
     {
-      tree type = TRAIT_EXPR_TYPE2 (TREE_VALUE (treq));
-      pp_space (pp);
-      pp_cxx_arrow (pp);
-      pp_space (pp);
+      pp_cxx_ws_string (pp, "->");
       pp->type_id (type);
     }
 }
 
-// simple-requirement:
-//    expression
-static void
-pp_cxx_simple_requirement (cxx_pretty_printer *pp, tree t)
+/* nested requirement:
+     'requires' constraint-expression */
+void
+pp_cxx_nested_requirement (cxx_pretty_printer *pp, tree t)
 {
-  tree req = TREE_OPERAND (t, 0);
-  pp->expression (TREE_OPERAND (req, 0));
+  pp_cxx_ws_string (pp, "requires");
+  pp->expression (TREE_OPERAND (t, 0));
+  pp_cxx_semicolon (pp);
 }
 
 void
-pp_cxx_expr_requirement (cxx_pretty_printer *pp, tree t)
+pp_cxx_predicate_constraint (cxx_pretty_printer *pp, tree t)
 {
-  tree reqs = TREE_OPERAND (t, 0);
-  if (TREE_CODE (reqs) == TREE_LIST)
-    pp_cxx_compound_requirement (pp, t);
-  else
-    pp_cxx_simple_requirement (pp, t);
-  pp_cxx_semicolon (pp);
+  pp_cxx_ws_string (pp, "__pred");
+  pp->expression (TREE_OPERAND (t, 0));
 }
 
-// type-requirement:
-//    type-id
 void
-pp_cxx_type_requirement (cxx_pretty_printer *pp, tree t)
+pp_cxx_expression_constraint (cxx_pretty_printer *pp, tree t)
 {
-  tree req = TREE_OPERAND (t, 0);
-  pp->type_id (TREE_OPERAND (req, 0));
-  pp_cxx_semicolon (pp);
+  pp_cxx_ws_string (pp, "__is_valid ");
+  pp_left_paren (pp);
+  pp->expression (TREE_OPERAND (t, 0)); 
+  pp_right_paren (pp);
 }
 
-// nested requirement:
-//    'requires' logical-or-expression
 void
-pp_cxx_nested_requirement (cxx_pretty_printer *pp, tree t)
+pp_cxx_type_constraint (cxx_pretty_printer *pp, tree t)
 {
-  pp_cxx_ws_string (pp, "requires");
-  pp->expression (TREE_OPERAND (t, 0));
-  pp_cxx_semicolon (pp);
+  pp_cxx_ws_string (pp, "__is_valid ");
+  pp_left_paren (pp);
+  pp->expression (TREE_OPERAND (t, 0)); 
+  pp_right_paren (pp);
 }
 
 void
-pp_cxx_validexpr_expr (cxx_pretty_printer *pp, tree t)
+pp_cxx_implicit_conversion_constraint (cxx_pretty_printer *pp, tree t)
 {
-  pp_cxx_ws_string (pp, "__is_valid_expr");
-  pp_cxx_left_paren (pp);
-  pp->expression (TREE_OPERAND (t, 0));
-  pp_cxx_right_paren (pp);
+  pp_cxx_ws_string (pp, "__implicitly_convertible");
+  pp_left_paren (pp);
+  pp->expression (ICONV_CONSTR_EXPR (t));
+  pp->expression (ICONV_CONSTR_TYPE (t));
+  pp_right_paren (pp);
 }
 
 void
-pp_cxx_validtype_expr (cxx_pretty_printer *pp, tree t)
+pp_cxx_argument_deduction_constraint (cxx_pretty_printer *pp, tree t)
 {
-  pp_cxx_ws_string (pp, "__is_valid_expr");
-  pp_cxx_left_paren (pp);
-  pp->type_id(TREE_OPERAND (t, 0));
-  pp_cxx_right_paren (pp);
+  pp_cxx_ws_string (pp, "__deducible");
+  pp_left_paren (pp);
+  pp->expression (DEDUCT_CONSTR_EXPR (t));
+  pp->expression (DEDUCT_CONSTR_PATTERN (t));
+  pp_right_paren (pp);
 }
 
 void
-pp_cxx_constexpr_expr (cxx_pretty_printer *pp, tree t)
+pp_cxx_exception_constraint (cxx_pretty_printer *pp, tree t)
 {
-  pp_cxx_ws_string (pp, "__is_valid_expr");
-  pp_cxx_left_paren (pp);
+  pp_cxx_ws_string (pp, "noexcept");
+  pp_left_paren (pp);
   pp->expression (TREE_OPERAND (t, 0));
-  pp_cxx_right_paren (pp);
+  pp_right_paren (pp);
 }
 
+void
+pp_cxx_parameterized_constraint (cxx_pretty_printer *pp, tree t)
+{
+  pp_cxx_ws_string (pp, "\\...");
+  pp_left_paren (pp);
+  pp_cxx_parameter_declaration_clause (pp, PARM_CONSTR_PARMS (t));
+  pp_cxx_whitespace (pp);
+  pp_cxx_constraint (pp, PARM_CONSTR_OPERAND (t));
+  pp_right_paren (pp);
+}
+
+void
+pp_cxx_conjunction (cxx_pretty_printer *pp, tree t)
+{
+  pp_cxx_constraint (pp, TREE_OPERAND (t, 0));
+  pp_cxx_ws_string (pp, "and");
+  pp_cxx_constraint (pp, TREE_OPERAND (t, 1));
+}
+
+void
+pp_cxx_disjunction (cxx_pretty_printer *pp, tree t)
+{
+  pp_cxx_constraint (pp, TREE_OPERAND (t, 0));
+  pp_cxx_ws_string (pp, "or");
+  pp_cxx_constraint (pp, TREE_OPERAND (t, 1));
+}
+
+void
+pp_cxx_constraint (cxx_pretty_printer *pp, tree t)
+{
+  switch (TREE_CODE (t))
+    {
+    case PRED_CONSTR:
+      pp_cxx_predicate_constraint (pp, t);
+      break;
+
+    case EXPR_CONSTR:
+      pp_cxx_expression_constraint (pp, t);
+      break;
+
+    case TYPE_CONSTR:
+      pp_cxx_type_constraint (pp, t);
+      break;
+
+    case ICONV_CONSTR:
+      pp_cxx_implicit_conversion_constraint (pp, t);
+      break;
+
+    case DEDUCT_CONSTR:
+      pp_cxx_argument_deduction_constraint (pp, t);
+      break;
+
+    case EXCEPT_CONSTR:
+      pp_cxx_exception_constraint (pp, t);
+      break;
+
+    case PARM_CONSTR:
+      pp_cxx_parameterized_constraint (pp, t);
+      break;
+
+    case CONJ_CONSTR:
+      pp_cxx_conjunction (pp, t);
+      break;
+
+    case DISJ_CONSTR:
+      pp_cxx_disjunction (pp, t);
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
+
 
 typedef c_pretty_print_fn pp_fun;
 
diff --git a/gcc/cp/cxx-pretty-print.h b/gcc/cp/cxx-pretty-print.h
index 4606455..42897b8 100644
--- a/gcc/cp/cxx-pretty-print.h
+++ b/gcc/cp/cxx-pretty-print.h
@@ -94,12 +94,19 @@ void pp_cxx_userdef_literal (cxx_pretty_printer *, tree);
 void pp_cxx_parameter_declaration_clause (cxx_pretty_printer *, tree);
 void pp_cxx_requires_clause (cxx_pretty_printer *, tree);
 void pp_cxx_requires_expr (cxx_pretty_printer *, tree);
-void pp_cxx_expr_requirement (cxx_pretty_printer *, tree);
+void pp_cxx_simple_requirement (cxx_pretty_printer *, tree);
 void pp_cxx_type_requirement (cxx_pretty_printer *, tree);
+void pp_cxx_compound_requirement (cxx_pretty_printer *, tree);
 void pp_cxx_nested_requirement (cxx_pretty_printer *, tree);
-void pp_cxx_validexpr_expr (cxx_pretty_printer *, tree);
-void pp_cxx_validtype_expr (cxx_pretty_printer *, tree);
-void pp_cxx_constexpr_expr (cxx_pretty_printer *, tree);
-
+void pp_cxx_predicate_constraint (cxx_pretty_printer *, tree);
+void pp_cxx_expression_constraint (cxx_pretty_printer *, tree);
+void pp_cxx_type_constraint (cxx_pretty_printer *, tree);
+void pp_cxx_implicit_conversion_constraint (cxx_pretty_printer *, tree);
+void pp_cxx_argument_deduction_constraint (cxx_pretty_printer *, tree);
+void pp_cxx_exception_constraint (cxx_pretty_printer *, tree);
+void pp_cxx_parameterized_constraint (cxx_pretty_printer *, tree);
+void pp_cxx_conjunction (cxx_pretty_printer *, tree);
+void pp_cxx_disjunction (cxx_pretty_printer *, tree);
+void pp_cxx_constraint (cxx_pretty_printer *, tree);
 
 #endif /* GCC_CXX_PRETTY_PRINT_H */
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 4686ab4..72bdb54 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -2604,9 +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);
+  /* Remove the associated constraints for newdecl, if any, before
+     reclaiming memory. */
+  if (flag_concepts)
+    remove_constraints (newdecl);
 
   ggc_free (newdecl);
 
@@ -7678,13 +7679,18 @@ grokfndecl (tree ctype,
 
   decl = build_lang_decl (FUNCTION_DECL, declarator, type);
 
-  // Set the constraints on the declaration.
+  /* Set the constraints on the declaration. */
   if (flag_concepts)
     {
-      tree temp_reqs = NULL_TREE;
+      tree tmpl_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);
+        tmpl_reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
+
+      /* Adjust the required expression into a constraint. */
+      if (decl_reqs)
+        decl_reqs = make_predicate_constraint (decl_reqs);
+
+      tree ci = build_constraints (tmpl_reqs, decl_reqs);
       set_constraints (decl, ci);
     }
 
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index eb3b0f9..3d8db12 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -4941,6 +4941,7 @@ mark_used (tree decl, tsubst_flags_t complain)
 	      && (DECL_DECLARED_CONSTEXPR_P (decl)
 		  || DECL_OMP_DECLARE_REDUCTION_P (decl)))
 	  || undeduced_auto_decl (decl))
+      && !DECL_DECLARED_CONCEPT_P (decl)
       && !uses_template_parms (DECL_TI_ARGS (decl)))
     {
       /* Instantiating a function will result in garbage collection.  We
@@ -5034,6 +5035,7 @@ mark_used (tree decl, tsubst_flags_t complain)
     }
   else if (VAR_OR_FUNCTION_DECL_P (decl)
 	   && DECL_TEMPLATE_INFO (decl)
+           && !DECL_DECLARED_CONCEPT_P (decl)
 	   && (!DECL_EXPLICIT_INSTANTIATION (decl)
 	       || always_instantiate_p (decl)))
     /* If this is a function or variable that is an instance of some
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 3779f14..022033e 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -2696,29 +2696,38 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
       pp_cxx_requires_expr (cxx_pp, t);
       break;
 
-    case EXPR_REQ:
-      pp_cxx_expr_requirement (cxx_pp, t);
+    case SIMPLE_REQ:
+      pp_cxx_simple_requirement (cxx_pp, t);
       break;
 
     case TYPE_REQ:
       pp_cxx_type_requirement (cxx_pp, t);
       break;
 
+    case COMPOUND_REQ:
+      pp_cxx_compound_requirement (cxx_pp, t);
+      break;
+
     case NESTED_REQ:
       pp_cxx_nested_requirement (cxx_pp, t);
       break;
 
-    case VALIDEXPR_EXPR:
-      pp_cxx_validexpr_expr (cxx_pp, t);
+    case PRED_CONSTR:
+      pp_cxx_ws_string (cxx_pp, "__pred");
+      dump_expr (cxx_pp, TREE_OPERAND (t, 0), flags | TFF_EXPR_IN_PARENS);
       break;
 
-    case VALIDTYPE_EXPR:
-      pp_cxx_validtype_expr (cxx_pp, t);
+    case EXPR_CONSTR:
+    case TYPE_CONSTR:
+    case ICONV_CONSTR:
+    case DEDUCT_CONSTR:
+    case EXCEPT_CONSTR:
+    case PARM_CONSTR:
+    case CONJ_CONSTR:
+    case DISJ_CONSTR:
+      pp_cxx_constraint (cxx_pp, t);
       break;
 
-    case CONSTEXPR_EXPR:
-      pp_cxx_constexpr_expr (cxx_pp, t);
-
     case PLACEHOLDER_EXPR:
       pp_string (pp, M_("*this"));
       break;
diff --git a/gcc/cp/logic.cc b/gcc/cp/logic.cc
index 389df02..5390ac4 100644
--- a/gcc/cp/logic.cc
+++ b/gcc/cp/logic.cc
@@ -52,16 +52,17 @@ template<typename I1, typename I2, typename I3>
     return iter;
   }
 
+/*---------------------------------------------------------------------------
+                           Proof state
+---------------------------------------------------------------------------*/
 
-// -------------------------------------------------------------------------- //
-// Term List
-//
-// A term list is a list of propositions in the constraint language. It is
-// used to maintain the lists of assumptions and conclusions in a proof goal.
-//
-// Each term list maintains an iterator that refers to the current term. This
-// can be used by various tactics to support iteration and stateful
-// manipulation of the list.
+/* A term list is a list of atomic constraints. It is used 
+   to maintain the lists of assumptions and conclusions in a 
+   proof goal.
+
+   Each term list maintains an iterator that refers to the current 
+   term. This can be used by various tactics to support iteration 
+   and stateful manipulation of the list. */
 struct term_list : std::list<tree>
 {
   term_list ();
@@ -101,19 +102,19 @@ term_list::operator= (const term_list &x)
   return *this;
 }
 
-// Insert the term T into the list before the current position, making
-// this term current.
+/* Insert the term T into the list before the current 
+   position, making this term current. */
 inline void
 term_list::insert (tree t)
 {
   current = std::list<tree>::insert (current, t);
 }
 
-// Remove the current term from the list, repositioning to the term
-// following the removed term. Note that the new position could be past
-// the end of the list.
-//
-// The removed term is returned.
+/* Remove the current term from the list, repositioning to 
+   the term following the removed term. Note that the new 
+   position could be past the end of the list.
+
+   The removed term is returned. */
 inline tree
 term_list::erase ()
 {
@@ -122,21 +123,21 @@ term_list::erase ()
   return t;
 }
 
-// Initialize the current term to the first in the list.
+/* Initialize the current term to the first in the list. */
 inline void
 term_list::start ()
 {
   current = begin ();
 }
 
-// Advance to the next term in the list.
+/* Advance to the next term in the list. */
 inline void
 term_list::next ()
 {
   ++current;
 }
 
-// Returns true when the current position is past the end.
+/* Returns true when the current position is past the end. */
 inline bool
 term_list::done () const
 {
@@ -144,25 +145,20 @@ term_list::done () const
 }
 
 
-// -------------------------------------------------------------------------- //
-// Proof Goal
-//
-// A goal (or subgoal) models a sequent of the form 'A |- C' where A and C are
-// lists of assumptions and conclusions written as propositions in the
-// constraint language (i.e., lists of trees).
+/* A goal (or subgoal) models a sequent of the form 
+   'A |- C' where A and C are lists of assumptions and 
+   conclusions written as propositions in the constraint 
+   language (i.e., lists of trees).
+*/
 struct proof_goal
 {
   term_list assumptions;
   term_list conclusions;
 };
 
-
-// -------------------------------------------------------------------------- //
-// Proof State
-//
-// A proof state owns a list of goals and tracks the current sub-goal.
-// The class also provides facilities for managing subgoals and constructing
-// term lists.
+/* A proof state owns a list of goals and tracks the 
+   current sub-goal. The class also provides facilities 
+   for managing subgoals and constructing term lists. */
 struct proof_state : std::list<proof_goal>
 {
   proof_state ();
@@ -170,144 +166,95 @@ struct proof_state : std::list<proof_goal>
   iterator branch (iterator i);
 };
 
-// An alias for proof state iterators.
+/* An alias for proof state iterators. */
 typedef proof_state::iterator goal_iterator;
 
-// Initialize the state with a single empty goal, and set that goal as the
-// current subgoal.
+/* Initialize the state with a single empty goal, 
+   and set that goal as the current subgoal. */
 inline
 proof_state::proof_state ()
   : std::list<proof_goal> (1)
 { }
 
 
-// Branch the current goal by creating a new subgoal, returning a reference to
-// the new object. This does not update the current goal.
+/* Branch the current goal by creating a new subgoal, 
+   returning a reference to // the new object. This does 
+   not update the current goal. */
 inline proof_state::iterator
 proof_state::branch (iterator i)
 {
   return insert (++i, *i);
 }
 
+/*---------------------------------------------------------------------------
+                           Logical rules
+---------------------------------------------------------------------------*/
 
-// -------------------------------------------------------------------------- //
-// Logical Rules
-//
-// These functions modify the current state and goal by decomposing
-// logical expressions using the logical rules of sequent calculus for
-// first order logic.
-//
-// Note that in each decomposition rule, the term T has been erased
-// from term list before the specific rule is applied.
-
-// Left-and logical rule.
-//
-//  Gamma, P, Q |- Delta
-//  -------------------------
-//  Gamma, P and Q |- Delta
-inline void
-left_and (proof_state &, goal_iterator i, tree t)
+/*These functions modify the current state and goal by decomposing
+  logical expressions using the logical rules of sequent calculus for
+  first order logic.
+
+  Note that in each decomposition rule, the term T has been erased
+  from term list before the specific rule is applied. */
+
+/* The left logical rule for conjunction adds both operands
+   to the current set of constraints. */
+void
+left_conjunction (proof_state &, goal_iterator i, tree t)
 {
-  gcc_assert (TREE_CODE (t) == TRUTH_ANDIF_EXPR);
+  gcc_assert (TREE_CODE (t) == CONJ_CONSTR);
 
-  // Insert the operands into the current branch. Note that the
-  // final order of insertion is left-to-right.
+  /* Insert the operands into the current branch. Note that the
+     final order of insertion is left-to-right. */
   term_list &l = i->assumptions;
   l.insert (TREE_OPERAND (t, 1));
   l.insert (TREE_OPERAND (t, 0));
 }
 
-// Left-or logical rule.
-//
-//  Gamma, P |- Delta    Gamma, Q |- Delta
-//  -----------------------------------------
-//  Gamma, P or Q |- Delta
-inline void
-left_or (proof_state &s, goal_iterator i, tree t)
+/* The left logical rule for disjunction creates a new goal, 
+   adding the first operand to the original set of 
+   constraints and the second operand to the new set 
+   of constraints. */
+void
+left_disjunction (proof_state &s, goal_iterator i, tree t)
 {
-  gcc_assert (TREE_CODE (t) == TRUTH_ORIF_EXPR);
+  gcc_assert (TREE_CODE (t) == DISJ_CONSTR);
 
-  // Branch the current subgoal.
+  /* Branch the current subgoal. */
   goal_iterator j = s.branch (i);
   term_list &l1 = i->assumptions;
   term_list &l2 = j->assumptions;
 
-  // Insert operands into the different branches.
+  /* Insert operands into the different branches. */
   l1.insert (TREE_OPERAND (t, 0));
   l2.insert (TREE_OPERAND (t, 1));
 }
 
-// Left-requires logical rule
-// A requirement is effectively a conjunction of syntactic requirements.
-// The arguments are discarded.
-//
-//  Gamma, P1, P2, ..., Pn |- Delta
-//  --------------------------------------------------
-//  Gamma, requires(args) { P1, P2, ..., Pn } |- Delta
-inline void
-left_requires (proof_state &, goal_iterator i, tree t)
+/* The left logical rules for parameterized constraints
+   adds its operand to the current goal. The list of
+   parameters are effectively discarded. */
+void
+left_parameterized_constraint (proof_state &, goal_iterator i, tree t)
 {
-  gcc_assert (TREE_CODE (t) == REQUIRES_EXPR);
-
-  // Insert the sub-expressions into the curent term list.
+  gcc_assert (TREE_CODE (t) == PARM_CONSTR);
   term_list &l = i->assumptions;
-  for (tree p = TREE_OPERAND (t, 1); p; p = TREE_CHAIN (p))
-    l.insert (TREE_VALUE (p));
+  l.insert (PARM_CONSTR_OPERAND (t));
 }
 
-// Right-and logical rule.
-//
-//  Gamma |- P, Delta    Gamma |- Q, Delta
-//  -----------------------------------------
-//  Gamma |- P and Q, Delta
-inline void
-right_and (proof_state &s, goal_iterator i, tree t)
-{
-  gcc_assert (TREE_CODE (t) == TRUTH_ORIF_EXPR);
+/*---------------------------------------------------------------------------
+                           Decomposition
+---------------------------------------------------------------------------*/
 
-  // Branch the current subgoal.
-  goal_iterator j = s.branch (i);
-  term_list &l1 = i->conclusions;
-  term_list &l2 = j->conclusions;
+/* The following algorithms decompose expressions into sets of 
+   atomic propositions. In terms of the sequent calculus, these
+   functions exercise the logical rules only. 
 
-  // Insert operands into the different branches.
-  l1.insert (TREE_OPERAND (t, 0));
-  l2.insert (TREE_OPERAND (t, 1));
-}
-
-// Right-or logical rule.
-//
-//  Gamma |- P, Q, Delta
-//  ------------------------
-//  Gamma |- P or Q, Delta
-inline void
-right_or (proof_state &, goal_iterator i, tree t)
-{
-  gcc_assert (TREE_CODE (t) == TRUTH_ANDIF_EXPR);
-
-  // Insert the operands into the current branch. Note that the
-  // final order of insertion is left-to-right.
-  term_list &l = i->conclusions;
-  l.insert (TREE_OPERAND (t, 1));
-  l.insert (TREE_OPERAND (t, 0));
-}
-
-
-// -------------------------------------------------------------------------- //
-// Decomposition
-//
-// The following algorithms decompose expressions into sets of atomic
-// propositions.
-//
-// These decomposition strategies do not branch conclusions so that
-// only a single term exists on the right side. These algorithms decompose
-// expressions until we have a set of atomic sequent that contain no
-// more logical expressions.
-
-// Left decomposition.
-// Continually decompose assumptions until there are no terms in any
-// subgoal that can be further decomposed.
+   This is equivalent, for the purpose of determining subsumption,
+   to rewriting a constraint in disjunctive normal form. It also
+   allows the resulting assumptions to be used as declarations
+   for the purpose of separate checking. */
 
+/* Apply the left logical rules to the proof state. */
 void
 decompose_left_term (proof_state &s, goal_iterator i)
 {
@@ -315,14 +262,14 @@ decompose_left_term (proof_state &s, goal_iterator i)
   tree t = l.current_term ();
   switch (TREE_CODE (t))
     {
-    case TRUTH_ANDIF_EXPR:
-      left_and (s, i, l.erase ());
+    case CONJ_CONSTR:
+      left_conjunction (s, i, l.erase ());
       break;
-    case TRUTH_ORIF_EXPR:
-      left_or (s, i, l.erase ());
+    case DISJ_CONSTR:
+      left_disjunction (s, i, l.erase ());
       break;
-    case REQUIRES_EXPR:
-      left_requires (s, i, l.erase ());
+    case PARM_CONSTR:
+      left_parameterized_constraint (s, i, l.erase ());
       break;
     default:
       l.next ();
@@ -330,6 +277,9 @@ decompose_left_term (proof_state &s, goal_iterator i)
     }
 }
 
+/* Apply the left logical rules of the sequent calculus 
+   until the current goal is fully decomposed into atomic 
+   constraints. */
 void
 decompose_left_goal (proof_state &s, goal_iterator i)
 {
@@ -339,7 +289,10 @@ decompose_left_goal (proof_state &s, goal_iterator i)
     decompose_left_term (s, i);
 }
 
-inline void
+/* Apply the left logical rules of the sequent calculus 
+   until the antecedents are fully decomposed into atomic
+   constraints. */
+void
 decompose_left (proof_state& s)
 {
   goal_iterator iter = s.begin ();
@@ -348,14 +301,7 @@ decompose_left (proof_state& s)
     decompose_left_goal (s, iter);
 }
 
-
-// -------------------------------------------------------------------------- //
-// Term Extraction
-//
-// Extract a list of term lists from a proof state, and return it as a
-// a tree (a vector of vectors).
-
-// Returns a vector of terms from the given term list.
+/* Returns a vector of terms from the term list L. */
 tree
 extract_terms (term_list& l)
 {
@@ -367,7 +313,8 @@ extract_terms (term_list& l)
   return result;
 }
 
-// Extract the assumption vector from the proof state s.
+/* Extract the assumptions from the proof state S
+   as a vector of vectors of atomic constraints. */
 inline tree
 extract_assumptions (proof_state& s)
 {
@@ -381,59 +328,56 @@ extract_assumptions (proof_state& s)
 
 } // namespace
 
-
-// Decompose the required expression T into a constraint set: a
-// vector of vectors containing only atomic propositions. If T is
-// invalid, return an error.
+/* Decompose the required expression T into a constraint set: a
+   vector of vectors containing only atomic propositions. If T is
+   invalid, return an error. */
 tree
 decompose_assumptions (tree t)
 {
   if (!t || t == error_mark_node)
     return t;
 
-  // Create a proof state, and insert T as the sole assumption.
+  /* Create a proof state, and insert T as the sole assumption. */
   proof_state s;
   term_list &l = s.begin ()->assumptions;
   l.insert (t);
 
-  // Decompose the expression into a constraint set, and then
-  // extract the terms for the AST.
+  /* Decompose the expression into a constraint set, and then
+     extract the terms for the AST. */
   decompose_left (s);
   return extract_assumptions (s);
 }
 
 
-// -------------------------------------------------------------------------- //
-// Subsumption and Entailment
-//
-// The following framework implements the subsumption and entailment
-// logic used for overload resolution and lookup.
+/*---------------------------------------------------------------------------
+                           Subsumption Rules
+---------------------------------------------------------------------------*/
 
 namespace {
 
-bool subsumes_prop(tree, tree);
-bool subsumes_atom(tree, tree);
-bool subsumes_and(tree, tree);
-bool subsumes_or(tree, tree);
-
-// Returns true if the assumption A matches the conclusion C. This
-// is generally the case when A and C have the same syntax.
-//
-// TODO: Implement special cases for:
-//    * __is_same_as |- __is_convertible_to
-//    * __is_same_as |- __is_derived_from
-//    * Any other built-in predicates?
+bool subsumes_constraint (tree, tree);
+bool subsumes_conjunction (tree, tree);
+bool subsumes_disjunction (tree, tree);
+bool subsumes_parameterized_constraint (tree, tree);
+bool subsumes_atomic_constraint (tree, tree);
+
+/* Returns true if the assumption A matches the conclusion C. This
+   is generally the case when A and C have the same syntax. 
+
+   NOTE: There will be specialized matching rules to accommodate
+   type equivalence, conversion, inheritance, etc. But this is not
+   in the current concepts draft. */
 inline bool
 match_terms (tree a, tree c)
 {
   return cp_tree_equal (a, c);
 }
 
-// Returns true if the list of assumptions AS subsumes the atomic
-// proposition C. This is the case when we can find a proposition in
-// AS that entails the conclusion C.
+/* Returns true if the list of assumptions AS subsumes the atomic
+   proposition C. This is the case when we can find a proposition
+  in AS that entails the conclusion C. */
 bool
-subsumes_atom (tree as, tree c)
+subsumes_atomic_constraint (tree as, tree c)
 {
   for (int i = 0; i < TREE_VEC_LENGTH (as); ++i)
     if (match_terms (TREE_VEC_ELT (as, i), c))
@@ -441,80 +385,79 @@ subsumes_atom (tree as, tree c)
   return false;
 }
 
-// Returns true when both operands of C are subsumed by the assumptions AS.
+/* Returns true when both operands of C are subsumed by the 
+   assumptions AS. */
 inline bool
-subsumes_and (tree as, tree c)
+subsumes_conjunction (tree as, tree c)
 {
   tree l = TREE_OPERAND (c, 0);
   tree r = TREE_OPERAND (c, 1);
-  return subsumes_prop (as, l) && subsumes_prop (as, r);
+  return subsumes_constraint (as, l) && subsumes_constraint (as, r);
 }
 
-// Returns true when either operand of C is subsumed by the assumptions AS.
+/* Returns true when either operand of C is subsumed by the 
+   assumptions AS. */
 inline bool
-subsumes_or (tree as, tree c)
+subsumes_disjunction (tree as, tree c)
 {
   tree l = TREE_OPERAND (c, 0);
   tree r = TREE_OPERAND (c, 1);
-  return subsumes_prop (as, l) || subsumes_prop (as, r);
+  return subsumes_constraint (as, l) || subsumes_constraint (as, r);
 }
 
-// Returns true when the sub-requirements of C are subsumed by the
-// assumptions in AS.
+/* Returns true when the operand of C is subsumed by the
+   assumptions in AS. The parameters are not considered in
+   the subsumption rules. */
 bool
-subsumes_requires (tree as, tree c)
+subsumes_parameterized_constraint (tree as, tree c)
 {
-  tree t = TREE_OPERAND (c, 1);
-  while (t && subsumes_prop (as, TREE_VALUE (t)))
-    t = TREE_CHAIN (t);
-  return !t;
+  tree t = PARM_CONSTR_OPERAND (c);
+  return subsumes_constraint (as, t);
 }
 
-// Returns true when the list of assumptions AS subsumes the
-// concluded proposition C.
-//
-// This is a simple recursive descent on C, matching against
-// propositions in the assumption list AS.
+
+/* Returns true when the list of assumptions AS subsumes the
+   concluded proposition C. This is a simple recursive descent 
+   on C, matching against propositions in the assumption list AS. */
 bool
-subsumes_prop (tree as, tree c)
+subsumes_constraint (tree as, tree c)
 {
   switch (TREE_CODE (c))
     {
-    case TRUTH_ANDIF_EXPR:
-      return subsumes_and (as, c);
-    case TRUTH_ORIF_EXPR:
-      return subsumes_or (as, c);
-    case REQUIRES_EXPR:
-      return subsumes_requires (as, c);
+    case CONJ_CONSTR:
+      return subsumes_conjunction (as, c);
+    case DISJ_CONSTR:
+      return subsumes_disjunction (as, c);
+    case PARM_CONSTR:
+      return subsumes_parameterized_constraint (as, c);
     default:
-      return subsumes_atom (as, c);
+      return subsumes_atomic_constraint (as, c);
     }
 }
 
-// Returns true if the LEFT constraints subsume the RIGHT constraints.
-// This is done by checking that the RIGHT requirements follow from
-// each of the LEFT subgoals.
+/* Returns true if the LEFT constraints subsume the RIGHT constraints.
+   This is done by checking that the RIGHT requirements follow from
+   each of the LEFT subgoals. */
 bool
 subsumes_constraints_nonnull (tree left, tree right)
 {
   gcc_assert (check_constraint_info (left));
   gcc_assert (check_constraint_info (right));
 
-  // Check that the required expression in RIGHT is subsumed by each
-  // subgoal in the assumptions of LEFT.
+  /* 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_NORMALIZED_CONSTRAINTS (right);
   for (int i = 0; i < TREE_VEC_LENGTH (as); ++i)
-    if (!subsumes_prop (TREE_VEC_ELT (as, i), c))
+    if (!subsumes_constraint (TREE_VEC_ELT (as, i), c))
       return false;
   return true;
 }
 
-} // end namespace
-
+} /* namespace */
 
-// Returns true if the LEFT constraints subsume the RIGHT constraints. Note
-// that subsumption is a reflexive relation (e.g., <=)
+/* Returns true if the LEFT constraints subsume the RIGHT 
+   constraints. */
 bool
 subsumes (tree left, tree right)
 {
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index a786d60..a7f6e02 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -1939,13 +1939,14 @@ 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. 
+  /* Propagate constraints from the inherited constructor. */
   if (flag_concepts && inherited_ctor)
   {
-    tree orig_ci = get_constraints (inherited_ctor);
-    tree new_ci = copy_node (orig_ci);
-    set_constraints (fn, new_ci);
+    if (tree orig_ci = get_constraints (inherited_ctor))
+      {
+        tree new_ci = copy_node (orig_ci);
+        set_constraints (fn, new_ci);
+      }
   }
 
   /* Restore PROCESSING_TEMPLATE_DECL.  */
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 2752436..3d349b9 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -1363,7 +1363,7 @@ clear_decl_specs (cp_decl_specifier_seq *decl_specs)
    VAR_DECLs or FUNCTION_DECLs) should do that directly.  */
 
 static cp_declarator *make_call_declarator
-  (cp_declarator *, tree, cp_cv_quals, cp_virt_specifiers, cp_ref_qualifier, tree, tree);
+  (cp_declarator *, tree, cp_cv_quals, cp_virt_specifiers, cp_ref_qualifier, tree, tree, tree);
 static cp_declarator *make_array_declarator
   (cp_declarator *, tree);
 static cp_declarator *make_pointer_declarator
@@ -1544,7 +1544,8 @@ make_call_declarator (cp_declarator *target,
 		      cp_virt_specifiers virt_specifiers,
 		      cp_ref_qualifier ref_qualifier,
 		      tree exception_specification,
-		      tree late_return_type)
+		      tree late_return_type,
+                      tree requires_clause)
 {
   cp_declarator *declarator;
 
@@ -1556,6 +1557,7 @@ make_call_declarator (cp_declarator *target,
   declarator->u.function.ref_qualifier = ref_qualifier;
   declarator->u.function.exception_specification = exception_specification;
   declarator->u.function.late_return_type = late_return_type;
+  declarator->u.function.requires_clause = requires_clause;
   if (target)
     {
       declarator->id_loc = target->id_loc;
@@ -2099,6 +2101,8 @@ static tree cp_parser_type_specifier
 static tree cp_parser_simple_type_specifier
   (cp_parser *, cp_decl_specifier_seq *, cp_parser_flags);
 static tree cp_parser_type_name
+  (cp_parser *, bool);
+static tree cp_parser_type_name
   (cp_parser *);
 static tree cp_parser_nonclass_name 
   (cp_parser* parser);
@@ -2354,14 +2358,6 @@ static tree cp_parser_type_requirement
   (cp_parser *);
 static tree cp_parser_nested_requirement
   (cp_parser *);
-static tree cp_parser_constexpr_constraint_spec
-  (cp_parser *, tree);
-static tree cp_parser_noexcept_constraint_spec
-  (cp_parser *, tree);
-static tree cp_parser_constraint_spec
-  (cp_parser *, tree);
-static tree cp_parser_constraint_specifier_seq
-  (cp_parser *, tree);
 
 /* Transactional Memory Extensions */
 
@@ -9457,9 +9453,11 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
 				       VIRT_SPEC_UNSPECIFIED,
                                        REF_QUAL_NONE,
 				       exception_spec,
-                                       /*late_return_type=*/NULL_TREE);
+                                       /*late_return_type=*/NULL_TREE,
+                                       /*requires_clause*/NULL_TREE);
     declarator->id_loc = LAMBDA_EXPR_LOCATION (lambda_expr);
 
+
     fco = grokmethod (&return_type_specs,
 		      declarator,
 		      attributes);
@@ -13523,6 +13521,7 @@ finish_constrained_parameter (cp_parser *parser,
   // default argument and constraint.
   parm = build_tree_list (def, parm);
   TEMPLATE_PARM_CONSTRAINTS (parm) = decl;
+  
   return parm;
 }
 
@@ -13912,7 +13911,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);
+              reqs = conjoin_constraints (reqs, make_predicate_constraint (r));
             TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = reqs;
           }
 
@@ -15488,13 +15487,20 @@ cp_parser_simple_type_specifier (cp_parser* parser,
 static tree
 cp_parser_type_name (cp_parser* parser)
 {
+  return cp_parser_type_name (parser, /*typename_keyword_p=*/false);
+}
+
+/* See above. */
+static tree
+cp_parser_type_name (cp_parser* parser, bool typename_keyword_p)
+{
   tree type_decl;
 
   /* We can't know yet whether it is a class-name or not.  */
   cp_parser_parse_tentatively (parser);
   /* Try a class-name.  */
   type_decl = cp_parser_class_name (parser,
-				    /*typename_keyword_p=*/false,
+				    typename_keyword_p,
 				    /*template_keyword_p=*/false,
 				    none_type,
 				    /*check_dependency_p=*/true,
@@ -17048,7 +17054,7 @@ cp_parser_alias_declaration (cp_parser* parser)
     return decl;
 
   // Attach constraints to the alias declaration.
-  if (flag_concepts)
+  if (flag_concepts && current_template_parms)
     {
       tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
       tree constr = build_constraints (reqs, NULL_TREE);
@@ -18123,7 +18129,8 @@ cp_parser_direct_declarator (cp_parser* parser,
 						     virt_specifiers,
 						     ref_qual,
 						     exception_specification,
-						     late_return);
+						     late_return,
+                                                     /*requires_clause=*/NULL_TREE);
 		  declarator->std_attributes = attrs;
 		  /* Any subsequent parameter lists are to do with
 		     return type, so are not those of the declared
@@ -23256,39 +23263,24 @@ cp_parser_requires_clause_opt (cp_parser *parser)
 }
 
 
-// -------------------------------------------------------------------------- //
-// Requires Expression
-
-
-// An RAII helper that provides scoped control for entering and exiting
-// the local scope defined by a requires expression. Name bindings introduced
-// within the scope are popped prior to exiting the scope.
-struct cp_parser_requires_expr_scope
-{
-  cp_parser_requires_expr_scope ()
-  {
-    begin_scope (sk_block, NULL_TREE);
-  }
+/*---------------------------------------------------------------------------
+                           Requires expressions
+---------------------------------------------------------------------------*/
 
-  ~cp_parser_requires_expr_scope ()
-  {
-    pop_bindings_and_leave_scope ();
-  }
-};
+/* Parse a requires expression
 
-// Parse a requires expression
-//
-//    requirement-expression:
-//        'requires' requirement-parameter-list requirement-body
+   requirement-expression:
+       'requires' requirement-parameter-list [opt] requirement-body */
 static tree
 cp_parser_requires_expression (cp_parser *parser)
 {
   gcc_assert (cp_lexer_next_token_is_keyword (parser->lexer, RID_REQUIRES));
   location_t loc = cp_lexer_consume_token (parser->lexer)->location;
 
-  // TODO: Earlier versions of the concepts lite spec did not allow
-  // requires expressions outside of template declarations. That
-  // restriction was relaxed in Chicago, but it has not been implemented.
+  /* A requires-expression shall appear only within a concept
+     definition or a requires-clause.
+
+     TODO: Implement this diagnostic correctly. */
   if (!processing_template_decl)
     {
       error_at (loc, "a requires expression cannot appear outside a template");
@@ -23296,15 +23288,32 @@ cp_parser_requires_expression (cp_parser *parser)
       return error_mark_node;
     }
 
-  // Parse the optional parameter list. Any local parameter declarations
-  // are added to a new scope and are visible within the nested
-  // requirement list.
-  cp_parser_requires_expr_scope guard;
-  tree parms = cp_parser_requirement_parameter_list (parser);
-  if (parms == error_mark_node)
-    return error_mark_node;
+  /* Local parameters are delared as variables within the scope
+     of the expression. They are not visible past the end of
+     the expression. */
+  struct scope_sentinel
+  {
+    scope_sentinel ()
+    {
+      begin_scope (sk_block, NULL_TREE);
+    }
 
-  // Parse the requirement body.
+    ~scope_sentinel ()
+    {
+      pop_bindings_and_leave_scope ();
+    }
+  } s;
+
+  /* Parse the optional parameter list. */
+  tree parms = NULL_TREE;
+  if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
+    {
+      parms = cp_parser_requirement_parameter_list (parser);
+      if (parms == error_mark_node)
+        return error_mark_node;
+    }
+
+  /* Parse the requirement body. */
   tree reqs = cp_parser_requirement_body (parser);
   if (reqs == error_mark_node)
     return error_mark_node;
@@ -23312,17 +23321,16 @@ cp_parser_requires_expression (cp_parser *parser)
   return finish_requires_expr (parms, reqs);
 }
 
-// Parse a parameterized requirement.
-//
-//    requirement-parameter-list:
-//        '(' parameter-declaration-clause ')'
+/* Parse a parameterized requirement.
+
+   requirement-parameter-list:
+       '(' parameter-declaration-clause ')' */
 static tree
 cp_parser_requirement_parameter_list (cp_parser *parser)
 {
   if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
     return error_mark_node;
 
-  // Parse the nested parameter declaration clause.
   tree parms = cp_parser_parameter_declaration_clause (parser);
   if (parms == error_mark_node)
     return error_mark_node;
@@ -23333,10 +23341,10 @@ cp_parser_requirement_parameter_list (cp_parser *parser)
   return parms;
 }
 
-// Parse the body of a requirement.
-//
-//    requirement-body:
-//        '{' requirement-list '}'
+/* Parse the body of a requirement.
+
+   requirement-body:
+       '{' requirement-list '}' */
 static tree
 cp_parser_requirement_body (cp_parser *parser)
 {
@@ -23351,11 +23359,11 @@ cp_parser_requirement_body (cp_parser *parser)
   return reqs;
 }
 
-// Parse a list of requirements.
-//
-//    requirement-list:
-//        requirement
-//        requirement-list ';' requirement[opt]
+/* Parse a list of requirements.
+
+   requirement-list:
+       requirement
+       requirement-list ';' requirement[opt] */
 static tree
 cp_parser_requirement_list (cp_parser *parser)
 {
@@ -23364,91 +23372,95 @@ cp_parser_requirement_list (cp_parser *parser)
     {
       tree req = cp_parser_requirement (parser);
       if (req == error_mark_node)
-        return req;
+        return error_mark_node;
 
       result = tree_cons (NULL_TREE, req, result);
 
-      // If we see a semi-colon, consume it.
+      /* If we see a semi-colon, consume it. */
       if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
           cp_lexer_consume_token (parser->lexer);
 
-      // If we've found the end of the list, stop processing
-      // the list.
+      /* Stop processing at the end of the list. */
       if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE))
         break;
     }
 
-  // Reverse the order of requirements so they are analyzed in
-  // declaration order.
+  /* Reverse the order of requirements so they are analyzed in
+     declaration order. */
   return nreverse (result);
 }
 
-// Parse a syntactic requirement or type requirement.
-//
-//    requirement:
-//        simple-requirement
-//        compound-requirement
-//        type-requirement
-//        nested-requirement
+/* Parse a syntactic requirement or type requirement.
+
+     requirement:
+       simple-requirement
+       compound-requirement
+       type-requirement
+       nested-requirement */
 static tree
 cp_parser_requirement (cp_parser *parser)
 {
-  if (cp_lexer_next_token_is_keyword (parser->lexer, RID_REQUIRES))
-    return cp_parser_nested_requirement (parser);
-
   if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
     return cp_parser_compound_requirement (parser);
-
-  // Try parsing a type requirement first.
-  cp_parser_parse_tentatively (parser);
-  tree req = cp_parser_type_requirement (parser);
-  if (!cp_parser_parse_definitely (parser))
-    req = cp_parser_simple_requirement (parser);
-
-  return req;
+  else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TYPENAME))
+    return cp_parser_type_requirement (parser);
+  else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_REQUIRES))
+    return cp_parser_nested_requirement (parser);
+  else
+    return cp_parser_simple_requirement (parser);
 }
 
-// Parse a nested requirement. This is the same as a requires clause.
-//
-//    nested-requirement:
-//      requires-clause
+/* Parse a simple requirement.
+
+     simple-requirement:
+       expression ';' */
 static tree
-cp_parser_nested_requirement (cp_parser *parser)
+cp_parser_simple_requirement (cp_parser *parser)
 {
-  cp_lexer_consume_token (parser->lexer);
-  tree req = cp_parser_requires_clause (parser);
-  if (req == error_mark_node)
+  tree expr = cp_parser_expression (parser, NULL, false, false);
+  if (!expr || expr == error_mark_node)
     return error_mark_node;
-  return finish_nested_requirement (req);
+  
+  if (!cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON))
+    return error_mark_node;
+
+  return finish_simple_requirement (expr);
 }
 
-// Parse a simple requirement.
-//
-//    simple-requirement:
-//      expression
+/* Parse a type requirement
+
+     type-requirement
+         nested-name-specifier [opt] type-name ';' */
 static tree
-cp_parser_simple_requirement (cp_parser *parser)
+cp_parser_type_requirement (cp_parser *parser)
 {
-  tree expr = cp_parser_expression (parser, NULL, false, false);
-  if (!expr || expr == error_mark_node)
+  cp_lexer_consume_token (parser->lexer);
+
+  cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/true);
+  cp_parser_nested_name_specifier_opt (parser,
+                                       /*typename_keyword_p=*/true,
+                                       /*check_dependency_p=*/false,
+                                       /*type_p=*/true,
+                                       /*is_declaration=*/false);
+  
+  tree type = cp_parser_type_name (parser, /*typename_keyword_p=*/true);
+  if (type == error_mark_node)
+    return error_mark_node;
+
+  if (!cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON))
     return error_mark_node;
-  return finish_expr_requirement (expr);
+
+  return finish_type_requirement (type);
 }
 
-// Parse a compound requirement
-//
-//    compound-requirement:
-//        '{' expression '}' trailing-constraint-specifiers
-//
-//    trailing-constraint-specifiers:
-//      constraint-specifiers-seq[opt] result-type-requirement[opt]
-//
-//    result-type-requirement:
-//       '->' type-id
+/* Parse a compound requirement
+
+     compound-requirement:
+         '{' expression '}' 'noexcept' [opt] trailing-return-type [opt] ';' */
 static tree
 cp_parser_compound_requirement (cp_parser *parser)
 {
-  // Parse an expression enclosed in '{ }'s.
+  /* Parse an expression enclosed in '{ }'s. */
   if (!cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE))
     return error_mark_node;
 
@@ -23459,10 +23471,15 @@ cp_parser_compound_requirement (cp_parser *parser)
   if (!cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE))
     return error_mark_node;
 
-  // Parse trailing expression specifiers.
-  tree cs = cp_parser_constraint_specifier_seq (parser, expr);
+  /* Parse the optional noexcept. */
+  bool noexcept_p = false;
+  if (cp_lexer_next_token_is_keyword (parser->lexer, RID_NOEXCEPT))
+    {
+      cp_lexer_consume_token (parser->lexer);
+      noexcept_p = true;
+    }
 
-  // Parse the optional trailing type requirement.
+  /* Parse the optional trailing return type. */
   tree type = NULL_TREE;
   if (cp_lexer_next_token_is (parser->lexer, CPP_DEREF))
     {
@@ -23475,79 +23492,21 @@ cp_parser_compound_requirement (cp_parser *parser)
         return error_mark_node;
     }
 
-  return finish_expr_requirement (expr, type, cs);
+  return finish_compound_requirement (expr, type, noexcept_p);
 }
 
-// Parse a type requirement
-//
-//    type-requirement
-//        type-id
-static tree
-cp_parser_type_requirement (cp_parser *parser)
-{
-  // Try parsing the type-id
-  tree type = cp_parser_type_id (parser);
-  if (type == error_mark_node)
-    return error_mark_node;
-
-  // It can only be a type requirement if nothing comes after it.
-  // For example, this:
-  //
-  //    typename T::value_type x = a;
-  //
-  // Is not a type requirement even though it stars with a type-id.
-  if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
-    return error_mark_node;
+/* Parse a nested requirement. This is the same as a requires clause.
 
-  return finish_type_requirement (type);
-}
-
-// Parse an optional constexpr specifier in a constraint expression.
+   nested-requirement:
+     requires-clause */
 static tree
-cp_parser_constexpr_constraint_spec (cp_parser *parser, tree expr)
-{
-  cp_lexer_consume_token (parser->lexer);
-  return finish_constexpr_requirement (expr);
-}
-
-// Parse an optional noexcept specifier in a constraint expression.
-static tree
-cp_parser_noexcept_constraint_spec (cp_parser *parser, tree expr)
+cp_parser_nested_requirement (cp_parser *parser)
 {
   cp_lexer_consume_token (parser->lexer);
-  return finish_noexcept_requirement (expr);
-}
-
-static tree
-cp_parser_constraint_spec (cp_parser *parser, tree expr)
-{
-  if (cp_lexer_next_token_is_keyword (parser->lexer, RID_CONSTEXPR))
-    return cp_parser_constexpr_constraint_spec (parser, expr);
-  if (cp_lexer_next_token_is_keyword (parser->lexer, RID_NOEXCEPT))
-    return cp_parser_noexcept_constraint_spec (parser, expr);
-  return NULL_TREE;
-}
-
-// Parse an optional expression specifier sequence.
-//
-//    constraint-specifier-sequence:
-//        constexpr [opt] noexcept [opt]
-static tree
-cp_parser_constraint_specifier_seq (cp_parser *parser, tree expr)
-{
-  tree result = NULL_TREE;
-  while (1)
-    {
-      // If we can parse a constraint specifier, insert it into
-      // the list of requirements.
-      if (tree spec = cp_parser_constraint_spec (parser, expr))
-        {
-          result = tree_cons (NULL_TREE, spec, result);
-          continue;
-        }
-      break;
-    }
-  return result;
+  tree req = cp_parser_requires_clause (parser);
+  if (req == error_mark_node)
+    return error_mark_node;
+  return finish_nested_requirement (req);
 }
 
 /* Support Functions */
@@ -24428,7 +24387,7 @@ cp_parser_template_introduction (cp_parser* parser)
     }
 
   // Build and associate the constraint.
-  tree parms = finish_concept_introduction (tmpl_decl, introduction_list);
+  tree parms = finish_template_introduction (tmpl_decl, introduction_list);
   if (parms)
     return parms;
 
@@ -24515,14 +24474,15 @@ cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p)
       /* Look for the `>'.  */
       cp_parser_skip_to_end_of_template_parameter_list (parser);
 
-      // Manage template requirements
-      if (flag_concepts)
-	{
-	  tree reqs = get_shorthand_constraints (current_template_parms);
-	  if (tree r = cp_parser_requires_clause_opt (parser))
-	    reqs = conjoin_constraints (reqs, r);
+        /* Manage template requirements */
+        if (flag_concepts)
+        {
+          tree reqs = get_shorthand_constraints (current_template_parms);
+          if (tree r = cp_parser_requires_clause_opt (parser)) {
+            reqs = conjoin_constraints (reqs, make_predicate_constraint (r));
+           }
           TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = reqs;
-	}
+        }
     }
   else if (flag_concepts)
     {
@@ -33624,14 +33584,16 @@ tree_type_is_auto_or_concept (const_tree t)
   return TREE_TYPE (t) && is_auto_or_concept (TREE_TYPE (t));
 }
 
-// Return the template decl being called or evaluated as part of the
-// constraint check.
+/* Returns the template declaration being called or evaluated as 
+   part of the constraint check. Note that T must be a predicate
+   constraint (it can't be any other kind of constraint). */
 static tree
 get_concept_from_constraint (tree t)
 {
+  gcc_assert (TREE_CODE (t) == PRED_CONSTR);
+  t = PRED_CONSTR_EXPR (t);
   gcc_assert (TREE_CODE (t) == CALL_EXPR || TREE_CODE (t) == TEMPLATE_ID_EXPR);
 
-  // Variable concepts will be a TEMPLATE_ID_EXPR.
   if (TREE_CODE (t) == TEMPLATE_ID_EXPR)
     return DECL_TEMPLATE_RESULT (TREE_OPERAND (t, 0));
   else
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 58d5223..11aacd3 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -46,6 +46,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "timevar.h"
 #include "tree-iterator.h"
 #include "type-utils.h"
+#include "hash-map.h"
 #include "gimplify.h"
 
 /* The type of functions taking a tree, and some additional data, and
@@ -916,9 +917,9 @@ maybe_new_partial_specialization (tree type)
 
       // 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));
+      tree tmpl_constr = TEMPLATE_PARM_CONSTRAINTS (current_template_parms);
+      tree type_constr = build_constraints (tmpl_constr, NULL_TREE);
+      tree main_constr = get_constraints (tmpl);
       if (equivalent_constraints (type_constr, main_constr))
         return NULL_TREE;
 
@@ -928,7 +929,7 @@ maybe_new_partial_specialization (tree type)
       while (specs)
         {
           tree spec_tmpl = TREE_VALUE (specs);
-          tree spec_constr = get_constraints (DECL_TEMPLATE_RESULT (spec_tmpl));
+          tree spec_constr = get_constraints (spec_tmpl);
           if (equivalent_constraints (type_constr, spec_constr))
             return NULL_TREE;
           specs = TREE_CHAIN (specs);
@@ -1954,10 +1955,26 @@ print_candidates (tree fns)
   gcc_assert (str == NULL);
 }
 
-// Among candidates having the same signature, return the most constrained
-// or NULL_TREE if there is no best candidate. If the signatures of candidates
-// vary (e.g., template specialization vs. member function), then there can
-// be no most constrained.
+/* Get a (possibly) constrained template declaration for the
+   purpose of ordering candidates.  */
+static tree
+get_template_for_ordering (tree list)
+{
+  gcc_assert (TREE_CODE (list) == TREE_LIST);
+  tree f = TREE_VALUE (list);
+  if (tree ti = DECL_TEMPLATE_INFO (f))
+    return TI_TEMPLATE (ti);
+  return f;
+}
+
+/* Among candidates having the same signature, return the 
+   most constrained or NULL_TREE if there is no best candidate. 
+   If the signatures of candidates vary (e.g., template 
+   specialization vs. member function), then there can be no 
+   most constrained. 
+
+   Note that we don't compare constraints on the functions
+   themselves, but rather those of their templates. */
 static tree
 most_constrained_function (tree candidates)
 {
@@ -1965,7 +1982,8 @@ most_constrained_function (tree candidates)
   tree champ = candidates;
   for (tree c = TREE_CHAIN (champ); c; c = TREE_CHAIN (c))
     {
-      int winner = more_constrained (TREE_VALUE (champ), TREE_VALUE (c));
+      int winner = more_constrained (get_template_for_ordering (champ), 
+                                     get_template_for_ordering (c));
       if (winner == -1)
         champ = c; // The candidate is more constrained
       else if (winner == 0)
@@ -1974,7 +1992,8 @@ most_constrained_function (tree candidates)
 
   // Verify that the champ is better than previous candidates.
   for (tree c = candidates; c != champ; c = TREE_CHAIN (c)) {
-    if (!more_constrained (TREE_VALUE (champ), TREE_VALUE (c)))
+    if (!more_constrained (get_template_for_ordering (champ), 
+                           get_template_for_ordering (c)))
       return NULL_TREE;
   }
 
@@ -2174,9 +2193,9 @@ determine_specialization (tree template_id,
 	       specialize TMPL will produce DECL.  */
 	    continue;
 
-	  // The deduced arguments must satisfy the template constraints
-          // in order to be viable.
-          if (!check_template_constraints (fn, targs))
+          /* Remove, from the set of candidates, all those functions
+             whose constraints are not satisfied. */
+          if (flag_concepts && !constraints_satisfied_p (fn, targs)) 
             continue;
 
           // Then, try to form the new function type.
@@ -2245,8 +2264,7 @@ determine_specialization (tree template_id,
           // If the deduced arguments do not satisfy the constraints,
           // this is not a candidate. If it fails, record the
           // rejected candidate.
-          tree targs = DECL_TI_ARGS (fn);
-          if (!check_template_constraints (fn, targs))
+          if (flag_concepts && !constraints_satisfied_p (fn))
           {
             rejections = tree_cons (NULL_TREE, fn, rejections);
             continue;
@@ -2366,9 +2384,14 @@ determine_specialization (tree template_id,
     *targs_out = TREE_PURPOSE (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));
+  if (tree ci = get_constraints (tmpl))
+    {
+      ci = tsubst_constraint_info (ci, *targs_out, tf_none, NULL_TREE);
+      set_constraints (decl, ci);
+    }
+  */
 
   return TREE_VALUE (templates);
 }
@@ -4473,7 +4496,7 @@ process_partial_specialization (tree decl)
      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
+     shall be more specialized than the primary.
 
      Note that concepts allow partial specializations with the same list of
      arguments but different constraints. */
@@ -4649,6 +4672,7 @@ process_partial_specialization (tree decl)
   SET_DECL_TEMPLATE_SPECIALIZATION (tmpl);
   DECL_TEMPLATE_INFO (tmpl) = build_template_info (maintmpl, specargs);
   DECL_PRIMARY_TEMPLATE (tmpl) = maintmpl;
+  set_constraints (tmpl, tmpl_constr);
 
   DECL_TEMPLATE_SPECIALIZATIONS (maintmpl)
     = tree_cons (specargs, tmpl,
@@ -6812,7 +6836,7 @@ is_compatible_template_arg (tree parm, tree arg)
   if (parm_cons)
     {
       tree args = template_parms_to_args (DECL_TEMPLATE_PARMS (arg));
-      parm_cons = tsubst_constraint_info (parm_cons, args);
+      parm_cons = tsubst_constraint_info (parm_cons, args, tf_none, NULL_TREE);
       if (parm_cons == error_mark_node)
         return false;
     }
@@ -8154,21 +8178,19 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context,
       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))
+      /* 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 previously
+         instantiated specializations. */
+      if (flag_concepts && !constraints_satisfied_p (gen_tmpl, arglist))
         {
-          // Diagnose constraints here since they are not diagnosed
-          // anywhere else.
           if (complain & tf_error)
             {
               error ("template constraint failure");
               diagnose_constraints (input_location, gen_tmpl, arglist);
             }
-          return error_mark_node;
         }
 
       is_dependent_type = uses_template_parms (arglist);
@@ -10279,20 +10301,22 @@ gen_elem_of_pack_expansion_instantiation (tree pattern,
   return t;
 }
 
-// Substitute args into the pack expansion T, and rewrite the resulting
-// list as a conjunction of the specified terms. If the result is an empty
-// expression, return boolean_true_node.
+/* Substitute args into the pack expansion T, and rewrite the resulting
+   list as a conjunction of the specified terms. If the result is an empty
+   expression, return boolean_true_node.
+
+   FIXME: This goes away with fold expressions.  */
 tree
 tsubst_pack_conjunction (tree t, tree args, tsubst_flags_t complain,
                          tree in_decl)
 {
   tree terms = tsubst_pack_expansion (t, args, complain, in_decl);
 
-  // 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. Just rebuild
-  // the dependent pack expansion.
+/* 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. Just rebuild
+   the dependent pack expansion.  */
   if (instantiation_dependent_expression_p (terms))
     {
       terms = TREE_VEC_ELT (terms, 0);
@@ -10300,11 +10324,18 @@ tsubst_pack_conjunction (tree t, tree args, tsubst_flags_t complain,
       return terms;
     }
 
-  // Conjoin requirements. An empty conjunction is equivalent to ture.
-  if (tree reqs = conjoin_constraints (terms))
-    return reqs;
-  else
+  /* Empty expansions are equivalent to 'true'.  */
+  if (TREE_VEC_LENGTH (terms) == 0)
     return boolean_true_node;
+
+  /* Otherwise, and the terms together.  These are transformed
+     into constraints later.  */  
+  tree result = TREE_VEC_ELT (terms, 0);
+  for (int i = 1; i < TREE_VEC_LENGTH (terms); ++i) {
+    tree t = TREE_VEC_ELT (terms, i);
+    result = build_min (TRUTH_ANDIF_EXPR, boolean_type_node, result, t);
+  }
+  return result;
 }
 
 
@@ -11299,16 +11330,15 @@ 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.
+        /* When instantiating a constrained member, substitute
+           into the constraints to create a new constraint into
+           the  */
         if (tree ci = get_constraints (t)) {
-          if (!uses_template_parms (argvec))
+          if (member)
             {
-              tree tr = CI_TEMPLATE_REQS (ci);
-              tree dr = CI_DECLARATOR_REQS (ci);
-              ci = build_constraints (NULL_TREE, conjoin_constraints (tr, dr));
+              ci = tsubst_constraint_info (ci, argvec, complain, NULL_TREE);
+              set_constraints (r, ci);
             }
-          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
@@ -12197,8 +12227,6 @@ tsubst_exception_specification (tree fntype,
   return new_specs;
 }
 
-extern int processing_constraint;
-
 /* Take the tree structure T and replace template parameters used
    therein with the argument vector ARGS.  IN_DECL is an associated
    decl for diagnostics.  If an error occurs, returns ERROR_MARK_NODE.
@@ -12233,7 +12261,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
   if (DECL_P (t))
     return tsubst_decl (t, args, complain);
 
-  if (args == NULL_TREE && !processing_constraint)
+  if (args == NULL_TREE)
     return t;
 
   code = TREE_CODE (t);
@@ -12379,7 +12407,6 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	if (level <= levels)
 	  {
 	    arg = TMPL_ARG (args, level, idx);
-
 	    if (arg && TREE_CODE (arg) == ARGUMENT_PACK_SELECT)
 	      {
 		/* See through ARGUMENT_PACK_SELECT arguments. */
@@ -16178,28 +16205,6 @@ tsubst_copy_and_build (tree t,
     case REQUIRES_EXPR:
       RETURN (tsubst_requires_expr (t, args, complain, in_decl));
 
-    case VALIDEXPR_EXPR:
-      RETURN (tsubst_validexpr_expr (t, args, in_decl));
-
-    case VALIDTYPE_EXPR:
-      RETURN (tsubst_validtype_expr (t, args, in_decl));
-
-    case CONSTEXPR_EXPR:
-      RETURN (tsubst_constexpr_expr (t, args, in_decl));
-
-    // Normally, *_REQ are reduced out of requiremetns when used
-    // as constraints. If a concept is checked directly via e.g.,
-    // a static_assert, however, these appear in the input tree.
-
-    case EXPR_REQ:
-      RETURN (tsubst_expr_req (t, args, in_decl));
-
-    case TYPE_REQ:
-      RETURN (tsubst_type_req (t, args, in_decl));
-
-    case NESTED_REQ:
-      RETURN (tsubst_nested_req (t, args, in_decl));
-
     default:
       /* Handle Objective-C++ constructs, if appropriate.  */
       {
@@ -16528,8 +16533,9 @@ instantiate_alias_template (tree tmpl, tree args, tsubst_flags_t complain)
   /* We can't free this if a pending_template entry or last_error_tinst_level
      is pointing at it.  */
   if (last_pending_template == old_last_pend
-      && last_error_tinst_level == old_error_tinst)
+      && last_error_tinst_level == old_error_tinst) {
     ggc_free (tinst);
+  }
 
   return r;
 }
@@ -16897,8 +16903,9 @@ fn_type_unification (tree fn,
   /* We can't free this if a pending_template entry or last_error_tinst_level
      is pointing at it.  */
   if (last_pending_template == old_last_pend
-      && last_error_tinst_level == old_error_tinst)
+      && last_error_tinst_level == old_error_tinst) {
     ggc_free (tinst);
+  }
 
   return r;
 }
@@ -19881,13 +19888,12 @@ most_specialized_partial_spec (tree target, tsubst_flags_t complain)
 	  if (outer_args)
 	    spec_args = add_to_template_args (outer_args, spec_args);
 
-          // Keep the candidate only if the constraints are satisfied.
-          tree spec_decl = DECL_TEMPLATE_RESULT (spec_tmpl);
-          tree spec_constr = get_constraints (spec_decl);
-          if (check_constraints (spec_constr, spec_args))
+          /* Keep the candidate only if the constraints are satisfied,
+             or if we're not compiling with concepts.  */
+          if (!flag_concepts || constraints_satisfied_p (spec_tmpl, spec_args))
             {
-	      list = tree_cons (spec_args, TREE_VALUE (t), list);
-	      TREE_TYPE (list) = TREE_TYPE (t);
+              list = tree_cons (spec_args, TREE_VALUE (t), list);
+              TREE_TYPE (list) = TREE_TYPE (t);
             }
 	}
     }
@@ -20456,7 +20462,7 @@ template_for_substitution (tree decl)
 }
 
 /* Returns true if we need to instantiate this template instance even if we
-   know we aren't going to emit it..  */
+   know we aren't going to emit it.  */
 
 bool
 always_instantiate_p (tree decl)
@@ -20566,6 +20572,9 @@ instantiate_decl (tree d, int defer_ok,
      functions and static member variables.  */
   gcc_assert (VAR_OR_FUNCTION_DECL_P (d));
 
+  /* A concept is never instantiated. */
+  gcc_assert (!DECL_DECLARED_CONCEPT_P (d));
+
   /* Variables are never deferred; if instantiation is required, they
      are instantiated right away.  That allows for better code in the
      case that an expression refers to the value of the variable --
@@ -21704,20 +21713,6 @@ value_dependent_expression_p (tree expression)
 		|| has_value_dependent_address (op));
       }
 
-    case REQUIRES_EXPR:
-      {
-        // Check if any parts of a requires expression are dependent.
-        tree req = TREE_OPERAND (expression, 1);
-        while (req != NULL_TREE)
-          {
-            tree r = TREE_VALUE (req);
-            if (value_dependent_expression_p (r))
-              return true;
-            req = TREE_CHAIN (req);
-          }
-        return false;
-      }
-
     case TYPE_REQ:
     case VALIDEXPR_EXPR:
     case VALIDTYPE_EXPR:
@@ -21837,7 +21832,8 @@ type_dependent_expression_p (tree expression)
       || TREE_CODE (expression) == TYPEID_EXPR
       || TREE_CODE (expression) == DELETE_EXPR
       || TREE_CODE (expression) == VEC_DELETE_EXPR
-      || TREE_CODE (expression) == THROW_EXPR)
+      || TREE_CODE (expression) == THROW_EXPR
+      || TREE_CODE (expression) == REQUIRES_EXPR)
     return false;
 
   /* The types of these expressions depends only on the type to which
@@ -21869,16 +21865,6 @@ type_dependent_expression_p (tree expression)
 	return dependent_type_p (type);
     }
 
-  // A requires expression has type bool, but is always treated as if
-  // it were a dependent expression.
-  //
-  // FIXME: This could be improved. Perhaps the type of the requires
-  // expression depends on the satisfaction of its constraints. That
-  // is, its type is bool only if its substitution into its normalized
-  // constraints succeeds.
-  if (TREE_CODE (expression) == REQUIRES_EXPR)
-    return true;
-
   if (TREE_CODE (expression) == SCOPE_REF)
     {
       tree scope = TREE_OPERAND (expression, 0);
@@ -22091,6 +22077,10 @@ instantiation_dependent_r (tree *tp, int *walk_subtrees,
     case BIND_EXPR:
       return *tp;
 
+    case REQUIRES_EXPR:
+      /* Treat requires-expressions as dependent. */
+      return *tp;
+
     default:
       break;
     }
@@ -23015,6 +23005,100 @@ convert_generic_types_to_packs (tree parm, int start_idx, int end_idx)
   return tsubst (parm, replacement, tf_none, NULL_TREE);
 }
 
+/* Entries in the decl_constraint hash table. */
+struct GTY((for_user)) constr_entry
+{
+  tree decl;
+  tree ci;
+};
+
+/* Hashing function and equality fo constraint entries.. */
+struct constr_hasher : ggc_hasher<constr_entry *>
+{
+  static hashval_t hash (constr_entry *e)
+  {
+    return (hashval_t)DECL_UID (e->decl);
+  }
+  
+  static bool equal (constr_entry *e1, constr_entry *e2)
+  {
+    return e1->decl == e2->decl;
+  }
+};
+
+
+/* A mapping from declarations to constraint information. Note that 
+   both templates and their underlying declarations are mapped to the 
+   same constraint information.
+
+   FIXME: This is defined in pt.c because it's garbage collection
+   code is not being generated for constraint.cc. */
+static GTY (()) hash_table<constr_hasher> *decl_constraints;
+
+/* Returns true iff cinfo contains a valid set of constraints.
+   This is the case when the associated requirements have been
+   successfully decomposed into lists of atomic constraints.
+   That is, when the saved assumptions are not error_mark_node.  */
+bool
+valid_constraints_p (tree cinfo)
+{
+  gcc_assert (cinfo);
+  return CI_ASSUMPTIONS (cinfo) != error_mark_node;
+}
+
+/* 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));
+  if (TREE_CODE (t) == TEMPLATE_DECL)
+    t = DECL_TEMPLATE_RESULT (t);
+  constr_entry elt = { t, NULL_TREE };
+  constr_entry* found = decl_constraints->find (&elt);
+  if (found)
+    return found->ci;
+  else
+    return NULL_TREE;
+}
+
+/* Associate the given constraint information CI with the declaration 
+   T. If T is a template, then the constraints are associated with 
+   its underlying declaration. Don't build associations if CI is 
+   NULL_TREE.  */
+void
+set_constraints (tree t, tree ci)
+{
+  if (!ci)
+    return;
+  gcc_assert (t);
+  if (TREE_CODE (t) == TEMPLATE_DECL)
+    t = DECL_TEMPLATE_RESULT (t);
+  gcc_assert (!get_constraints (t));
+  constr_entry elt = {t, ci};
+  constr_entry** slot = decl_constraints->find_slot (&elt, INSERT);
+  constr_entry* entry = ggc_alloc<constr_entry> ();
+  *entry = elt;
+  *slot = entry;
+}
+
+/* Remove the associated constraints of the declaration T. 
+   If there are no constraints associated with T, then
+   return NULL_TREE.  */
+void
+remove_constraints (tree t)
+{
+  if (!DECL_P (t))
+    debug_tree (t);
+  gcc_assert (DECL_P (t));
+  if (TREE_CODE (t) == TEMPLATE_DECL)
+    t = DECL_TEMPLATE_RESULT (t);
+
+  constr_entry elt = {t, NULL_TREE};
+  constr_entry** slot = decl_constraints->find_slot (&elt, NO_INSERT);
+  if (slot)
+    decl_constraints->clear_slot(slot);
+}
 
 /* Set up the hash tables for template instantiations.  */
 
@@ -23023,6 +23107,7 @@ init_template_processing (void)
 {
   decl_specializations = hash_table<spec_hasher>::create_ggc (37);
   type_specializations = hash_table<spec_hasher>::create_ggc (37);
+  decl_constraints = hash_table<constr_hasher>::create_ggc(37);
 }
 
 /* Print stats about the template hash tables for -fstats.  */
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index f83df7f..cf88d33 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2440,7 +2440,7 @@ finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual,
 	    {
 	      next = OVL_CHAIN (fn);
               if (flag_concepts)
-                remove_constraints (fn);
+                remove_constraints (OVL_FUNCTION (fn));
 	      ggc_free (fn);
 	    }
 	}
@@ -2454,11 +2454,24 @@ finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual,
 tree
 finish_template_variable (tree var)
 {
+  gcc_assert (TREE_CODE (var) == TEMPLATE_ID_EXPR);
   if (processing_template_decl)
     return var;
 
-  return instantiate_template (TREE_OPERAND (var, 0), TREE_OPERAND (var, 1),
-                               tf_error);
+  /* If a template-id refers to a specialization of a variable
+     concept, then the expression is true if and only if the
+     concept's constraints are satisfied by the given template
+     arguments.
+
+     NOTE: This is an extension of Concepts Lite TS that
+     allows constraints to be used in expressions. */
+  tree tmpl = TREE_OPERAND (var, 0);
+  tree args = TREE_OPERAND (var, 1);
+  tree decl = DECL_TEMPLATE_RESULT (tmpl);
+  if (flag_concepts && DECL_DECLARED_CONCEPT_P (decl))
+    return evaluate_variable_concept (decl, args);
+
+  return instantiate_template (tmpl, args, tf_error);
 }
 
 /* Finish a call to a postfix increment or decrement or EXPR.  (Which
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 0afeee8..248e17f 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -3463,22 +3463,22 @@ cp_build_function_call_vec (tree function, vec<tree, va_gc> **params,
 
   if (TREE_CODE (function) == FUNCTION_DECL)
     {
-      // If the function is a non-template member function or a
-      // non-template friend, then we need to check the constraints.
-      //
-      // Note that if overload resolution failed with a single candidate
-      // this function will be used to explicitly diagnose the failure
-      // for the single call expression. The check is technically
-      // redundant since we would have failed in add_function_candidate.
-      if (flag_concepts)
-        if (tree ci = get_constraints (function))
-          if (!check_constraints (ci))
-            {
-              error ("cannot call function %qD", function);
-              location_t loc = DECL_SOURCE_LOCATION (function);
-              diagnose_constraints (loc, function, NULL_TREE);
-              return error_mark_node;
-            }
+      /* If the function is a non-template member function 
+         or a non-template friend, then we need to check the 
+         constraints.
+      
+        Note that if overload resolution failed with a single 
+        candidate this function will be used to explicitly diagnose 
+        the failure for the single call expression. The check is 
+        technically redundant since we also would have failed in
+        add_function_candidate. */
+      if (flag_concepts && !constraints_satisfied_p (function))
+        {
+          error ("cannot call function %qD", function);
+          location_t loc = DECL_SOURCE_LOCATION (function);
+          diagnose_constraints (loc, function, NULL_TREE);
+          return error_mark_node;
+        }
 
       mark_used (function);
       fndecl = function;
diff --git a/gcc/testsuite/g++.dg/concepts/concepts.exp b/gcc/testsuite/g++.dg/concepts/concepts.exp
new file mode 100644
index 0000000..df56277
--- /dev/null
+++ b/gcc/testsuite/g++.dg/concepts/concepts.exp
@@ -0,0 +1,35 @@
+#   Copyright (C) 2002-2013 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Load support procs.
+load_lib g++-dg.exp
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_CXXFLAGS
+if ![info exists DEFAULT_CXXFLAGS] then {
+    set DEFAULT_CXXFLAGS " -pedantic-errors -Wno-long-long"
+}
+
+# Initialize `dg'.
+dg-init
+
+# Main loop.
+g++-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C]] "" $DEFAULT_CXXFLAGS
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/g++.dg/concepts/expression.C b/gcc/testsuite/g++.dg/concepts/expression.C
new file mode 100644
index 0000000..e44684d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/concepts/expression.C
@@ -0,0 +1,20 @@
+// { dg-do run }
+// { dg-options "-std=c++1z" }
+
+#include <cassert>
+#include <iostream>
+
+template<typename T>
+  concept bool C1 = __is_class(T);
+
+template<typename T>  
+  concept bool C2() { return __is_class(T); }
+
+template<typename T>
+  concept bool C3() { return requires (T a) { ++a; }; }
+
+int main() {
+  if (C1<int>) assert(false);
+  if (C2<int>()) assert(false);
+  if (!C3<int>()) assert(false);
+}
diff --git a/gcc/testsuite/g++.dg/concepts/fn7.C b/gcc/testsuite/g++.dg/concepts/fn7.C
index fa1b27f..2abd34a 100644
--- a/gcc/testsuite/g++.dg/concepts/fn7.C
+++ b/gcc/testsuite/g++.dg/concepts/fn7.C
@@ -1,8 +1,8 @@
 // { dg-do link }
 // { dg-options "-std=c++1z" }
 
-#include <cassert>
+// FIXME: What is this actually testing?
 
-void f() requires true { }; // { dg-xfail-if "" { *-*-* } }
+void f() requires true { }
 
 int main() { }
diff --git a/gcc/testsuite/g++.dg/concepts/generic-fn-err.C b/gcc/testsuite/g++.dg/concepts/generic-fn-err.C
index bce8653..c6b7457 100644
--- a/gcc/testsuite/g++.dg/concepts/generic-fn-err.C
+++ b/gcc/testsuite/g++.dg/concepts/generic-fn-err.C
@@ -1,7 +1,5 @@
 // { dg-options "-std=c++1z" }
 
-#include <cassert>
-
 template<typename T>
   concept bool C() { return __is_class(T); }
 
diff --git a/gcc/testsuite/g++.dg/concepts/intro4.C b/gcc/testsuite/g++.dg/concepts/intro4.C
index f821c1c..526aa23 100644
--- a/gcc/testsuite/g++.dg/concepts/intro4.C
+++ b/gcc/testsuite/g++.dg/concepts/intro4.C
@@ -18,9 +18,9 @@ template<typename T, typename U = int>
   concept bool C5() { return __is_class(U); }
 
 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" }
+C1{A} void f2() {} // { dg-error "cannot match pack|no matching concept" }
+C2{A, B} void f3() {}; // { dg-error "cannot match pack|no matching concept" }
+C3{...A} void f4() {}; // { dg-error "cannot match pack|no matching concept" }
 C4{A} void f5() {}; // { dg-error "no matching concept" }
 C5{A, B} void f6() {};
 
diff --git a/gcc/testsuite/g++.dg/concepts/req1.C b/gcc/testsuite/g++.dg/concepts/req1.C
index e5f2fc9..7fad1d9 100644
--- a/gcc/testsuite/g++.dg/concepts/req1.C
+++ b/gcc/testsuite/g++.dg/concepts/req1.C
@@ -4,6 +4,10 @@
 template<typename T>
   concept bool Class () { return __is_class(T); }
 
+// Allow a requires-expression with no parms.
+template<typename T>
+  concept bool C = requires { typename T::type; };
+
 void f1(auto a) requires Class<decltype(a)>() { }
 void f2(auto a) requires requires (decltype(a) x) { -x; } { }
 
diff --git a/gcc/testsuite/g++.dg/concepts/req2.C b/gcc/testsuite/g++.dg/concepts/req2.C
index c5855df..6250128 100644
--- a/gcc/testsuite/g++.dg/concepts/req2.C
+++ b/gcc/testsuite/g++.dg/concepts/req2.C
@@ -1,7 +1,5 @@
 // { dg-options "-std=c++1z" }
 
-#include <cassert>
-
 template<typename T>
   concept bool Class () { return __is_class(T); }
 
@@ -19,3 +17,5 @@ int main() {
   f1(0); // { dg-error "cannot call" }
   f2((void*)0); // { dg-error "cannot call" }
 }
+
+// { dg-excess-errors "x|with" }
diff --git a/gcc/testsuite/g++.dg/concepts/req4.C b/gcc/testsuite/g++.dg/concepts/req4.C
index 927e4e5..b26c471 100644
--- a/gcc/testsuite/g++.dg/concepts/req4.C
+++ b/gcc/testsuite/g++.dg/concepts/req4.C
@@ -9,10 +9,13 @@ template<typename T> constexpr fool p1() { return {}; }
 template<typename T> constexpr fool p2() { return {}; }
 
 template<typename T>
-  concept bool C() { return p1<T>() && p2<T>(); }
+  concept bool C() { return p1<T>() && p2<T>(); } 
 
-template<C T> void f(T x) { }
+template<C T> void f(T x) { } // { dg-error "user-defined operator" }
 
 int main() {
-  f(0); // { dg-error "cannot call|predicate constraint" }
+  // FIXME: We should be diagnosing the failed lookup
+  // of operator&&, not the fact that neither have the
+  // right type (which is true, but not the best error).
+  f(0); // { dg-error "not|bool" }
 }
diff --git a/gcc/testsuite/g++.dg/concepts/req5.C b/gcc/testsuite/g++.dg/concepts/req5.C
index c566d31..b63ca77 100644
--- a/gcc/testsuite/g++.dg/concepts/req5.C
+++ b/gcc/testsuite/g++.dg/concepts/req5.C
@@ -9,10 +9,10 @@ template<typename T> constexpr fool p1() { return {}; }
 template<typename T> constexpr fool p2() { return {}; }
 
 template<typename T>
-  concept bool C() { return p1<T>() && p2<T>(); }
+  concept bool C() { return p1<T>() && p2<T>(); } 
 
-template<C T> void f(T x) { }
+template<C T> void f(T x) { } // { dg-error "user-defined operator" }
 
 int main() {
-  f(0); // { dg-error "cannot call|predicate constraint" }
+  f(0); // { dg-error "not|bool" }
 }
diff --git a/gcc/testsuite/g++.dg/concepts/req6.C b/gcc/testsuite/g++.dg/concepts/req6.C
index 00e33fc..9cac8f8 100644
--- a/gcc/testsuite/g++.dg/concepts/req6.C
+++ b/gcc/testsuite/g++.dg/concepts/req6.C
@@ -7,7 +7,7 @@ template<typename T>
   concept bool C1() { return X(); }
 
 template<C1 T>
-  void h(T) { } // { dg-error "not convertible" }
+  void h(T) { } // { dg-error "not|bool" }
 
 template<typename T>
   concept bool C2() { return X() == X(); } // OK
diff --git a/gcc/testsuite/g++.dg/concepts/req7.C b/gcc/testsuite/g++.dg/concepts/req7.C
index dd66b39..10c3e65 100644
--- a/gcc/testsuite/g++.dg/concepts/req7.C
+++ b/gcc/testsuite/g++.dg/concepts/req7.C
@@ -20,6 +20,6 @@ template<typename Seq, typename Fn>
     }
 
 int main() {
-  all(vector<int>{0, 2}, true); // { dg-error "cannot call" }
+  all(vector<int>{0, 2}, true); // { dg-error "not|bool" }
 }
 
diff --git a/gcc/testsuite/g++.dg/concepts/var-concepts3.C b/gcc/testsuite/g++.dg/concepts/var-concepts3.C
index 010a96e..5f6be73 100644
--- a/gcc/testsuite/g++.dg/concepts/var-concepts3.C
+++ b/gcc/testsuite/g++.dg/concepts/var-concepts3.C
@@ -12,11 +12,11 @@ template<typename T>
 
 template<typename U>
   requires C1<U>()
-  void f1(U) { } // { dg-error "invalid constraint" }
+  void f1(U) { } // { dg-error "function call" }
 
 template<typename U>
   requires C2<U>
-  void f2(U) { } // { dg-error "invalid constraint" }
+  void f2(U) { } // { dg-error "invalid reference" }
 
 template<C3 T>  // { dg-error "not a type" }
   void f(T) { } // { dg-error "declared void" }

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]