Re: [PATCH] c++: Some improvements to concept diagnostics

2020-02-25 Thread Jason Merrill

On 2/24/20 12:30 PM, Patrick Palka wrote:

On Mon, 24 Feb 2020, Jason Merrill wrote:


On 2/20/20 7:27 PM, Patrick Palka wrote:

This patch improves our concept diagnostics in two ways.  First, it sets a
more
precise location for the constraint expressions built in
finish_constraint_binary_op.  As a result, when a disjunction is unsatisfied
we
now print e.g.

.../include/bits/range_access.h:467:2: note: neither operand of the
disjunction is satisfied
466 |  requires is_bounded_array_v> ||
__member_end<_Tp>
|

467 |  || __adl_end<_Tp>
|  ^

instead of

.../include/bits/range_access.h:467:2: note: neither operand of the
disjunction is satisfied
467 |  || __adl_end<_Tp>
|  ^~


This hunk is OK.


Second, this patch changes diagnose_atomic_constraint to pretty-print
unsatisfied atomic constraint expressions with their template arguments
substituted in (if doing so does not result in a trivial expression).  So
for
example we now emit

cpp2a/concepts-pr67719.C:9:8: note: the expression ‘((C() && C()) && C())’ evaluated to ‘false’

instead of

cpp2a/concepts-pr67719.C:9:8: note: the expression ‘(... &&(C)())’
evaluated to ‘false’


Generally with templates we try to print the dependent form and then the
arguments; pp_cxx_atomic_constraint already wants to do that, but we don't get
there from here.  Perhaps pass 'map' instead of 'args' into
diagnose_atomic_constraint, and then build a new ATOMIC_CONSTR for printing
with %E?


That works really well.  I had to add handling of TYPE_ARGUMENT_PACK to
cxx_pretty_printer::type_id because otherwise an "unsupported
type_argument_pack" placeholder would get printed in these diagnostics
instead.  For consistency with the way we print TYPE_ARGUMENT_PACKs and
NONTYPE_ARGUMENT_PACKs elsewhere I also made
cxx_pretty_printer::expression print curly braces around a
NONTYPE_ARGUMENT_PACK.  Tested on x86_64-pc-linux-gnu, does this look
OK?


OK.


-- >8 --

gcc/cp/ChangeLog:

* constraint.cc (finish_constraint_binary_op): Set expr's location range
to the range of its operands.
(satisfy_atom): Pass MAP instead of ARGS to diagnose_atomic_constraint.
(diagnose_trait_expr): Take the instantiated parameter mapping MAP
instead of the corresponding template arguments ARGS and adjust body
accordingly.
(diagnose_requires_expr): Likewise.
(diagnose_atomic_constraint): Likewise.  When printing an atomic
constraint expression, print the instantiated parameter mapping
alongside it.
* cxx-pretty-print.cc (cxx_pretty_printer::expression)
[NONTYPE_ARGUMENT_PACK]: Print braces around a NONTYPE_ARGUMENT_PACK.
(cxx_pretty_printer::type_id): Handle TYPE_ARGUMENT_PACK.

gcc/testsuite/ChangeLog:

* g++.dg/concepts/diagnostic2.C: New test.
* g++.dg/concepts/diagnostic3.C: New test.
---
  gcc/cp/constraint.cc| 33 -
  gcc/cp/cxx-pretty-print.c   | 17 +++
  gcc/testsuite/g++.dg/concepts/diagnostic2.C | 30 +++
  gcc/testsuite/g++.dg/concepts/diagnostic3.C | 29 ++
  4 files changed, 95 insertions(+), 14 deletions(-)
  create mode 100644 gcc/testsuite/g++.dg/concepts/diagnostic2.C
  create mode 100644 gcc/testsuite/g++.dg/concepts/diagnostic3.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 58044cd0f9d..4e6ed440211 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -155,14 +155,14 @@ finish_constraint_binary_op (location_t loc,
if (!check_constraint_operands (loc, lhs, rhs))
  return error_mark_node;
tree overload;
-  tree expr = build_x_binary_op (loc, code,
-lhs, TREE_CODE (lhs),
-rhs, TREE_CODE (rhs),
-&overload, tf_none);
+  cp_expr expr = build_x_binary_op (loc, code,
+   lhs, TREE_CODE (lhs),
+   rhs, TREE_CODE (rhs),
+   &overload, tf_none);
/* When either operand is dependent, the overload set may be non-empty.  */
if (expr == error_mark_node)
  return error_mark_node;
-  SET_EXPR_LOCATION (expr, loc);
+  expr.set_range (lhs.get_start (), rhs.get_finish ());
return expr;
  }
  
