public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Jakub Jelinek <jakub@redhat.com>
To: Jason Merrill <jason@redhat.com>
Cc: gcc-patches@gcc.gnu.org
Subject: Re: [C++ PATCH] Fix __builtin_{is_constant_evaluated,constant_p} handling in static_assert (PR c++/86524, PR c++/88446)
Date: Thu, 20 Dec 2018 21:43:00 -0000	[thread overview]
Message-ID: <20181220214035.GR23305@tucnak> (raw)
In-Reply-To: <f6649576-b422-ae57-b712-5a5fc2e0498d@redhat.com>

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

  reply	other threads:[~2018-12-20 21:40 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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
2018-12-20 21:26   ` Jakub Jelinek
2018-12-20 21:28     ` Jason Merrill
2018-12-20 21:43       ` Jakub Jelinek [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20181220214035.GR23305@tucnak \
    --to=jakub@redhat.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=jason@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).