From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 59435 invoked by alias); 21 Dec 2018 08:51:51 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 59416 invoked by uid 89); 21 Dec 2018 08:51:51 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-10.9 required=5.0 tests=BAYES_00,GIT_PATCH_2,GIT_PATCH_3,KAM_LAZY_DOMAIN_SECURITY,SPF_HELO_PASS autolearn=ham version=3.3.2 spammy= X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 21 Dec 2018 08:51:48 +0000 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 0BC17C057F80 for ; Fri, 21 Dec 2018 08:51:47 +0000 (UTC) Received: from tucnak.zalov.cz (ovpn-117-214.ams2.redhat.com [10.36.117.214]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 752A117555; Fri, 21 Dec 2018 08:51:46 +0000 (UTC) Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.15.2/8.15.2) with ESMTP id wBL8ph8P011691; Fri, 21 Dec 2018 09:51:43 +0100 Received: (from jakub@localhost) by tucnak.zalov.cz (8.15.2/8.15.2/Submit) id wBL8pfV2011690; Fri, 21 Dec 2018 09:51:41 +0100 Date: Fri, 21 Dec 2018 09:05:00 -0000 From: Jakub Jelinek To: Jason Merrill 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) Message-ID: <20181221085141.GV23305@tucnak> Reply-To: Jakub Jelinek References: <20181212223037.GL12380@tucnak> <310c40c2-ee1c-8a96-0e09-098ffbb1dba1@redhat.com> <20181220210812.GQ23305@tucnak> <20181220214035.GR23305@tucnak> <20181220222719.GS23305@tucnak> <4abcfe78-7e84-5188-6616-ddba47d9a5bd@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <4abcfe78-7e84-5188-6616-ddba47d9a5bd@redhat.com> User-Agent: Mutt/1.9.2 (2017-12-15) X-IsSubscribed: yes X-SW-Source: 2018-12/txt/msg01538.txt.bz2 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 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