@@ -2547,7 +2547,7 @@ satisfy_atom (tree t, tree args, subst_info info)

/* Compute the value of the constraint.  */
result = satisfaction_value (cxx_constant_value (result));
if (result == boolean_false_node && info.noisy ())
-diagnose_atomic_constraint (t, args, info);
+diagnose_atomic_constraint (t, map, info);
  
return cache.save (result);

  }
@@ -3056,9 +3056,10 @@ get_constraint_error_location (tree

Re: [PATCH] c++: Some improvements to concept diagnostics

2020-02-24 Thread Patrick Palka
On Mon, 24 Feb 2020, Jason Merrill wrote:

> On 2/20/20 7:27 PM, Patrick Palka wrote:
> > This patch improves our concept diagnostics in two ways.  First, it sets a
> > more
> > precise location for the constraint expressions built in
> > finish_constraint_binary_op.  As a result, when a disjunction is unsatisfied
> > we
> > now print e.g.
> > 
> > .../include/bits/range_access.h:467:2: note: neither operand of the
> > disjunction is satisfied
> >466 |  requires is_bounded_array_v> ||
> > __member_end<_Tp>
> >|
> > 
> >467 |  || __adl_end<_Tp>
> >|  ^
> > 
> > instead of
> > 
> > .../include/bits/range_access.h:467:2: note: neither operand of the
> > disjunction is satisfied
> >467 |  || __adl_end<_Tp>
> >|  ^~
> 
> This hunk is OK.
> 
> > Second, this patch changes diagnose_atomic_constraint to pretty-print
> > unsatisfied atomic constraint expressions with their template arguments
> > substituted in (if doing so does not result in a trivial expression).  So
> > for
> > example we now emit
> > 
> > cpp2a/concepts-pr67719.C:9:8: note: the expression ‘((C() && C > int>()) && C())’ evaluated to ‘false’
> > 
> > instead of
> > 
> > cpp2a/concepts-pr67719.C:9:8: note: the expression ‘(... &&(C)())’
> > evaluated to ‘false’
> 
> Generally with templates we try to print the dependent form and then the
> arguments; pp_cxx_atomic_constraint already wants to do that, but we don't get
> there from here.  Perhaps pass 'map' instead of 'args' into
> diagnose_atomic_constraint, and then build a new ATOMIC_CONSTR for printing
> with %E?

That works really well.  I had to add handling of TYPE_ARGUMENT_PACK to
cxx_pretty_printer::type_id because otherwise an "unsupported
type_argument_pack" placeholder would get printed in these diagnostics
instead.  For consistency with the way we print TYPE_ARGUMENT_PACKs and
NONTYPE_ARGUMENT_PACKs elsewhere I also made
cxx_pretty_printer::expression print curly braces around a
NONTYPE_ARGUMENT_PACK.  Tested on x86_64-pc-linux-gnu, does this look
OK?

-- >8 --

gcc/cp/ChangeLog:

* constraint.cc (finish_constraint_binary_op): Set expr's location range
to the range of its operands.
(satisfy_atom): Pass MAP instead of ARGS to diagnose_atomic_constraint.
(diagnose_trait_expr): Take the instantiated parameter mapping MAP
instead of the corresponding template arguments ARGS and adjust body
accordingly.
(diagnose_requires_expr): Likewise.
(diagnose_atomic_constraint): Likewise.  When printing an atomic
constraint expression, print the instantiated parameter mapping
alongside it.
* cxx-pretty-print.cc (cxx_pretty_printer::expression)
[NONTYPE_ARGUMENT_PACK]: Print braces around a NONTYPE_ARGUMENT_PACK.
(cxx_pretty_printer::type_id): Handle TYPE_ARGUMENT_PACK.

gcc/testsuite/ChangeLog:

* g++.dg/concepts/diagnostic2.C: New test.
* g++.dg/concepts/diagnostic3.C: New test.
---
 gcc/cp/constraint.cc| 33 -
 gcc/cp/cxx-pretty-print.c   | 17 +++
 gcc/testsuite/g++.dg/concepts/diagnostic2.C | 30 +++
 gcc/testsuite/g++.dg/concepts/diagnostic3.C | 29 ++
 4 files changed, 95 insertions(+), 14 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/concepts/diagnostic2.C
 create mode 100644 gcc/testsuite/g++.dg/concepts/diagnostic3.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 58044cd0f9d..4e6ed440211 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -155,14 +155,14 @@ finish_constraint_binary_op (location_t loc,
   if (!check_constraint_operands (loc, lhs, rhs))
 return error_mark_node;
   tree overload;
-  tree expr = build_x_binary_op (loc, code,
-lhs, TREE_CODE (lhs),
-rhs, TREE_CODE (rhs),
-&overload, tf_none);
+  cp_expr expr = build_x_binary_op (loc, code,
+   lhs, TREE_CODE (lhs),
+   rhs, TREE_CODE (rhs),
+   &overload, tf_none);
   /* When either operand is dependent, the overload set may be non-empty.  */
   if (expr == error_mark_node)
 return error_mark_node;
-  SET_EXPR_LOCATION (expr, loc);
+  expr.set_range (lhs.get_start (), rhs.get_finish ());
   return expr;
 }
 
@@ -2547,7 +2547,7 @@ satisfy_atom (tree t, tree args, subst_info info)
   /* Compute the value of the constraint.  */
   result = sat

Re: [PATCH] c++: Some improvements to concept diagnostics

2020-02-24 Thread Jason Merrill

On 2/20/20 7:27 PM, Patrick Palka wrote:

This patch improves our concept diagnostics in two ways.  First, it sets a more
precise location for the constraint expressions built in
finish_constraint_binary_op.  As a result, when a disjunction is unsatisfied we
now print e.g.

.../include/bits/range_access.h:467:2: note: neither operand of the disjunction 
is satisfied
   466 |  requires is_bounded_array_v> || 
__member_end<_Tp>
   |   

   467 |  || __adl_end<_Tp>
   |  ^

instead of

.../include/bits/range_access.h:467:2: note: neither operand of the disjunction 
is satisfied
   467 |  || __adl_end<_Tp>
   |  ^~


This hunk is OK.


Second, this patch changes diagnose_atomic_constraint to pretty-print
unsatisfied atomic constraint expressions with their template arguments
substituted in (if doing so does not result in a trivial expression).  So for
example we now emit

cpp2a/concepts-pr67719.C:9:8: note: the expression ‘((C() && C()) && 
C())’ evaluated to ‘false’

instead of

cpp2a/concepts-pr67719.C:9:8: note: the expression ‘(... &&(C)())’ 
evaluated to ‘false’


Generally with templates we try to print the dependent form and then the 
arguments; pp_cxx_atomic_constraint already wants to do that, but we 
don't get there from here.  Perhaps pass 'map' instead of 'args' into 
diagnose_atomic_constraint, and then build a new ATOMIC_CONSTR for 
printing with %E?



Tested on x86_64-pc-linux-gnu, and verified that all the diagnostics emitted in
our concept tests are no worse with this patch.  Does this look OK to commit?

gcc/cp/ChangeLog:

* constraint.cc (finish_constraint_binary_op): Set expr's location range
to the range of its operands.
(diagnose_atomic_constraint): Prefer to pretty-print the atomic
constraint with template arguments substituted in.

gcc/testsuite/ChangeLog:

* g++.dg/concepts/diagnostic2.C: New test.
* g++.dg/concepts/diagnostic3.C: New test.
---
  gcc/cp/constraint.cc| 15 +++
  gcc/testsuite/g++.dg/concepts/diagnostic2.C | 30 +
  gcc/testsuite/g++.dg/concepts/diagnostic3.C | 19 +
  3 files changed, 59 insertions(+), 5 deletions(-)
  create mode 100644 gcc/testsuite/g++.dg/concepts/diagnostic2.C
  create mode 100644 gcc/testsuite/g++.dg/concepts/diagnostic3.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 58044cd0f9d..4f6bc11e7e8 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -155,14 +155,14 @@ finish_constraint_binary_op (location_t loc,
if (!check_constraint_operands (loc, lhs, rhs))
  return error_mark_node;
tree overload;
-  tree expr = build_x_binary_op (loc, code,
-lhs, TREE_CODE (lhs),
-rhs, TREE_CODE (rhs),
-&overload, tf_none);
+  cp_expr expr = build_x_binary_op (loc, code,
+   lhs, TREE_CODE (lhs),
+   rhs, TREE_CODE (rhs),
+   &overload, tf_none);
/* When either operand is dependent, the overload set may be non-empty.  */
if (expr == error_mark_node)
  return error_mark_node;
-  SET_EXPR_LOCATION (expr, loc);
+  expr.set_range (lhs.get_start (), rhs.get_finish ());
return expr;
  }
  
@@ -3330,6 +3330,11 @@ diagnose_atomic_constraint (tree t, tree args, subst_info info)

inform (loc, "%qE is never satisfied", expr);
break;
  default:
+  tree orig_expr = expr;
+  expr = tsubst_expr (expr, args, tf_none, NULL_TREE, false);
+  if (CONSTANT_CLASS_P (expr))
+   /* We are better off printing the original expression.  */
+   expr = orig_expr;
inform (loc, "the expression %qE evaluated to %", expr);
  }
  }
diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic2.C 
b/gcc/testsuite/g++.dg/concepts/diagnostic2.C
new file mode 100644
index 000..ce51b71fa8b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/concepts/diagnostic2.C
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++2a } }
+// { dg-options "-fdiagnostics-show-caret" }
+
+template
+  inline constexpr bool foo_v = false;
+
+template
+  concept foo = foo_v || foo_v; // { dg-message "neither operand" }
+/* { dg-begin-multiline-output "" }
+   concept foo = foo_v || foo_v;
+ ~^~~~
+   { dg-end-multiline-output "" } */
+
+template
+  requires foo
+  void bar();
+/* { dg-begin-multiline-output "" }
+   void bar();
+   { dg-end-multiline-output "" } */
+/* { dg-prune-output "~" } */
+
+void
+baz()
+{
+  bar(); // { dg-error "unsatisfied constraints" }
+/* { dg-begin-multiline-output "" }
+   bar();
+

[PATCH] c++: Some improvements to concept diagnostics

2020-02-20 Thread Patrick Palka
This patch improves our concept diagnostics in two ways.  First, it sets a more
precise location for the constraint expressions built in
finish_constraint_binary_op.  As a result, when a disjunction is unsatisfied we
now print e.g.

.../include/bits/range_access.h:467:2: note: neither operand of the disjunction 
is satisfied
  466 |  requires is_bounded_array_v> || 
__member_end<_Tp>
  |   

  467 |  || __adl_end<_Tp>
  |  ^

instead of

.../include/bits/range_access.h:467:2: note: neither operand of the disjunction 
is satisfied
  467 |  || __adl_end<_Tp>
  |  ^~

Second, this patch changes diagnose_atomic_constraint to pretty-print
unsatisfied atomic constraint expressions with their template arguments
substituted in (if doing so does not result in a trivial expression).  So for
example we now emit

cpp2a/concepts-pr67719.C:9:8: note: the expression ‘((C() && C()) && C())’ evaluated to ‘false’

instead of

cpp2a/concepts-pr67719.C:9:8: note: the expression ‘(... &&(C)())’ 
evaluated to ‘false’

Tested on x86_64-pc-linux-gnu, and verified that all the diagnostics emitted in
our concept tests are no worse with this patch.  Does this look OK to commit?

gcc/cp/ChangeLog:

* constraint.cc (finish_constraint_binary_op): Set expr's location range
to the range of its operands.
(diagnose_atomic_constraint): Prefer to pretty-print the atomic
constraint with template arguments substituted in.

gcc/testsuite/ChangeLog:

* g++.dg/concepts/diagnostic2.C: New test.
* g++.dg/concepts/diagnostic3.C: New test.
---
 gcc/cp/constraint.cc| 15 +++
 gcc/testsuite/g++.dg/concepts/diagnostic2.C | 30 +
 gcc/testsuite/g++.dg/concepts/diagnostic3.C | 19 +
 3 files changed, 59 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/concepts/diagnostic2.C
 create mode 100644 gcc/testsuite/g++.dg/concepts/diagnostic3.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 58044cd0f9d..4f6bc11e7e8 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -155,14 +155,14 @@ finish_constraint_binary_op (location_t loc,
   if (!check_constraint_operands (loc, lhs, rhs))
 return error_mark_node;
   tree overload;
-  tree expr = build_x_binary_op (loc, code,
-lhs, TREE_CODE (lhs),
-rhs, TREE_CODE (rhs),
-&overload, tf_none);
+  cp_expr expr = build_x_binary_op (loc, code,
+   lhs, TREE_CODE (lhs),
+   rhs, TREE_CODE (rhs),
+   &overload, tf_none);
   /* When either operand is dependent, the overload set may be non-empty.  */
   if (expr == error_mark_node)
 return error_mark_node;
-  SET_EXPR_LOCATION (expr, loc);
+  expr.set_range (lhs.get_start (), rhs.get_finish ());
   return expr;
 }
 
