From cc79378c9782d521052c364e1ca29f8310248a03 Mon Sep 17 00:00:00 2001
From: Andrew Sutton <asutton@lock3software.com>
Date: Tue, 15 Oct 2019 15:47:31 -0400
Subject: [PATCH 1/1] Emit hard errors for certain satisfaction errors.

gcc/cp/
	* constraint.cc (satisfy_atom): Fix the error location for expressions.
	Emit "hard errors" on the first pass, but not the second. Add comments
	suggesting how to establish context for those errors.
	(evaluate_concept_check): Remove tsubst_flags parameter.
	(current_failed_constraint): Move from pt.c.
	* cp-tree.h (evaluate_concept_check): Likewise.
	* pt.c (tsubst_copy_and_build): Update calls accordingly.
	* semantics.c (finish_call_expr): Likewise.
	(finish_id_expression_1): Likewise. Also, remove a duplicated case.

gcc/testsuite/g++.dg/cpp2a/
	* g++.dg/cpp2a/concepts-requires2.C: Likewise.

gcc/testsuite/g++.dg/concepts/
	* g++.dg/concepts/pr84330.C: Update diagnostics.
---
 gcc/cp/ChangeLog                              | 13 +++++++
 gcc/cp/constraint.cc                          | 35 ++++++++-----------
 gcc/cp/cp-tree.h                              |  2 +-
 gcc/cp/pt.c                                   |  6 ++--
 gcc/cp/semantics.c                            | 14 ++------
 gcc/testsuite/ChangeLog                       |  6 ++++
 gcc/testsuite/g++.dg/concepts/pr84330.C       |  2 +-
 .../g++.dg/cpp2a/concepts-requires2.C         |  8 ++---
 8 files changed, 43 insertions(+), 43 deletions(-)

diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 28641071757..a08a50988fd 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,16 @@
+2019-10-15  Andrew Sutton  <asutton@lock3software.com>
+
+	Emit hard errors for certain satisfaction errors.
+	* constraint.cc (satisfy_atom): Fix the error location for expressions.
+	Emit "hard errors" on the first pass, but not the second. Add comments
+	suggesting how to establish context for those errors.
+	(evaluate_concept_check): Remove tsubst_flags parameter.
+	(current_failed_constraint): Move from pt.c.
+	* cp-tree.h (evaluate_concept_check): Likewise.
+	* pt.c (tsubst_copy_and_build): Update calls accordingly.
+	* semantics.c (finish_call_expr): Likewise.
+	(finish_id_expression_1): Likewise. Also, remove a duplicated case.
+
 2019-10-14  Paolo Carlini  <paolo.carlini@oracle.com>
 
 	* decl.c (check_tag_decl): Use DECL_SOURCE_LOCATION.
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index db4a81858f6..c72cff36723 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -2350,21 +2350,24 @@ satisfy_atom (tree t, tree args, subst_info info)
       return cache.save (boolean_false_node);
     }
 
-  location_t loc = cp_expr_location (expr);
+  location_t loc = cp_expr_loc_or_input_loc (expr);
 
   /* [17.4.1.2] ... lvalue-to-value conversion is performed as necessary,
      and EXPR shall be a constant expression of type bool.  */
   result = force_rvalue (result, tf_error);
   if (result == error_mark_node)
     {
-      if (info.noisy ())
-        inform (loc, "cannot convert constraint to rvalue");
+      /* FIXME: Perform the first conversion quietly. If that failed, redo
+         the conversion after having established the appropriate context.  */
       return cache.save (error_mark_node);
     }
   if (!same_type_p (TREE_TYPE (result), boolean_type_node))
     {
-      if (info.noisy ())
-	inform (loc, "constraint does not have type %<bool%>");
+      /* FIXME: We should be able to establish an appropriate context for
+         the error we're about to emit. That requires ensuring the constraint
+         references its normalization tree.  */
+      if (info.quiet ())
+	error_at (loc, "constraint does not have type %<bool%>");
       return cache.save (error_mark_node);
     }
 
@@ -2584,31 +2587,19 @@ constraints_satisfied_p (tree t, tree args)
 }
 
 /* Evaluate a concept check of the form C<ARGS>, returning either TRUE
-   or FALSE. If ARGS contains any template parameters, this returns the
-   check. If satisfaction yields a hard error, diagnose the error.  */
+   or FALSE. This never diagnoses constraint errors, unless they are the
+   are required.  */
 
 tree
-evaluate_concept_check (tree check, tsubst_flags_t complain)
+evaluate_concept_check (tree check)
 {
-  /* FIXME we ought to be able to pass complain into subst_info rather
-     than repeat satisfaction, but currently that will complain about
-     non-satisfaction as well as errors.  */
   if (check == error_mark_node)
     return error_mark_node;
 
   gcc_assert (concept_check_p (check));
 
   subst_info info (tf_none, NULL_TREE);
-  tree result = satisfy_constraint_expression (check, NULL_TREE, info);
-  if (result == error_mark_node && (complain & tf_error))
-    {
-      location_t loc = cp_expr_loc_or_input_loc (check);
-      error_at (loc, "concept satisfaction failed");
-      info.complain = complain;
-      satisfy_constraint_expression (check, NULL_TREE, info);
-    }
-
-  return result;
+  return satisfy_constraint_expression (check, NULL_TREE, info);
 }
 
 /*---------------------------------------------------------------------------
@@ -3132,6 +3123,8 @@ diagnose_atomic_constraint (tree t, tree args, subst_info info)
     }
 }
 
+GTY(()) tree current_failed_constraint;
+
 diagnosing_failed_constraint::
 diagnosing_failed_constraint (tree t, tree args, bool diag)
   : diagnosing_error (diag)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 663d84b2a58..d2199076533 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7739,7 +7739,7 @@ struct processing_constraint_expression_sentinel
 extern bool processing_constraint_expression_p	();
 
 extern tree unpack_concept_check		(tree);
-extern tree evaluate_concept_check              (tree, tsubst_flags_t);
+extern tree evaluate_concept_check              (tree);
 extern tree satisfy_constraint_expression	(tree);
 extern bool constraints_satisfied_p             (tree);
 extern bool constraints_satisfied_p             (tree, tree);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 773eb43d934..3ce695df2ac 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -18723,7 +18723,7 @@ tsubst_copy_and_build (tree t,
 	    tree args = TREE_OPERAND (id, 1);
 	    if (!uses_template_parms (args)
 		&& !processing_constraint_expression_p ())
-	      RETURN (evaluate_concept_check (check, complain));
+	      RETURN (evaluate_concept_check (check));
 
 	    RETURN (check);
 	  }
@@ -19507,7 +19507,7 @@ tsubst_copy_and_build (tree t,
 	    /* Possibly evaluate the check if it is non-dependent.   */
 	    if (!uses_template_parms (args)
 		&& !processing_constraint_expression_p ())
