From 13de99bc7d085125e614ffdb75d486e9a7a8a48f Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Wed, 12 Dec 2018 09:44:27 +0100 Subject: [PATCH] re PR c++/88446 (__builtin_is_constant_evaluated rejects some converted constant expressions.) PR c++/88446 * cp-tree.h (maybe_constant_value): Add manifestly_const_eval argument. * constexpr.c (struct constexpr_call): Rename pretend_const_required member to manifestly_const_eval. (struct constexpr_ctx): Likewise. (constexpr_call_hasher::equal): Adjust users. (cxx_eval_builtin_function_call): Likewise. Formatting fix. (cxx_eval_call_expression): Adjust users. (cxx_eval_outermost_constant_expr, maybe_constant_init_1, maybe_constant_init): Rename pretend_const_required argument to manifestly_const_eval, adjust function comments. (maybe_constant_value): Add manifestly_const_eval argument. If true, don't cache and call cxx_eval_outermost_constant_expr with true as manifestly_const_eval. * decl.c (compute_array_index_type_loc): Call maybe_constant_value with true as manifestly_const_eval. * g++.dg/cpp2a/is-constant-evaluated3.C: New test. From-SVN: r267047 --- gcc/cp/ChangeLog | 18 ++++++++ gcc/cp/constexpr.c | 43 +++++++++++-------- gcc/cp/cp-tree.h | 2 +- gcc/cp/decl.c | 6 ++- gcc/testsuite/ChangeLog | 3 ++ .../g++.dg/cpp2a/is-constant-evaluated3.C | 26 +++++++++++ 6 files changed, 77 insertions(+), 21 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated3.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 0347daa2bd3..2c1f39288c4 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,23 @@ 2018-12-12 Jakub Jelinek + PR c++/88446 + * cp-tree.h (maybe_constant_value): Add manifestly_const_eval + argument. + * constexpr.c (struct constexpr_call): Rename pretend_const_required + member to manifestly_const_eval. + (struct constexpr_ctx): Likewise. + (constexpr_call_hasher::equal): Adjust users. + (cxx_eval_builtin_function_call): Likewise. Formatting fix. + (cxx_eval_call_expression): Adjust users. + (cxx_eval_outermost_constant_expr, maybe_constant_init_1, + maybe_constant_init): Rename pretend_const_required argument to + manifestly_const_eval, adjust function comments. + (maybe_constant_value): Add manifestly_const_eval argument. If true, + don't cache and call cxx_eval_outermost_constant_expr with true as + manifestly_const_eval. + * decl.c (compute_array_index_type_loc): Call maybe_constant_value + with true as manifestly_const_eval. + PR c++/88449 * constexpr.c (struct constexpr_call): Add pretend_const_required member. diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 81ce4cdbe75..f8049468c22 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -977,7 +977,7 @@ struct GTY((for_user)) constexpr_call { recalculate it when expanding the hash table. */ hashval_t hash; /* Whether __builtin_is_constant_evaluated() should evaluate to true. */ - bool pretend_const_required; + bool manifestly_const_eval; }; struct constexpr_call_hasher : ggc_ptr_hash @@ -1025,7 +1025,7 @@ struct constexpr_ctx { trying harder to get a constant value. */ bool strict; /* Whether __builtin_is_constant_evaluated () should be true. */ - bool pretend_const_required; + bool manifestly_const_eval; }; /* A table of all constexpr calls that have been evaluated by the @@ -1057,7 +1057,7 @@ constexpr_call_hasher::equal (constexpr_call *lhs, constexpr_call *rhs) return true; if (lhs->hash != rhs->hash) return false; - if (lhs->pretend_const_required != rhs->pretend_const_required) + if (lhs->manifestly_const_eval != rhs->manifestly_const_eval) return false; if (!constexpr_fundef_hasher::equal (lhs->fundef, rhs->fundef)) return false; @@ -1206,11 +1206,11 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, } /* For __builtin_is_constant_evaluated, defer it if not - ctx->pretend_const_required, otherwise fold it to true. */ + ctx->manifestly_const_eval, otherwise fold it to true. */ if (fndecl_built_in_p (fun, CP_BUILT_IN_IS_CONSTANT_EVALUATED, - BUILT_IN_FRONTEND)) + BUILT_IN_FRONTEND)) { - if (!ctx->pretend_const_required) + if (!ctx->manifestly_const_eval) { *non_constant_p = true; return t; @@ -1508,7 +1508,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, location_t loc = cp_expr_loc_or_loc (t, input_location); tree fun = get_function_named_in_call (t); constexpr_call new_call - = { NULL, NULL, NULL, 0, ctx->pretend_const_required }; + = { NULL, NULL, NULL, 0, ctx->manifestly_const_eval }; bool depth_ok; if (fun == NULL_TREE) @@ -1684,7 +1684,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, new_call.hash = iterative_hash_template_arg (new_call.bindings, new_call.hash); new_call.hash - = iterative_hash_object (ctx->pretend_const_required, new_call.hash); + = iterative_hash_object (ctx->manifestly_const_eval, new_call.hash); /* If we have seen this call before, we are done. */ maybe_initialize_constexpr_call_table (); @@ -5022,13 +5022,13 @@ instantiate_constexpr_fns (tree t) STRICT has the same sense as for constant_value_1: true if we only allow conforming C++ constant expressions, or false if we want a constant value even if it doesn't conform. - PRETEND_CONST_REQUIRED is true if T is required to be const-evaluated as + MANIFESTLY_CONST_EVAL is true if T is manifestly const-evaluated as per P0595 even when ALLOW_NON_CONSTANT is true. */ static tree cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, bool strict = true, - bool pretend_const_required = false, + bool manifestly_const_eval = false, tree object = NULL_TREE) { auto_timevar time (TV_CONSTEXPR); @@ -5039,7 +5039,7 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, constexpr_ctx ctx = { NULL, &map, NULL, NULL, NULL, NULL, allow_non_constant, strict, - pretend_const_required || !allow_non_constant }; + manifestly_const_eval || !allow_non_constant }; tree type = initialized_type (t); tree r = t; @@ -5131,7 +5131,7 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, /* If __builtin_is_constant_evaluated () was evaluated to true and the result is not a valid constant expression, we need to punt. */ - if (pretend_const_required) + if (manifestly_const_eval) return cxx_eval_outermost_constant_expr (t, true, strict, false, object); /* This isn't actually constant, so unset TREE_CONSTANT. @@ -5274,12 +5274,14 @@ fold_simple (tree t) /* If T is a constant expression, returns its reduced value. Otherwise, if T does not have TREE_CONSTANT set, returns T. - Otherwise, returns a version of T without TREE_CONSTANT. */ + Otherwise, returns a version of T without TREE_CONSTANT. + MANIFESTLY_CONST_EVAL is true if T is manifestly const-evaluated + as per P0595. */ static GTY((deletable)) hash_map *cv_cache; tree -maybe_constant_value (tree t, tree decl) +maybe_constant_value (tree t, tree decl, bool manifestly_const_eval) { tree r; @@ -5296,6 +5298,9 @@ maybe_constant_value (tree t, tree decl) /* No caching or evaluation needed. */ return t; + if (manifestly_const_eval) + return cxx_eval_outermost_constant_expr (t, true, true, true, decl); + if (cv_cache == NULL) cv_cache = hash_map::create_ggc (101); if (tree *cached = cv_cache->get (t)) @@ -5399,12 +5404,12 @@ fold_non_dependent_expr (tree t, /* Like maybe_constant_value, but returns a CONSTRUCTOR directly, rather than wrapped in a TARGET_EXPR. ALLOW_NON_CONSTANT is false if T is required to be a constant expression. - PRETEND_CONST_REQUIRED is true if T is required to be const-evaluated as + MANIFESTLY_CONST_EVAL is true if T is manifestly const-evaluated as per P0595 even when ALLOW_NON_CONSTANT is true. */ static tree maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant, - bool pretend_const_required) + bool manifestly_const_eval) { if (!t) return t; @@ -5424,7 +5429,7 @@ maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant, else t = cxx_eval_outermost_constant_expr (t, allow_non_constant, /*strict*/false, - pretend_const_required, decl); + manifestly_const_eval, decl); if (TREE_CODE (t) == TARGET_EXPR) { tree init = TARGET_EXPR_INITIAL (t); @@ -5437,9 +5442,9 @@ maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant, /* Wrapper for maybe_constant_init_1 which permits non constants. */ tree -maybe_constant_init (tree t, tree decl, bool pretend_const_required) +maybe_constant_init (tree t, tree decl, bool manifestly_const_eval) { - return maybe_constant_init_1 (t, decl, true, pretend_const_required); + return maybe_constant_init_1 (t, decl, true, manifestly_const_eval); } /* Wrapper for maybe_constant_init_1 which does not permit non constants. */ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 3645965d7f3..1d806b782bd 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7663,7 +7663,7 @@ extern bool require_rvalue_constant_expression (tree); extern bool require_potential_rvalue_constant_expression (tree); extern tree cxx_constant_value (tree, tree = NULL_TREE); extern tree cxx_constant_init (tree, tree = NULL_TREE); -extern tree maybe_constant_value (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_simple (tree); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 3a53af4f866..9b0ea702ec4 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -9646,7 +9646,11 @@ compute_array_index_type_loc (location_t name_loc, tree name, tree size, { size = instantiate_non_dependent_expr_sfinae (size, complain); size = build_converted_constant_expr (size_type_node, size, complain); - size = maybe_constant_value (size); + /* Pedantically a constant expression is required here and so + __builtin_is_constant_evaluated () should fold to true if it + is successfully folded into a constant. */ + size = maybe_constant_value (size, NULL_TREE, + /*manifestly_const_eval=*/true); if (!TREE_CONSTANT (size)) size = osize; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index aa11d0ecb2d..9e851e4042a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,8 @@ 2018-12-12 Jakub Jelinek + PR c++/88446 + * g++.dg/cpp2a/is-constant-evaluated3.C: New test. + PR c++/88449 * g++.dg/cpp2a/is-constant-evaluated1.C: Change from dg-do compile to dg-do run. diff --git a/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated3.C b/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated3.C new file mode 100644 index 00000000000..dd6104eced4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated3.C @@ -0,0 +1,26 @@ +// P0595R1 +// { dg-do run { target c++14 } } + +struct false_type { static constexpr bool value = false; }; +struct true_type { static constexpr bool value = true; }; +template +struct is_same : false_type {}; +template +struct is_same : true_type {}; + +int a[__builtin_is_constant_evaluated () ? 1 : 2]; +int b[1]; +static_assert (is_same::value, ""); + +int +main () +{ + int c[__builtin_is_constant_evaluated () ? 3 : 4]; + int d[3]; + static_assert (is_same::value, ""); + int (*e)[7][9] = new int[__builtin_is_constant_evaluated () ? -1 : 5] + [__builtin_is_constant_evaluated () ? 7 : 8] + [__builtin_is_constant_evaluated () ? 9 : 10]; + e[0][0][0] = 6; + delete[] e; +} -- 2.30.2