@@ -3330,6 +3330,11 @@ diagnose_atomic_constraint (tree t, tree args, 
subst_info info)
   inform (loc, "%qE is never satisfied", expr);
   break;
 default:
+  tree orig_expr = expr;
+  expr = tsubst_expr (expr, args, tf_none, NULL_TREE, false);
+  if (CONSTANT_CLASS_P (expr))
+   /* We are better off printing the original expression.  */
+   expr = orig_expr;
   inform (loc, "the expression %qE evaluated to %", expr);
 }
 }
diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic2.C 
b/gcc/testsuite/g++.dg/concepts/diagnostic2.C
new file mode 100644
index 000..ce51b71fa8b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/concepts/diagnostic2.C
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++2a } }
+// { dg-options "-fdiagnostics-show-caret" }
+
+template
+  inline constexpr bool foo_v = false;
+
+template
+  concept foo = foo_v || foo_v; // { dg-message "neither operand" }
+/* { dg-begin-multiline-output "" }
+   concept foo = foo_v || foo_v;
+ ~^~~~
+   { dg-end-multiline-output "" } */
+
+template
+  requires foo
+  void bar();
+/* { dg-begin-multiline-output "" }
+   void bar();
+   { dg-end-multiline-output "" } */
+/* { dg-prune-output "~" } */
+
+void
+baz()
+{
+  bar(); // { dg-error "unsatisfied constraints" }
+/* { dg-begin-multiline-output "" }
+   bar();
+^
+   { dg-end-multiline-output "" } */
+}
diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic3.C 
b/gcc/testsuite/g++.dg/concepts/diagnostic3.C
new file mode 100644
index 000..e0649dac51a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/concepts/diagnostic3.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++2a } }
+
+template
+  inline constexpr bool foo_v = false;
+
+template
+  con

