public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [C++ PATCH] Fix __builtin_{is_constant_evaluated,constant_p} handling in static_assert (PR c++/86524, PR c++/88446)
@ 2018-12-12 22:30 Jakub Jelinek
  2018-12-19 10:19 ` Patch ping (Re: [C++ PATCH] Fix __builtin_{is_constant_evaluated,constant_p} handling in static_assert (PR c++/86524, PR c++/88446)) Jakub Jelinek
  2018-12-20 19:49 ` [C++ PATCH] Fix __builtin_{is_constant_evaluated,constant_p} handling in static_assert (PR c++/86524, PR c++/88446) Jason Merrill
  0 siblings, 2 replies; 11+ messages in thread
From: Jakub Jelinek @ 2018-12-12 22:30 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

Hi!

The following patch fixes __builtin_is_constant_evaluated and
__builtin_constant_p handling during static_assert evaluation.
finish_static_assert calls fold_non_dependent_expr and complains if the
result is not a constant expression, instead of requiring a constant
expression, which causes __builtin_is_constant_evaluated () during the
evaluation to be not considered as constant expression and
__builtin_constant_p calls too if they appear in constexpr functions.

The patch makes sure that manifestly_const_eval is true while evaluating
the expression and also makes sure to fold __builtin_constant_p when that is
true even when in constexpr functions.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2018-12-12  Jakub Jelinek  <jakub@redhat.com>

	PR c++/86524
	PR c++/88446
	* cp-tree.h (fold_non_dependent_expr): Add manifestly_const_eval
	argument.
	* constexpr.c (cxx_eval_builtin_function_call): Evaluate
	__builtin_constant_p if ctx->manifestly_const_eval even in constexpr
	functions.  For arguments to builtins, if ctx->manifestly_const_eval
	try to first evaluate arguments with it, but if that doesn't result
	in a constant expression, retry without it.  Fix comment typo.
	(fold_non_dependent_expr): Add manifestly_const_eval argument, pass
	it through to cxx_eval_outermost_constant_expr and
	maybe_constant_value.
	* semantics.c (finish_static_assert): Call fold_non_dependent_expr
	with true as manifestly_const_eval.

	* g++.dg/cpp1y/constexpr-86524.C: New test.
	* g++.dg/cpp2a/is-constant-evaluated4.C: New test.
	* g++.dg/cpp2a/is-constant-evaluated5.C: New test.
	* g++.dg/cpp2a/is-constant-evaluated6.C: New test.

