Commit e4082611 by Jakub Jelinek Committed by Jakub Jelinek

P0595R1 - is_constant_evaluated

	P0595R1 - is_constant_evaluated
cp/
	* cp-tree.h (enum cp_built_in_function): New.
	(maybe_constant_init): Add pretend_const_required argument.
	* typeck2.c (store_init_value): Pass true as new argument to
	maybe_constant_init.
	* constexpr.c (constexpr_fn_retval): Check also DECL_BUILT_IN_CLASS
	for BUILT_IN_UNREACHABLE.
	(struct constexpr_ctx): Add pretend_const_required field.
	(cxx_eval_builtin_function_call): Use DECL_IS_BUILTIN_CONSTANT_P
	macro.  Handle CP_BUILT_IN_IS_CONSTANT_EVALUATED.  Check also
	DECL_BUILT_IN_CLASS for BUILT_IN_UNREACHABLE.
	(cxx_eval_outermost_constant_expr): Add pretend_const_required
	argument, initialize pretend_const_required field in ctx.  If the
	result is TREE_CONSTANT and non_constant_p, retry with
	pretend_const_required false if it was true.
	(is_sub_constant_expr): Initialize pretend_const_required_field in
	ctx.
	(cxx_constant_value): Pass true as pretend_const_required to
	cxx_eval_outermost_constant_expr.
	(maybe_constant_value): Pass false as pretend_const_required to
	cxx_eval_outermost_constant_expr.
	(fold_non_dependent_expr): Likewise.
	(maybe_constant_init_1): Add pretend_const_required argument, pass it
	down to cxx_eval_outermost_constant_expr.  Pass !allow_non_constant
	instead of false as strict to cxx_eval_outermost_constant_expr.
	(maybe_constant_init): Add pretend_const_required argument, pass it
	down to maybe_constant_init_1.
	(cxx_constant_init): Pass true as pretend_const_required to
	maybe_constant_init_1.
	* cp-gimplify.c (cp_gimplify_expr): Handle CALL_EXPRs to
	CP_BUILT_IN_IS_CONSTANT_EVALUATED.
	(cp_fold): Don't fold CP_BUILT_IN_IS_CONSTANT_EVALUATED calls.
	* decl.c: Include langhooks.h.
	(cxx_init_decl_processing): Register __builtin_is_constant_evaluated
	built-in.
	* tree.c (builtin_valid_in_constant_expr_p): Return true for
	CP_BUILT_IN_IS_CONSTANT_EVALUATED.
	* pt.c (declare_integer_pack): Initialize DECL_FUNCTION_CODE.
testsuite/
	* g++.dg/cpp2a/is-constant-evaluated1.C: New test.

