constexpr functions. These routines are used both during actual parsing
and during the instantiation of template functions.
- Copyright (C) 1998-2018 Free Software Foundation, Inc.
+ Copyright (C) 1998-2019 Free Software Foundation, Inc.
This file is part of GCC.
#include "ubsan.h"
#include "gimple-fold.h"
#include "timevar.h"
+#include "fold-const-call.h"
static bool verify_constant (tree, bool, bool *, bool *);
#define VERIFY_CONSTANT(X) \
return t; \
} while (0)
+static HOST_WIDE_INT find_array_ctor_elt (tree ary, tree dindex,
+ bool insert = false);
+
/* Returns true iff FUN is an instantiation of a constexpr function
template or a defaulted constexpr function. */
{
if (SCALAR_TYPE_P (t)
|| VECTOR_TYPE_P (t)
- || TREE_CODE (t) == REFERENCE_TYPE
+ || TYPE_REF_P (t)
|| (VOID_TYPE_P (t) && cxx_dialect >= cxx14))
return true;
if (CLASS_TYPE_P (t))
if (CLASS_TYPE_P (stype) && !COMPLETE_TYPE_P (complete_type (stype)))
/* Don't complain here, we'll complain about incompleteness
when we try to initialize the variable. */;
+ else if (type_uses_auto (type))
+ /* We don't know the actual type yet. */;
else if (!literal_type_p (type))
{
if (DECL_DECLARED_CONSTEXPR_P (decl))
{
- error ("the type %qT of %<constexpr%> variable %qD "
- "is not literal", type, decl);
+ auto_diagnostic_group d;
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "the type %qT of %<constexpr%> variable %qD "
+ "is not literal", type, decl);
explain_non_literal_class (type);
decl = error_mark_node;
}
{
if (!is_instantiation_of_constexpr (current_function_decl))
{
- error ("variable %qD of non-literal type %qT in %<constexpr%> "
- "function", decl, type);
+ auto_diagnostic_group d;
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "variable %qD of non-literal type %qT in "
+ "%<constexpr%> function", decl, type);
explain_non_literal_class (type);
decl = error_mark_node;
}
cp_function_chain->invalid_constexpr = true;
}
}
+ else if (DECL_DECLARED_CONSTEXPR_P (decl)
+ && variably_modified_type_p (type, NULL_TREE))
+ {
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "%<constexpr%> variable %qD has variably-modified "
+ "type %qT", decl, type);
+ decl = error_mark_node;
+ }
}
return decl;
}
ret = false;
if (complain)
{
+ auto_diagnostic_group d;
error ("invalid type for parameter %d of %<constexpr%> "
"function %q+#D", DECL_PARM_INDEX (parm), fun);
explain_non_literal_class (TREE_TYPE (parm));
ret = false;
if (complain)
{
+ auto_diagnostic_group d;
error ("invalid return type %qT of %<constexpr%> function %q+D",
rettype, fun);
explain_non_literal_class (rettype);
&& !CLASSTYPE_LITERAL_P (DECL_CONTEXT (fun)))
{
ret = false;
- if (complain
- && pedwarn (DECL_SOURCE_LOCATION (fun), OPT_Wpedantic,
- "enclosing class of %<constexpr%> non-static member "
- "function %q+#D is not a literal type", fun))
- explain_non_literal_class (DECL_CONTEXT (fun));
+ if (complain)
+ {
+ auto_diagnostic_group d;
+ if (pedwarn (DECL_SOURCE_LOCATION (fun), OPT_Wpedantic,
+ "enclosing class of %<constexpr%> non-static"
+ " member function %q+#D is not a literal type",
+ fun))
+ explain_non_literal_class (DECL_CONTEXT (fun));
+ }
}
}
else if (CLASSTYPE_VBASECLASSES (DECL_CONTEXT (fun)))
return value if suitable, error_mark_node for a statement not allowed in
a constexpr function, or NULL_TREE if no return value was found. */
-static tree
+tree
constexpr_fn_retval (tree body)
{
switch (TREE_CODE (body))
{
tree fun = get_function_named_in_call (body);
if (fun != NULL_TREE
- && DECL_FUNCTION_CODE (fun) == BUILT_IN_UNREACHABLE)
+ && fndecl_built_in_p (fun, BUILT_IN_UNREACHABLE))
return NULL_TREE;
}
/* Fallthru. */
tree ftype;
if (TREE_CODE (field) != FIELD_DECL)
continue;
- if (DECL_C_BIT_FIELD (field) && !DECL_NAME (field))
+ if (DECL_UNNAMED_BIT_FIELD (field))
continue;
if (DECL_ARTIFICIAL (field))
continue;
}
if (!complain)
return true;
+ auto_diagnostic_group d;
error ("member %qD must be initialized by mem-initializer "
"in %<constexpr%> constructor", field);
inform (DECL_SOURCE_LOCATION (field), "declared here");
/* The hash of this call; we remember it here to avoid having to
recalculate it when expanding the hash table. */
hashval_t hash;
+ /* Whether __builtin_is_constant_evaluated() should evaluate to true. */
+ bool manifestly_const_eval;
};
struct constexpr_call_hasher : ggc_ptr_hash<constexpr_call>
/* Whether we are strictly conforming to constant expression rules or
trying harder to get a constant value. */
bool strict;
+ /* Whether __builtin_is_constant_evaluated () should be true. */
+ bool manifestly_const_eval;
};
/* A table of all constexpr calls that have been evaluated by the
tree lhs_bindings;
tree rhs_bindings;
if (lhs == rhs)
- return 1;
+ return true;
+ if (lhs->hash != rhs->hash)
+ return false;
+ if (lhs->manifestly_const_eval != rhs->manifestly_const_eval)
+ return false;
if (!constexpr_fundef_hasher::equal (lhs->fundef, rhs->fundef))
- return 0;
+ return false;
lhs_bindings = lhs->bindings;
rhs_bindings = rhs->bindings;
while (lhs_bindings != NULL && rhs_bindings != NULL)
{
tree lhs_arg = TREE_VALUE (lhs_bindings);
tree rhs_arg = TREE_VALUE (rhs_bindings);
- gcc_assert (TREE_TYPE (lhs_arg) == TREE_TYPE (rhs_arg));
+ gcc_assert (same_type_p (TREE_TYPE (lhs_arg), TREE_TYPE (rhs_arg)));
if (!cp_tree_equal (lhs_arg, rhs_arg))
- return 0;
+ return false;
lhs_bindings = TREE_CHAIN (lhs_bindings);
rhs_bindings = TREE_CHAIN (rhs_bindings);
}
int i;
/* 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
+ in a constexpr function until we have values for the parameters. */
if (bi_const_p
+ && !ctx->manifestly_const_eval
&& current_function_decl
&& DECL_DECLARED_CONSTEXPR_P (current_function_decl))
{
return t;
}
+ /* For __builtin_is_constant_evaluated, defer it if not
+ ctx->manifestly_const_eval, otherwise fold it to true. */
+ if (fndecl_built_in_p (fun, CP_BUILT_IN_IS_CONSTANT_EVALUATED,
+ BUILT_IN_FRONTEND))
+ {
+ if (!ctx->manifestly_const_eval)
+ {
+ *non_constant_p = true;
+ return t;
+ }
+ return boolean_true_node;
+ }
+
/* Be permissive for arguments to built-ins; __builtin_constant_p should
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] = cxx_eval_constant_expression (&new_ctx, CALL_EXPR_ARG (t, i),
- false, &dummy1, &dummy2);
+ args[i] = CALL_EXPR_ARG (t, i);
+ /* If builtin_valid_in_constant_expr_p is true,
+ potential_constant_expression_1 has not recursed into the arguments
+ of the builtin, verify it here. */
+ if (!builtin_valid_in_constant_expr_p (fun)
+ || potential_constant_expression (args[i]))
+ {
+ 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] = cp_fold_rvalue (args[i]);
}
bool save_ffbcp = force_folding_builtin_constant_p;
/* Do not allow__builtin_unreachable in constexpr function.
The __builtin_unreachable call with BUILTINS_LOCATION
comes from cp_maybe_instrument_return. */
- if (DECL_FUNCTION_CODE (fun) == BUILT_IN_UNREACHABLE
+ if (fndecl_built_in_p (fun, BUILT_IN_UNREACHABLE)
&& EXPR_LOCATION (t) == BUILTINS_LOCATION)
error ("%<constexpr%> call flows off the end of the function");
else
static tree
adjust_temp_type (tree type, tree temp)
{
- if (TREE_TYPE (temp) == type)
+ if (same_type_p (TREE_TYPE (temp), type))
return temp;
/* Avoid wrapping an aggregate value in a NOP_EXPR. */
if (TREE_CODE (temp) == CONSTRUCTOR)
return build_constructor (type, CONSTRUCTOR_ELTS (temp));
+ if (TREE_CODE (temp) == EMPTY_CLASS_EXPR)
+ return build0 (EMPTY_CLASS_EXPR, type);
gcc_assert (scalarish_type_p (type));
return cp_fold_convert (type, temp);
}
if (!*non_constant_p)
{
+ /* Don't share a CONSTRUCTOR that might be changed. */
+ arg = unshare_constructor (arg);
/* Make sure the binding has the same type as the parm. But
only for constant args. */
- if (TREE_CODE (type) != REFERENCE_TYPE)
+ if (!TYPE_REF_P (type))
arg = adjust_temp_type (type, arg);
if (!TREE_CONSTANT (arg))
*non_constant_args = true;
return cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, 0),
false, non_constant_p, overflow_p);
+ case IFN_VEC_CONVERT:
+ {
+ tree arg = cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, 0),
+ false, non_constant_p,
+ overflow_p);
+ if (TREE_CODE (arg) == VECTOR_CST)
+ return fold_const_call (CFN_VEC_CONVERT, TREE_TYPE (t), arg);
+ else
+ {
+ *non_constant_p = true;
+ return t;
+ }
+ }
+
default:
if (!ctx->quiet)
- error_at (EXPR_LOC_OR_LOC (t, input_location),
+ error_at (cp_expr_loc_or_loc (t, input_location),
"call to internal function %qE", t);
*non_constant_p = true;
return t;
if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST)
{
- location_t loc = EXPR_LOC_OR_LOC (t, input_location);
+ location_t loc = cp_expr_loc_or_loc (t, input_location);
tree type = TREE_TYPE (TREE_TYPE (t));
tree result = fold_binary_loc (loc, opcode, type,
fold_convert_loc (loc, type, arg0),
return t;
}
-/* Clean CONSTRUCTOR_NO_IMPLICIT_ZERO from CTOR and its sub-aggregates. */
+/* Clean CONSTRUCTOR_NO_CLEARING from CTOR and its sub-aggregates. */
static void
clear_no_implicit_zero (tree ctor)
{
- if (CONSTRUCTOR_NO_IMPLICIT_ZERO (ctor))
+ if (CONSTRUCTOR_NO_CLEARING (ctor))
{
- CONSTRUCTOR_NO_IMPLICIT_ZERO (ctor) = false;
+ CONSTRUCTOR_NO_CLEARING (ctor) = false;
tree elt; unsigned HOST_WIDE_INT idx;
FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (ctor), idx, elt)
if (TREE_CODE (elt) == CONSTRUCTOR)
bool lval,
bool *non_constant_p, bool *overflow_p)
{
- location_t loc = EXPR_LOC_OR_LOC (t, input_location);
+ 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 };
+ constexpr_call new_call
+ = { NULL, NULL, NULL, 0, ctx->manifestly_const_eval };
bool depth_ok;
if (fun == NULL_TREE)
STRIP_NOPS (fun);
if (TREE_CODE (fun) == ADDR_EXPR)
fun = TREE_OPERAND (fun, 0);
+ /* For TARGET_VTABLE_USES_DESCRIPTORS targets, there is no
+ indirection, the called expression is a pointer into the
+ virtual table which should contain FDESC_EXPR. Extract the
+ FUNCTION_DECL from there. */
+ else if (TARGET_VTABLE_USES_DESCRIPTORS
+ && TREE_CODE (fun) == POINTER_PLUS_EXPR
+ && TREE_CODE (TREE_OPERAND (fun, 0)) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (fun, 1)) == INTEGER_CST)
+ {
+ tree d = TREE_OPERAND (TREE_OPERAND (fun, 0), 0);
+ if (VAR_P (d)
+ && DECL_VTABLE_OR_VTT_P (d)
+ && TREE_CODE (TREE_TYPE (d)) == ARRAY_TYPE
+ && TREE_TYPE (TREE_TYPE (d)) == vtable_entry_type
+ && DECL_INITIAL (d)
+ && TREE_CODE (DECL_INITIAL (d)) == CONSTRUCTOR)
+ {
+ tree i = int_const_binop (TRUNC_DIV_EXPR, TREE_OPERAND (fun, 1),
+ TYPE_SIZE_UNIT (vtable_entry_type));
+ HOST_WIDE_INT idx = find_array_ctor_elt (DECL_INITIAL (d), i);
+ if (idx >= 0)
+ {
+ tree fdesc
+ = (*CONSTRUCTOR_ELTS (DECL_INITIAL (d)))[idx].value;
+ if (TREE_CODE (fdesc) == FDESC_EXPR
+ && integer_zerop (TREE_OPERAND (fdesc, 1)))
+ fun = TREE_OPERAND (fdesc, 0);
+ }
+ }
+ }
}
if (TREE_CODE (fun) != FUNCTION_DECL)
{
if (is_ubsan_builtin_p (fun))
return void_node;
- if (is_builtin_fn (fun))
+ if (fndecl_built_in_p (fun))
return cxx_eval_builtin_function_call (ctx, t, fun,
lval, non_constant_p, overflow_p);
if (!DECL_DECLARED_CONSTEXPR_P (fun))
If we don't already have one in CTX, use the AGGR_INIT_EXPR_SLOT. */
new_ctx.object = AGGR_INIT_EXPR_SLOT (t);
tree ctor = new_ctx.ctor = build_constructor (DECL_CONTEXT (fun), NULL);
- CONSTRUCTOR_NO_IMPLICIT_ZERO (ctor) = true;
+ CONSTRUCTOR_NO_CLEARING (ctor) = true;
ctx->values->put (new_ctx.object, ctor);
ctx = &new_ctx;
}
constexpr_call *entry = NULL;
if (depth_ok && !non_constant_args && ctx->strict)
{
- new_call.hash = iterative_hash_template_arg
- (new_call.bindings, constexpr_fundef_hasher::hash (new_call.fundef));
+ new_call.hash = constexpr_fundef_hasher::hash (new_call.fundef);
+ new_call.hash
+ = iterative_hash_template_arg (new_call.bindings, new_call.hash);
+ 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 ();
{
if (!ctx->quiet)
error ("%<constexpr%> evaluation depth exceeds maximum of %d (use "
- "-fconstexpr-depth= to increase the maximum)",
+ "%<-fconstexpr-depth=%> to increase the maximum)",
max_constexpr_depth);
*non_constant_p = true;
result = error_mark_node;
bool
reduced_constant_expression_p (tree t)
{
+ if (t == NULL_TREE)
+ return false;
+
switch (TREE_CODE (t))
{
case PTRMEM_CST:
case CONSTRUCTOR:
/* And we need to handle PTRMEM_CST wrapped in a CONSTRUCTOR. */
tree idx, val, field; unsigned HOST_WIDE_INT i;
- if (CONSTRUCTOR_NO_IMPLICIT_ZERO (t))
- field = next_initializable_field (TYPE_FIELDS (TREE_TYPE (t)));
+ if (CONSTRUCTOR_NO_CLEARING (t))
+ {
+ if (TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
+ /* An initialized vector would have a VECTOR_CST. */
+ return false;
+ else
+ field = next_initializable_field (TYPE_FIELDS (TREE_TYPE (t)));
+ }
else
field = NULL_TREE;
FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t), i, idx, val)
{
- if (!val)
- /* We're in the middle of initializing this element. */
- return false;
+ /* If VAL is null, we're in the middle of initializing this
+ element. */
if (!reduced_constant_expression_p (val))
return false;
if (field)
}
if (field)
return false;
- else if (CONSTRUCTOR_NO_IMPLICIT_ZERO (t))
+ else if (CONSTRUCTOR_NO_CLEARING (t))
/* All the fields are initialized. */
- CONSTRUCTOR_NO_IMPLICIT_ZERO (t) = false;
+ CONSTRUCTOR_NO_CLEARING (t) = false;
return true;
default:
}
/* Some expressions may have constant operands but are not constant
- themselves, such as 1/0. Call this function (or rather, the macro
- following it) to check for that condition.
+ themselves, such as 1/0. Call this function to check for that
+ condition.
We only call this in places that require an arithmetic constant, not in
places where we might have a non-constant expression that can be a
if E1 has a signed type and non-negative value, and E1x2^E2 is
representable in the corresponding unsigned type of the result type,
then that value, converted to the result type, is the resulting value;
- otherwise, the behavior is undefined. */
- if (code == LSHIFT_EXPR && !TYPE_UNSIGNED (lhstype)
- && (cxx_dialect >= cxx11))
+ otherwise, the behavior is undefined.
+ For C++2a:
+ The value of E1 << E2 is the unique value congruent to E1 x 2^E2 modulo
+ 2^N, where N is the range exponent of the type of the result. */
+ if (code == LSHIFT_EXPR
+ && !TYPE_UNSIGNED (lhstype)
+ && cxx_dialect >= cxx11
+ && cxx_dialect < cxx2a)
{
if (tree_int_cst_sgn (lhs) == -1)
{
if (TREE_CODE (lhs) == PTRMEM_CST
&& TREE_CODE (rhs) == PTRMEM_CST)
- r = constant_boolean_node (cp_tree_equal (lhs, rhs) == is_code_eq,
- type);
+ {
+ tree lmem = PTRMEM_CST_MEMBER (lhs);
+ tree rmem = PTRMEM_CST_MEMBER (rhs);
+ bool eq;
+ if (TREE_CODE (lmem) == TREE_CODE (rmem)
+ && TREE_CODE (lmem) == FIELD_DECL
+ && TREE_CODE (DECL_CONTEXT (lmem)) == UNION_TYPE
+ && same_type_p (DECL_CONTEXT (lmem),
+ DECL_CONTEXT (rmem)))
+ /* If both refer to (possibly different) members of the same union
+ (12.3), they compare equal. */
+ eq = true;
+ else
+ eq = cp_tree_equal (lhs, rhs);
+ r = constant_boolean_node (eq == is_code_eq, type);
+ }
else if ((TREE_CODE (lhs) == PTRMEM_CST
|| TREE_CODE (rhs) == PTRMEM_CST)
&& (null_member_pointer_value_p (lhs)
{
if (!ctx->quiet)
error ("arithmetic involving a null pointer in %qE", lhs);
+ *non_constant_p = true;
return t;
}
else if (code == POINTER_PLUS_EXPR)
*non_constant_p = true;
/* Don't VERIFY_CONSTANT if this might be dealing with a pointer to
a local array in a constexpr function. */
- bool ptr = POINTER_TYPE_P (TREE_TYPE (lhs));
+ bool ptr = INDIRECT_TYPE_P (TREE_TYPE (lhs));
if (!ptr)
VERIFY_CONSTANT (r);
return r;
if none. If INSERT is true, insert a matching element rather than fail. */
static HOST_WIDE_INT
-find_array_ctor_elt (tree ary, tree dindex, bool insert = false)
+find_array_ctor_elt (tree ary, tree dindex, bool insert)
{
if (tree_int_cst_sgn (dindex) < 0)
return -1;
that the same is true of the other elements and index directly. */
if (end > 0)
{
- tree cindex = (*elts)[end-1].index;
+ tree cindex = (*elts)[end - 1].index;
if (TREE_CODE (cindex) == INTEGER_CST
- && compare_tree_int (cindex, end-1) == 0)
+ && compare_tree_int (cindex, end - 1) == 0)
{
if (i < end)
return i;
constructor_elt e;
tree lo = TREE_OPERAND (idx, 0);
tree hi = TREE_OPERAND (idx, 1);
+ tree value = elt.value;
+ dindex = fold_convert (sizetype, dindex);
if (tree_int_cst_lt (lo, dindex))
{
/* There are still some lower elts; shorten the range. */
/* Append the element we want to insert. */
++middle;
e.index = dindex;
- e.value = unshare_constructor (elt.value);
+ e.value = unshare_constructor (value);
vec_safe_insert (CONSTRUCTOR_ELTS (ary), middle, e);
}
else
e.index = hi;
else
e.index = build2 (RANGE_EXPR, sizetype, new_lo, hi);
- e.value = unshare_constructor (elt.value);
- vec_safe_insert (CONSTRUCTOR_ELTS (ary), middle+1, e);
+ e.value = unshare_constructor (value);
+ vec_safe_insert (CONSTRUCTOR_ELTS (ary), middle + 1, e);
}
}
return middle;
tree sidx = fold_convert (ssizetype, index);
if (DECL_P (array))
{
- error ("array subscript value %qE is outside the bounds "
- "of array %qD of type %qT", sidx, array, arraytype);
+ if (TYPE_DOMAIN (arraytype))
+ error ("array subscript value %qE is outside the bounds "
+ "of array %qD of type %qT", sidx, array, arraytype);
+ else
+ error ("non-zero array subscript %qE is used with array %qD of "
+ "type %qT with unknown bounds", sidx, array, arraytype);
inform (DECL_SOURCE_LOCATION (array), "declared here");
}
- else
+ else if (TYPE_DOMAIN (arraytype))
error ("array subscript value %qE is outside the bounds "
"of array type %qT", sidx, arraytype);
+ else
+ error ("non-zero array subscript %qE is used with array of type %qT "
+ "with unknown bounds", sidx, arraytype);
}
}
+/* Return the number of elements for TYPE (which is an ARRAY_TYPE or
+ a VECTOR_TYPE). */
+
+static tree
+get_array_or_vector_nelts (const constexpr_ctx *ctx, tree type,
+ bool *non_constant_p, bool *overflow_p)
+{
+ tree nelts;
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ if (TYPE_DOMAIN (type))
+ nelts = array_type_nelts_top (type);
+ else
+ nelts = size_zero_node;
+ }
+ else if (VECTOR_TYPE_P (type))
+ nelts = size_int (TYPE_VECTOR_SUBPARTS (type));
+ else
+ gcc_unreachable ();
+
+ /* For VLAs, the number of elements won't be an integer constant. */
+ nelts = cxx_eval_constant_expression (ctx, nelts, false,
+ non_constant_p, overflow_p);
+ return nelts;
+}
+
/* Extract element INDEX consisting of CHARS_PER_ELT chars from
STRING_CST STRING. */
}
}
- tree nelts;
- if (TREE_CODE (TREE_TYPE (ary)) == ARRAY_TYPE)
- nelts = array_type_nelts_top (TREE_TYPE (ary));
- else if (VECTOR_TYPE_P (TREE_TYPE (ary)))
- nelts = size_int (TYPE_VECTOR_SUBPARTS (TREE_TYPE (ary)));
- else
- gcc_unreachable ();
-
- /* For VLAs, the number of elements won't be an integer constant. */
- nelts = cxx_eval_constant_expression (ctx, nelts, false, non_constant_p,
- overflow_p);
+ tree nelts = get_array_or_vector_nelts (ctx, TREE_TYPE (ary), non_constant_p,
+ overflow_p);
VERIFY_CONSTANT (nelts);
if ((lval
? !tree_int_cst_le (index, nelts)
/* Not found. */
if (TREE_CODE (ary) == CONSTRUCTOR
- && CONSTRUCTOR_NO_IMPLICIT_ZERO (ary))
+ && CONSTRUCTOR_NO_CLEARING (ary))
{
/* 'ary' is part of the aggregate initializer we're currently
building; if there's no initializer for this element yet,
tree whole = cxx_eval_constant_expression (ctx, orig_whole,
lval,
non_constant_p, overflow_p);
- if (TREE_CODE (whole) == INDIRECT_REF
- && integer_zerop (TREE_OPERAND (whole, 0))
- && !ctx->quiet)
- error ("dereferencing a null pointer in %qE", orig_whole);
+ if (INDIRECT_REF_P (whole)
+ && integer_zerop (TREE_OPERAND (whole, 0)))
+ {
+ if (!ctx->quiet)
+ error ("dereferencing a null pointer in %qE", orig_whole);
+ *non_constant_p = true;
+ return t;
+ }
if (TREE_CODE (whole) == PTRMEM_CST)
whole = cplus_expand_constant (whole);
gcc_assert (DECL_CONTEXT (part) == TYPE_MAIN_VARIANT (TREE_TYPE (whole)));
- if (CONSTRUCTOR_NO_IMPLICIT_ZERO (whole))
+ if (CONSTRUCTOR_NO_CLEARING (whole))
{
/* 'whole' is part of the aggregate initializer we're currently
building; if there's no initializer for this member yet, that's an
{
if (TYPE_P (t))
return t;
- tree type = cv_unqualified (TREE_TYPE (t));
- if (TREE_CODE (t) == CALL_EXPR || TREE_CODE (t) == AGGR_INIT_EXPR)
+ tree type = TREE_TYPE (t);
+ if (!VOID_TYPE_P (type))
+ /* No need to look deeper. */;
+ else if (TREE_CODE (t) == CALL_EXPR)
{
/* A constructor call has void type, so we need to look deeper. */
tree fn = get_function_named_in_call (t);
&& DECL_CXX_CONSTRUCTOR_P (fn))
type = DECL_CONTEXT (fn);
}
- return type;
+ else if (TREE_CODE (t) == AGGR_INIT_EXPR)
+ type = TREE_TYPE (AGGR_INIT_EXPR_SLOT (t));
+ return cv_unqualified (type);
}
/* We're about to initialize element INDEX of an array or class from VALUE.
if (ctx->object)
new_ctx.object = build_ctor_subob_ref (index, type, ctx->object);
tree elt = build_constructor (type, NULL);
- CONSTRUCTOR_NO_IMPLICIT_ZERO (elt) = true;
+ CONSTRUCTOR_NO_CLEARING (elt) = true;
new_ctx.ctor = elt;
if (TREE_CODE (value) == TARGET_EXPR)
gcc_assert (is_empty_class (TREE_TYPE (TREE_TYPE (index))));
changed = true;
}
- else if (new_ctx.ctor != ctx->ctor)
+ else
{
- /* We appended this element above; update the value. */
- gcc_assert ((*p)->last().index == index);
- (*p)->last().value = elt;
+ if (new_ctx.ctor != ctx->ctor)
+ {
+ /* We appended this element above; update the value. */
+ gcc_assert ((*p)->last().index == index);
+ (*p)->last().value = elt;
+ }
+ else
+ CONSTRUCTOR_APPEND_ELT (*p, index, elt);
+ /* Adding or replacing an element might change the ctor's flags. */
+ TREE_CONSTANT (ctx->ctor) = constant_p;
+ TREE_SIDE_EFFECTS (ctx->ctor) = side_effects_p;
}
- else
- CONSTRUCTOR_APPEND_ELT (*p, index, elt);
}
if (*non_constant_p || !changed)
return t;
t = ctx->ctor;
/* We're done building this CONSTRUCTOR, so now we can interpret an
element without an explicit initializer as value-initialized. */
- CONSTRUCTOR_NO_IMPLICIT_ZERO (t) = false;
+ CONSTRUCTOR_NO_CLEARING (t) = false;
TREE_CONSTANT (t) = constant_p;
TREE_SIDE_EFFECTS (t) = side_effects_p;
if (VECTOR_TYPE_P (type))
bool *non_constant_p, bool *overflow_p)
{
tree elttype = TREE_TYPE (atype);
- unsigned HOST_WIDE_INT max = tree_to_uhwi (array_type_nelts_top (atype));
verify_ctor_sanity (ctx, atype);
vec<constructor_elt, va_gc> **p = &CONSTRUCTOR_ELTS (ctx->ctor);
- vec_alloc (*p, max + 1);
bool pre_init = false;
unsigned HOST_WIDE_INT i;
+ tsubst_flags_t complain = ctx->quiet ? tf_none : tf_warning_or_error;
/* For the default constructor, build up a call to the default
constructor of the element type. We only need to handle class types
/* We only do this at the lowest level. */;
else if (value_init)
{
- init = build_value_init (elttype, tf_warning_or_error);
+ init = build_value_init (elttype, complain);
pre_init = true;
}
else if (!init)
vec<tree, va_gc> *argvec = make_tree_vector ();
init = build_special_member_call (NULL_TREE, complete_ctor_identifier,
&argvec, elttype, LOOKUP_NORMAL,
- tf_warning_or_error);
+ complain);
release_tree_vector (argvec);
- init = build_aggr_init_expr (TREE_TYPE (init), init);
+ init = build_aggr_init_expr (elttype, init);
pre_init = true;
}
+ tree nelts = get_array_or_vector_nelts (ctx, atype, non_constant_p,
+ overflow_p);
+ unsigned HOST_WIDE_INT max = tree_to_uhwi (nelts);
for (i = 0; i < max; ++i)
{
tree idx = build_int_cst (size_type_node, i);
reuse = i == 0;
}
else
- eltinit = cp_build_array_ref (input_location, init, idx,
- tf_warning_or_error);
+ eltinit = cp_build_array_ref (input_location, init, idx, complain);
eltinit = cxx_eval_vec_init_1 (&new_ctx, elttype, eltinit, value_init,
lval,
non_constant_p, overflow_p);
{
/* Initializing an element using value or default initialization
we just pre-built above. */
+ if (init == void_node)
+ /* Trivial default-init, don't do anything to the CONSTRUCTOR. */
+ return ctx->ctor;
eltinit = cxx_eval_constant_expression (&new_ctx, init, lval,
non_constant_p, overflow_p);
reuse = i == 0;
/* Copying an element. */
gcc_assert (same_type_ignoring_top_level_qualifiers_p
(atype, TREE_TYPE (init)));
- eltinit = cp_build_array_ref (input_location, init, idx,
- tf_warning_or_error);
+ eltinit = cp_build_array_ref (input_location, init, idx, complain);
if (!lvalue_p (init))
eltinit = move (eltinit);
- eltinit = force_rvalue (eltinit, tf_warning_or_error);
- eltinit = (cxx_eval_constant_expression
- (&new_ctx, eltinit, lval,
- non_constant_p, overflow_p));
+ eltinit = force_rvalue (eltinit, complain);
+ eltinit = cxx_eval_constant_expression (&new_ctx, eltinit, lval,
+ non_constant_p, overflow_p);
}
if (*non_constant_p && !ctx->quiet)
break;
else
CONSTRUCTOR_APPEND_ELT (*p, idx, eltinit);
/* Reuse the result of cxx_eval_constant_expression call
- from the first iteration to all others if it is a constant
- initializer that doesn't require relocations. */
+ from the first iteration to all others if it is a constant
+ initializer that doesn't require relocations. */
if (reuse
&& max > 1
- && (initializer_constant_valid_p (eltinit, TREE_TYPE (eltinit))
- == null_pointer_node))
+ && (eltinit == NULL_TREE
+ || (initializer_constant_valid_p (eltinit, TREE_TYPE (eltinit))
+ == null_pointer_node)))
{
if (new_ctx.ctor != ctx->ctor)
eltinit = new_ctx.ctor;
- for (i = 1; i < max; ++i)
- {
- idx = build_int_cst (size_type_node, i);
- CONSTRUCTOR_APPEND_ELT (*p, idx, unshare_constructor (eltinit));
- }
+ tree range = build2 (RANGE_EXPR, size_type_node,
+ build_int_cst (size_type_node, 1),
+ build_int_cst (size_type_node, max - 1));
+ CONSTRUCTOR_APPEND_ELT (*p, range, unshare_constructor (eltinit));
break;
}
+ else if (i == 0)
+ vec_safe_reserve (*p, max);
}
if (!*non_constant_p)
{
init = ctx->ctor;
- CONSTRUCTOR_NO_IMPLICIT_ZERO (init) = false;
+ CONSTRUCTOR_NO_CLEARING (init) = false;
}
return init;
}
return r;
}
+/* Like same_type_ignoring_top_level_qualifiers_p, but also handle the case
+ where the desired type is an array of unknown bounds because the variable
+ has had its bounds deduced since the wrapping expression was created. */
+
+static bool
+same_type_ignoring_tlq_and_bounds_p (tree type1, tree type2)
+{
+ while (TREE_CODE (type1) == ARRAY_TYPE
+ && TREE_CODE (type2) == ARRAY_TYPE
+ && (!TYPE_DOMAIN (type1) || !TYPE_DOMAIN (type2)))
+ {
+ type1 = TREE_TYPE (type1);
+ type2 = TREE_TYPE (type2);
+ }
+ return same_type_ignoring_top_level_qualifiers_p (type1, type2);
+}
+
/* A less strict version of fold_indirect_ref_1, which requires cv-quals to
match. We want to be less strict for simple *& folding; if we have a
non-const temporary that we access through a const pointer, that should
static tree
cxx_fold_indirect_ref (location_t loc, tree type, tree op0, bool *empty_base)
{
- tree sub, subtype;
+ tree sub = op0;
+ tree subtype;
+ poly_uint64 const_op01;
- sub = op0;
STRIP_NOPS (sub);
subtype = TREE_TYPE (sub);
- if (!POINTER_TYPE_P (subtype))
+ if (!INDIRECT_TYPE_P (subtype))
return NULL_TREE;
if (TREE_CODE (sub) == ADDR_EXPR)
if (TREE_CODE (op) == CONST_DECL)
return DECL_INITIAL (op);
/* *&p => p; make sure to handle *&"str"[cst] here. */
- if (same_type_ignoring_top_level_qualifiers_p (optype, type)
- /* Also handle the case where the desired type is an array of unknown
- bounds because the variable has had its bounds deduced since the
- ADDR_EXPR was created. */
- || (TREE_CODE (type) == ARRAY_TYPE
- && TREE_CODE (optype) == ARRAY_TYPE
- && TYPE_DOMAIN (type) == NULL_TREE
- && same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (optype),
- TREE_TYPE (type))))
+ if (same_type_ignoring_tlq_and_bounds_p (optype, type))
{
tree fop = fold_read_from_constant_string (op);
if (fop)
{
tree part_width = TYPE_SIZE (type);
tree index = bitsize_int (0);
- return fold_build3_loc (loc, BIT_FIELD_REF, type, op, part_width, index);
+ return fold_build3_loc (loc, BIT_FIELD_REF, type, op, part_width,
+ index);
}
/* Also handle conversion to an empty base class, which
is represented with a NOP_EXPR. */
}
}
else if (TREE_CODE (sub) == POINTER_PLUS_EXPR
- && TREE_CODE (TREE_OPERAND (sub, 1)) == INTEGER_CST)
+ && poly_int_tree_p (TREE_OPERAND (sub, 1), &const_op01))
{
tree op00 = TREE_OPERAND (sub, 0);
tree op01 = TREE_OPERAND (sub, 1);
/* ((foo*)&vectorfoo)[1] => BIT_FIELD_REF<vectorfoo,...> */
if (VECTOR_TYPE_P (op00type)
- && (same_type_ignoring_top_level_qualifiers_p
- (type, TREE_TYPE (op00type))))
+ && same_type_ignoring_top_level_qualifiers_p
+ (type, TREE_TYPE (op00type))
+ /* POINTER_PLUS_EXPR second operand is sizetype, unsigned,
+ but we want to treat offsets with MSB set as negative.
+ For the code below negative offsets are invalid and
+ TYPE_SIZE of the element is something unsigned, so
+ check whether op01 fits into poly_int64, which implies
+ it is from 0 to INTTYPE_MAXIMUM (HOST_WIDE_INT), and
+ then just use poly_uint64 because we want to treat the
+ value as unsigned. */
+ && tree_fits_poly_int64_p (op01))
{
- HOST_WIDE_INT offset = tree_to_shwi (op01);
tree part_width = TYPE_SIZE (type);
- unsigned HOST_WIDE_INT part_widthi = tree_to_shwi (part_width)/BITS_PER_UNIT;
- unsigned HOST_WIDE_INT indexi = offset * BITS_PER_UNIT;
- tree index = bitsize_int (indexi);
-
- if (known_lt (offset / part_widthi,
- TYPE_VECTOR_SUBPARTS (op00type)))
- return fold_build3_loc (loc,
- BIT_FIELD_REF, type, op00,
- part_width, index);
-
+ poly_uint64 max_offset
+ = (tree_to_uhwi (part_width) / BITS_PER_UNIT
+ * TYPE_VECTOR_SUBPARTS (op00type));
+ if (known_lt (const_op01, max_offset))
+ {
+ tree index = bitsize_int (const_op01 * BITS_PER_UNIT);
+ return fold_build3_loc (loc,
+ BIT_FIELD_REF, type, op00,
+ part_width, index);
+ }
}
/* ((foo*)&complexfoo)[1] => __imag__ complexfoo */
else if (TREE_CODE (op00type) == COMPLEX_TYPE
&& (same_type_ignoring_top_level_qualifiers_p
(type, TREE_TYPE (op00type))))
{
- tree size = TYPE_SIZE_UNIT (type);
- if (tree_int_cst_equal (size, op01))
+ if (known_eq (wi::to_poly_offset (TYPE_SIZE_UNIT (type)),
+ const_op01))
return fold_build1_loc (loc, IMAGPART_EXPR, type, op00);
}
/* ((foo *)&fooarray)[1] => fooarray[1] */
tree min_val = size_zero_node;
if (type_domain && TYPE_MIN_VALUE (type_domain))
min_val = TYPE_MIN_VALUE (type_domain);
- op01 = size_binop_loc (loc, EXACT_DIV_EXPR, op01,
- TYPE_SIZE_UNIT (type));
- op01 = size_binop_loc (loc, PLUS_EXPR, op01, min_val);
- return build4_loc (loc, ARRAY_REF, type, op00, op01,
- NULL_TREE, NULL_TREE);
+ offset_int off = wi::to_offset (op01);
+ offset_int el_sz = wi::to_offset (TYPE_SIZE_UNIT (type));
+ offset_int remainder;
+ off = wi::divmod_trunc (off, el_sz, SIGNED, &remainder);
+ if (remainder == 0 && TREE_CODE (min_val) == INTEGER_CST)
+ {
+ off = off + wi::to_offset (min_val);
+ op01 = wide_int_to_tree (sizetype, off);
+ return build4_loc (loc, ARRAY_REF, type, op00, op01,
+ NULL_TREE, NULL_TREE);
+ }
}
/* Also handle conversion to an empty base class, which
is represented with a NOP_EXPR. */
{
tree type_domain;
tree min_val = size_zero_node;
- tree newsub = cxx_fold_indirect_ref (loc, TREE_TYPE (subtype), sub, NULL);
+ tree newsub
+ = cxx_fold_indirect_ref (loc, TREE_TYPE (subtype), sub, NULL);
if (newsub)
sub = newsub;
else
else
gcc_unreachable ();
}
- else if (TREE_CODE (type) == REFERENCE_TYPE)
+ else if (TYPE_REF_P (type))
inform (DECL_SOURCE_LOCATION (r),
"%qD was not initialized with a constant "
"expression", r);
case ARRAY_REF:
tree nelts, ary;
ary = TREE_OPERAND (probe, 0);
- if (TREE_CODE (TREE_TYPE (ary)) == ARRAY_TYPE)
- nelts = array_type_nelts_top (TREE_TYPE (ary));
- else if (VECTOR_TYPE_P (TREE_TYPE (ary)))
- nelts = size_int (TYPE_VECTOR_SUBPARTS (TREE_TYPE (ary)));
- else
- gcc_unreachable ();
- nelts = cxx_eval_constant_expression (ctx, nelts, false,
- non_constant_p, overflow_p);
+ nelts = get_array_or_vector_nelts (ctx, TREE_TYPE (ary),
+ non_constant_p, overflow_p);
VERIFY_CONSTANT (nelts);
gcc_assert (TREE_CODE (nelts) == INTEGER_CST
&& TREE_CODE (TREE_OPERAND (probe, 1)) == INTEGER_CST);
if (*valp == NULL_TREE)
{
*valp = build_constructor (type, NULL);
- CONSTRUCTOR_NO_IMPLICIT_ZERO (*valp) = no_zero_init;
+ CONSTRUCTOR_NO_CLEARING (*valp) = no_zero_init;
}
else if (TREE_CODE (*valp) == STRING_CST)
{
/* If the value of object is already zero-initialized, any new ctors for
subobjects will also be zero-initialized. */
- no_zero_init = CONSTRUCTOR_NO_IMPLICIT_ZERO (*valp);
+ no_zero_init = CONSTRUCTOR_NO_CLEARING (*valp);
vec_safe_push (ctors, *valp);
if (*valp == NULL_TREE)
{
*valp = build_constructor (type, NULL);
- CONSTRUCTOR_NO_IMPLICIT_ZERO (*valp) = no_zero_init;
+ CONSTRUCTOR_NO_CLEARING (*valp) = no_zero_init;
}
else if (TREE_CODE (*valp) == PTRMEM_CST)
*valp = cplus_expand_constant (*valp);
CONSTRUCTOR_ELTS (*valp) = CONSTRUCTOR_ELTS (init);
TREE_CONSTANT (*valp) = TREE_CONSTANT (init);
TREE_SIDE_EFFECTS (*valp) = TREE_SIDE_EFFECTS (init);
- CONSTRUCTOR_NO_IMPLICIT_ZERO (*valp)
- = CONSTRUCTOR_NO_IMPLICIT_ZERO (init);
+ CONSTRUCTOR_NO_CLEARING (*valp)
+ = CONSTRUCTOR_NO_CLEARING (init);
}
else
*valp = init;
non_constant_p, overflow_p);
/* Don't VERIFY_CONSTANT if this might be dealing with a pointer to
a local array in a constexpr function. */
- bool ptr = POINTER_TYPE_P (TREE_TYPE (val));
+ bool ptr = INDIRECT_TYPE_P (TREE_TYPE (val));
if (!ptr)
VERIFY_CONSTANT (val);
/* The modified value. */
bool inc = (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR);
tree mod;
- if (POINTER_TYPE_P (type))
+ if (INDIRECT_TYPE_P (type))
{
/* The middle end requires pointers to use POINTER_PLUS_EXPR. */
offset = convert_to_ptrofftype (offset);
return *jump_target
&& ((TREE_CODE (*jump_target) == LABEL_DECL
&& LABEL_DECL_BREAK (*jump_target))
+ || TREE_CODE (*jump_target) == BREAK_STMT
|| TREE_CODE (*jump_target) == EXIT_EXPR);
}
continues (tree *jump_target)
{
return *jump_target
- && TREE_CODE (*jump_target) == LABEL_DECL
- && LABEL_DECL_CONTINUE (*jump_target);
+ && ((TREE_CODE (*jump_target) == LABEL_DECL
+ && LABEL_DECL_CONTINUE (*jump_target))
+ || TREE_CODE (*jump_target) == CONTINUE_STMT);
+
}
static bool
for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
{
tree stmt = tsi_stmt (i);
+ /* We've found a continue, so skip everything until we reach
+ the label its jumping to. */
+ if (continues (jump_target))
+ {
+ if (label_matches (ctx, jump_target, stmt))
+ /* Found it. */
+ *jump_target = NULL_TREE;
+ else
+ continue;
+ }
if (TREE_CODE (stmt) == DEBUG_BEGIN_STMT)
continue;
r = cxx_eval_constant_expression (ctx, stmt, false,
if (++count >= constexpr_loop_limit)
{
if (!ctx->quiet)
- error_at (EXPR_LOC_OR_LOC (t, input_location),
+ error_at (cp_expr_loc_or_loc (t, input_location),
"%<constexpr%> loop iteration count exceeds limit of %d "
"(use -fconstexpr-loop-limit= to increase the limit)",
constexpr_loop_limit);
cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
bool lval,
bool *non_constant_p, bool *overflow_p,
- tree *jump_target)
+ tree *jump_target /* = NULL */)
{
constexpr_ctx new_ctx;
tree r = t;
return NULL_TREE;
}
}
- if (t == error_mark_node)
+ if (error_operand_p (t))
{
*non_constant_p = true;
return t;
}
if (TREE_CODE (t) == INTEGER_CST
- && TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE
+ && TYPE_PTR_P (TREE_TYPE (t))
&& !integer_zerop (t))
{
if (!ctx->quiet)
/* We ask for an rvalue for the RESULT_DECL when indirecting
through an invisible reference, or in named return value
optimization. */
- return (*ctx->values->get (t));
+ if (tree *p = ctx->values->get (t))
+ return *p;
+ else
+ {
+ if (!ctx->quiet)
+ error ("%qE is not a constant expression", t);
+ *non_constant_p = true;
+ }
+ break;
case VAR_DECL:
if (DECL_HAS_VALUE_EXPR_P (t))
CONST_DECL for aggregate constants. */
if (lval)
return t;
+ /* is_really_empty_class doesn't take into account _vptr, so initializing
+ otherwise empty class with { } would overwrite the initializer that
+ initialize_vtable created for us. */
if (COMPLETE_TYPE_P (TREE_TYPE (t))
+ && !TYPE_POLYMORPHIC_P (TREE_TYPE (t))
&& is_really_empty_class (TREE_TYPE (t)))
{
/* If the class is empty, we aren't actually loading anything. */
return t;
case PARM_DECL:
- if (lval && TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE)
+ if (lval && !TYPE_REF_P (TREE_TYPE (t)))
/* glvalue use. */;
else if (tree *p = ctx->values->get (r))
r = *p;
else if (lval)
/* Defer in case this is only used for its type. */;
- else if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE)
+ else if (TYPE_REF_P (TREE_TYPE (t)))
/* Defer, there's no lvalue->rvalue conversion. */;
else if (COMPLETE_TYPE_P (TREE_TYPE (t))
&& is_really_empty_class (TREE_TYPE (t)))
new_ctx = *ctx;
new_ctx.object = r;
new_ctx.ctor = build_constructor (TREE_TYPE (r), NULL);
- CONSTRUCTOR_NO_IMPLICIT_ZERO (new_ctx.ctor) = true;
+ CONSTRUCTOR_NO_CLEARING (new_ctx.ctor) = true;
new_ctx.values->put (r, new_ctx.ctor);
ctx = &new_ctx;
}
{
if (!ctx->quiet)
{
+ auto_diagnostic_group d;
error ("temporary of non-literal type %qT in a "
"constant expression", TREE_TYPE (t));
explain_non_literal_class (TREE_TYPE (t));
strips the TARGET_EXPR before we get here. */
new_ctx = *ctx;
new_ctx.ctor = build_constructor (TREE_TYPE (t), NULL);
- CONSTRUCTOR_NO_IMPLICIT_ZERO (new_ctx.ctor) = true;
+ CONSTRUCTOR_NO_CLEARING (new_ctx.ctor) = true;
new_ctx.object = TARGET_EXPR_SLOT (t);
ctx->values->put (new_ctx.object, new_ctx.ctor);
ctx = &new_ctx;
r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
lval,
non_constant_p, overflow_p);
- *jump_target = t;
+ if (jump_target)
+ *jump_target = t;
+ else
+ {
+ /* Can happen with ({ return true; }) && false; passed to
+ maybe_constant_value. There is nothing to jump over in this
+ case, and the bug will be diagnosed later. */
+ gcc_assert (ctx->quiet);
+ *non_constant_p = true;
+ }
break;
case SAVE_EXPR:
case FLOAT_EXPR:
case NEGATE_EXPR:
case ABS_EXPR:
+ case ABSU_EXPR:
case BIT_NOT_EXPR:
case TRUTH_NOT_EXPR:
case FIXED_CONVERT_EXPR:
break;
case CONSTRUCTOR:
- if (TREE_CONSTANT (t))
+ if (TREE_CONSTANT (t) && reduced_constant_expression_p (t))
{
/* Don't re-process a constant CONSTRUCTOR, but do fold it to
VECTOR_CST if applicable. */
- /* FIXME after GCC 6 branches, make the verify unconditional. */
- if (CHECKING_P)
- verify_constructor_flags (t);
- else
- recompute_constructor_flags (t);
+ verify_constructor_flags (t);
if (TREE_CONSTANT (t))
return fold (t);
}
non_constant_p, overflow_p);
break;
- case FMA_EXPR:
case VEC_PERM_EXPR:
r = cxx_eval_trinary_expression (ctx, t, lval,
non_constant_p, overflow_p);
break;
+ case NOP_EXPR:
+ if (REINTERPRET_CAST_P (t))
+ {
+ if (!ctx->quiet)
+ error_at (cp_expr_loc_or_loc (t, input_location),
+ "a reinterpret_cast is not a constant expression");
+ *non_constant_p = true;
+ return t;
+ }
+ /* FALLTHROUGH. */
case CONVERT_EXPR:
case VIEW_CONVERT_EXPR:
- case NOP_EXPR:
case UNARY_PLUS_EXPR:
{
tree oldop = TREE_OPERAND (t, 0);
if (TREE_CODE (op) == PTRMEM_CST
&& !TYPE_PTRMEM_P (type))
op = cplus_expand_constant (op);
+
if (TREE_CODE (op) == PTRMEM_CST && tcode == NOP_EXPR)
{
- if (same_type_ignoring_top_level_qualifiers_p (type,
- TREE_TYPE (op))
- || can_convert_qual (type, op))
- return cp_fold_convert (type, op);
- else
- {
- if (!ctx->quiet)
- error_at (EXPR_LOC_OR_LOC (t, input_location),
- "a reinterpret_cast is not a constant expression");
- *non_constant_p = true;
- return t;
- }
+ if (!same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (op))
+ && !can_convert_qual (type, op))
+ op = cplus_expand_constant (op);
+ return cp_fold_convert (type, op);
}
- if (POINTER_TYPE_P (type) && TREE_CODE (op) == INTEGER_CST)
+ if (INDIRECT_TYPE_P (type) && TREE_CODE (op) == INTEGER_CST)
{
if (integer_zerop (op))
{
- if (TREE_CODE (type) == REFERENCE_TYPE)
+ if (TYPE_REF_P (type))
{
if (!ctx->quiet)
- error_at (EXPR_LOC_OR_LOC (t, input_location),
+ error_at (cp_expr_loc_or_loc (t, input_location),
"dereferencing a null pointer");
*non_constant_p = true;
return t;
}
- else if (TREE_CODE (TREE_TYPE (op)) == POINTER_TYPE)
+ else if (TYPE_PTR_P (TREE_TYPE (op)))
{
tree from = TREE_TYPE (op);
if (!can_convert (type, from, tf_none))
{
if (!ctx->quiet)
- error_at (EXPR_LOC_OR_LOC (t, input_location),
+ error_at (cp_expr_loc_or_loc (t, input_location),
"conversion of %qT null pointer to %qT "
"is not a constant expression",
from, type);
reinterpret_cast<void*>(sizeof 0)
*/
if (!ctx->quiet)
- error_at (EXPR_LOC_OR_LOC (t, input_location),
+ error_at (cp_expr_loc_or_loc (t, input_location),
"%<reinterpret_cast<%T>(%E)%> is not "
"a constant expression",
type, op);
return t;
}
}
+
if (op == oldop && tcode != UNARY_PLUS_EXPR)
/* We didn't fold at the top so we could check for ptr-int
conversion. */
return fold (t);
- if (tcode == UNARY_PLUS_EXPR)
+
+ /* Handle an array's bounds having been deduced after we built
+ the wrapping expression. */
+ if (same_type_ignoring_tlq_and_bounds_p (type, TREE_TYPE (op)))
+ r = op;
+ else if (tcode == UNARY_PLUS_EXPR)
r = fold_convert (TREE_TYPE (t), op);
else
r = fold_build1 (tcode, type, op);
+
/* Conversion of an out-of-range value has implementation-defined
behavior; the language considers it different from arithmetic
overflow, which is undefined. */
case MODOP_EXPR:
/* GCC internal stuff. */
case VA_ARG_EXPR:
- case OBJ_TYPE_REF:
case NON_DEPENDENT_EXPR:
case BASELINK:
case OFFSET_REF:
if (!ctx->quiet)
- error_at (EXPR_LOC_OR_LOC (t, input_location),
+ error_at (cp_expr_loc_or_loc (t, input_location),
"expression %qE is not a constant expression", t);
*non_constant_p = true;
break;
+ case OBJ_TYPE_REF:
+ {
+ /* Virtual function call. Let the constexpr machinery figure out
+ the dynamic type. */
+ int token = tree_to_shwi (OBJ_TYPE_REF_TOKEN (t));
+ tree obj = OBJ_TYPE_REF_OBJECT (t);
+ obj = cxx_eval_constant_expression (ctx, obj, lval, non_constant_p,
+ overflow_p);
+ /* We expect something in the form of &x.D.2103.D.2094; get x. */
+ if (TREE_CODE (obj) != ADDR_EXPR
+ || !DECL_P (get_base_address (TREE_OPERAND (obj, 0))))
+ {
+ if (!ctx->quiet)
+ error_at (cp_expr_loc_or_loc (t, input_location),
+ "expression %qE is not a constant expression", t);
+ *non_constant_p = true;
+ return t;
+ }
+ obj = TREE_OPERAND (obj, 0);
+ while (TREE_CODE (obj) == COMPONENT_REF
+ && DECL_FIELD_IS_BASE (TREE_OPERAND (obj, 1)))
+ obj = TREE_OPERAND (obj, 0);
+ tree objtype = TREE_TYPE (obj);
+ /* Find the function decl in the virtual functions list. TOKEN is
+ the DECL_VINDEX that says which function we're looking for. */
+ tree virtuals = BINFO_VIRTUALS (TYPE_BINFO (objtype));
+ if (TARGET_VTABLE_USES_DESCRIPTORS)
+ token /= MAX (TARGET_VTABLE_USES_DESCRIPTORS, 1);
+ r = TREE_VALUE (chain_index (token, virtuals));
+ break;
+ }
+
case PLACEHOLDER_EXPR:
/* Use of the value or address of the current object. */
if (tree ctor = lookup_placeholder (ctx, lval, TREE_TYPE (t)))
jump_target);
break;
+ case USING_STMT:
+ r = void_node;
+ break;
+
default:
if (STATEMENT_CODE_P (TREE_CODE (t)))
{
return r;
}
+/* P0859: A function is needed for constant evaluation if it is a constexpr
+ function that is named by an expression ([basic.def.odr]) that is
+ potentially constant evaluated.
+
+ So we need to instantiate any constexpr functions mentioned by the
+ expression even if the definition isn't needed for evaluating the
+ expression. */
+
+static tree
+instantiate_cx_fn_r (tree *tp, int *walk_subtrees, void */*data*/)
+{
+ if (TREE_CODE (*tp) == FUNCTION_DECL
+ && DECL_DECLARED_CONSTEXPR_P (*tp)
+ && !DECL_INITIAL (*tp)
+ && !trivial_fn_p (*tp)
+ && DECL_TEMPLOID_INSTANTIATION (*tp))
+ {
+ ++function_depth;
+ instantiate_decl (*tp, /*defer_ok*/false, /*expl_inst*/false);
+ --function_depth;
+ }
+ else if (TREE_CODE (*tp) == CALL_EXPR
+ || TREE_CODE (*tp) == AGGR_INIT_EXPR)
+ {
+ if (EXPR_HAS_LOCATION (*tp))
+ input_location = EXPR_LOCATION (*tp);
+ }
+
+ if (!EXPR_P (*tp))
+ *walk_subtrees = 0;
+
+ return NULL_TREE;
+}
+static void
+instantiate_constexpr_fns (tree t)
+{
+ location_t loc = input_location;
+ cp_walk_tree_without_duplicates (&t, instantiate_cx_fn_r, NULL);
+ input_location = loc;
+}
+
+/* ALLOW_NON_CONSTANT is false if T is required to be a constant expression.
+ 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.
+ 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, tree object = NULL_TREE)
+ bool strict = true,
+ bool manifestly_const_eval = false,
+ tree object = NULL_TREE)
{
auto_timevar time (TV_CONSTEXPR);
hash_map<tree,tree> map;
constexpr_ctx ctx = { NULL, &map, NULL, NULL, NULL, NULL,
- allow_non_constant, strict };
+ allow_non_constant, strict,
+ manifestly_const_eval || !allow_non_constant };
tree type = initialized_type (t);
tree r = t;
for C++11 constexpr constructors that refer to the object being
initialized. */
ctx.ctor = build_constructor (type, NULL);
- CONSTRUCTOR_NO_IMPLICIT_ZERO (ctx.ctor) = true;
+ CONSTRUCTOR_NO_CLEARING (ctx.ctor) = true;
if (!object)
{
if (TREE_CODE (t) == TARGET_EXPR)
r = TARGET_EXPR_INITIAL (r);
}
+ instantiate_constexpr_fns (r);
r = cxx_eval_constant_expression (&ctx, r,
false, &non_constant_p, &overflow_p);
}
if (TREE_CODE (r) == CONSTRUCTOR
- && CONSTRUCTOR_NO_IMPLICIT_ZERO (r))
+ && CONSTRUCTOR_NO_CLEARING (r))
{
if (!allow_non_constant)
error ("%qE is not a constant expression because it refers to "
return error_mark_node;
else if (non_constant_p && TREE_CONSTANT (r))
{
- /* This isn't actually constant, so unset TREE_CONSTANT. */
- if (EXPR_P (r))
+ /* If __builtin_is_constant_evaluated () was evaluated to true
+ and the result is not a valid constant expression, we need to
+ punt. */
+ if (manifestly_const_eval)
+ return cxx_eval_outermost_constant_expr (t, true, strict,
+ false, object);
+ /* This isn't actually constant, so unset TREE_CONSTANT.
+ 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
+ a valid C++ constant expression. Wrap it with a NOP_EXPR
+ instead. */
+ if (EXPR_P (r) && TREE_CODE (r) != ADDR_EXPR)
r = copy_node (r);
else if (TREE_CODE (r) == CONSTRUCTOR)
r = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (r), r);
r = build_nop (TREE_TYPE (r), r);
TREE_CONSTANT (r) = false;
}
- else if (non_constant_p || r == t)
+ else if (non_constant_p)
return t;
if (should_unshare)
if (TREE_CODE (r) == CONSTRUCTOR && CLASS_TYPE_P (TREE_TYPE (r)))
{
+ r = adjust_temp_type (type, r);
if (TREE_CODE (t) == TARGET_EXPR
&& TARGET_EXPR_INITIAL (t) == r)
return t;
- else
+ else if (TREE_CODE (t) != CONSTRUCTOR)
{
r = get_target_expr (r);
TREE_CONSTANT (r) = true;
- return r;
}
}
- else
- return r;
+
+ return r;
}
/* Returns true if T is a valid subexpression of a constant expression,
bool overflow_p = false;
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);
cxx_eval_constant_expression (&ctx, t, false, &non_constant_p,
&overflow_p);
return !non_constant_p && !overflow_p;
tree
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
return fold_sizeof_expr (t);
case ABS_EXPR:
+ case ABSU_EXPR:
case CONJ_EXPR:
case REALPART_EXPR:
case IMAGPART_EXPR:
/* 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<tree, tree> *cv_cache;
tree
-maybe_constant_value (tree t, tree decl)
+maybe_constant_value (tree t, tree decl, bool manifestly_const_eval)
{
tree r;
/* 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<tree, tree>::create_ggc (101);
if (tree *cached = cv_cache->get (t))
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
|| CONVERT_EXPR_P (t)
|| TREE_CODE (t) == VIEW_CONVERT_EXPR
/* Like maybe_constant_value but first fully instantiate the argument.
Note: this is equivalent to instantiate_non_dependent_expr_sfinae
- (t, tf_none) followed by maybe_constant_value but is more efficient,
- because calls instantiation_dependent_expression_p and
- potential_constant_expression at most once. */
+ (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
+ tf_warning_or_error. Callers that might be within a template context, don't
+ have a complain parameter, and aren't going to remember the result for long
+ (e.g. null_ptr_cst_p), can pass tf_none and deal with error_mark_node
+ appropriately. */
tree
-fold_non_dependent_expr (tree t)
+fold_non_dependent_expr (tree t,
+ tsubst_flags_t complain /* = tf_warning_or_error */,
+ bool manifestly_const_eval /* = false */)
{
if (t == NULL_TREE)
return NULL_TREE;
if (is_nondependent_constant_expression (t))
{
processing_template_decl_sentinel s;
- t = instantiate_non_dependent_expr_internal (t, tf_none);
+ t = instantiate_non_dependent_expr_internal (t, complain);
if (type_unknown_p (t)
|| BRACE_ENCLOSED_INITIALIZER_P (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,
+ manifestly_const_eval,
+ NULL_TREE);
/* cp_tree_equal looks through NOPs, so allow them. */
gcc_checking_assert (r == t
|| CONVERT_EXPR_P (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
- 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.
+ MANIFESTLY_CONST_EVAL is true if T is manifestly const-evaluated as
+ per P0595 even when ALLOW_NON_CONSTANT is true. */
-tree
-maybe_constant_init (tree t, tree decl)
+static tree
+maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant,
+ bool manifestly_const_eval)
{
if (!t)
return t;
t = TARGET_EXPR_INITIAL (t);
if (!is_nondependent_static_init_expression (t))
/* Don't try to evaluate it. */;
- else if (CONSTANT_CLASS_P (t))
+ else if (CONSTANT_CLASS_P (t) && allow_non_constant)
/* No evaluation needed. */;
else
- t = cxx_eval_outermost_constant_expr (t, true, false, decl);
+ t = cxx_eval_outermost_constant_expr (t, allow_non_constant,
+ /*strict*/false,
+ manifestly_const_eval, decl);
if (TREE_CODE (t) == TARGET_EXPR)
{
tree init = TARGET_EXPR_INITIAL (t);
return t;
}
+/* Wrapper for maybe_constant_init_1 which permits non constants. */
+
+tree
+maybe_constant_init (tree t, tree decl, bool manifestly_const_eval)
+{
+ return maybe_constant_init_1 (t, decl, true, manifestly_const_eval);
+}
+
+/* Wrapper for maybe_constant_init_1 which does not permit non constants. */
+
+tree
+cxx_constant_init (tree t, tree decl)
+{
+ return maybe_constant_init_1 (t, decl, false, true);
+}
+
#if 0
/* FIXME see ADDR_EXPR section in potential_constant_expression_1. */
/* Return true if the object referred to by REF has automatic or thread
static bool
potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
- tsubst_flags_t flags)
+ tsubst_flags_t flags, tree *jump_target)
{
#define RECUR(T,RV) \
- potential_constant_expression_1 ((T), (RV), strict, now, flags)
+ potential_constant_expression_1 ((T), (RV), strict, now, flags, jump_target)
enum { any = false, rval = true };
int i;
return false;
if (t == NULL_TREE)
return true;
- location_t loc = EXPR_LOC_OR_LOC (t, input_location);
- if (TREE_THIS_VOLATILE (t) && !DECL_P (t))
+ location_t loc = cp_expr_loc_or_loc (t, input_location);
+
+ if (*jump_target)
+ /* If we are jumping, ignore everything. This is simpler than the
+ cxx_eval_constant_expression handling because we only need to be
+ conservatively correct, and we don't necessarily have a constant value
+ available, so we don't bother with switch tracking. */
+ return true;
+
+ if (TREE_THIS_VOLATILE (t) && want_rval)
{
if (flags & tf_error)
- error_at (loc, "expression %qE has side-effects", t);
+ error_at (loc, "lvalue-to-rvalue conversion of a volatile lvalue "
+ "%qE with type %qT", t, TREE_TYPE (t));
return false;
}
if (CONSTANT_CLASS_P (t))
case USING_DECL:
case USING_STMT:
case PLACEHOLDER_EXPR:
- case BREAK_STMT:
- case CONTINUE_STMT:
case REQUIRES_EXPR:
case STATIC_ASSERT:
case DEBUG_BEGIN_STMT:
return true;
+ case RETURN_EXPR:
+ if (!RECUR (TREE_OPERAND (t, 0), any))
+ return false;
+ /* FALLTHROUGH */
+
+ case BREAK_STMT:
+ case CONTINUE_STMT:
+ *jump_target = t;
+ return true;
+
case PARM_DECL:
if (now)
{
case IFN_SUB_OVERFLOW:
case IFN_MUL_OVERFLOW:
case IFN_LAUNDER:
+ case IFN_VEC_CONVERT:
bail = false;
+ break;
default:
break;
if (!DECL_DECLARED_CONSTEXPR_P (fun)
/* Allow any built-in function; if the expansion
isn't constant, we'll deal with that then. */
- && !is_builtin_fn (fun))
+ && !fndecl_built_in_p (fun))
{
if (flags & tf_error)
{
constexpr substitution might not use the value. */
bool sub_now = false;
if (!potential_constant_expression_1 (x, rval, strict,
- sub_now, flags))
+ sub_now, flags,
+ jump_target))
return false;
i = 1;
}
substitution might not use the value of the argument. */
bool sub_now = false;
if (!potential_constant_expression_1 (x, rv, strict,
- sub_now, flags))
+ sub_now, flags, jump_target))
return false;
}
return true;
may change to something more specific to type-punning (DR 1312). */
{
tree from = TREE_OPERAND (t, 0);
- if (POINTER_TYPE_P (TREE_TYPE (t))
- && TREE_CODE (from) == INTEGER_CST
- && !integer_zerop (from))
+ if (location_wrapper_p (t))
+ return (RECUR (from, want_rval));
+ if (INDIRECT_TYPE_P (TREE_TYPE (t)))
{
- if (flags & tf_error)
- error_at (loc, "reinterpret_cast from integer to pointer");
- return false;
+ STRIP_ANY_LOCATION_WRAPPER (from);
+ if (TREE_CODE (from) == INTEGER_CST
+ && !integer_zerop (from))
+ {
+ if (flags & tf_error)
+ error_at (loc, "reinterpret_cast from integer to pointer");
+ return false;
+ }
}
return (RECUR (from, TREE_CODE (t) != VIEW_CONVERT_EXPR));
}
return false;
if (!RECUR (DO_BODY (t), any))
return false;
+ if (breaks (jump_target) || continues (jump_target))
+ *jump_target = NULL_TREE;
return true;
case FOR_STMT:
if (!RECUR (FOR_INIT_STMT (t), any))
return false;
- if (!RECUR (FOR_COND (t), rval))
+ tmp = FOR_COND (t);
+ if (!RECUR (tmp, rval))
return false;
+ if (tmp)
+ {
+ if (!processing_template_decl)
+ tmp = cxx_eval_outermost_constant_expr (tmp, true);
+ /* If we couldn't evaluate the condition, it might not ever be
+ true. */
+ if (!integer_onep (tmp))
+ return true;
+ }
if (!RECUR (FOR_EXPR (t), any))
return false;
if (!RECUR (FOR_BODY (t), any))
return false;
+ if (breaks (jump_target) || continues (jump_target))
+ *jump_target = NULL_TREE;
return true;
case RANGE_FOR_STMT:
+ if (!RECUR (RANGE_FOR_INIT_STMT (t), any))
+ return false;
if (!RECUR (RANGE_FOR_EXPR (t), any))
return false;
if (!RECUR (RANGE_FOR_BODY (t), any))
return false;
+ if (breaks (jump_target) || continues (jump_target))
+ *jump_target = NULL_TREE;
return true;
case WHILE_STMT:
- if (!RECUR (WHILE_COND (t), rval))
+ tmp = WHILE_COND (t);
+ if (!RECUR (tmp, rval))
return false;
+ if (!processing_template_decl)
+ tmp = cxx_eval_outermost_constant_expr (tmp, true);
+ /* If we couldn't evaluate the condition, it might not ever be true. */
+ if (!integer_onep (tmp))
+ return true;
if (!RECUR (WHILE_BODY (t), any))
return false;
+ if (breaks (jump_target) || continues (jump_target))
+ *jump_target = NULL_TREE;
return true;
case SWITCH_STMT:
case OMP_PARALLEL:
case OMP_TASK:
case OMP_FOR:
+ case OMP_SIMD:
case OMP_DISTRIBUTE:
case OMP_TASKLOOP:
case OMP_TEAMS:
case OMP_ATOMIC_READ:
case OMP_ATOMIC_CAPTURE_OLD:
case OMP_ATOMIC_CAPTURE_NEW:
+ case OMP_DEPOBJ:
case OACC_PARALLEL:
case OACC_KERNELS:
case OACC_DATA:
case OACC_UPDATE:
/* GCC internal stuff. */
case VA_ARG_EXPR:
- case OBJ_TYPE_REF:
case TRANSACTION_EXPR:
case ASM_EXPR:
case AT_ENCODE_EXPR:
error_at (loc, "expression %qE is not a constant expression", t);
return false;
+ case OBJ_TYPE_REF:
+ if (cxx_dialect >= cxx2a)
+ /* In C++2a virtual calls can be constexpr, don't give up yet. */
+ return true;
+ else if (flags & tf_error)
+ error_at (loc, "virtual functions cannot be constexpr before C++2a");
+ return false;
+
case TYPEID_EXPR:
/* -- a typeid expression whose operand is of polymorphic
class type; */
case FLOAT_EXPR:
case NEGATE_EXPR:
case ABS_EXPR:
+ case ABSU_EXPR:
case TRUTH_NOT_EXPR:
case FIXED_CONVERT_EXPR:
case UNARY_PLUS_EXPR:
TREE_TYPE (t));
return false;
}
+ /* This might be a conversion from a class to a (potentially) literal
+ type. Let's consider it potentially constant since the conversion
+ might be a constexpr user-defined conversion. */
+ else if (cxx_dialect >= cxx11
+ && (dependent_type_p (TREE_TYPE (t))
+ || !COMPLETE_TYPE_P (TREE_TYPE (t))
+ || literal_type_p (TREE_TYPE (t)))
+ && TREE_OPERAND (t, 0))
+ {
+ tree type = TREE_TYPE (TREE_OPERAND (t, 0));
+ /* If this is a dependent type, it could end up being a class
+ with conversions. */
+ if (type == NULL_TREE || WILDCARD_TYPE_P (type))
+ return true;
+ /* Or a non-dependent class which has conversions. */
+ else if (CLASS_TYPE_P (type)
+ && (TYPE_HAS_CONVERSION (type) || dependent_scope_p (type)))
+ return true;
+ }
return (RECUR (TREE_OPERAND (t, 0),
- TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE));
+ !TYPE_REF_P (TREE_TYPE (t))));
case BIND_EXPR:
return RECUR (BIND_EXPR_BODY (t), want_rval);
case PAREN_EXPR:
case NON_DEPENDENT_EXPR:
/* For convenience. */
- case RETURN_EXPR:
case LOOP_EXPR:
case EXIT_EXPR:
return RECUR (TREE_OPERAND (t, 0), want_rval);
{
if (flags & tf_error)
{
+ auto_diagnostic_group d;
error_at (loc, "temporary of non-literal type %qT in a "
"constant expression", TREE_TYPE (t));
explain_non_literal_class (TREE_TYPE (t));
return false;
return true;
- case FMA_EXPR:
case VEC_PERM_EXPR:
for (i = 0; i < 3; ++i)
if (!RECUR (TREE_OPERAND (t, i), true))
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, strict, now, tf_none))
+ want_rval, strict, now,
+ tf_none, jump_target))
return true;
if (flags & tf_error)
error_at (loc, "expression %qE is not a constant expression", t);
tree *target = &TREE_OPERAND (t, 0);
/* Gotos representing break and continue are OK. */
if (breaks (target) || continues (target))
- return true;
+ {
+ *jump_target = *target;
+ return true;
+ }
if (flags & tf_error)
error_at (loc, "%<goto%> is not a constant expression");
return false;
#undef RECUR
}
+bool
+potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
+ tsubst_flags_t flags)
+{
+ tree target = NULL_TREE;
+ return potential_constant_expression_1 (t, want_rval, strict, now,
+ flags, &target);
+}
+
/* The main entry point to the above. */
bool
bool
require_potential_constant_expression (tree t)
{
- return potential_constant_expression_1 (t, false, true, false, tf_warning_or_error);
+ return potential_constant_expression_1 (t, false, true, false,
+ tf_warning_or_error);
}
/* Cross product of the above. */
bool
require_potential_rvalue_constant_expression (tree t)
{
- return potential_constant_expression_1 (t, true, true, false, tf_warning_or_error);
+ return potential_constant_expression_1 (t, true, true, false,
+ tf_warning_or_error);
+}
+
+/* Like above, but don't consider PARM_DECL a potential_constant_expression. */
+
+bool
+require_rvalue_constant_expression (tree t)
+{
+ return potential_constant_expression_1 (t, true, true, true,
+ tf_warning_or_error);
}
/* Like potential_constant_expression, but don't consider possible constexpr