--- gcc/cp/cp-tree.h.jj	2018-12-12 09:32:27.408535853 +0100
+++ gcc/cp/cp-tree.h	2018-12-12 11:07:24.250459779 +0100
@@ -7665,7 +7665,9 @@ extern tree cxx_constant_value			(tree,
 extern tree cxx_constant_init			(tree, tree = NULL_TREE);
 extern tree maybe_constant_value		(tree, tree = NULL_TREE, bool = false);
 extern tree maybe_constant_init			(tree, tree = NULL_TREE, bool = false);
-extern tree fold_non_dependent_expr		(tree, tsubst_flags_t = tf_warning_or_error);
+extern tree fold_non_dependent_expr		(tree,
+						 tsubst_flags_t = tf_warning_or_error,
+						 bool = false);
 extern tree fold_simple				(tree);
 extern bool is_sub_constant_expr                (tree);
 extern bool reduced_constant_expression_p       (tree);
--- gcc/cp/constexpr.c.jj	2018-12-12 09:34:17.531736075 +0100
+++ gcc/cp/constexpr.c	2018-12-12 11:30:33.986756914 +0100
@@ -1198,6 +1198,7 @@ cxx_eval_builtin_function_call (const co
      in a constexpr function until we have values for the parameters.  */
   if (bi_const_p
       && ctx->quiet
+      && !ctx->manifestly_const_eval
       && current_function_decl
       && DECL_DECLARED_CONSTEXPR_P (current_function_decl))
     {
@@ -1222,7 +1223,6 @@ cxx_eval_builtin_function_call (const co
      return constant false for a non-constant argument.  */
   constexpr_ctx new_ctx = *ctx;
   new_ctx.quiet = true;
-  bool dummy1 = false, dummy2 = false;
   for (i = 0; i < nargs; ++i)
     {
       args[i] = CALL_EXPR_ARG (t, i);
@@ -1231,10 +1231,23 @@ cxx_eval_builtin_function_call (const co
 	 of the builtin, verify it here.  */
       if (!builtin_valid_in_constant_expr_p (fun)
 	  || potential_constant_expression (args[i]))
-	args[i] = cxx_eval_constant_expression (&new_ctx, args[i], false,
-						&dummy1, &dummy2);
+	{
+	  bool non_cst_p = false, ovf_p = false;
+	  tree a = cxx_eval_constant_expression (&new_ctx, args[i], false,
+						 &non_cst_p, &ovf_p);
+	  if ((non_cst_p || ovf_p) && ctx->manifestly_const_eval)
+	    {
+	      new_ctx.manifestly_const_eval = false;
+	      non_cst_p = false;
+	      ovf_p = false;
+	      a = cxx_eval_constant_expression (&new_ctx, args[i], false,
+						&non_cst_p, &ovf_p);
+	      new_ctx.manifestly_const_eval = true;
+	    }
+	  args[i] = a;
+	}
       if (bi_const_p)
-	/* For __built_in_constant_p, fold all expressions with constant values
+	/* For __builtin_constant_p, fold all expressions with constant values
 	   even if they aren't C++ constant-expressions.  */
 	args[i] = cp_fully_fold (args[i]);
     }
@@ -5340,6 +5353,7 @@ clear_cv_and_fold_caches (void)
    (t, complain) followed by maybe_constant_value but is more efficient,
    because it calls instantiation_dependent_expression_p and
    potential_constant_expression at most once.
+   The manifestly_const_eval argument is passed to maybe_constant_value.
 
    Callers should generally pass their active complain, or if they are in a
    non-template, diagnosing context, they can use the default of
@@ -5350,7 +5364,8 @@ clear_cv_and_fold_caches (void)
 
 tree
 fold_non_dependent_expr (tree t,
-			 tsubst_flags_t complain /* = tf_warning_or_error */)
+			 tsubst_flags_t complain /* = tf_warning_or_error */,
+			 bool manifestly_const_eval /* = false */)
 {
   if (t == NULL_TREE)
     return NULL_TREE;
@@ -5380,7 +5395,8 @@ fold_non_dependent_expr (tree t,
 	      return t;
 	    }
 
-	  tree r = cxx_eval_outermost_constant_expr (t, true, true, false,
+	  tree r = cxx_eval_outermost_constant_expr (t, true, true,
+						     manifestly_const_eval,
 						     NULL_TREE);
 	  /* cp_tree_equal looks through NOPs, so allow them.  */
 	  gcc_checking_assert (r == t
@@ -5398,7 +5414,7 @@ fold_non_dependent_expr (tree t,
       return t;
     }
 
-  return maybe_constant_value (t);
+  return maybe_constant_value (t, NULL_TREE, manifestly_const_eval);
 }
 
 /* Like maybe_constant_value, but returns a CONSTRUCTOR directly, rather
--- gcc/cp/semantics.c.jj	2018-12-07 00:23:15.010998822 +0100
+++ gcc/cp/semantics.c	2018-12-12 11:12:14.418720123 +0100
@@ -9189,7 +9189,8 @@ finish_static_assert (tree condition, tr
   /* Fold the expression and convert it to a boolean value. */
   condition = perform_implicit_conversion_flags (boolean_type_node, condition,
 						 complain, LOOKUP_NORMAL);
-  condition = fold_non_dependent_expr (condition, complain);
+  condition = fold_non_dependent_expr (condition, complain,
+				       /*manifestly_const_eval=*/true);
 
   if (TREE_CODE (condition) == INTEGER_CST && !integer_zerop (condition))
     /* Do nothing; the condition is satisfied. */
--- gcc/testsuite/g++.dg/cpp1y/constexpr-86524.C.jj	2018-12-12 12:21:43.854621504 +0100
+++ gcc/testsuite/g++.dg/cpp1y/constexpr-86524.C	2018-12-12 12:21:59.228370406 +0100
@@ -0,0 +1,41 @@
+// PR c++/86524
+// { dg-do run { target c++14 } }
+// { dg-options "-O2" }
+
+extern "C" void abort ();
+typedef __UINTPTR_TYPE__ uintptr_t;
+
+constexpr bool
+foo (const int *x, const int *y)
+{
+  if (__builtin_constant_p (x < y))
+    return x < y;
+  return (uintptr_t) x < (uintptr_t) y;
+}
+
+void
+bar ()
+{
+  constexpr int x = 0;
+  static_assert (!(&x < &x));
+  static_assert (!foo (&x, &x));
+}
+
+constexpr void
+baz ()
+{
+  constexpr int x = 0;
+  static_assert (!(&x < &x));
+  static_assert (!foo (&x, &x));
+}
+
+int i, j;
+
+int
+main ()
+{
+  bar ();
+  baz ();
+  if (!(foo (&i, &j) ^ foo (&j, &i)))
+    abort ();
+}
--- gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated4.C.jj	2018-12-12 11:58:45.673134560 +0100
+++ gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated4.C	2018-12-12 11:58:20.154551558 +0100
@@ -0,0 +1,19 @@
+// P0595R2
+// { dg-do compile { target c++14 } }
+
+namespace std {
+  constexpr inline bool
+  is_constant_evaluated () noexcept
+  {
+    return __builtin_is_constant_evaluated ();
+  }
+}
+
+constexpr int
+foo () noexcept
+{
+  return std::is_constant_evaluated () ? 5 : 12;
+}
+
+static_assert (std::is_constant_evaluated (), "");
+static_assert (foo () == 5, "");
--- gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated5.C.jj	2018-12-12 12:23:01.147359102 +0100
+++ gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated5.C	2018-12-12 12:23:21.444027606 +0100
@@ -0,0 +1,41 @@
+// PR c++/86524
+// { dg-do run { target c++14 } }
+// { dg-options "-O2" }
+
+extern "C" void abort ();
+typedef __UINTPTR_TYPE__ uintptr_t;
+
+constexpr bool
+foo (const int *x, const int *y)
+{
+  if (__builtin_is_constant_evaluated ())
+    return x < y;
+  return (uintptr_t) x < (uintptr_t) y;
+}
+
+void
+bar ()
+{
+  constexpr int x = 0;
+  static_assert (!(&x < &x));
+  static_assert (!foo (&x, &x));
+}
+
+constexpr void
+baz ()
+{
+  constexpr int x = 0;
+  static_assert (!(&x < &x));
+  static_assert (!foo (&x, &x));
+}
+
+int i, j;
+
+int
+main ()
+{
+  bar ();
+  baz ();
+  if (!(foo (&i, &j) ^ foo (&j, &i)))
+    abort ();
+}
--- gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated6.C.jj	2018-12-12 12:36:48.381866271 +0100
+++ gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated6.C	2018-12-12 12:35:04.140566444 +0100
@@ -0,0 +1,29 @@
+// P0595R2
+// { dg-do compile { target c++14 } }
+
+namespace std {
+  constexpr inline bool
+  is_constant_evaluated () noexcept
+  {
+    return __builtin_is_constant_evaluated ();
+  }
+}
+
+int a;
+
+constexpr bool
+foo (int x)
+{
+  return __builtin_constant_p (x);
+}
+
+constexpr bool
+bar (int x)
+{
+  return __builtin_constant_p (x + a);
+}
+
+static_assert (__builtin_constant_p (0) + 2 * std::is_constant_evaluated () == 3, "");
+static_assert (__builtin_constant_p (a) + 2 * std::is_constant_evaluated () == 2, "");
+static_assert (foo (0) + 2 * std::is_constant_evaluated () == 3, "");
+static_assert (bar (0) + 2 * std::is_constant_evaluated () == 2, "");

	Jakub

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Patch ping (Re: [C++ PATCH] Fix __builtin_{is_constant_evaluated,constant_p} handling in static_assert (PR c++/86524, PR c++/88446))
  2018-12-12 22:30 [C++ PATCH] Fix __builtin_{is_constant_evaluated,constant_p} handling in static_assert (PR c++/86524, PR c++/88446) Jakub Jelinek
@ 2018-12-19 10:19 ` Jakub Jelinek
  2018-12-20 19:49 ` [C++ PATCH] Fix __builtin_{is_constant_evaluated,constant_p} handling in static_assert (PR c++/86524, PR c++/88446) Jason Merrill
  1 sibling, 0 replies; 11+ messages in thread
From: Jakub Jelinek @ 2018-12-19 10:19 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

Hi!

On Wed, Dec 12, 2018 at 11:30:37PM +0100, Jakub Jelinek wrote:
> 2018-12-12  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR c++/86524
> 	PR c++/88446
> 	* cp-tree.h (fold_non_dependent_expr): Add manifestly_const_eval
> 	argument.
> 	* constexpr.c (cxx_eval_builtin_function_call): Evaluate
> 	__builtin_constant_p if ctx->manifestly_const_eval even in constexpr
> 	functions.  For arguments to builtins, if ctx->manifestly_const_eval
> 	try to first evaluate arguments with it, but if that doesn't result
> 	in a constant expression, retry without it.  Fix comment typo.
> 	(fold_non_dependent_expr): Add manifestly_const_eval argument, pass
> 	it through to cxx_eval_outermost_constant_expr and
> 	maybe_constant_value.
> 	* semantics.c (finish_static_assert): Call fold_non_dependent_expr
> 	with true as manifestly_const_eval.
> 
> 	* g++.dg/cpp1y/constexpr-86524.C: New test.
> 	* g++.dg/cpp2a/is-constant-evaluated4.C: New test.
> 	* g++.dg/cpp2a/is-constant-evaluated5.C: New test.
> 	* g++.dg/cpp2a/is-constant-evaluated6.C: New test.

I'd like to ping this patch.

Thanks.

	Jakub

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [C++ PATCH] Fix __builtin_{is_constant_evaluated,constant_p} handling in static_assert (PR c++/86524, PR c++/88446)
  2018-12-12 22:30 [C++ PATCH] Fix __builtin_{is_constant_evaluated,constant_p} handling in static_assert (PR c++/86524, PR c++/88446) Jakub Jelinek
  2018-12-19 10:19 ` Patch ping (Re: [C++ PATCH] Fix __builtin_{is_constant_evaluated,constant_p} handling in static_assert (PR c++/86524, PR c++/88446)) Jakub Jelinek
@ 2018-12-20 19:49 ` Jason Merrill
  2018-12-20 21:26   ` Jakub Jelinek
  1 sibling, 1 reply; 11+ messages in thread
From: Jason Merrill @ 2018-12-20 19:49 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

On 12/12/18 5:30 PM, Jakub Jelinek wrote:
> Hi!
> 
> The following patch fixes __builtin_is_constant_evaluated and
> __builtin_constant_p handling during static_assert evaluation.
> finish_static_assert calls fold_non_dependent_expr and complains if the
> result is not a constant expression, instead of requiring a constant
> expression, which causes __builtin_is_constant_evaluated () during the
> evaluation to be not considered as constant expression and
> __builtin_constant_p calls too if they appear in constexpr functions.
> 
> The patch makes sure that manifestly_const_eval is true while evaluating
> the expression and also makes sure to fold __builtin_constant_p when that is
> true even when in constexpr functions.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
> 
> 2018-12-12  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR c++/86524
> 	PR c++/88446
> 	* cp-tree.h (fold_non_dependent_expr): Add manifestly_const_eval
> 	argument.
> 	* constexpr.c (cxx_eval_builtin_function_call): Evaluate
> 	__builtin_constant_p if ctx->manifestly_const_eval even in constexpr
> 	functions.  For arguments to builtins, if ctx->manifestly_const_eval
> 	try to first evaluate arguments with it, but if that doesn't result
> 	in a constant expression, retry without it.  Fix comment typo.
> 	(fold_non_dependent_expr): Add manifestly_const_eval argument, pass
> 	it through to cxx_eval_outermost_constant_expr and
> 	maybe_constant_value.
> 	* semantics.c (finish_static_assert): Call fold_non_dependent_expr
> 	with true as manifestly_const_eval.
> 
> 	* g++.dg/cpp1y/constexpr-86524.C: New test.
> 	* g++.dg/cpp2a/is-constant-evaluated4.C: New test.
> 	* g++.dg/cpp2a/is-constant-evaluated5.C: New test.
> 	* g++.dg/cpp2a/is-constant-evaluated6.C: New test.
> 
> --- gcc/cp/cp-tree.h.jj	2018-12-12 09:32:27.408535853 +0100
> +++ gcc/cp/cp-tree.h	2018-12-12 11:07:24.250459779 +0100
> @@ -7665,7 +7665,9 @@ extern tree cxx_constant_value			(tree,
>   extern tree cxx_constant_init			(tree, tree = NULL_TREE);
>   extern tree maybe_constant_value		(tree, tree = NULL_TREE, bool = false);
>   extern tree maybe_constant_init			(tree, tree = NULL_TREE, bool = false);
> -extern tree fold_non_dependent_expr		(tree, tsubst_flags_t = tf_warning_or_error);
> +extern tree fold_non_dependent_expr		(tree,
> +						 tsubst_flags_t = tf_warning_or_error,
> +						 bool = false);
>   extern tree fold_simple				(tree);
>   extern bool is_sub_constant_expr                (tree);
>   extern bool reduced_constant_expression_p       (tree);
> --- gcc/cp/constexpr.c.jj	2018-12-12 09:34:17.531736075 +0100
> +++ gcc/cp/constexpr.c	2018-12-12 11:30:33.986756914 +0100
> @@ -1198,6 +1198,7 @@ cxx_eval_builtin_function_call (const co
>        in a constexpr function until we have values for the parameters.  */
>     if (bi_const_p
>         && ctx->quiet
> +      && !ctx->manifestly_const_eval

I think we want to replace the "quiet" check with manifestly_const_eval, 
rather than adding to it.

> @@ -1222,7 +1223,6 @@ cxx_eval_builtin_function_call (const co
>        return constant false for a non-constant argument.  */
>     constexpr_ctx new_ctx = *ctx;
>     new_ctx.quiet = true;
> -  bool dummy1 = false, dummy2 = false;
>     for (i = 0; i < nargs; ++i)
>       {
>         args[i] = CALL_EXPR_ARG (t, i);
> @@ -1231,10 +1231,23 @@ cxx_eval_builtin_function_call (const co
>   	 of the builtin, verify it here.  */
>         if (!builtin_valid_in_constant_expr_p (fun)
>   	  || potential_constant_expression (args[i]))
> -	args[i] = cxx_eval_constant_expression (&new_ctx, args[i], false,
> -						&dummy1, &dummy2);
> +	{
> +	  bool non_cst_p = false, ovf_p = false;
> +	  tree a = cxx_eval_constant_expression (&new_ctx, args[i], false,
> +						 &non_cst_p, &ovf_p);
> +	  if ((non_cst_p || ovf_p) && ctx->manifestly_const_eval)
> +	    {
> +	      new_ctx.manifestly_const_eval = false;
> +	      non_cst_p = false;
> +	      ovf_p = false;
> +	      a = cxx_eval_constant_expression (&new_ctx, args[i], false,
> +						&non_cst_p, &ovf_p);
> +	      new_ctx.manifestly_const_eval = true;
> +	    }

Why retry without manifestly_const_eval?  For static initialization we 
don't want to try constant evaluation again with 
__builtin_is_constant_evaluated false if it failed with it true.

Jason

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [C++ PATCH] Fix __builtin_{is_constant_evaluated,constant_p} handling in static_assert (PR c++/86524, PR c++/88446)
  2018-12-20 19:49 ` [C++ PATCH] Fix __builtin_{is_constant_evaluated,constant_p} handling in static_assert (PR c++/86524, PR c++/88446) Jason Merrill
@ 2018-12-20 21:26   ` Jakub Jelinek
  2018-12-20 21:28     ` Jason Merrill
  0 siblings, 1 reply; 11+ messages in thread
From: Jakub Jelinek @ 2018-12-20 21:26 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

On Thu, Dec 20, 2018 at 02:47:01PM -0500, Jason Merrill wrote:
> > --- gcc/cp/constexpr.c.jj	2018-12-12 09:34:17.531736075 +0100
> > +++ gcc/cp/constexpr.c	2018-12-12 11:30:33.986756914 +0100
> > @@ -1198,6 +1198,7 @@ cxx_eval_builtin_function_call (const co
> >        in a constexpr function until we have values for the parameters.  */
> >     if (bi_const_p
> >         && ctx->quiet
> > +      && !ctx->manifestly_const_eval
> 
> I think we want to replace the "quiet" check with manifestly_const_eval,
> rather than adding to it.

Will change that.

> > -	args[i] = cxx_eval_constant_expression (&new_ctx, args[i], false,
> > -						&dummy1, &dummy2);
> > +	{
> > +	  bool non_cst_p = false, ovf_p = false;
> > +	  tree a = cxx_eval_constant_expression (&new_ctx, args[i], false,
> > +						 &non_cst_p, &ovf_p);
> > +	  if ((non_cst_p || ovf_p) && ctx->manifestly_const_eval)
> > +	    {
> > +	      new_ctx.manifestly_const_eval = false;
> > +	      non_cst_p = false;
> > +	      ovf_p = false;
> > +	      a = cxx_eval_constant_expression (&new_ctx, args[i], false,
> > +						&non_cst_p, &ovf_p);
> > +	      new_ctx.manifestly_const_eval = true;
> > +	    }
> 
> Why retry without manifestly_const_eval?  For static initialization we don't
> want to try constant evaluation again with __builtin_is_constant_evaluated
> false if it failed with it true.

The point is that we don't actually require arguments of the builtins to be
constant expressions.  So the above was an attempt - if the argument of a
builtin is a constant expression, then __builtin_is_constant_evaluated
will evaluate to true in there, if it is something different, we can still
try to fold it to something (like maybe_constant_value would be), in
a non-manifestly constant evaluated context; either the whole builtin will
not fold and we give up anyway, or it folds to some constant.
Essentially arguments to the builtin would be treated like separate
constexpr evaluations.

But if you think this is a bad idea, I can remove it, I haven't been
successful in constructing a testcase where this would matter.

	Jakub

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [C++ PATCH] Fix __builtin_{is_constant_evaluated,constant_p} handling in static_assert (PR c++/86524, PR c++/88446)
  2018-12-20 21:26   ` Jakub Jelinek
@ 2018-12-20 21:28     ` Jason Merrill
  2018-12-20 21:43       ` Jakub Jelinek
  0 siblings, 1 reply; 11+ messages in thread
From: Jason Merrill @ 2018-12-20 21:28 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

On 12/20/18 4:08 PM, Jakub Jelinek wrote:
> On Thu, Dec 20, 2018 at 02:47:01PM -0500, Jason Merrill wrote:
>>> --- gcc/cp/constexpr.c.jj	2018-12-12 09:34:17.531736075 +0100
>>> +++ gcc/cp/constexpr.c	2018-12-12 11:30:33.986756914 +0100
>>> @@ -1198,6 +1198,7 @@ cxx_eval_builtin_function_call (const co
>>>         in a constexpr function until we have values for the parameters.  */
>>>      if (bi_const_p
>>>          && ctx->quiet
>>> +      && !ctx->manifestly_const_eval
>>
>> I think we want to replace the "quiet" check with manifestly_const_eval,
>> rather than adding to it.
> 
> Will change that.
> 
>>> -	args[i] = cxx_eval_constant_expression (&new_ctx, args[i], false,
>>> -						&dummy1, &dummy2);
>>> +	{
>>> +	  bool non_cst_p = false, ovf_p = false;
>>> +	  tree a = cxx_eval_constant_expression (&new_ctx, args[i], false,
>>> +						 &non_cst_p, &ovf_p);
>>> +	  if ((non_cst_p || ovf_p) && ctx->manifestly_const_eval)
>>> +	    {
>>> +	      new_ctx.manifestly_const_eval = false;
>>> +	      non_cst_p = false;
>>> +	      ovf_p = false;
>>> +	      a = cxx_eval_constant_expression (&new_ctx, args[i], false,
>>> +						&non_cst_p, &ovf_p);
>>> +	      new_ctx.manifestly_const_eval = true;
>>> +	    }
>>
>> Why retry without manifestly_const_eval?  For static initialization we don't
>> want to try constant evaluation again with __builtin_is_constant_evaluated
>> false if it failed with it true.
> 
> The point is that we don't actually require arguments of the builtins to be
> constant expressions.

Right, but they either are or they aren't.  Doing this isn't likely to 
help anything, and can lead to paradoxical results in contrived testcases.

> But if you think this is a bad idea, I can remove it, I haven't been
> successful in constructing a testcase where this would matter.

Please.  OK with those changes.

Jason

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [C++ PATCH] Fix __builtin_{is_constant_evaluated,constant_p} handling in static_assert (PR c++/86524, PR c++/88446)
  2018-12-20 21:28     ` Jason Merrill
@ 2018-12-20 21:43       ` Jakub Jelinek
  2018-12-20 21:47         ` Jason Merrill
  0 siblings, 1 reply; 11+ messages in thread
From: Jakub Jelinek @ 2018-12-20 21:43 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

On Thu, Dec 20, 2018 at 04:26:21PM -0500, Jason Merrill wrote:
> Right, but they either are or they aren't.  Doing this isn't likely to help
> anything, and can lead to paradoxical results in contrived testcases.
> 
> > But if you think this is a bad idea, I can remove it, I haven't been
> > successful in constructing a testcase where this would matter.
> 
> Please.  OK with those changes.

Actually, the main reason for any changes in that block was mainly that I thought
it is a bad idea to fold the argument with __builtin_is_const_evaluated ()
folded into true if that argument isn't a constant expression.

So are you ok with what is in the patch below, i.e.
       {
         bool non_cst_p = false, ovf_p = false;
         tree a = cxx_eval_constant_expression (&new_ctx, args[i], false,
                                                &non_cst_p, &ovf_p);
         if ((!non_cst_p && !ovf_p) || !ctx->manifestly_const_eval)
           args[i] = a;
       }
, or perhaps without the || !ctx->manifestly_const_eval?  So, if the
argument is a constant expression, fold to that, if it is not, just do
cp_fully_fold on it if it is __builtin_constant_p, otherwise nothing?

2018-12-20  Jakub Jelinek  <jakub@redhat.com>

	PR c++/86524
	PR c++/88446
	* cp-tree.h (fold_non_dependent_expr): Add manifestly_const_eval
	argument.
	* constexpr.c (cxx_eval_builtin_function_call): Evaluate
	__builtin_constant_p if ctx->manifestly_const_eval even in constexpr
	functions.  For arguments to builtins, if ctx->manifestly_const_eval
	and argument is not a constant expression, use original argument.
	Fix comment typo.
	(fold_non_dependent_expr): Add manifestly_const_eval argument, pass
	it through to cxx_eval_outermost_constant_expr and
	maybe_constant_value.
	* semantics.c (finish_static_assert): Call fold_non_dependent_expr
	with true as manifestly_const_eval.

	* g++.dg/cpp1y/constexpr-86524.C: New test.
	* g++.dg/cpp2a/is-constant-evaluated4.C: New test.
	* g++.dg/cpp2a/is-constant-evaluated5.C: New test.
	* g++.dg/cpp2a/is-constant-evaluated6.C: New test.

--- gcc/cp/cp-tree.h.jj	2018-12-20 18:29:24.069715207 +0100
+++ gcc/cp/cp-tree.h	2018-12-20 22:10:46.686521475 +0100
@@ -7668,7 +7668,9 @@ extern tree cxx_constant_value			(tree,
 extern tree cxx_constant_init			(tree, tree = NULL_TREE);
 extern tree maybe_constant_value		(tree, tree = NULL_TREE, bool = false);
 extern tree maybe_constant_init			(tree, tree = NULL_TREE, bool = false);
-extern tree fold_non_dependent_expr		(tree, tsubst_flags_t = tf_warning_or_error);
+extern tree fold_non_dependent_expr		(tree,
+						 tsubst_flags_t = tf_warning_or_error,
+						 bool = false);
 extern tree fold_simple				(tree);
 extern bool is_sub_constant_expr                (tree);
 extern bool reduced_constant_expression_p       (tree);
--- gcc/cp/constexpr.c.jj	2018-12-20 08:50:29.695444227 +0100
+++ gcc/cp/constexpr.c	2018-12-20 22:12:43.754615737 +0100
@@ -1197,7 +1197,7 @@ cxx_eval_builtin_function_call (const co
   /* If we aren't requiring a constant expression, defer __builtin_constant_p
      in a constexpr function until we have values for the parameters.  */
   if (bi_const_p
-      && ctx->quiet
+      && !ctx->manifestly_const_eval
       && current_function_decl
       && DECL_DECLARED_CONSTEXPR_P (current_function_decl))
     {
@@ -1222,7 +1222,6 @@ cxx_eval_builtin_function_call (const co
      return constant false for a non-constant argument.  */
   constexpr_ctx new_ctx = *ctx;
   new_ctx.quiet = true;
-  bool dummy1 = false, dummy2 = false;
   for (i = 0; i < nargs; ++i)
     {
       args[i] = CALL_EXPR_ARG (t, i);
@@ -1231,10 +1230,16 @@ cxx_eval_builtin_function_call (const co
 	 of the builtin, verify it here.  */
       if (!builtin_valid_in_constant_expr_p (fun)
 	  || potential_constant_expression (args[i]))
-	args[i] = cxx_eval_constant_expression (&new_ctx, args[i], false,
-						&dummy1, &dummy2);
+	{
+	  bool non_cst_p = false, ovf_p = false;
+	  tree a = cxx_eval_constant_expression (&new_ctx, args[i], false,
+						 &non_cst_p, &ovf_p);
+	  if ((!non_cst_p && !ovf_p) || !ctx->manifestly_const_eval)
+	    args[i] = a;
+	}
+
       if (bi_const_p)
-	/* For __built_in_constant_p, fold all expressions with constant values
+	/* For __builtin_constant_p, fold all expressions with constant values
 	   even if they aren't C++ constant-expressions.  */
 	args[i] = cp_fully_fold (args[i]);
     }
@@ -5340,6 +5345,7 @@ clear_cv_and_fold_caches (void)
    (t, complain) followed by maybe_constant_value but is more efficient,
    because it calls instantiation_dependent_expression_p and
    potential_constant_expression at most once.
+   The manifestly_const_eval argument is passed to maybe_constant_value.
 
    Callers should generally pass their active complain, or if they are in a
    non-template, diagnosing context, they can use the default of
@@ -5350,7 +5356,8 @@ clear_cv_and_fold_caches (void)
 
 tree
 fold_non_dependent_expr (tree t,
-			 tsubst_flags_t complain /* = tf_warning_or_error */)
+			 tsubst_flags_t complain /* = tf_warning_or_error */,
+			 bool manifestly_const_eval /* = false */)
 {
   if (t == NULL_TREE)
     return NULL_TREE;
@@ -5380,7 +5387,8 @@ fold_non_dependent_expr (tree t,
 	      return t;
 	    }
 
-	  tree r = cxx_eval_outermost_constant_expr (t, true, true, false,
+	  tree r = cxx_eval_outermost_constant_expr (t, true, true,
+						     manifestly_const_eval,
 						     NULL_TREE);
 	  /* cp_tree_equal looks through NOPs, so allow them.  */
 	  gcc_checking_assert (r == t
@@ -5398,7 +5406,7 @@ fold_non_dependent_expr (tree t,
       return t;
     }
 
-  return maybe_constant_value (t);
+  return maybe_constant_value (t, NULL_TREE, manifestly_const_eval);
 }
 
 /* Like maybe_constant_value, but returns a CONSTRUCTOR directly, rather
--- gcc/cp/semantics.c.jj	2018-12-20 08:50:29.712443949 +0100
+++ gcc/cp/semantics.c	2018-12-20 22:10:46.690521410 +0100
@@ -9225,7 +9225,8 @@ finish_static_assert (tree condition, tr
   /* Fold the expression and convert it to a boolean value. */
   condition = perform_implicit_conversion_flags (boolean_type_node, condition,
 						 complain, LOOKUP_NORMAL);
-  condition = fold_non_dependent_expr (condition, complain);
+  condition = fold_non_dependent_expr (condition, complain,
+				       /*manifestly_const_eval=*/true);
 
   if (TREE_CODE (condition) == INTEGER_CST && !integer_zerop (condition))
     /* Do nothing; the condition is satisfied. */
--- gcc/testsuite/g++.dg/cpp1y/constexpr-86524.C.jj	2018-12-20 22:10:46.690521410 +0100
+++ gcc/testsuite/g++.dg/cpp1y/constexpr-86524.C	2018-12-20 22:10:46.690521410 +0100
@@ -0,0 +1,41 @@
+// PR c++/86524
+// { dg-do run { target c++14 } }
+// { dg-options "-O2" }
+
+extern "C" void abort ();
+typedef __UINTPTR_TYPE__ uintptr_t;
+
+constexpr bool
+foo (const int *x, const int *y)
+{
+  if (__builtin_constant_p (x < y))
+    return x < y;
+  return (uintptr_t) x < (uintptr_t) y;
+}
+
+void
+bar ()
+{
+  constexpr int x = 0;
+  static_assert (!(&x < &x));
+  static_assert (!foo (&x, &x));
+}
+
+constexpr void
+baz ()
+{
+  constexpr int x = 0;
+  static_assert (!(&x < &x));
+  static_assert (!foo (&x, &x));
+}
+
+int i, j;
+
+int
+main ()
+{
+  bar ();
+  baz ();
+  if (!(foo (&i, &j) ^ foo (&j, &i)))
+    abort ();
+}
--- gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated4.C.jj	2018-12-20 22:10:46.691521394 +0100
+++ gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated4.C	2018-12-20 22:10:46.691521394 +0100
@@ -0,0 +1,19 @@
+// P0595R2
+// { dg-do compile { target c++14 } }
+
+namespace std {
+  constexpr inline bool
+  is_constant_evaluated () noexcept
+  {
+    return __builtin_is_constant_evaluated ();
+  }
+}
+
+constexpr int
+foo () noexcept
+{
+  return std::is_constant_evaluated () ? 5 : 12;
+}
+
+static_assert (std::is_constant_evaluated (), "");
+static_assert (foo () == 5, "");
--- gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated5.C.jj	2018-12-20 22:10:46.691521394 +0100
+++ gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated5.C	2018-12-20 22:10:46.691521394 +0100
@@ -0,0 +1,41 @@
+// PR c++/86524
+// { dg-do run { target c++14 } }
+// { dg-options "-O2" }
+
+extern "C" void abort ();
+typedef __UINTPTR_TYPE__ uintptr_t;
+
+constexpr bool
+foo (const int *x, const int *y)
+{
+  if (__builtin_is_constant_evaluated ())
+    return x < y;
+  return (uintptr_t) x < (uintptr_t) y;
+}
+
+void
+bar ()
+{
+  constexpr int x = 0;
+  static_assert (!(&x < &x));
+  static_assert (!foo (&x, &x));
+}
+
+constexpr void
+baz ()
+{
+  constexpr int x = 0;
+  static_assert (!(&x < &x));
+  static_assert (!foo (&x, &x));
+}
+
+int i, j;
+
+int
+main ()
+{
+  bar ();
+  baz ();
+  if (!(foo (&i, &j) ^ foo (&j, &i)))
+    abort ();
+}
--- gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated6.C.jj	2018-12-20 22:10:46.691521394 +0100
+++ gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated6.C	2018-12-20 22:10:46.691521394 +0100
@@ -0,0 +1,29 @@
+// P0595R2
+// { dg-do compile { target c++14 } }
+
+namespace std {
+  constexpr inline bool
+  is_constant_evaluated () noexcept
+  {
+    return __builtin_is_constant_evaluated ();
+  }
+}
+
+int a;
+
+constexpr bool
+foo (int x)
+{
+  return __builtin_constant_p (x);
+}
+
+constexpr bool
+bar (int x)
+{
+  return __builtin_constant_p (x + a);
+}
+
+static_assert (__builtin_constant_p (0) + 2 * std::is_constant_evaluated () == 3, "");
+static_assert (__builtin_constant_p (a) + 2 * std::is_constant_evaluated () == 2, "");
+static_assert (foo (0) + 2 * std::is_constant_evaluated () == 3, "");
+static_assert (bar (0) + 2 * std::is_constant_evaluated () == 2, "");

	Jakub

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [C++ PATCH] Fix __builtin_{is_constant_evaluated,constant_p} handling in static_assert (PR c++/86524, PR c++/88446)
  2018-12-20 21:43       ` Jakub Jelinek
@ 2018-12-20 21:47         ` Jason Merrill
  2018-12-20 22:41           ` Jakub Jelinek
  0 siblings, 1 reply; 11+ messages in thread
From: Jason Merrill @ 2018-12-20 21:47 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

On 12/20/18 4:40 PM, Jakub Jelinek wrote:
> On Thu, Dec 20, 2018 at 04:26:21PM -0500, Jason Merrill wrote:
>> Right, but they either are or they aren't.  Doing this isn't likely to help
>> anything, and can lead to paradoxical results in contrived testcases.
>>
>>> But if you think this is a bad idea, I can remove it, I haven't been
>>> successful in constructing a testcase where this would matter.
>>
>> Please.  OK with those changes.
> 
> Actually, the main reason for any changes in that block was mainly that I thought
> it is a bad idea to fold the argument with __builtin_is_const_evaluated ()
> folded into true if that argument isn't a constant expression.
> 
> So are you ok with what is in the patch below, i.e.
>         {
>           bool non_cst_p = false, ovf_p = false;
>           tree a = cxx_eval_constant_expression (&new_ctx, args[i], false,
>                                                  &non_cst_p, &ovf_p);
>           if ((!non_cst_p && !ovf_p) || !ctx->manifestly_const_eval)
>             args[i] = a;
>         }
> , or perhaps without the || !ctx->manifestly_const_eval?

I don't see how that makes a difference from what was there before; if 
the argument to cxx_eval_constant_expression is non-constant, it returns 
the argument unchanged.

> So, if the
> argument is a constant expression, fold to that, if it is not, just do
> cp_fully_fold on it if it is __builtin_constant_p, otherwise nothing?

Hmm, cp_fully_fold probably also needs to add a manifestly_const_eval 
parameter to pass along to maybe_constant_value.

Jason

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [C++ PATCH] Fix __builtin_{is_constant_evaluated,constant_p} handling in static_assert (PR c++/86524, PR c++/88446)
  2018-12-20 21:47         ` Jason Merrill
@ 2018-12-20 22:41           ` Jakub Jelinek
  2018-12-21  2:51             ` Jason Merrill
  0 siblings, 1 reply; 11+ messages in thread
From: Jakub Jelinek @ 2018-12-20 22:41 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

On Thu, Dec 20, 2018 at 04:47:29PM -0500, Jason Merrill wrote:
> > So are you ok with what is in the patch below, i.e.
> >         {
> >           bool non_cst_p = false, ovf_p = false;
> >           tree a = cxx_eval_constant_expression (&new_ctx, args[i], false,
> >                                                  &non_cst_p, &ovf_p);
> >           if ((!non_cst_p && !ovf_p) || !ctx->manifestly_const_eval)
> >             args[i] = a;
> >         }
> > , or perhaps without the || !ctx->manifestly_const_eval?
> 
> I don't see how that makes a difference from what was there before; if the
> argument to cxx_eval_constant_expression is non-constant, it returns the
> argument unchanged.

If that is guaranteed, then it is ok to keep it as is I guess.
Will change it then.

> > So, if the
> > argument is a constant expression, fold to that, if it is not, just do
> > cp_fully_fold on it if it is __builtin_constant_p, otherwise nothing?
> 
> Hmm, cp_fully_fold probably also needs to add a manifestly_const_eval
> parameter to pass along to maybe_constant_value.

But if we need cp_fully_fold, doesn't that mean that the earlier
cxx_eval_constant_expression failed and thus the argument is not a constant
expression?  Should __builtin_is_constant_evaluated () evaluate to true
even if the argument is not a constant expression?
Say if there is
int v;
constexpr int foo (void)
{
  return __builtin_constant_p (v * (__builtin_is_constant_evaluated () ? 1 : 0));
}
Because v is not a constant expression,
v * (__builtin_is_constant_evaluated () ? 1 : 0) shouldn't be either.

cp_fully_fold does:
  /* FIXME cp_fold ought to be a superset of maybe_constant_value so we don't
     have to call both.  */
  if (cxx_dialect >= cxx11)
    {
      x = maybe_constant_value (x);
      /* Sometimes we are given a CONSTRUCTOR but the call above wraps it into
         a TARGET_EXPR; undo that here.  */
      if (TREE_CODE (x) == TARGET_EXPR)
        x = TARGET_EXPR_INITIAL (x);
      else if (TREE_CODE (x) == VIEW_CONVERT_EXPR
               && TREE_CODE (TREE_OPERAND (x, 0)) == CONSTRUCTOR
               && TREE_TYPE (TREE_OPERAND (x, 0)) == TREE_TYPE (x))
        x = TREE_OPERAND (x, 0);
    }
  return cp_fold_rvalue (x);
Is there a reason to call that maybe_constant_value at all when we've called
cxx_eval_constant_expression first?  Wouldn't cp_fold_rvalue (or
c_fully_fold with false as last argument) be sufficient there?

	Jakub

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [C++ PATCH] Fix __builtin_{is_constant_evaluated,constant_p} handling in static_assert (PR c++/86524, PR c++/88446)
  2018-12-20 22:41           ` Jakub Jelinek
@ 2018-12-21  2:51             ` Jason Merrill
  2018-12-21  9:05               ` [C++ PATCH] Fix __builtin_{is_constant_evaluated,constant_p} handling in static_assert (PR c++/86524, PR c++/88446, take 2) Jakub Jelinek
  0 siblings, 1 reply; 11+ messages in thread
From: Jason Merrill @ 2018-12-21  2:51 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

On 12/20/18 5:27 PM, Jakub Jelinek wrote:
> On Thu, Dec 20, 2018 at 04:47:29PM -0500, Jason Merrill wrote:
>>> So are you ok with what is in the patch below, i.e.
>>>          {
>>>            bool non_cst_p = false, ovf_p = false;
>>>            tree a = cxx_eval_constant_expression (&new_ctx, args[i], false,
>>>                                                   &non_cst_p, &ovf_p);
>>>            if ((!non_cst_p && !ovf_p) || !ctx->manifestly_const_eval)
>>>              args[i] = a;
>>>          }
>>> , or perhaps without the || !ctx->manifestly_const_eval?
>>
>> I don't see how that makes a difference from what was there before; if the
>> argument to cxx_eval_constant_expression is non-constant, it returns the
>> argument unchanged.
> 
> If that is guaranteed, then it is ok to keep it as is I guess.
> Will change it then.
> 
>>> So, if the
>>> argument is a constant expression, fold to that, if it is not, just do
>>> cp_fully_fold on it if it is __builtin_constant_p, otherwise nothing?
>>
>> Hmm, cp_fully_fold probably also needs to add a manifestly_const_eval
>> parameter to pass along to maybe_constant_value.
> 
> But if we need cp_fully_fold, doesn't that mean that the earlier
> cxx_eval_constant_expression failed and thus the argument is not a constant
> expression?  Should __builtin_is_constant_evaluated () evaluate to true
> even if the argument is not a constant expression?

Ah, no, good point.

> Say if there is
> int v;
> constexpr int foo (void)
> {
>    return __builtin_constant_p (v * (__builtin_is_constant_evaluated () ? 1 : 0));
> }
> Because v is not a constant expression,
> v * (__builtin_is_constant_evaluated () ? 1 : 0) shouldn't be either.
> 
> cp_fully_fold does:
>    /* FIXME cp_fold ought to be a superset of maybe_constant_value so we don't
>       have to call both.  */
>    if (cxx_dialect >= cxx11)
>      {
>        x = maybe_constant_value (x);
>        /* Sometimes we are given a CONSTRUCTOR but the call above wraps it into
>           a TARGET_EXPR; undo that here.  */
>        if (TREE_CODE (x) == TARGET_EXPR)
>          x = TARGET_EXPR_INITIAL (x);
>        else if (TREE_CODE (x) == VIEW_CONVERT_EXPR
>                 && TREE_CODE (TREE_OPERAND (x, 0)) == CONSTRUCTOR
>                 && TREE_TYPE (TREE_OPERAND (x, 0)) == TREE_TYPE (x))
>          x = TREE_OPERAND (x, 0);
>      }
>    return cp_fold_rvalue (x);
> Is there a reason to call that maybe_constant_value at all when we've called
> cxx_eval_constant_expression first?  Wouldn't cp_fold_rvalue (or
> c_fully_fold with false as last argument) be sufficient there?

I think that would be better, yes.

Jason

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [C++ PATCH] Fix __builtin_{is_constant_evaluated,constant_p} handling in static_assert (PR c++/86524, PR c++/88446, take 2)
  2018-12-21  2:51             ` Jason Merrill
@ 2018-12-21  9:05               ` Jakub Jelinek
  2018-12-21 19:31                 ` Jason Merrill
  0 siblings, 1 reply; 11+ messages in thread
From: Jakub Jelinek @ 2018-12-21  9:05 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

On Thu, Dec 20, 2018 at 09:49:39PM -0500, Jason Merrill wrote:
> > But if we need cp_fully_fold, doesn't that mean that the earlier
> > cxx_eval_constant_expression failed and thus the argument is not a constant
> > expression?  Should __builtin_is_constant_evaluated () evaluate to true
> > even if the argument is not a constant expression?
> 
> Ah, no, good point.
> 
> > Is there a reason to call that maybe_constant_value at all when we've called
> > cxx_eval_constant_expression first?  Wouldn't cp_fold_rvalue (or
> > c_fully_fold with false as last argument) be sufficient there?
> 
> I think that would be better, yes.

As cp_fold_rvalue* is static in cp-gimplify.c, I've used c_fully_fold
(or do you want to export cp_fold_rvalue*?).

There is another fix, not reusing the dummy bools between different args,
I think if e.g. the first argument is non-constant and dummy1 would be set,
then the processing of the second argument which might be a constant
expression could behave differently, as *non_constant_p would be true from
the start of the processing.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2018-12-20  Jakub Jelinek  <jakub@redhat.com>

	PR c++/86524
	PR c++/88446
	* cp-tree.h (fold_non_dependent_expr): Add manifestly_const_eval
	argument.
	* constexpr.c (cxx_eval_builtin_function_call): Evaluate
	__builtin_constant_p if ctx->manifestly_const_eval even in constexpr
	functions.  Don't reuse dummy{1,2} vars between different arguments.
	Use c_fully_fold instead of cp_fully_fold.  Fix comment typo.
	(fold_non_dependent_expr): Add manifestly_const_eval argument, pass
	it through to cxx_eval_outermost_constant_expr and
	maybe_constant_value.
	* semantics.c (finish_static_assert): Call fold_non_dependent_expr
	with true as manifestly_const_eval.

	* g++.dg/cpp1y/constexpr-86524.C: New test.
	* g++.dg/cpp2a/is-constant-evaluated4.C: New test.
	* g++.dg/cpp2a/is-constant-evaluated5.C: New test.
	* g++.dg/cpp2a/is-constant-evaluated6.C: New test.

--- gcc/cp/cp-tree.h.jj	2018-12-20 18:29:24.069715207 +0100
+++ gcc/cp/cp-tree.h	2018-12-20 22:10:46.686521475 +0100
@@ -7668,7 +7668,9 @@ extern tree cxx_constant_value			(tree,
 extern tree cxx_constant_init			(tree, tree = NULL_TREE);
 extern tree maybe_constant_value		(tree, tree = NULL_TREE, bool = false);
 extern tree maybe_constant_init			(tree, tree = NULL_TREE, bool = false);
-extern tree fold_non_dependent_expr		(tree, tsubst_flags_t = tf_warning_or_error);
+extern tree fold_non_dependent_expr		(tree,
+						 tsubst_flags_t = tf_warning_or_error,
+						 bool = false);
 extern tree fold_simple				(tree);
 extern bool is_sub_constant_expr                (tree);
 extern bool reduced_constant_expression_p       (tree);
--- gcc/cp/constexpr.c.jj	2018-12-20 08:50:29.695444227 +0100
+++ gcc/cp/constexpr.c	2018-12-20 22:12:43.754615737 +0100
@@ -1197,7 +1197,7 @@ cxx_eval_builtin_function_call (const co
   /* If we aren't requiring a constant expression, defer __builtin_constant_p
      in a constexpr function until we have values for the parameters.  */
   if (bi_const_p
-      && ctx->quiet
+      && !ctx->manifestly_const_eval
       && current_function_decl
       && DECL_DECLARED_CONSTEXPR_P (current_function_decl))
     {
@@ -1222,7 +1222,6 @@ cxx_eval_builtin_function_call (const co
      return constant false for a non-constant argument.  */
   constexpr_ctx new_ctx = *ctx;
   new_ctx.quiet = true;
-  bool dummy1 = false, dummy2 = false;
   for (i = 0; i < nargs; ++i)
     {
       args[i] = CALL_EXPR_ARG (t, i);
@@ -1231,12 +1230,16 @@ cxx_eval_builtin_function_call (const co
 	 of the builtin, verify it here.  */
       if (!builtin_valid_in_constant_expr_p (fun)
 	  || potential_constant_expression (args[i]))
-	args[i] = cxx_eval_constant_expression (&new_ctx, args[i], false,
-						&dummy1, &dummy2);
+	{
+	  bool dummy1 = false, dummy2 = false;
+	  args[i] = cxx_eval_constant_expression (&new_ctx, args[i], false,
+						  &dummy1, &dummy2);
+	}
+
       if (bi_const_p)
-	/* For __built_in_constant_p, fold all expressions with constant values
+	/* For __builtin_constant_p, fold all expressions with constant values
 	   even if they aren't C++ constant-expressions.  */
-	args[i] = cp_fully_fold (args[i]);
+	args[i] = c_fully_fold (args[i], false, NULL, false);
     }
 
   bool save_ffbcp = force_folding_builtin_constant_p;
@@ -5340,6 +5343,7 @@ clear_cv_and_fold_caches (void)
    (t, complain) followed by maybe_constant_value but is more efficient,
    because it calls instantiation_dependent_expression_p and
    potential_constant_expression at most once.
+   The manifestly_const_eval argument is passed to maybe_constant_value.
 
    Callers should generally pass their active complain, or if they are in a
    non-template, diagnosing context, they can use the default of
@@ -5350,7 +5354,8 @@ clear_cv_and_fold_caches (void)
 
 tree
 fold_non_dependent_expr (tree t,
-			 tsubst_flags_t complain /* = tf_warning_or_error */)
+			 tsubst_flags_t complain /* = tf_warning_or_error */,
+			 bool manifestly_const_eval /* = false */)
 {
   if (t == NULL_TREE)
     return NULL_TREE;
@@ -5380,7 +5385,8 @@ fold_non_dependent_expr (tree t,
 	      return t;
 	    }
 
-	  tree r = cxx_eval_outermost_constant_expr (t, true, true, false,
+	  tree r = cxx_eval_outermost_constant_expr (t, true, true,
+						     manifestly_const_eval,
 						     NULL_TREE);
 	  /* cp_tree_equal looks through NOPs, so allow them.  */
 	  gcc_checking_assert (r == t
@@ -5398,7 +5404,7 @@ fold_non_dependent_expr (tree t,
       return t;
     }
 
-  return maybe_constant_value (t);
+  return maybe_constant_value (t, NULL_TREE, manifestly_const_eval);
 }
 
 /* Like maybe_constant_value, but returns a CONSTRUCTOR directly, rather
--- gcc/cp/semantics.c.jj	2018-12-20 08:50:29.712443949 +0100
+++ gcc/cp/semantics.c	2018-12-20 22:10:46.690521410 +0100
@@ -9225,7 +9225,8 @@ finish_static_assert (tree condition, tr
   /* Fold the expression and convert it to a boolean value. */
   condition = perform_implicit_conversion_flags (boolean_type_node, condition,
 						 complain, LOOKUP_NORMAL);
-  condition = fold_non_dependent_expr (condition, complain);
+  condition = fold_non_dependent_expr (condition, complain,
+				       /*manifestly_const_eval=*/true);
 
   if (TREE_CODE (condition) == INTEGER_CST && !integer_zerop (condition))
     /* Do nothing; the condition is satisfied. */
--- gcc/testsuite/g++.dg/cpp1y/constexpr-86524.C.jj	2018-12-20 22:10:46.690521410 +0100
+++ gcc/testsuite/g++.dg/cpp1y/constexpr-86524.C	2018-12-20 22:10:46.690521410 +0100
@@ -0,0 +1,41 @@
+// PR c++/86524
+// { dg-do run { target c++14 } }
+// { dg-options "-O2" }
+
+extern "C" void abort ();
+typedef __UINTPTR_TYPE__ uintptr_t;
+
+constexpr bool
+foo (const int *x, const int *y)
+{
+  if (__builtin_constant_p (x < y))
+    return x < y;
+  return (uintptr_t) x < (uintptr_t) y;
+}
+
+void
+bar ()
+{
+  constexpr int x = 0;
+  static_assert (!(&x < &x));
+  static_assert (!foo (&x, &x));
+}
+
+constexpr void
+baz ()
+{
+  constexpr int x = 0;
+  static_assert (!(&x < &x));
+  static_assert (!foo (&x, &x));
+}
+
+int i, j;
+
+int
+main ()
+{
+  bar ();
+  baz ();
+  if (!(foo (&i, &j) ^ foo (&j, &i)))
+    abort ();
+}
--- gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated4.C.jj	2018-12-20 22:10:46.691521394 +0100
+++ gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated4.C	2018-12-20 22:10:46.691521394 +0100
@@ -0,0 +1,19 @@
+// P0595R2
+// { dg-do compile { target c++14 } }
+
+namespace std {
+  constexpr inline bool
+  is_constant_evaluated () noexcept
+  {
+    return __builtin_is_constant_evaluated ();
+  }
+}
+
+constexpr int
+foo () noexcept
+{
+  return std::is_constant_evaluated () ? 5 : 12;
+}
+
+static_assert (std::is_constant_evaluated (), "");
+static_assert (foo () == 5, "");
--- gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated5.C.jj	2018-12-20 22:10:46.691521394 +0100
+++ gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated5.C	2018-12-20 22:10:46.691521394 +0100
@@ -0,0 +1,41 @@
+// PR c++/86524
+// { dg-do run { target c++14 } }
+// { dg-options "-O2" }
+
+extern "C" void abort ();
+typedef __UINTPTR_TYPE__ uintptr_t;
+
+constexpr bool
+foo (const int *x, const int *y)
+{
+  if (__builtin_is_constant_evaluated ())
+    return x < y;
+  return (uintptr_t) x < (uintptr_t) y;
+}
+
+void
+bar ()
+{
+  constexpr int x = 0;
+  static_assert (!(&x < &x));
+  static_assert (!foo (&x, &x));
+}
+
+constexpr void
+baz ()
+{
+  constexpr int x = 0;
+  static_assert (!(&x < &x));
+  static_assert (!foo (&x, &x));
+}
+
+int i, j;
+
+int
+main ()
+{
+  bar ();
+  baz ();
+  if (!(foo (&i, &j) ^ foo (&j, &i)))
+    abort ();
+}
--- gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated6.C.jj	2018-12-20 22:10:46.691521394 +0100
+++ gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated6.C	2018-12-20 22:10:46.691521394 +0100
@@ -0,0 +1,29 @@
+// P0595R2
+// { dg-do compile { target c++14 } }
+
+namespace std {
+  constexpr inline bool
+  is_constant_evaluated () noexcept
+  {
+    return __builtin_is_constant_evaluated ();
+  }
+}
+
+int a;
+
+constexpr bool
+foo (int x)
+{
+  return __builtin_constant_p (x);
+}
+
+constexpr bool
+bar (int x)
+{
+  return __builtin_constant_p (x + a);
+}
+
+static_assert (__builtin_constant_p (0) + 2 * std::is_constant_evaluated () == 3, "");
+static_assert (__builtin_constant_p (a) + 2 * std::is_constant_evaluated () == 2, "");
+static_assert (foo (0) + 2 * std::is_constant_evaluated () == 3, "");
+static_assert (bar (0) + 2 * std::is_constant_evaluated () == 2, "");


	Jakub

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [C++ PATCH] Fix __builtin_{is_constant_evaluated,constant_p} handling in static_assert (PR c++/86524, PR c++/88446, take 2)
  2018-12-21  9:05               ` [C++ PATCH] Fix __builtin_{is_constant_evaluated,constant_p} handling in static_assert (PR c++/86524, PR c++/88446, take 2) Jakub Jelinek
@ 2018-12-21 19:31                 ` Jason Merrill
  0 siblings, 0 replies; 11+ messages in thread
From: Jason Merrill @ 2018-12-21 19:31 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

On 12/21/18 3:51 AM, Jakub Jelinek wrote:
> On Thu, Dec 20, 2018 at 09:49:39PM -0500, Jason Merrill wrote:
>>> But if we need cp_fully_fold, doesn't that mean that the earlier
>>> cxx_eval_constant_expression failed and thus the argument is not a constant
>>> expression?  Should __builtin_is_constant_evaluated () evaluate to true
>>> even if the argument is not a constant expression?
>>
>> Ah, no, good point.
>>
>>> Is there a reason to call that maybe_constant_value at all when we've called
>>> cxx_eval_constant_expression first?  Wouldn't cp_fold_rvalue (or
>>> c_fully_fold with false as last argument) be sufficient there?
>>
>> I think that would be better, yes.
> 
> As cp_fold_rvalue* is static in cp-gimplify.c, I've used c_fully_fold
> (or do you want to export cp_fold_rvalue*?).

Let's export it.  OK with that change.

Jason

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2018-12-21 19:31 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-12-12 22:30 [C++ PATCH] Fix __builtin_{is_constant_evaluated,constant_p} handling in static_assert (PR c++/86524, PR c++/88446) Jakub Jelinek
2018-12-19 10:19 ` Patch ping (Re: [C++ PATCH] Fix __builtin_{is_constant_evaluated,constant_p} handling in static_assert (PR c++/86524, PR c++/88446)) Jakub Jelinek
2018-12-20 19:49 ` [C++ PATCH] Fix __builtin_{is_constant_evaluated,constant_p} handling in static_assert (PR c++/86524, PR c++/88446) Jason Merrill
2018-12-20 21:26   ` Jakub Jelinek
2018-12-20 21:28     ` Jason Merrill
2018-12-20 21:43       ` Jakub Jelinek
2018-12-20 21:47         ` Jason Merrill
2018-12-20 22:41           ` Jakub Jelinek
2018-12-21  2:51             ` Jason Merrill
2018-12-21  9:05               ` [C++ PATCH] Fix __builtin_{is_constant_evaluated,constant_p} handling in static_assert (PR c++/86524, PR c++/88446, take 2) Jakub Jelinek
2018-12-21 19:31                 ` Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).