matching constructor_elt exists, then add one to CTOR.
As an optimization, if POS_HINT is non-negative then it is used as a guess
- for the (integer) index of the matching constructor_elt within CTOR. */
+ for the (integer) index of the matching constructor_elt within CTOR.
+
+ If POS_HINT is -2, it means do not insert. */
static constructor_elt *
get_or_insert_ctor_field (tree ctor, tree index, int pos_hint = -1)
&& CONSTRUCTOR_ELT (ctor, pos_hint)->index == index)
return CONSTRUCTOR_ELT (ctor, pos_hint);
+ bool insertp = (pos_hint != -2);
tree type = TREE_TYPE (ctor);
if (TREE_CODE (type) == VECTOR_TYPE && index == NULL_TREE)
{
+ gcc_assert (insertp);
CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (ctor), index, NULL_TREE);
return &CONSTRUCTOR_ELTS (ctor)->last();
}
tree lo = TREE_OPERAND (index, 0);
gcc_assert (array_index_cmp (elts->last().index, lo) < 0);
}
+ gcc_assert (insertp);
CONSTRUCTOR_APPEND_ELT (elts, index, NULL_TREE);
return &elts->last();
}
- HOST_WIDE_INT i = find_array_ctor_elt (ctor, index, /*insert*/true);
- gcc_assert (i >= 0);
+ HOST_WIDE_INT i = find_array_ctor_elt (ctor, index, insertp);
+ if (i < 0)
+ {
+ gcc_assert (!insertp);
+ return nullptr;
+ }
constructor_elt *cep = CONSTRUCTOR_ELT (ctor, i);
+ if (!insertp && cep->index && TREE_CODE (cep->index) == RANGE_EXPR)
+ {
+ /* Split a range even if we aren't inserting new entries. */
+ gcc_assert (!insertp);
+ i = find_array_ctor_elt (ctor, index, /*insert*/true);
+ gcc_assert (i >= 0);
+ cep = CONSTRUCTOR_ELT (ctor, i);
+ }
gcc_assert (cep->index == NULL_TREE
|| TREE_CODE (cep->index) != RANGE_EXPR);
return cep;
entry at the end. */
insert:
+ if (!insertp)
+ return nullptr;
+
{
constructor_elt ce = { index, NULL_TREE };
if (pmf ? DECL_NAME (field) == DECL_NAME (part)
: field == part)
{
+ if (value == void_node)
+ goto uninit;
if (value)
{
STRIP_ANY_LOCATION_WRAPPER (value);
if (CONSTRUCTOR_NO_CLEARING (whole))
{
+ uninit:
/* 'whole' is part of the aggregate initializer we're currently
building; if there's no initializer for this member yet, that's an
error. */
/* If we're modifying a const object, save it. */
tree const_object_being_modified = NULL_TREE;
bool mutable_p = false;
+ /* If we see a union, we can't ignore clobbers. */
+ int seen_union = 0;
for (tree probe = target; object == NULL_TREE; )
{
switch (TREE_CODE (probe))
vec_safe_push (refs, elt);
vec_safe_push (refs, TREE_TYPE (probe));
probe = ob;
+ if (TREE_CODE (TREE_TYPE (ob)) == UNION_TYPE)
+ ++seen_union;
}
break;
}
/* Handle explicit end-of-lifetime. */
- if (TREE_CLOBBER_P (init)
- && CLOBBER_KIND (init) >= CLOBBER_OBJECT_END)
+ if (TREE_CLOBBER_P (init))
{
- if (refs->is_empty ())
+ if (CLOBBER_KIND (init) >= CLOBBER_OBJECT_END
+ && refs->is_empty ())
{
ctx->global->destroy_value (object);
return void_node;
}
+ if (!seen_union && !*valp
+ && CLOBBER_KIND (init) < CLOBBER_OBJECT_END)
+ return void_node;
+
/* Ending the lifetime of a const object is OK. */
const_object_being_modified = NULL_TREE;
}
ctors.safe_push (valp);
vec_safe_push (indexes, index);
+ /* Avoid adding an _elt for a clobber when the whole CONSTRUCTOR is
+ uninitialized. */
+ int pos = (!seen_union && TREE_CLOBBER_P (init)
+ && CONSTRUCTOR_NO_CLEARING (*valp)
+ && CLOBBER_KIND (init) < CLOBBER_OBJECT_END) ? -2 : -1;
constructor_elt *cep
- = get_or_insert_ctor_field (*valp, index);
+ = get_or_insert_ctor_field (*valp, index, pos);
+ if (cep == nullptr)
+ return void_node;
index_pos_hints.safe_push (cep - CONSTRUCTOR_ELTS (*valp)->begin());
if (code == UNION_TYPE)
- activated_union_member_p = true;
+ {
+ activated_union_member_p = true;
+ --seen_union;
+ }
valp = &cep->value;
type = reftype;
value_cat lval = vc_discard;
/* The result of a statement-expression is not wrapped in EXPR_STMT. */
- if (tsi_one_before_end_p (i) && TREE_CODE (stmt) != EXPR_STMT)
+ if (tsi_one_before_end_p (i)
+ && !VOID_TYPE_P (TREE_TYPE (stmt)))
lval = vc_prvalue;
r = cxx_eval_constant_expression (ctx, stmt, lval,
*jump_target = NULL_TREE;
if (expr)
- cxx_eval_constant_expression (ctx, expr, vc_prvalue,
+ cxx_eval_constant_expression (ctx, expr, vc_discard,
non_constant_p, overflow_p,
jump_target);
cleanup_cond ();
if (TREE_CONSTANT (t))
return t;
}
+ if (TREE_CLOBBER_P (t))
+ {
+ /* Assignment from a clobber is handled in cxx_eval_store_expression;
+ a clobber by itself isn't a constant-expression. */
+ gcc_assert (ctx->quiet);
+ *non_constant_p = true;
+ break;
+ }
r = cxx_eval_bare_aggregate (ctx, t, lval,
non_constant_p, overflow_p, jump_target);
break;
if (r == error_mark_node)
*non_constant_p = true;
+ if (r == void_node && lval != vc_discard && !*jump_target
+ && !VOID_TYPE_P (TREE_TYPE (t)))
+ {
+ /* For diagnostic quality we should have handled this sooner, where we
+ can be more specific about the out-of-lifetime object. But here we
+ can still be correct. */
+ gcc_checking_assert (false);
+ if (!ctx->quiet)
+ error_at (EXPR_LOCATION (t),
+ "%qE accesses an object outside its lifetime", t);
+ *non_constant_p = true;
+ }
+
if (*non_constant_p)
return t;
else
&& (now || !var_in_maybe_constexpr_fn (t))
&& !type_dependent_expression_p (t)
&& !decl_maybe_constant_var_p (t)
+ && !is_local_temp (t)
&& (strict
|| !CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (t))
|| (DECL_INITIAL (t)
void warn_new ()
{
- T (int32_t, 0, 0); // { dg-warning "array subscript 0 is outside array bounds of 'int32_t \\\[0]'" }
+ T (int32_t, 0, 0); // { dg-warning "array subscript 0 is outside array bounds" }
// { dg-message "object of size \\d allocated by '\[^\n\r]*operator new\[^\n\r]*'" "note" { target *-*-* } .-1 }
T (int32_t, 1, 0); // { dg-warning "array subscript 'int32_t {aka (long )?int}\\\[0]' is partly outside array bounds of 'unsigned char \\\[1]'" }
T (int32_t, 2, 0); // { dg-warning "array subscript 'int32_t {aka (long )?int}\\\[0]' is partly outside array bounds of 'unsigned char \\\[2]'" }
#undef NEW
#define NEW(n) new char [n]
- T (int32_t, 0, 0); // { dg-warning "array subscript 0 is outside array bounds of 'int32_t \\\[0]'" }
+ T (int32_t, 0, 0); // { dg-warning "array subscript 0 is outside array bounds" }
// { dg-message "object of size \\d allocated by '\[^\n\r]*operator new\[^\n\r]*'" "note" { target *-*-* } .-1 }
T (int32_t, 1, 0); // { dg-warning "array subscript 'int32_t {aka (long )?int}\\\[0]' is partly outside array bounds of 'unsigned char \\\[1]'" }
T (int32_t, 2, 0); // { dg-warning "array subscript 'int32_t {aka (long )?int}\\\[0]' is partly outside array bounds of 'unsigned char \\\[2]'" }
T (int32_t, 4, 0);
- T (int32_t, 0, 1); // { dg-warning "array subscript 1 is outside array bounds of 'int32_t \\\[0]'" }
+ T (int32_t, 0, 1); // { dg-warning "array subscript 1 is outside array bounds" }
T (int32_t, 1, 1); // { dg-warning "array subscript 1 is outside array bounds " }
T (int32_t, 2, 1); // { dg-warning "array subscript 1 is outside array bounds " }
T (int32_t, 3, 1); // { dg-warning "array subscript 1 is outside array bounds " }