From: Jakub Jelinek <jakub@redhat.com>
To: Jason Merrill <jason@redhat.com>
Cc: gcc-patches@gcc.gnu.org
Subject: [C++ PATCH] Fix __builtin_{is_constant_evaluated,constant_p} handling in static_assert (PR c++/86524, PR c++/88446, take 2)
Date: Fri, 21 Dec 2018 09:05:00 -0000 [thread overview]
Message-ID: <20181221085141.GV23305@tucnak> (raw)
In-Reply-To: <4abcfe78-7e84-5188-6616-ddba47d9a5bd@redhat.com>
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
next prev parent reply other threads:[~2018-12-21 8:51 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
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 ` Jakub Jelinek [this message]
2018-12-21 19:31 ` [C++ PATCH] Fix __builtin_{is_constant_evaluated,constant_p} handling in static_assert (PR c++/86524, PR c++/88446, take 2) 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=20181221085141.GV23305@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).