Re: [C++ PATCH] Tweak concept diagnostics

2019-12-06 Thread Jason Merrill

On 12/6/19 3:20 PM, Jakub Jelinek wrote:

Hi!

I've noticed that while for requires keyword we have a diagnostics like
   error_at (cp_lexer_peek_token (parser->lexer)->location,
 "% only available with "
 "%<-std=c++2a%> or %<-fconcepts%>");
for concept keyword we emit
inform (location, "% only available with %<-fconcepts%>");
The following patch adjusts the latter to match the former, because I think
more people will use -std=c++2a than -fconcepts in the GCC 10 timeframe.

Tested on x86_64-linux, ok for trunk?


OK, thanks.


2019-12-06  Jakub Jelinek  

* parser.c (cp_parser_diagnose_invalid_type_name): Mention
that concept is also available with -std=c++2a.

--- gcc/cp/parser.c.jj  2019-12-05 10:03:04.072181899 +0100
+++ gcc/cp/parser.c 2019-12-06 19:40:44.090311079 +0100
@@ -3367,7 +3367,8 @@ cp_parser_diagnose_invalid_type_name (cp
inform (location, "C++20 % only available with "
"%<-std=c++2a%> or %<-std=gnu++2a%>");
else if (!flag_concepts && id == ridpointers[(int)RID_CONCEPT])
-   inform (location, "% only available with %<-fconcepts%>");
+   inform (location, "% only available with %<-std=c++2a%> or "
+   "%<-fconcepts%>");
else if (processing_template_decl && current_class_type
   && TYPE_BINFO (current_class_type))
{

Jakub





[C++ PATCH] Tweak concept diagnostics

2019-12-06 Thread Jakub Jelinek
Hi!

I've noticed that while for requires keyword we have a diagnostics like
  error_at (cp_lexer_peek_token (parser->lexer)->location,
"% only available with "
"%<-std=c++2a%> or %<-fconcepts%>");
for concept keyword we emit
inform (location, "% only available with %<-fconcepts%>");
The following patch adjusts the latter to match the former, because I think
more people will use -std=c++2a than -fconcepts in the GCC 10 timeframe.

Tested on x86_64-linux, ok for trunk?

2019-12-06  Jakub Jelinek  

* parser.c (cp_parser_diagnose_invalid_type_name): Mention
that concept is also available with -std=c++2a.

--- gcc/cp/parser.c.jj  2019-12-05 10:03:04.072181899 +0100
+++ gcc/cp/parser.c 2019-12-06 19:40:44.090311079 +0100
@@ -3367,7 +3367,8 @@ cp_parser_diagnose_invalid_type_name (cp
inform (location, "C++20 % only available with "
"%<-std=c++2a%> or %<-std=gnu++2a%>");
   else if (!flag_concepts && id == ridpointers[(int)RID_CONCEPT])
-   inform (location, "% only available with %<-fconcepts%>");
+   inform (location, "% only available with %<-std=c++2a%> or "
+   "%<-fconcepts%>");
   else if (processing_template_decl && current_class_type
   && TYPE_BINFO (current_class_type))
{

Jakub



concept diagnostics

2015-08-18 Thread Andrew Sutton
This is not a proper patch. I'm missing the usual changelog and I'm
still running the regression tests, but I wanted to get some opinions
before committing more time to it.

This patch extends the diagnostics for concepts to report precise
failures when constraints are not satisfied. It currently reports up
to 7 errors and then elides the rest. That should probably be under
control of a compiler option, but I'd like some suggestions on how to
proceed.

Also, diagnostics are currently emitted as notes against the location
of the concept declaration. It would be better to diagnose the failure
against location of each requirement, but we're not doing a very good
job tracking source locations for those.

Also, in a lot of cases, we probably just want to replay a
substitution with tf_error to generate precise failures. Although that
potentially generates *way* more information (e.g., candidate sets for
failed overload resolution).

I also started try to apply these diagnostics to static_if. The basic
idea being: if you write static_if(C, "") where C is a concept,
then you should get the full diagnostics for that concept. I suspect
that this will be the most requested feature within a few months time.

Unfortunately, I ran into a little problem that C is immediately
folded into true/false and the original expression is unrecoverable
from finish_static_if. I tinkered with parsing the condition as a
non-constant expression and then folding it on demand, but that caused
a number of regressions, so I had to back it out. Any thoughts on how
to proceed?

Andrew
Index: cxx-pretty-print.c
===
--- cxx-pretty-print.c	(revision 226937)
+++ cxx-pretty-print.c	(working copy)
@@ -2600,6 +2600,7 @@ pp_cxx_compound_requirement (cxx_pretty_
   pp_cxx_ws_string (pp, "->");
   pp->type_id (type);
 }
+  pp_cxx_semicolon (pp);
 }
 
 /* nested requirement:
@@ -2646,7 +2647,7 @@ pp_cxx_implicit_conversion_constraint (c
   pp_left_paren (pp);
   pp->expression (ICONV_CONSTR_EXPR (t));
   pp_cxx_separate_with (pp, ',');
-  pp->expression (ICONV_CONSTR_TYPE (t));
+  pp->type_id (ICONV_CONSTR_TYPE (t));
   pp_right_paren (pp);
 }
 
Index: cp-tree.h
===
--- cp-tree.h	(revision 226937)
+++ cp-tree.h	(working copy)
@@ -6680,6 +6680,8 @@ extern tree tsubst_requires_expr
 extern tree tsubst_constraint   (tree, tree, tsubst_flags_t, tree);
 extern tree tsubst_constraint_info  (tree, tree, tsubst_flags_t, tree);
 extern bool function_concept_check_p(tree);
+extern bool variable_concept_check_p(tree);
+extern bool concept_check_p (tree);
 
 extern tree evaluate_constraints(tree, tree);
 extern tree evaluate_function_concept   (tree, tree);
@@ -6687,6 +6689,7 @@ extern tree evaluate_variable_concept
 extern tree evaluate_constraint_expression  (tree, tree);
 extern bool constraints_satisfied_p (tree);
 extern bool constraints_satisfied_p (tree, tree);
+extern bool constraint_expression_satisfied_p   (tree, tree);
 
 extern bool equivalent_constraints  (tree, tree);
 extern bool equivalently_constrained(tree, tree);
Index: constraint.cc
===
--- constraint.cc	(revision 226937)
+++ constraint.cc	(working copy)
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.
 #include "wide-int.h"
 #include "inchash.h"
 #include "tree.h"
+#include "print-tree.h"
 #include "stringpool.h"
 #include "attribs.h"
 #include "intl.h"
@@ -113,13 +114,22 @@ conjoin_constraints (tree t)
   return r;
 }
 
-/* Returns true if T is a call expression to a function
-   concept. */
+/* Returns true if T is an expression that would evaluate
+   a variable or function concept. */
+
+bool
+concept_check_p (tree t)
+{
+  return function_concept_check_p (t) || variable_concept_check_p (t);
+}
+
+/* Returns true if T is a call to a function concept. */
 
 bool
 function_concept_check_p (tree t)
 {
-  gcc_assert (TREE_CODE (t) == CALL_EXPR);
+  if (!t || t == error_mark_node || TREE_CODE (t) != CALL_EXPR)
+return false;
   tree fn = CALL_EXPR_FN (t);
   if (TREE_CODE (fn) == TEMPLATE_ID_EXPR
   && TREE_CODE (TREE_OPERAND (fn, 0)) == OVERLOAD)
@@ -132,6 +142,17 @@ function_concept_check_p (tree t)
   return false;
 }
 
+/* Returns true if T is a template-id referring to a variable concept. */
+
+bool
+variable_concept_check_p (tree t)
+{
+  if (!t || t == error_mark_node || TREE_CODE (t) != TEMPLATE_ID_EXPR)
+return false;
+  return variable_template_p (TREE_OPERAND (t, 0));
+}
+
+
 /*---
 Resolution of qualified concept names
 ---*/
@@ -350,12 +371,12 @@ lift_func