-	      ret = evaluate_concept_check (ret, complain);
+	      ret = evaluate_concept_check (ret);
 	  }
 	else
 	  ret = finish_call_expr (function, &call_args,
@@ -28641,8 +28641,6 @@ init_constraint_processing (void)
   subsumption_table = hash_table<subsumption_hasher>::create_ggc(37);
 }
 
-GTY(()) tree current_failed_constraint;
-
 /* __integer_pack(N) in a pack expansion expands to a sequence of numbers from
    0..N-1.  */
 
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 59def3170ab..f81e82df0ce 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2608,7 +2608,7 @@ finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual,
 
       /* Evaluate the check if it is non-dependent.   */
       if (!uses_template_parms (args))
-	result = evaluate_concept_check (result, complain);
+	result = evaluate_concept_check (result);
     }
   else if (is_overloaded_fn (fn))
     {
@@ -3888,7 +3888,7 @@ finish_id_expression_1 (tree id_expression,
 	  tree tmpl = TREE_OPERAND (decl, 0);
 	  tree args = TREE_OPERAND (decl, 1);
 	  if (!function_concept_p (tmpl) && !uses_template_parms (args))
-	    decl = evaluate_concept_check (decl, tf_warning_or_error);
+	    decl = evaluate_concept_check (decl);
 	}
       else if (scope)
 	{
@@ -3962,16 +3962,6 @@ finish_id_expression_1 (tree id_expression,
 
 	  decl = baselink_for_fns (decl);
 	}
-      else if (concept_check_p (decl))
-	{
-	  /* If this is a standard or variable concept check, potentially
-	     evaluate it. Function concepts need to be called as functions,
-	     so don't try evaluating them here.  */
-	  tree tmpl = TREE_OPERAND (decl, 0);
-	  tree args = TREE_OPERAND (decl, 1);
-	  if (!function_concept_p (tmpl) && !uses_template_parms (args))
-	    decl = evaluate_concept_check (decl, tf_warning_or_error);
-	}
       else
 	{
 	  if (DECL_P (decl) && DECL_NONLOCAL (decl)
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 281da7ff85e..59947d2cfcb 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2019-10-15  Andrew Sutton  <asutton@lock3software.com>
+
+	Emit hard errors for certain satisfaction errors.
+	* g++.dg/concepts/pr84330.C: Update diagnostics.
+	* g++.dg/cpp2a/concepts-requires2.C: Likewise.
+
 2019-10-14  Richard Biener  <rguenther@suse.de>
 
 	PR tree-optimization/92069
diff --git a/gcc/testsuite/g++.dg/concepts/pr84330.C b/gcc/testsuite/g++.dg/concepts/pr84330.C
index 0c2f45602d1..ba035d02555 100644
--- a/gcc/testsuite/g++.dg/concepts/pr84330.C
+++ b/gcc/testsuite/g++.dg/concepts/pr84330.C
@@ -5,7 +5,7 @@
 struct A
 {
   template<typename T>
-    requires (sizeof(T) >> 0)
+    requires (sizeof(T) >> 0) // { dg-error "constraint does not have type 'bool'" }
   void foo(T);
 
   void bar()
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires2.C
index 45bb423af65..259e62a46d8 100644
--- a/gcc/testsuite/g++.dg/cpp2a/concepts-requires2.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires2.C
@@ -12,7 +12,7 @@ template<typename T> constexpr fool p1() { return {}; }
 template<typename T> constexpr fool p2() { return {}; }
 
 template<typename T>
-concept Bad = p1<T>() && p2<T>();
+concept Bad = p1<T>() && p2<T>(); // { dg-error "does not have type 'bool'" }
 
 template<typename T> requires Bad<T> void bad(T x) { }
 
@@ -26,10 +26,10 @@ struct X { };
 int operator==(X, X) { return 0; }
 
 template<typename T>
-concept C1 = (X());
+concept C1 = (X()); // { dg-error "does not have type 'bool'" }
 
 template<typename T>
-concept C2 = (X() == X());
+concept C2 = (X() == X()); // { dg-error "does not have type 'bool'" }
 
 template<typename T>
   requires C1<T>
@@ -42,7 +42,7 @@ void h2(T);
 void driver_3()
 {
   h1(0); // { dg-error "cannot call" }
-  h2(0); // { dg-error "cannot call" } 
+  h2(0); // { dg-error "cannot call" }
 }
 
 // req7.C
-- 
2.18.0