From-SVN: r263392
parent 5e539332
2018-08-08 Jakub Jelinek <jakub@redhat.com> 2018-08-08 Jakub Jelinek <jakub@redhat.com>
P0595R1 - is_constant_evaluated
* cp-tree.h (enum cp_built_in_function): New.
(maybe_constant_init): Add pretend_const_required argument.
* typeck2.c (store_init_value): Pass true as new argument to
maybe_constant_init.
* constexpr.c (constexpr_fn_retval): Check also DECL_BUILT_IN_CLASS
for BUILT_IN_UNREACHABLE.
(struct constexpr_ctx): Add pretend_const_required field.
(cxx_eval_builtin_function_call): Use DECL_IS_BUILTIN_CONSTANT_P
macro. Handle CP_BUILT_IN_IS_CONSTANT_EVALUATED. Check also
DECL_BUILT_IN_CLASS for BUILT_IN_UNREACHABLE.
(cxx_eval_outermost_constant_expr): Add pretend_const_required
argument, initialize pretend_const_required field in ctx. If the
result is TREE_CONSTANT and non_constant_p, retry with
pretend_const_required false if it was true.
(is_sub_constant_expr): Initialize pretend_const_required_field in
ctx.
(cxx_constant_value): Pass true as pretend_const_required to
cxx_eval_outermost_constant_expr.
(maybe_constant_value): Pass false as pretend_const_required to
cxx_eval_outermost_constant_expr.
(fold_non_dependent_expr): Likewise.
(maybe_constant_init_1): Add pretend_const_required argument, pass it
down to cxx_eval_outermost_constant_expr. Pass !allow_non_constant
instead of false as strict to cxx_eval_outermost_constant_expr.
(maybe_constant_init): Add pretend_const_required argument, pass it
down to maybe_constant_init_1.
(cxx_constant_init): Pass true as pretend_const_required to
maybe_constant_init_1.
* cp-gimplify.c (cp_gimplify_expr): Handle CALL_EXPRs to
CP_BUILT_IN_IS_CONSTANT_EVALUATED.
(cp_fold): Don't fold CP_BUILT_IN_IS_CONSTANT_EVALUATED calls.
* decl.c: Include langhooks.h.
(cxx_init_decl_processing): Register __builtin_is_constant_evaluated
built-in.
* tree.c (builtin_valid_in_constant_expr_p): Return true for
CP_BUILT_IN_IS_CONSTANT_EVALUATED.
* pt.c (declare_integer_pack): Initialize DECL_FUNCTION_CODE.
PR c++/86836 PR c++/86836
* pt.c (tsubst_expr): For structured bindings, call tsubst_decomp_names * pt.c (tsubst_expr): For structured bindings, call tsubst_decomp_names
before tsubst_init, not after it. before tsubst_init, not after it.
......
...@@ -713,6 +713,7 @@ constexpr_fn_retval (tree body) ...@@ -713,6 +713,7 @@ constexpr_fn_retval (tree body)
{ {
tree fun = get_function_named_in_call (body); tree fun = get_function_named_in_call (body);
if (fun != NULL_TREE if (fun != NULL_TREE
&& DECL_BUILT_IN_CLASS (fun) == BUILT_IN_NORMAL
&& DECL_FUNCTION_CODE (fun) == BUILT_IN_UNREACHABLE) && DECL_FUNCTION_CODE (fun) == BUILT_IN_UNREACHABLE)
return NULL_TREE; return NULL_TREE;
} }
...@@ -1007,6 +1008,8 @@ struct constexpr_ctx { ...@@ -1007,6 +1008,8 @@ struct constexpr_ctx {
/* Whether we are strictly conforming to constant expression rules or /* Whether we are strictly conforming to constant expression rules or
trying harder to get a constant value. */ trying harder to get a constant value. */
bool strict; bool strict;
/* Whether __builtin_is_constant_evaluated () should be true. */
bool pretend_const_required;
}; };
/* A table of all constexpr calls that have been evaluated by the /* A table of all constexpr calls that have been evaluated by the
...@@ -1171,7 +1174,7 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, ...@@ -1171,7 +1174,7 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
int i; int i;
/* Don't fold __builtin_constant_p within a constexpr function. */ /* Don't fold __builtin_constant_p within a constexpr function. */
bool bi_const_p = (DECL_FUNCTION_CODE (fun) == BUILT_IN_CONSTANT_P); bool bi_const_p = DECL_IS_BUILTIN_CONSTANT_P (fun);
/* If we aren't requiring a constant expression, defer __builtin_constant_p /* If we aren't requiring a constant expression, defer __builtin_constant_p
in a constexpr function until we have values for the parameters. */ in a constexpr function until we have values for the parameters. */
...@@ -1184,6 +1187,19 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, ...@@ -1184,6 +1187,19 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
return t; return t;
} }
/* For __builtin_is_constant_evaluated, defer it if not
ctx->pretend_const_required, otherwise fold it to true. */
if (DECL_BUILT_IN_CLASS (fun) == BUILT_IN_FRONTEND
&& (int) DECL_FUNCTION_CODE (fun) == CP_BUILT_IN_IS_CONSTANT_EVALUATED)
{
if (!ctx->pretend_const_required)
{
*non_constant_p = true;
return t;
}
return boolean_true_node;
}
/* Be permissive for arguments to built-ins; __builtin_constant_p should /* Be permissive for arguments to built-ins; __builtin_constant_p should
return constant false for a non-constant argument. */ return constant false for a non-constant argument. */
constexpr_ctx new_ctx = *ctx; constexpr_ctx new_ctx = *ctx;
...@@ -1217,7 +1233,8 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, ...@@ -1217,7 +1233,8 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
/* Do not allow__builtin_unreachable in constexpr function. /* Do not allow__builtin_unreachable in constexpr function.
The __builtin_unreachable call with BUILTINS_LOCATION The __builtin_unreachable call with BUILTINS_LOCATION
comes from cp_maybe_instrument_return. */ comes from cp_maybe_instrument_return. */
if (DECL_FUNCTION_CODE (fun) == BUILT_IN_UNREACHABLE if (DECL_BUILT_IN_CLASS (fun) == BUILT_IN_NORMAL
&& DECL_FUNCTION_CODE (fun) == BUILT_IN_UNREACHABLE
&& EXPR_LOCATION (t) == BUILTINS_LOCATION) && EXPR_LOCATION (t) == BUILTINS_LOCATION)
error ("%<constexpr%> call flows off the end of the function"); error ("%<constexpr%> call flows off the end of the function");
else else
...@@ -4897,9 +4914,15 @@ instantiate_constexpr_fns (tree t) ...@@ -4897,9 +4914,15 @@ instantiate_constexpr_fns (tree t)
input_location = loc; input_location = loc;
} }
/* 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
per P0595 even when ALLOW_NON_CONSTANT is true. */
static tree static tree
cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
bool strict = true, tree object = NULL_TREE) bool strict = true,
bool pretend_const_required = false,
tree object = NULL_TREE)
{ {
auto_timevar time (TV_CONSTEXPR); auto_timevar time (TV_CONSTEXPR);
...@@ -4908,7 +4931,8 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, ...@@ -4908,7 +4931,8 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
hash_map<tree,tree> map; hash_map<tree,tree> map;
constexpr_ctx ctx = { NULL, &map, NULL, NULL, NULL, NULL, constexpr_ctx ctx = { NULL, &map, NULL, NULL, NULL, NULL,
allow_non_constant, strict }; allow_non_constant, strict,
pretend_const_required || !allow_non_constant };
tree type = initialized_type (t); tree type = initialized_type (t);
tree r = t; tree r = t;
...@@ -4997,6 +5021,12 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, ...@@ -4997,6 +5021,12 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
return error_mark_node; return error_mark_node;
else if (non_constant_p && TREE_CONSTANT (r)) else if (non_constant_p && TREE_CONSTANT (r))
{ {
/* 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)
return cxx_eval_outermost_constant_expr (t, true, strict,
false, object);
/* This isn't actually constant, so unset TREE_CONSTANT. /* This isn't actually constant, so unset TREE_CONSTANT.
Don't clear TREE_CONSTANT on ADDR_EXPR, as the middle-end requires Don't clear TREE_CONSTANT on ADDR_EXPR, as the middle-end requires
it to be set if it is invariant address, even when it is not it to be set if it is invariant address, even when it is not
...@@ -5042,7 +5072,8 @@ is_sub_constant_expr (tree t) ...@@ -5042,7 +5072,8 @@ is_sub_constant_expr (tree t)
bool overflow_p = false; bool overflow_p = false;
hash_map <tree, tree> map; hash_map <tree, tree> map;
constexpr_ctx ctx = { NULL, &map, NULL, NULL, NULL, NULL, true, true }; constexpr_ctx ctx
= { NULL, &map, NULL, NULL, NULL, NULL, true, true, false };
instantiate_constexpr_fns (t); instantiate_constexpr_fns (t);
cxx_eval_constant_expression (&ctx, t, false, &non_constant_p, cxx_eval_constant_expression (&ctx, t, false, &non_constant_p,
...@@ -5057,7 +5088,7 @@ is_sub_constant_expr (tree t) ...@@ -5057,7 +5088,7 @@ is_sub_constant_expr (tree t)
tree tree
cxx_constant_value (tree t, tree decl) cxx_constant_value (tree t, tree decl)
{ {
return cxx_eval_outermost_constant_expr (t, false, true, decl); return cxx_eval_outermost_constant_expr (t, false, true, true, decl);
} }
/* Helper routine for fold_simple function. Either return simplified /* Helper routine for fold_simple function. Either return simplified
...@@ -5163,7 +5194,7 @@ maybe_constant_value (tree t, tree decl) ...@@ -5163,7 +5194,7 @@ maybe_constant_value (tree t, tree decl)
if (tree *cached = cv_cache->get (t)) if (tree *cached = cv_cache->get (t))
return *cached; return *cached;
r = cxx_eval_outermost_constant_expr (t, true, true, decl); r = cxx_eval_outermost_constant_expr (t, true, true, false, decl);
gcc_checking_assert (r == t gcc_checking_assert (r == t
|| CONVERT_EXPR_P (t) || CONVERT_EXPR_P (t)
|| TREE_CODE (t) == VIEW_CONVERT_EXPR || TREE_CODE (t) == VIEW_CONVERT_EXPR
...@@ -5237,7 +5268,8 @@ fold_non_dependent_expr (tree t, ...@@ -5237,7 +5268,8 @@ fold_non_dependent_expr (tree t,
return t; return t;
} }
tree r = cxx_eval_outermost_constant_expr (t, true, true, NULL_TREE); tree r = cxx_eval_outermost_constant_expr (t, true, true, false,
NULL_TREE);
/* cp_tree_equal looks through NOPs, so allow them. */ /* cp_tree_equal looks through NOPs, so allow them. */
gcc_checking_assert (r == t gcc_checking_assert (r == t
|| CONVERT_EXPR_P (t) || CONVERT_EXPR_P (t)
...@@ -5258,10 +5290,14 @@ fold_non_dependent_expr (tree t, ...@@ -5258,10 +5290,14 @@ fold_non_dependent_expr (tree t,
} }
/* Like maybe_constant_value, but returns a CONSTRUCTOR directly, rather /* Like maybe_constant_value, but returns a CONSTRUCTOR directly, rather
than wrapped in a TARGET_EXPR. */ 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
per P0595 even when ALLOW_NON_CONSTANT is true. */
static tree static tree
maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant) maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant,
bool pretend_const_required)
{ {
if (!t) if (!t)
return t; return t;
...@@ -5279,7 +5315,9 @@ maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant) ...@@ -5279,7 +5315,9 @@ maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant)
else if (CONSTANT_CLASS_P (t) && allow_non_constant) else if (CONSTANT_CLASS_P (t) && allow_non_constant)
/* No evaluation needed. */; /* No evaluation needed. */;
else else
t = cxx_eval_outermost_constant_expr (t, allow_non_constant, false, decl); t = cxx_eval_outermost_constant_expr (t, allow_non_constant,
!allow_non_constant,
pretend_const_required, decl);
if (TREE_CODE (t) == TARGET_EXPR) if (TREE_CODE (t) == TARGET_EXPR)
{ {
tree init = TARGET_EXPR_INITIAL (t); tree init = TARGET_EXPR_INITIAL (t);
...@@ -5292,9 +5330,9 @@ maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant) ...@@ -5292,9 +5330,9 @@ maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant)
/* Wrapper for maybe_constant_init_1 which permits non constants. */ /* Wrapper for maybe_constant_init_1 which permits non constants. */
tree tree
maybe_constant_init (tree t, tree decl) maybe_constant_init (tree t, tree decl, bool pretend_const_required)
{ {
return maybe_constant_init_1 (t, decl, true); return maybe_constant_init_1 (t, decl, true, pretend_const_required);
} }
/* Wrapper for maybe_constant_init_1 which does not permit non constants. */ /* Wrapper for maybe_constant_init_1 which does not permit non constants. */
...@@ -5302,7 +5340,7 @@ maybe_constant_init (tree t, tree decl) ...@@ -5302,7 +5340,7 @@ maybe_constant_init (tree t, tree decl)
tree tree
cxx_constant_init (tree t, tree decl) cxx_constant_init (tree t, tree decl)
{ {
return maybe_constant_init_1 (t, decl, false); return maybe_constant_init_1 (t, decl, false, true);
} }
#if 0 #if 0
......
...@@ -793,6 +793,15 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) ...@@ -793,6 +793,15 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
ret = GS_ERROR; ret = GS_ERROR;
} }
} }
if (ret != GS_ERROR)
{
tree decl = cp_get_callee_fndecl_nofold (*expr_p);
if (decl
&& DECL_BUILT_IN_CLASS (decl) == BUILT_IN_FRONTEND
&& ((int) DECL_FUNCTION_CODE (decl)
== CP_BUILT_IN_IS_CONSTANT_EVALUATED))
*expr_p = boolean_false_node;
}
break; break;
case RETURN_EXPR: case RETURN_EXPR:
...@@ -2483,6 +2492,13 @@ cp_fold (tree x) ...@@ -2483,6 +2492,13 @@ cp_fold (tree x)
&& DECL_DECLARED_CONSTEXPR_P (current_function_decl)) && DECL_DECLARED_CONSTEXPR_P (current_function_decl))
nw = 1; nw = 1;
/* Defer folding __builtin_is_constant_evaluated. */
if (callee
&& DECL_BUILT_IN_CLASS (callee) == BUILT_IN_FRONTEND
&& ((int) DECL_FUNCTION_CODE (callee)
== CP_BUILT_IN_IS_CONSTANT_EVALUATED))
break;
x = copy_node (x); x = copy_node (x);
m = call_expr_nargs (x); m = call_expr_nargs (x);
......
...@@ -5966,6 +5966,13 @@ struct GTY((chain_next ("%h.next"))) tinst_level { ...@@ -5966,6 +5966,13 @@ struct GTY((chain_next ("%h.next"))) tinst_level {
static const unsigned short refcount_infinity = (unsigned short) ~0; static const unsigned short refcount_infinity = (unsigned short) ~0;
}; };
/* BUILT_IN_FRONTEND function codes. */
enum cp_built_in_function {
CP_BUILT_IN_IS_CONSTANT_EVALUATED,
CP_BUILT_IN_INTEGER_PACK,
CP_BUILT_IN_LAST
};
bool decl_spec_seq_has_spec_p (const cp_decl_specifier_seq *, cp_decl_spec); bool decl_spec_seq_has_spec_p (const cp_decl_specifier_seq *, cp_decl_spec);
/* Return the type of the `this' parameter of FNTYPE. */ /* Return the type of the `this' parameter of FNTYPE. */
...@@ -7572,7 +7579,7 @@ extern bool require_potential_rvalue_constant_expression (tree); ...@@ -7572,7 +7579,7 @@ extern bool require_potential_rvalue_constant_expression (tree);
extern tree cxx_constant_value (tree, tree = NULL_TREE); extern tree cxx_constant_value (tree, tree = NULL_TREE);
extern tree cxx_constant_init (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);
extern tree maybe_constant_init (tree, tree = NULL_TREE); 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);
extern tree fold_simple (tree); extern tree fold_simple (tree);
extern bool is_sub_constant_expr (tree); extern bool is_sub_constant_expr (tree);
......
...@@ -52,6 +52,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -52,6 +52,7 @@ along with GCC; see the file COPYING3. If not see
#include "gimplify.h" #include "gimplify.h"
#include "asan.h" #include "asan.h"
#include "gcc-rich-location.h" #include "gcc-rich-location.h"
#include "langhooks.h"
/* Possible cases of bad specifiers type used by bad_specifiers. */ /* Possible cases of bad specifiers type used by bad_specifiers. */
enum bad_spec_place { enum bad_spec_place {
...@@ -4172,6 +4173,13 @@ cxx_init_decl_processing (void) ...@@ -4172,6 +4173,13 @@ cxx_init_decl_processing (void)
c_common_nodes_and_builtins (); c_common_nodes_and_builtins ();
tree bool_ftype = build_function_type_list (boolean_type_node, NULL_TREE);
tree decl
= add_builtin_function ("__builtin_is_constant_evaluated",
bool_ftype, CP_BUILT_IN_IS_CONSTANT_EVALUATED,
BUILT_IN_FRONTEND, NULL, NULL_TREE);
set_call_expr_flags (decl, ECF_CONST | ECF_NOTHROW | ECF_LEAF);
integer_two_node = build_int_cst (NULL_TREE, 2); integer_two_node = build_int_cst (NULL_TREE, 2);
/* Guess at the initial static decls size. */ /* Guess at the initial static decls size. */
......
...@@ -27538,6 +27538,8 @@ declare_integer_pack (void) ...@@ -27538,6 +27538,8 @@ declare_integer_pack (void)
NULL_TREE, ECF_CONST); NULL_TREE, ECF_CONST);
DECL_DECLARED_CONSTEXPR_P (ipfn) = true; DECL_DECLARED_CONSTEXPR_P (ipfn) = true;
DECL_BUILT_IN_CLASS (ipfn) = BUILT_IN_FRONTEND; DECL_BUILT_IN_CLASS (ipfn) = BUILT_IN_FRONTEND;
DECL_FUNCTION_CODE (ipfn)
= (enum built_in_function) (int) CP_BUILT_IN_INTEGER_PACK;
} }
/* Set up the hash tables for template instantiations. */ /* Set up the hash tables for template instantiations. */
......
...@@ -415,10 +415,18 @@ cp_stabilize_reference (tree ref) ...@@ -415,10 +415,18 @@ cp_stabilize_reference (tree ref)
bool bool
builtin_valid_in_constant_expr_p (const_tree decl) builtin_valid_in_constant_expr_p (const_tree decl)
{ {
if (!(TREE_CODE (decl) == FUNCTION_DECL if (TREE_CODE (decl) != FUNCTION_DECL)
&& DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)) /* Not a function. */
/* Not a built-in. */
return false; return false;
if (DECL_BUILT_IN_CLASS (decl) != BUILT_IN_NORMAL)
{
if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_FRONTEND
&& ((int) DECL_FUNCTION_CODE (decl)
== CP_BUILT_IN_IS_CONSTANT_EVALUATED))
return true;
/* Not a built-in. */
return false;
}
switch (DECL_FUNCTION_CODE (decl)) switch (DECL_FUNCTION_CODE (decl))
{ {
/* These always have constant results like the corresponding /* These always have constant results like the corresponding
......
...@@ -837,7 +837,7 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags) ...@@ -837,7 +837,7 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
value = cxx_constant_init (value, decl); value = cxx_constant_init (value, decl);
} }
else else
value = maybe_constant_init (value, decl); value = maybe_constant_init (value, decl, true);
if (TREE_CODE (value) == CONSTRUCTOR && cp_has_mutable_p (type)) if (TREE_CODE (value) == CONSTRUCTOR && cp_has_mutable_p (type))
/* Poison this CONSTRUCTOR so it can't be copied to another /* Poison this CONSTRUCTOR so it can't be copied to another
constexpr variable. */ constexpr variable. */
......
2018-08-08 Jakub Jelinek <jakub@redhat.com> 2018-08-08 Jakub Jelinek <jakub@redhat.com>
P0595R1 - is_constant_evaluated
* g++.dg/cpp2a/is-constant-evaluated1.C: New test.
PR c++/86836 PR c++/86836
* g++.dg/cpp1z/decomp46.C: New test. * g++.dg/cpp1z/decomp46.C: New test.
......
// P0595R1
// { dg-do compile { target c++14 } }
template<int N> struct X { int v = N; };
X<__builtin_is_constant_evaluated ()> x; // type X<true>
int y = 4;
int a = __builtin_is_constant_evaluated () ? y : 1; // initializes a to 1
int b = __builtin_is_constant_evaluated () ? 2 : y; // initializes b to 2
int c = y + (__builtin_is_constant_evaluated () ? 2 : y); // initializes c to 2*y
int d = __builtin_is_constant_evaluated (); // initializes d to 1
int e = d + __builtin_is_constant_evaluated (); // initializes e to 0
struct false_type { static constexpr bool value = false; };
struct true_type { static constexpr bool value = true; };
template<class T, class U>
struct is_same : false_type {};
template<class T>
struct is_same<T, T> : true_type {};
constexpr int
foo (int x)
{
const int n = __builtin_is_constant_evaluated () ? 13 : 17; // n == 13
int m = __builtin_is_constant_evaluated () ? 13 : 17; // m might be 13 or 17 (see below)
char arr[n] = {}; // char[13]
return m + sizeof (arr) + x;
}
constexpr int
bar ()
{
const int n = __builtin_is_constant_evaluated() ? 13 : 17;
X<n> x1;
X<__builtin_is_constant_evaluated() ? 13 : 17> x2;
static_assert (is_same<decltype (x1), decltype (x2)>::value, "x1/x2's type");
return x1.v + x2.v;
}
int p = foo (0); // m == 13; initialized to 26
int q = p + foo (0); // m == 17 for this call; initialized to 56
static_assert (bar () == 26, "bar");
struct S { int a, b; };
S s = { __builtin_is_constant_evaluated () ? 2 : 3, y };
S t = { __builtin_is_constant_evaluated () ? 2 : 3, 4 };
static_assert (is_same<decltype (x), X<true> >::value, "x's type");
int
main ()
{
if (a != 1 || b != 2 || c != 8 || d != 1 || e != 0 || p != 26 || q != 56)
__builtin_abort ();
if (s.a != 3 || s.b != 4 || t.a != 2 || t.b != 4)
__builtin_abort ();
if (foo (y) != 34)
__builtin_abort ();
#if __cplusplus >= 201703L
if constexpr (foo (0) != 26)
__builtin_abort ();
#endif
constexpr int w = foo (0);
if (w != 26)
__builtin_abort ();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment