tree ctor;
tree object;
bool quiet;
+ bool strict;
};
/* A table of all constexpr calls that have been evaluated by the
return t;
/* else fall through. */
case CONST_DECL:
- r = integral_constant_value (t);
+ if (ctx->strict)
+ r = decl_really_constant_value (t);
+ else
+ r = decl_constant_value (t);
if (TREE_CODE (r) == TARGET_EXPR
&& TREE_CODE (TARGET_EXPR_INITIAL (r)) == CONSTRUCTOR)
r = TARGET_EXPR_INITIAL (r);
static tree
cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
- tree object = NULL_TREE)
+ bool strict = true, tree object = NULL_TREE)
{
bool non_constant_p = false;
bool overflow_p = false;
- constexpr_ctx ctx = { NULL, NULL, NULL, NULL, allow_non_constant };
+ constexpr_ctx ctx = { NULL, NULL, NULL, NULL, allow_non_constant, strict };
hash_map<tree,tree> map;
ctx.values = ↦
tree type = initialized_type (t);
{
bool non_constant_p = false;
bool overflow_p = false;
- constexpr_ctx ctx = { NULL, NULL, NULL, NULL, true };
+ constexpr_ctx ctx = { NULL, NULL, NULL, NULL, true, true };
hash_map <tree, tree> map;
ctx.values = ↦
cxx_eval_constant_expression (&ctx, t, false, &non_constant_p,
tree
cxx_constant_value (tree t, tree decl)
{
- return cxx_eval_outermost_constant_expr (t, false, decl);
+ return cxx_eval_outermost_constant_expr (t, false, true, decl);
}
/* If T is a constant expression, returns its reduced value.
return t;
}
- r = cxx_eval_outermost_constant_expr (t, true, decl);
+ r = cxx_eval_outermost_constant_expr (t, true, true, decl);
#ifdef ENABLE_CHECKING
/* cp_tree_equal looks through NOPs, so allow them. */
gcc_assert (r == t
return t;
}
- tree r = cxx_eval_outermost_constant_expr (t, true, NULL_TREE);
+ tree r = cxx_eval_outermost_constant_expr (t, true, true, NULL_TREE);
#ifdef ENABLE_CHECKING
/* cp_tree_equal looks through NOPs, so allow them. */
gcc_assert (r == t
t = TREE_OPERAND (t, 0);
if (TREE_CODE (t) == INIT_EXPR)
t = TREE_OPERAND (t, 1);
- t = maybe_constant_value (t, decl);
+ if (instantiation_dependent_expression_p (t)
+ || type_unknown_p (t)
+ || BRACE_ENCLOSED_INITIALIZER_P (t)
+ || !potential_static_init_expression (t))
+ /* Don't try to evaluate it. */;
+ else
+ t = cxx_eval_outermost_constant_expr (t, true, false, decl);
if (TREE_CODE (t) == TARGET_EXPR)
{
tree init = TARGET_EXPR_INITIAL (t);
not evaluated are not considered. */
static bool
-potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags)
+potential_constant_expression_1 (tree t, bool want_rval, bool strict,
+ tsubst_flags_t flags)
{
+#define RECUR(T,RV) potential_constant_expression_1 ((T), (RV), strict, flags)
enum { any = false, rval = true };
int i;
tree tmp;
tree x = get_nth_callarg (t, 0);
if (is_this_parameter (x))
return true;
- else if (!potential_constant_expression_1 (x, rval, flags))
+ else if (!RECUR (x, rval))
return false;
i = 1;
}
}
else
{
- if (!potential_constant_expression_1 (fun, true, flags))
+ if (!RECUR (fun, true))
return false;
fun = get_first_fn (fun);
}
}
else
{
- if (potential_constant_expression_1 (fun, rval, flags))
+ if (RECUR (fun, rval))
/* Might end up being a constant function pointer. */;
else
return false;
for (; i < nargs; ++i)
{
tree x = get_nth_callarg (t, i);
- if (!potential_constant_expression_1 (x, rval, flags))
+ if (!RECUR (x, rval))
return false;
}
return true;
-- an lvalue of literal type that refers to non-volatile
object defined with constexpr, or that refers to a
sub-object of such an object; */
- return potential_constant_expression_1 (TREE_OPERAND (t, 0), rval, flags);
+ return RECUR (TREE_OPERAND (t, 0), rval);
case VAR_DECL:
- if (want_rval && !decl_constant_var_p (t)
+ if (want_rval
+ && !decl_constant_var_p (t)
+ && (strict
+ || !CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (t))
+ || !DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (t))
&& !var_in_constexpr_fn (t)
&& !dependent_type_p (TREE_TYPE (t)))
{
"reinterpret_cast from integer to pointer");
return false;
}
- return (potential_constant_expression_1
- (from, TREE_CODE (t) != VIEW_CONVERT_EXPR, flags));
+ return (RECUR (from, TREE_CODE (t) != VIEW_CONVERT_EXPR));
}
case ADDR_EXPR:
return false;
}
#endif
- return potential_constant_expression_1 (t, any, flags);
+ return RECUR (t, any);
case COMPONENT_REF:
case BIT_FIELD_REF:
of literal type or of pointer to literal type. */
/* This test would be redundant, as it follows from the
postfix-expression being a potential constant expression. */
- return potential_constant_expression_1 (TREE_OPERAND (t, 0),
- want_rval, flags);
+ return RECUR (TREE_OPERAND (t, 0), want_rval);
case EXPR_PACK_EXPANSION:
- return potential_constant_expression_1 (PACK_EXPANSION_PATTERN (t),
- want_rval, flags);
+ return RECUR (PACK_EXPANSION_PATTERN (t), want_rval);
case INDIRECT_REF:
{
}
return true;
}
- return potential_constant_expression_1 (x, rval, flags);
+ return RECUR (x, rval);
}
case STATEMENT_LIST:
tree_stmt_iterator i;
for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
{
- if (!potential_constant_expression_1 (tsi_stmt (i), any, flags))
+ if (!RECUR (tsi_stmt (i), any))
return false;
}
return true;
case MODIFY_EXPR:
if (cxx_dialect < cxx14)
goto fail;
- if (!potential_constant_expression_1 (TREE_OPERAND (t, 0), any, flags))
+ if (!RECUR (TREE_OPERAND (t, 0), any))
return false;
- if (!potential_constant_expression_1 (TREE_OPERAND (t, 1), rval, flags))
+ if (!RECUR (TREE_OPERAND (t, 1), rval))
return false;
return true;
case MODOP_EXPR:
if (cxx_dialect < cxx14)
goto fail;
- if (!potential_constant_expression_1 (TREE_OPERAND (t, 0), rval, flags))
+ if (!RECUR (TREE_OPERAND (t, 0), rval))
return false;
- if (!potential_constant_expression_1 (TREE_OPERAND (t, 2), rval, flags))
+ if (!RECUR (TREE_OPERAND (t, 2), rval))
return false;
return true;
case IF_STMT:
- if (!potential_constant_expression_1 (IF_COND (t), rval, flags))
+ if (!RECUR (IF_COND (t), rval))
return false;
- if (!potential_constant_expression_1 (THEN_CLAUSE (t), any, flags))
+ if (!RECUR (THEN_CLAUSE (t), any))
return false;
- if (!potential_constant_expression_1 (ELSE_CLAUSE (t), any, flags))
+ if (!RECUR (ELSE_CLAUSE (t), any))
return false;
return true;
case DO_STMT:
- if (!potential_constant_expression_1 (DO_COND (t), rval, flags))
+ if (!RECUR (DO_COND (t), rval))
return false;
- if (!potential_constant_expression_1 (DO_BODY (t), any, flags))
+ if (!RECUR (DO_BODY (t), any))
return false;
return true;
case FOR_STMT:
- if (!potential_constant_expression_1 (FOR_INIT_STMT (t), any, flags))
+ if (!RECUR (FOR_INIT_STMT (t), any))
return false;
- if (!potential_constant_expression_1 (FOR_COND (t), rval, flags))
+ if (!RECUR (FOR_COND (t), rval))
return false;
- if (!potential_constant_expression_1 (FOR_EXPR (t), any, flags))
+ if (!RECUR (FOR_EXPR (t), any))
return false;
- if (!potential_constant_expression_1 (FOR_BODY (t), any, flags))
+ if (!RECUR (FOR_BODY (t), any))
return false;
return true;
case WHILE_STMT:
- if (!potential_constant_expression_1 (WHILE_COND (t), rval, flags))
+ if (!RECUR (WHILE_COND (t), rval))
return false;
- if (!potential_constant_expression_1 (WHILE_BODY (t), any, flags))
+ if (!RECUR (WHILE_BODY (t), any))
return false;
return true;
case SWITCH_STMT:
- if (!potential_constant_expression_1 (SWITCH_STMT_COND (t), rval, flags))
+ if (!RECUR (SWITCH_STMT_COND (t), rval))
return false;
- if (!potential_constant_expression_1 (SWITCH_STMT_BODY (t), any, flags))
+ if (!RECUR (SWITCH_STMT_BODY (t), any))
return false;
return true;
case STMT_EXPR:
- return potential_constant_expression_1 (STMT_EXPR_STMT (t), rval, flags);
+ return RECUR (STMT_EXPR_STMT (t), rval);
case LAMBDA_EXPR:
case DYNAMIC_CAST_EXPR:
case FIXED_CONVERT_EXPR:
case UNARY_PLUS_EXPR:
unary:
- return potential_constant_expression_1 (TREE_OPERAND (t, 0), rval,
- flags);
+ return RECUR (TREE_OPERAND (t, 0), rval);
case CAST_EXPR:
case CONST_CAST_EXPR:
return false;
}
- return (potential_constant_expression_1
- (TREE_OPERAND (t, 0),
- TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE, flags));
+ return (RECUR (TREE_OPERAND (t, 0),
+ TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE));
case BIND_EXPR:
- return potential_constant_expression_1 (BIND_EXPR_BODY (t),
- want_rval, flags);
+ return RECUR (BIND_EXPR_BODY (t), want_rval);
case WITH_CLEANUP_EXPR:
case CLEANUP_POINT_EXPR:
case NON_DEPENDENT_EXPR:
/* For convenience. */
case RETURN_EXPR:
- return potential_constant_expression_1 (TREE_OPERAND (t, 0),
- want_rval, flags);
+ return RECUR (TREE_OPERAND (t, 0), want_rval);
case SCOPE_REF:
- return potential_constant_expression_1 (TREE_OPERAND (t, 1),
- want_rval, flags);
+ return RECUR (TREE_OPERAND (t, 1), want_rval);
case TARGET_EXPR:
if (!literal_type_p (TREE_TYPE (t)))
return false;
}
case INIT_EXPR:
- return potential_constant_expression_1 (TREE_OPERAND (t, 1),
- rval, flags);
+ return RECUR (TREE_OPERAND (t, 1), rval);
case CONSTRUCTOR:
{
vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (t);
constructor_elt *ce;
for (i = 0; vec_safe_iterate (v, i, &ce); ++i)
- if (!potential_constant_expression_1 (ce->value, want_rval, flags))
+ if (!RECUR (ce->value, want_rval))
return false;
return true;
}
{
gcc_assert (TREE_PURPOSE (t) == NULL_TREE
|| DECL_P (TREE_PURPOSE (t)));
- if (!potential_constant_expression_1 (TREE_VALUE (t), want_rval,
- flags))
+ if (!RECUR (TREE_VALUE (t), want_rval))
return false;
if (TREE_CHAIN (t) == NULL_TREE)
return true;
- return potential_constant_expression_1 (TREE_CHAIN (t), want_rval,
- flags);
+ return RECUR (TREE_CHAIN (t), want_rval);
}
case TRUNC_DIV_EXPR:
case ROUND_MOD_EXPR:
{
tree denom = TREE_OPERAND (t, 1);
- if (!potential_constant_expression_1 (denom, rval, flags))
+ if (!RECUR (denom, rval))
return false;
/* We can't call cxx_eval_outermost_constant_expr on an expression
that hasn't been through instantiate_non_dependent_expr yet. */
else
{
want_rval = true;
- return potential_constant_expression_1 (TREE_OPERAND (t, 0),
- want_rval, flags);
+ return RECUR (TREE_OPERAND (t, 0), want_rval);
}
}
STRIP_NOPS (op1);
if ((TREE_CODE (op0) == TARGET_EXPR && op1 == TARGET_EXPR_SLOT (op0))
|| TREE_CODE (op1) == EMPTY_CLASS_EXPR)
- return potential_constant_expression_1 (op0, want_rval, flags);
+ return RECUR (op0, want_rval);
else
goto binary;
}
truth:
{
tree op = TREE_OPERAND (t, 0);
- if (!potential_constant_expression_1 (op, rval, flags))
+ if (!RECUR (op, rval))
return false;
if (!processing_template_decl)
op = cxx_eval_outermost_constant_expr (op, true);
if (tree_int_cst_equal (op, tmp))
- return potential_constant_expression_1 (TREE_OPERAND (t, 1), rval, flags);
+ return RECUR (TREE_OPERAND (t, 1), rval);
else
return true;
}
case DOTSTAR_EXPR:
binary:
for (i = 0; i < 2; ++i)
- if (!potential_constant_expression_1 (TREE_OPERAND (t, i),
- want_rval, flags))
+ if (!RECUR (TREE_OPERAND (t, i), want_rval))
return false;
return true;
case FMA_EXPR:
case VEC_PERM_EXPR:
for (i = 0; i < 3; ++i)
- if (!potential_constant_expression_1 (TREE_OPERAND (t, i),
- true, flags))
+ if (!RECUR (TREE_OPERAND (t, i), true))
return false;
return true;
care about; otherwise we only require that the condition and
either of the legs be potentially constant. */
tmp = TREE_OPERAND (t, 0);
- if (!potential_constant_expression_1 (tmp, rval, flags))
+ if (!RECUR (tmp, rval))
return false;
if (!processing_template_decl)
tmp = cxx_eval_outermost_constant_expr (tmp, true);
if (integer_zerop (tmp))
- return potential_constant_expression_1 (TREE_OPERAND (t, 2),
- want_rval, flags);
+ return RECUR (TREE_OPERAND (t, 2), want_rval);
else if (TREE_CODE (tmp) == INTEGER_CST)
- return potential_constant_expression_1 (TREE_OPERAND (t, 1),
- want_rval, flags);
+ return RECUR (TREE_OPERAND (t, 1), want_rval);
for (i = 1; i < 3; ++i)
if (potential_constant_expression_1 (TREE_OPERAND (t, i),
- want_rval, tf_none))
+ want_rval, strict, tf_none))
return true;
if (flags & tf_error)
error ("expression %qE is not a constant-expression", t);
gcc_unreachable();
return false;
}
+#undef RECUR
}
/* The main entry point to the above. */
bool
potential_constant_expression (tree t)
{
- return potential_constant_expression_1 (t, false, tf_none);
+ return potential_constant_expression_1 (t, false, true, tf_none);
+}
+
+bool
+potential_static_init_expression (tree t)
+{
+ return potential_constant_expression_1 (t, false, false, tf_none);
}
/* As above, but require a constant rvalue. */
bool
potential_rvalue_constant_expression (tree t)
{
- return potential_constant_expression_1 (t, true, tf_none);
+ return potential_constant_expression_1 (t, true, true, tf_none);
}
/* Like above, but complain about non-constant expressions. */
bool
require_potential_constant_expression (tree t)
{
- return potential_constant_expression_1 (t, false, tf_warning_or_error);
+ return potential_constant_expression_1 (t, false, true, tf_warning_or_error);
}
/* Cross product of the above. */
bool
require_potential_rvalue_constant_expression (tree t)
{
- return potential_constant_expression_1 (t, true, tf_warning_or_error);
+ return potential_constant_expression_1 (t, true, true, tf_warning_or_error);
}
#include "gt-cp-constexpr.h"
/* If DECL is a scalar enumeration constant or variable with a
constant initializer, return the initializer (or, its initializers,
- recursively); otherwise, return DECL. If INTEGRAL_P, the
- initializer is only returned if DECL is an integral
+ recursively); otherwise, return DECL. If STRICT_P, the
+ initializer is only returned if DECL is a
constant-expression. If RETURN_AGGREGATE_CST_OK_P, it is ok to
return an aggregate constant. */
static tree
-constant_value_1 (tree decl, bool integral_p, bool return_aggregate_cst_ok_p)
+constant_value_1 (tree decl, bool strict_p, bool return_aggregate_cst_ok_p)
{
while (TREE_CODE (decl) == CONST_DECL
- || (integral_p
+ || (strict_p
? decl_constant_var_p (decl)
: (VAR_P (decl)
&& CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (decl)))))
if (!init
|| !TREE_TYPE (init)
|| !TREE_CONSTANT (init)
- || (!integral_p && !return_aggregate_cst_ok_p
+ || (!return_aggregate_cst_ok_p
/* Unless RETURN_AGGREGATE_CST_OK_P is true, do not
return an aggregate constant (of which string
literals are a special case), as we do not want
return decl;
}
-/* If DECL is a CONST_DECL, or a constant VAR_DECL initialized by
- constant of integral or enumeration type, then return that value.
- These are those variables permitted in constant expressions by
- [5.19/1]. */
+/* If DECL is a CONST_DECL, or a constant VAR_DECL initialized by constant
+ of integral or enumeration type, or a constexpr variable of scalar type,
+ then return that value. These are those variables permitted in constant
+ expressions by [5.19/1]. */
tree
-integral_constant_value (tree decl)
+scalar_constant_value (tree decl)
{
- return constant_value_1 (decl, /*integral_p=*/true,
+ return constant_value_1 (decl, /*strict_p=*/true,
/*return_aggregate_cst_ok_p=*/false);
}
-/* A more relaxed version of integral_constant_value, used by the
- common C/C++ code. */
+/* Like scalar_constant_value, but can also return aggregate initializers. */
tree
-decl_constant_value (tree decl)
+decl_really_constant_value (tree decl)
{
- return constant_value_1 (decl, /*integral_p=*/processing_template_decl,
+ return constant_value_1 (decl, /*strict_p=*/true,
/*return_aggregate_cst_ok_p=*/true);
}
-/* A version of integral_constant_value used by the C++ front end for
- optimization purposes. */
+/* A more relaxed version of scalar_constant_value, used by the
+ common C/C++ code. */
tree
-decl_constant_value_safe (tree decl)
+decl_constant_value (tree decl)
{
- return constant_value_1 (decl, /*integral_p=*/processing_template_decl,
- /*return_aggregate_cst_ok_p=*/false);
+ return constant_value_1 (decl, /*strict_p=*/processing_template_decl,
+ /*return_aggregate_cst_ok_p=*/true);
}
\f
/* Common subroutines of build_new and build_vec_delete. */