aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2014-10-27 13:42:12 -0400
committerJason Merrill <jason@gcc.gnu.org>2014-10-27 13:42:12 -0400
commit3e605b20a0c804d57d4be0f4f2bbab8b4e42fce6 (patch)
treeac2bca0b20f76ea658c7bbcb7dda73ababce83b9 /gcc/cp
parentddc8de034a1f79861fed57b231813a5c5c48a130 (diff)
downloadgcc-3e605b20a0c804d57d4be0f4f2bbab8b4e42fce6.zip
gcc-3e605b20a0c804d57d4be0f4f2bbab8b4e42fce6.tar.gz
gcc-3e605b20a0c804d57d4be0f4f2bbab8b4e42fce6.tar.bz2
Implement N3653 (Member initializers and aggregates) and fix references to 'this' in constexpr constructors.
Implement N3653 (Member initializers and aggregates) and fix references to 'this' in constexpr constructors. * class.c (check_field_decls): In C++14 an NSDMI does not make the class non-aggregate. * constexpr.c (struct constexpr_ctx): New. (cxx_bind_parameters_in_call): Handle 'this'. (cxx_eval_call_expression): Create new constexpr_ctx. (cxx_eval_component_reference): Check CONSTRUCTOR_NO_IMPLICIT_ZERO. (initialized_type, init_subob_ctx, verify_ctor_sanity): New. (cxx_eval_bare_aggregate): Use them. Build CONSTRUCTOR early. (cxx_eval_vec_init_1): Likewise. (cxx_eval_constant_expression) [PARM_DECL]: Allow 'this'. [TARGET_EXPR]: Build new constexpr_ctx. [PLACEHOLDER_EXPR]: New. (cxx_eval_outermost_constant_expr): Build new constexpr_ctx. Add object parameter. (is_sub_constant_expr): Build new constexpr_ctx. (potential_constant_expression_1): Handle PLACEHOLDER_EXPR. Allow 'this'. * cp-gimplify.c (cp_gimplify_init_expr): Call replace_placeholders. * cp-tree.h (CONSTRUCTOR_NO_IMPLICIT_ZERO): New. * error.c (dump_expr): Handle PLACEHOLDER_EXPR. * init.c (get_nsdmi): Generate PLACEHOLDER_EXPR. * tree.c (lvalue_kind): Handle PLACEHOLDER_EXPR. (build_ctor_subob_ref, replace_placeholders): New. * typeck2.c (store_init_value): Use replace_placeholders. (process_init_constructor_record): Make zero-init before NSDMI explicit. From-SVN: r216750
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog31
-rw-r--r--gcc/cp/class.c4
-rw-r--r--gcc/cp/constexpr.c512
-rw-r--r--gcc/cp/cp-gimplify.c4
-rw-r--r--gcc/cp/cp-tree.h14
-rw-r--r--gcc/cp/error.c4
-rw-r--r--gcc/cp/init.c11
-rw-r--r--gcc/cp/tree.c98
-rw-r--r--gcc/cp/typeck2.c39
9 files changed, 535 insertions, 182 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 39c03d6..90e69a3 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,34 @@
+2014-10-24 Jason Merrill <jason@redhat.com>
+
+ Implement N3653 (Member initializers and aggregates) and fix
+ references to 'this' in constexpr constructors.
+ * class.c (check_field_decls): In C++14 an NSDMI does not make the
+ class non-aggregate.
+ * constexpr.c (struct constexpr_ctx): New.
+ (cxx_bind_parameters_in_call): Handle 'this'.
+ (cxx_eval_call_expression): Create new constexpr_ctx.
+ (cxx_eval_component_reference): Check CONSTRUCTOR_NO_IMPLICIT_ZERO.
+ (initialized_type, init_subob_ctx, verify_ctor_sanity): New.
+ (cxx_eval_bare_aggregate): Use them. Build CONSTRUCTOR early.
+ (cxx_eval_vec_init_1): Likewise.
+ (cxx_eval_constant_expression) [PARM_DECL]: Allow 'this'.
+ [TARGET_EXPR]: Build new constexpr_ctx.
+ [PLACEHOLDER_EXPR]: New.
+ (cxx_eval_outermost_constant_expr): Build new constexpr_ctx. Add
+ object parameter.
+ (is_sub_constant_expr): Build new constexpr_ctx.
+ (potential_constant_expression_1): Handle PLACEHOLDER_EXPR.
+ Allow 'this'.
+ * cp-gimplify.c (cp_gimplify_init_expr): Call replace_placeholders.
+ * cp-tree.h (CONSTRUCTOR_NO_IMPLICIT_ZERO): New.
+ * error.c (dump_expr): Handle PLACEHOLDER_EXPR.
+ * init.c (get_nsdmi): Generate PLACEHOLDER_EXPR.
+ * tree.c (lvalue_kind): Handle PLACEHOLDER_EXPR.
+ (build_ctor_subob_ref, replace_placeholders): New.
+ * typeck2.c (store_init_value): Use replace_placeholders.
+ (process_init_constructor_record): Make zero-init before NSDMI
+ explicit.
+
2014-10-27 Andrew MacLeod <amacleod@redhat.com>
* cp-gimplify.c: Adjust include files.
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 99bfa95..5f50aff 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -3659,8 +3659,8 @@ check_field_decls (tree t, tree *access_decls,
/* Now that we've removed bit-field widths from DECL_INITIAL,
anything left in DECL_INITIAL is an NSDMI that makes the class
- non-aggregate. */
- if (DECL_INITIAL (x))
+ non-aggregate in C++11. */
+ if (DECL_INITIAL (x) && cxx_dialect < cxx14)
CLASSTYPE_NON_AGGREGATE (t) = true;
/* If any field is const, the structure type is pseudo-const. */
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 30a5e08..cd10766 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -846,14 +846,26 @@ struct constexpr_call_hasher : ggc_hasher<constexpr_call *>
{
static hashval_t hash (constexpr_call *);
static bool equal (constexpr_call *, constexpr_call *);
- };
+};
+
+/* The constexpr expansion context. CALL is the current function
+ expansion, CTOR is the current aggregate initializer, OBJECT is the
+ object being initialized by CTOR, either a VAR_DECL or a _REF. VALUES
+ is a map of values of variables initialized within the expression. */
+
+struct constexpr_ctx {
+ constexpr_call *call;
+ hash_map<tree,tree> *values;
+ tree ctor;
+ tree object;
+};
/* A table of all constexpr calls that have been evaluated by the
compiler in this translation unit. */
static GTY (()) hash_table<constexpr_call_hasher> *constexpr_call_table;
-static tree cxx_eval_constant_expression (const constexpr_call *, tree,
+static tree cxx_eval_constant_expression (const constexpr_ctx *, tree,
bool, bool, bool *, bool *);
/* Compute a hash value for a constexpr call representation. */
@@ -964,7 +976,7 @@ lookup_parameter_binding (const constexpr_call *call, tree t)
represented by _CST nodes. */
static tree
-cxx_eval_builtin_function_call (const constexpr_call *call, tree t,
+cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t,
bool allow_non_constant, bool addr,
bool *non_constant_p, bool *overflow_p)
{
@@ -974,7 +986,7 @@ cxx_eval_builtin_function_call (const constexpr_call *call, tree t,
int i;
for (i = 0; i < nargs; ++i)
{
- args[i] = cxx_eval_constant_expression (call, CALL_EXPR_ARG (t, i),
+ args[i] = cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, i),
allow_non_constant, addr,
non_constant_p, overflow_p);
if (allow_non_constant && *non_constant_p)
@@ -1006,12 +1018,12 @@ adjust_temp_type (tree type, tree temp)
/* Subroutine of cxx_eval_call_expression.
We are processing a call expression (either CALL_EXPR or
- AGGR_INIT_EXPR) in the call context of OLD_CALL. Evaluate
+ AGGR_INIT_EXPR) in the context of CTX. Evaluate
all arguments and bind their values to correspondings
parameters, making up the NEW_CALL context. */
static void
-cxx_bind_parameters_in_call (const constexpr_call *old_call, tree t,
+cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t,
constexpr_call *new_call,
bool allow_non_constant,
bool *non_constant_p, bool *overflow_p)
@@ -1024,12 +1036,18 @@ cxx_bind_parameters_in_call (const constexpr_call *old_call, tree t,
{
tree x, arg;
tree type = parms ? TREE_TYPE (parms) : void_type_node;
- /* For member function, the first argument is a pointer to the implied
- object. And for an object construction, don't bind `this' before
- it is fully constructed. */
- if (i == 0 && DECL_CONSTRUCTOR_P (fun))
- goto next;
x = get_nth_callarg (t, i);
+ /* For member function, the first argument is a pointer to the implied
+ object. For a constructor, it might still be a dummy object, in
+ which case we get the real argument from ctx or the AGGR_INIT_EXPR. */
+ if (i == 0 && DECL_CONSTRUCTOR_P (fun)
+ && is_dummy_object (x))
+ {
+ x = ctx->object;
+ if (!x)
+ x = AGGR_INIT_EXPR_SLOT (t);
+ x = cp_build_addr_expr (x, tf_warning_or_error);
+ }
if (parms && DECL_BY_REFERENCE (parms))
{
/* cp_genericize made this a reference for argument passing, but
@@ -1039,7 +1057,7 @@ cxx_bind_parameters_in_call (const constexpr_call *old_call, tree t,
type = TREE_TYPE (type);
x = convert_from_reference (x);
}
- arg = cxx_eval_constant_expression (old_call, x, allow_non_constant,
+ arg = cxx_eval_constant_expression (ctx, x, allow_non_constant,
TREE_CODE (type) == REFERENCE_TYPE,
non_constant_p, overflow_p);
/* Don't VERIFY_CONSTANT here. */
@@ -1104,7 +1122,7 @@ cx_error_context (void)
evaluation. */
static tree
-cxx_eval_call_expression (const constexpr_call *old_call, tree t,
+cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
bool allow_non_constant, bool addr,
bool *non_constant_p, bool *overflow_p)
{
@@ -1119,7 +1137,7 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t,
if (TREE_CODE (fun) != FUNCTION_DECL)
{
/* Might be a constexpr function pointer. */
- fun = cxx_eval_constant_expression (old_call, fun, allow_non_constant,
+ fun = cxx_eval_constant_expression (ctx, fun, allow_non_constant,
/*addr*/false, non_constant_p,
overflow_p);
STRIP_NOPS (fun);
@@ -1137,7 +1155,7 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t,
if (DECL_CLONED_FUNCTION_P (fun))
fun = DECL_CLONED_FUNCTION (fun);
if (is_builtin_fn (fun))
- return cxx_eval_builtin_function_call (old_call, t, allow_non_constant,
+ return cxx_eval_builtin_function_call (ctx, t, allow_non_constant,
addr, non_constant_p, overflow_p);
if (!DECL_DECLARED_CONSTEXPR_P (fun))
{
@@ -1156,7 +1174,7 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t,
if (call_expr_nargs (t) == 2)
{
tree arg = convert_from_reference (get_nth_callarg (t, 1));
- return cxx_eval_constant_expression (old_call, arg, allow_non_constant,
+ return cxx_eval_constant_expression (ctx, arg, allow_non_constant,
addr, non_constant_p, overflow_p);
}
else if (TREE_CODE (t) == AGGR_INIT_EXPR
@@ -1165,8 +1183,8 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t,
}
/* If in direct recursive call, optimize definition search. */
- if (old_call != NULL && old_call->fundef->decl == fun)
- new_call.fundef = old_call->fundef;
+ if (ctx && ctx->call && ctx->call->fundef->decl == fun)
+ new_call.fundef = ctx->call->fundef;
else
{
new_call.fundef = retrieve_constexpr_fundef (fun);
@@ -1187,7 +1205,7 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t,
return t;
}
}
- cxx_bind_parameters_in_call (old_call, t, &new_call,
+ cxx_bind_parameters_in_call (ctx, t, &new_call,
allow_non_constant, non_constant_p, overflow_p);
if (*non_constant_p)
return t;
@@ -1232,10 +1250,14 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t,
{
result = entry->result;
if (!result || result == error_mark_node)
- result = (cxx_eval_constant_expression
- (&new_call, new_call.fundef->body,
- allow_non_constant, addr,
- non_constant_p, overflow_p));
+ {
+ constexpr_ctx new_ctx = *ctx;
+ new_ctx.call = &new_call;
+ result = (cxx_eval_constant_expression
+ (&new_ctx, new_call.fundef->body,
+ allow_non_constant, addr,
+ non_constant_p, overflow_p));
+ }
if (result == error_mark_node)
*non_constant_p = true;
if (*non_constant_p)
@@ -1326,13 +1348,13 @@ verify_constant (tree t, bool allow_non_constant, bool *non_constant_p,
and return error_mark_node. */
static tree
-cxx_eval_unary_expression (const constexpr_call *call, tree t,
+cxx_eval_unary_expression (const constexpr_ctx *ctx, tree t,
bool allow_non_constant, bool addr,
bool *non_constant_p, bool *overflow_p)
{
tree r;
tree orig_arg = TREE_OPERAND (t, 0);
- tree arg = cxx_eval_constant_expression (call, orig_arg, allow_non_constant,
+ tree arg = cxx_eval_constant_expression (ctx, orig_arg, allow_non_constant,
addr, non_constant_p, overflow_p);
VERIFY_CONSTANT (arg);
if (arg == orig_arg)
@@ -1346,7 +1368,7 @@ cxx_eval_unary_expression (const constexpr_call *call, tree t,
Like cxx_eval_unary_expression, except for binary expressions. */
static tree
-cxx_eval_binary_expression (const constexpr_call *call, tree t,
+cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t,
bool allow_non_constant, bool addr,
bool *non_constant_p, bool *overflow_p)
{
@@ -1354,11 +1376,11 @@ cxx_eval_binary_expression (const constexpr_call *call, tree t,
tree orig_lhs = TREE_OPERAND (t, 0);
tree orig_rhs = TREE_OPERAND (t, 1);
tree lhs, rhs;
- lhs = cxx_eval_constant_expression (call, orig_lhs,
+ lhs = cxx_eval_constant_expression (ctx, orig_lhs,
allow_non_constant, addr,
non_constant_p, overflow_p);
VERIFY_CONSTANT (lhs);
- rhs = cxx_eval_constant_expression (call, orig_rhs,
+ rhs = cxx_eval_constant_expression (ctx, orig_rhs,
allow_non_constant, addr,
non_constant_p, overflow_p);
VERIFY_CONSTANT (rhs);
@@ -1374,20 +1396,20 @@ cxx_eval_binary_expression (const constexpr_call *call, tree t,
looked into. */
static tree
-cxx_eval_conditional_expression (const constexpr_call *call, tree t,
+cxx_eval_conditional_expression (const constexpr_ctx *ctx, tree t,
bool allow_non_constant, bool addr,
bool *non_constant_p, bool *overflow_p)
{
- tree val = cxx_eval_constant_expression (call, TREE_OPERAND (t, 0),
+ tree val = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
allow_non_constant, addr,
non_constant_p, overflow_p);
VERIFY_CONSTANT (val);
/* Don't VERIFY_CONSTANT the other operands. */
if (integer_zerop (val))
- return cxx_eval_constant_expression (call, TREE_OPERAND (t, 2),
+ return cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 2),
allow_non_constant, addr,
non_constant_p, overflow_p);
- return cxx_eval_constant_expression (call, TREE_OPERAND (t, 1),
+ return cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
allow_non_constant, addr,
non_constant_p, overflow_p);
}
@@ -1396,12 +1418,12 @@ cxx_eval_conditional_expression (const constexpr_call *call, tree t,
Attempt to reduce a reference to an array slot. */
static tree
-cxx_eval_array_reference (const constexpr_call *call, tree t,
+cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
bool allow_non_constant, bool addr,
bool *non_constant_p, bool *overflow_p)
{
tree oldary = TREE_OPERAND (t, 0);
- tree ary = cxx_eval_constant_expression (call, oldary,
+ tree ary = cxx_eval_constant_expression (ctx, oldary,
allow_non_constant, addr,
non_constant_p, overflow_p);
tree index, oldidx;
@@ -1411,7 +1433,7 @@ cxx_eval_array_reference (const constexpr_call *call, tree t,
if (*non_constant_p)
return t;
oldidx = TREE_OPERAND (t, 1);
- index = cxx_eval_constant_expression (call, oldidx,
+ index = cxx_eval_constant_expression (ctx, oldidx,
allow_non_constant, false,
non_constant_p, overflow_p);
VERIFY_CONSTANT (index);
@@ -1442,7 +1464,7 @@ cxx_eval_array_reference (const constexpr_call *call, tree t,
/* If it's within the array bounds but doesn't have an explicit
initializer, it's value-initialized. */
tree val = build_value_init (elem_type, tf_warning_or_error);
- return cxx_eval_constant_expression (call, val,
+ return cxx_eval_constant_expression (ctx, val,
allow_non_constant, addr,
non_constant_p, overflow_p);
}
@@ -1479,7 +1501,7 @@ cxx_eval_array_reference (const constexpr_call *call, tree t,
Attempt to reduce a field access of a value of class type. */
static tree
-cxx_eval_component_reference (const constexpr_call *call, tree t,
+cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
bool allow_non_constant, bool addr,
bool *non_constant_p, bool *overflow_p)
{
@@ -1488,7 +1510,7 @@ cxx_eval_component_reference (const constexpr_call *call, tree t,
tree value;
tree part = TREE_OPERAND (t, 1);
tree orig_whole = TREE_OPERAND (t, 0);
- tree whole = cxx_eval_constant_expression (call, orig_whole,
+ tree whole = cxx_eval_constant_expression (ctx, orig_whole,
allow_non_constant, addr,
non_constant_p, overflow_p);
if (whole == orig_whole)
@@ -1528,9 +1550,20 @@ cxx_eval_component_reference (const constexpr_call *call, tree t,
return t;
}
+ if (CONSTRUCTOR_NO_IMPLICIT_ZERO (whole))
+ {
+ /* '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 (!allow_non_constant)
+ error ("accessing uninitialized member %qD", part);
+ *non_constant_p = true;
+ return t;
+ }
+
/* If there's no explicit init for this field, it's value-initialized. */
value = build_value_init (TREE_TYPE (t), tf_warning_or_error);
- return cxx_eval_constant_expression (call, value,
+ return cxx_eval_constant_expression (ctx, value,
allow_non_constant, addr,
non_constant_p, overflow_p);
}
@@ -1540,7 +1573,7 @@ cxx_eval_component_reference (const constexpr_call *call, tree t,
expressed as a BIT_FIELD_REF. */
static tree
-cxx_eval_bit_field_ref (const constexpr_call *call, tree t,
+cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t,
bool allow_non_constant, bool addr,
bool *non_constant_p, bool *overflow_p)
{
@@ -1548,7 +1581,7 @@ cxx_eval_bit_field_ref (const constexpr_call *call, tree t,
tree retval, fldval, utype, mask;
bool fld_seen = false;
HOST_WIDE_INT istart, isize;
- tree whole = cxx_eval_constant_expression (call, orig_whole,
+ tree whole = cxx_eval_constant_expression (ctx, orig_whole,
allow_non_constant, addr,
non_constant_p, overflow_p);
tree start, field, value;
@@ -1625,20 +1658,20 @@ cxx_eval_bit_field_ref (const constexpr_call *call, tree t,
sanity check purposes. */
static tree
-cxx_eval_logical_expression (const constexpr_call *call, tree t,
+cxx_eval_logical_expression (const constexpr_ctx *ctx, tree t,
tree bailout_value, tree continue_value,
bool allow_non_constant, bool addr,
bool *non_constant_p, bool *overflow_p)
{
tree r;
- tree lhs = cxx_eval_constant_expression (call, TREE_OPERAND (t, 0),
+ tree lhs = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
allow_non_constant, addr,
non_constant_p, overflow_p);
VERIFY_CONSTANT (lhs);
if (tree_int_cst_equal (lhs, bailout_value))
return lhs;
gcc_assert (tree_int_cst_equal (lhs, continue_value));
- r = cxx_eval_constant_expression (call, TREE_OPERAND (t, 1),
+ r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
allow_non_constant, addr, non_constant_p, overflow_p);
VERIFY_CONSTANT (r);
return r;
@@ -1674,59 +1707,153 @@ base_field_constructor_elt (vec<constructor_elt, va_gc> *v, tree ref)
return NULL;
}
+/* Some of the expressions fed to the constexpr mechanism are calls to
+ constructors, which have type void. In that case, return the type being
+ initialized by the constructor. */
+
+static tree
+initialized_type (tree t)
+{
+ 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)
+ {
+ /* A constructor call has void type, so we need to look deeper. */
+ tree fn = get_function_named_in_call (t);
+ if (fn && TREE_CODE (fn) == FUNCTION_DECL
+ && DECL_CXX_CONSTRUCTOR_P (fn))
+ type = DECL_CONTEXT (fn);
+ }
+ return type;
+}
+
+/* We're about to initialize element INDEX of an array or class from VALUE.
+ Set up NEW_CTX appropriately by adjusting .object to refer to the
+ subobject and creating a new CONSTRUCTOR if the element is itself
+ a class or array. */
+
+static void
+init_subob_ctx (const constexpr_ctx *ctx, constexpr_ctx &new_ctx,
+ tree index, tree &value)
+{
+ new_ctx = *ctx;
+
+ if (index && TREE_CODE (index) != INTEGER_CST
+ && TREE_CODE (index) != FIELD_DECL)
+ /* This won't have an element in the new CONSTRUCTOR. */
+ return;
+
+ tree type = initialized_type (value);
+ if (!AGGREGATE_TYPE_P (type) && !VECTOR_TYPE_P (type))
+ /* A non-aggregate member doesn't get its own CONSTRUCTOR. */
+ return;
+
+ /* The sub-aggregate initializer might contain a placeholder;
+ update object to refer to the subobject and ctor to refer to
+ the (newly created) sub-initializer. */
+ 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;
+ new_ctx.ctor = elt;
+
+ if (TREE_CODE (value) == TARGET_EXPR)
+ /* Avoid creating another CONSTRUCTOR when we expand the TARGET_EXPR. */
+ value = TARGET_EXPR_INITIAL (value);
+}
+
+/* We're about to process an initializer for a class or array TYPE. Make
+ sure that CTX is set up appropriately. */
+
+static void
+verify_ctor_sanity (const constexpr_ctx *ctx, tree type)
+{
+ /* We don't bother building a ctor for an empty base subobject. */
+ if (is_empty_class (type))
+ return;
+
+ /* We're in the middle of an initializer that might involve placeholders;
+ our caller should have created a CONSTRUCTOR for us to put the
+ initializer into. We will either return that constructor or T. */
+ gcc_assert (ctx->ctor);
+ gcc_assert (same_type_ignoring_top_level_qualifiers_p
+ (type, TREE_TYPE (ctx->ctor)));
+ gcc_assert (CONSTRUCTOR_NELTS (ctx->ctor) == 0);
+ if (ctx->object)
+ gcc_assert (same_type_ignoring_top_level_qualifiers_p
+ (type, TREE_TYPE (ctx->object)));
+ gcc_assert (!ctx->object || !DECL_P (ctx->object)
+ || *(ctx->values->get (ctx->object)) == ctx->ctor);
+}
+
/* Subroutine of cxx_eval_constant_expression.
The expression tree T denotes a C-style array or a C-style
aggregate. Reduce it to a constant expression. */
static tree
-cxx_eval_bare_aggregate (const constexpr_call *call, tree t,
+cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t,
bool allow_non_constant, bool addr,
bool *non_constant_p, bool *overflow_p)
{
vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (t);
- vec<constructor_elt, va_gc> *n;
- vec_alloc (n, vec_safe_length (v));
- constructor_elt *ce;
- HOST_WIDE_INT i;
bool changed = false;
gcc_assert (!BRACE_ENCLOSED_INITIALIZER_P (t));
- for (i = 0; vec_safe_iterate (v, i, &ce); ++i)
+
+ verify_ctor_sanity (ctx, TREE_TYPE (t));
+ vec<constructor_elt, va_gc> **p = &CONSTRUCTOR_ELTS (ctx->ctor);
+ vec_alloc (*p, vec_safe_length (v));
+
+ unsigned i; tree index, value;
+ FOR_EACH_CONSTRUCTOR_ELT (v, i, index, value)
{
- tree elt = cxx_eval_constant_expression (call, ce->value,
+ constexpr_ctx new_ctx;
+ init_subob_ctx (ctx, new_ctx, index, value);
+ if (new_ctx.ctor != ctx->ctor)
+ /* If we built a new CONSTRUCTOR, attach it now so that other
+ initializers can refer to it. */
+ CONSTRUCTOR_APPEND_ELT (*p, index, new_ctx.ctor);
+ tree elt = cxx_eval_constant_expression (&new_ctx, value,
allow_non_constant, addr,
non_constant_p, overflow_p);
/* Don't VERIFY_CONSTANT here. */
if (allow_non_constant && *non_constant_p)
- goto fail;
- if (elt != ce->value)
+ break;
+ if (elt != value)
changed = true;
- if (ce->index && TREE_CODE (ce->index) == COMPONENT_REF)
+ if (index && TREE_CODE (index) == COMPONENT_REF)
{
/* This is an initialization of a vfield inside a base
subaggregate that we already initialized; push this
initialization into the previous initialization. */
- constructor_elt *inner = base_field_constructor_elt (n, ce->index);
+ constructor_elt *inner = base_field_constructor_elt (*p, index);
inner->value = elt;
+ changed = true;
}
- else if (ce->index
- && (TREE_CODE (ce->index) == NOP_EXPR
- || TREE_CODE (ce->index) == POINTER_PLUS_EXPR))
+ else if (index
+ && (TREE_CODE (index) == NOP_EXPR
+ || TREE_CODE (index) == POINTER_PLUS_EXPR))
{
/* This is an initializer for an empty base; now that we've
checked that it's constant, we can ignore it. */
- gcc_assert (is_empty_class (TREE_TYPE (TREE_TYPE (ce->index))));
+ gcc_assert (is_empty_class (TREE_TYPE (TREE_TYPE (index))));
+ changed = true;
+ }
+ else 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 (n, ce->index, elt);
+ CONSTRUCTOR_APPEND_ELT (*p, index, elt);
}
if (*non_constant_p || !changed)
- {
- fail:
- vec_free (n);
- return t;
- }
- t = build_constructor (TREE_TYPE (t), n);
- TREE_CONSTANT (t) = true;
+ 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;
if (TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
t = fold (t);
return t;
@@ -1745,14 +1872,15 @@ cxx_eval_bare_aggregate (const constexpr_call *call, tree t,
for the copy/move constructor. */
static tree
-cxx_eval_vec_init_1 (const constexpr_call *call, tree atype, tree init,
+cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
bool value_init, bool allow_non_constant, bool addr,
bool *non_constant_p, bool *overflow_p)
{
tree elttype = TREE_TYPE (atype);
int max = tree_to_shwi (array_type_nelts (atype));
- vec<constructor_elt, va_gc> *n;
- vec_alloc (n, max + 1);
+ verify_ctor_sanity (ctx, atype);
+ vec<constructor_elt, va_gc> **p = &CONSTRUCTOR_ELTS (ctx->ctor);
+ vec_alloc (*p, max + 1);
bool pre_init = false;
int i;
@@ -1766,8 +1894,6 @@ cxx_eval_vec_init_1 (const constexpr_call *call, tree atype, tree init,
else if (value_init)
{
init = build_value_init (elttype, tf_warning_or_error);
- init = cxx_eval_constant_expression
- (call, init, allow_non_constant, addr, non_constant_p, overflow_p);
pre_init = true;
}
else if (!init)
@@ -1777,18 +1903,17 @@ cxx_eval_vec_init_1 (const constexpr_call *call, tree atype, tree init,
&argvec, elttype, LOOKUP_NORMAL,
tf_warning_or_error);
release_tree_vector (argvec);
- init = cxx_eval_constant_expression (call, init, allow_non_constant,
- addr, non_constant_p, overflow_p);
pre_init = true;
}
- if (*non_constant_p && !allow_non_constant)
- goto fail;
-
for (i = 0; i <= max; ++i)
{
tree idx = build_int_cst (size_type_node, i);
tree eltinit;
+ constexpr_ctx new_ctx;
+ init_subob_ctx (ctx, new_ctx, idx, pre_init ? init : elttype);
+ if (new_ctx.ctor != ctx->ctor)
+ CONSTRUCTOR_APPEND_ELT (*p, idx, new_ctx.ctor);
if (TREE_CODE (elttype) == ARRAY_TYPE)
{
/* A multidimensional array; recurse. */
@@ -1797,7 +1922,7 @@ cxx_eval_vec_init_1 (const constexpr_call *call, tree atype, tree init,
else
eltinit = cp_build_array_ref (input_location, init, idx,
tf_warning_or_error);
- eltinit = cxx_eval_vec_init_1 (call, elttype, eltinit, value_init,
+ eltinit = cxx_eval_vec_init_1 (&new_ctx, elttype, eltinit, value_init,
allow_non_constant, addr,
non_constant_p, overflow_p);
}
@@ -1805,10 +1930,9 @@ cxx_eval_vec_init_1 (const constexpr_call *call, tree atype, tree init,
{
/* Initializing an element using value or default initialization
we just pre-built above. */
- if (i == 0)
- eltinit = init;
- else
- eltinit = unshare_expr (init);
+ eltinit = (cxx_eval_constant_expression
+ (&new_ctx, init, allow_non_constant,
+ addr, non_constant_p, overflow_p));
}
else
{
@@ -1820,34 +1944,38 @@ cxx_eval_vec_init_1 (const constexpr_call *call, tree atype, tree init,
if (!real_lvalue_p (init))
eltinit = move (eltinit);
eltinit = force_rvalue (eltinit, tf_warning_or_error);
- eltinit = cxx_eval_constant_expression
- (call, eltinit, allow_non_constant, addr, non_constant_p, overflow_p);
+ eltinit = (cxx_eval_constant_expression
+ (&new_ctx, eltinit, allow_non_constant, addr,
+ non_constant_p, overflow_p));
}
if (*non_constant_p && !allow_non_constant)
- goto fail;
- CONSTRUCTOR_APPEND_ELT (n, idx, eltinit);
+ break;
+ if (new_ctx.ctor != ctx->ctor)
+ {
+ /* We appended this element above; update the value. */
+ gcc_assert ((*p)->last().index == idx);
+ (*p)->last().value = eltinit;
+ }
+ else
+ CONSTRUCTOR_APPEND_ELT (*p, idx, eltinit);
}
if (!*non_constant_p)
{
- init = build_constructor (atype, n);
- TREE_CONSTANT (init) = true;
- return init;
+ init = ctx->ctor;
+ CONSTRUCTOR_NO_IMPLICIT_ZERO (init) = false;
}
-
- fail:
- vec_free (n);
return init;
}
static tree
-cxx_eval_vec_init (const constexpr_call *call, tree t,
+cxx_eval_vec_init (const constexpr_ctx *ctx, tree t,
bool allow_non_constant, bool addr,
bool *non_constant_p, bool *overflow_p)
{
tree atype = TREE_TYPE (t);
tree init = VEC_INIT_EXPR_INIT (t);
- tree r = cxx_eval_vec_init_1 (call, atype, init,
+ tree r = cxx_eval_vec_init_1 (ctx, atype, init,
VEC_INIT_EXPR_VALUE_INIT (t),
allow_non_constant, addr, non_constant_p, overflow_p);
if (*non_constant_p)
@@ -2048,12 +2176,12 @@ cxx_fold_indirect_ref (location_t loc, tree type, tree op0, bool *empty_base)
}
static tree
-cxx_eval_indirect_ref (const constexpr_call *call, tree t,
+cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
bool allow_non_constant, bool addr,
bool *non_constant_p, bool *overflow_p)
{
tree orig_op0 = TREE_OPERAND (t, 0);
- tree op0 = cxx_eval_constant_expression (call, orig_op0, allow_non_constant,
+ tree op0 = cxx_eval_constant_expression (ctx, orig_op0, allow_non_constant,
/*addr*/false, non_constant_p, overflow_p);
bool empty_base = false;
tree r;
@@ -2066,7 +2194,7 @@ cxx_eval_indirect_ref (const constexpr_call *call, tree t,
&empty_base);
if (r)
- r = cxx_eval_constant_expression (call, r, allow_non_constant,
+ r = cxx_eval_constant_expression (ctx, r, allow_non_constant,
addr, non_constant_p, overflow_p);
else
{
@@ -2157,7 +2285,7 @@ non_const_var_error (tree r)
Like cxx_eval_unary_expression, except for trinary expressions. */
static tree
-cxx_eval_trinary_expression (const constexpr_call *call, tree t,
+cxx_eval_trinary_expression (const constexpr_ctx *ctx, tree t,
bool allow_non_constant, bool addr,
bool *non_constant_p, bool *overflow_p)
{
@@ -2167,7 +2295,7 @@ cxx_eval_trinary_expression (const constexpr_call *call, tree t,
for (i = 0; i < 3; i++)
{
- args[i] = cxx_eval_constant_expression (call, TREE_OPERAND (t, i),
+ args[i] = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, i),
allow_non_constant, addr,
non_constant_p, overflow_p);
VERIFY_CONSTANT (args[i]);
@@ -2194,10 +2322,11 @@ var_in_constexpr_fn (tree t)
/* FIXME unify with c_fully_fold */
static tree
-cxx_eval_constant_expression (const constexpr_call *call, tree t,
+cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
bool allow_non_constant, bool addr,
bool *non_constant_p, bool *overflow_p)
{
+ constexpr_ctx new_ctx;
tree r = t;
if (t == error_mark_node)
@@ -2228,11 +2357,14 @@ cxx_eval_constant_expression (const constexpr_call *call, tree t,
if (TREE_CODE (r) == TARGET_EXPR
&& TREE_CODE (TARGET_EXPR_INITIAL (r)) == CONSTRUCTOR)
r = TARGET_EXPR_INITIAL (r);
- if (DECL_P (r) && var_in_constexpr_fn (r)
+ if (TREE_CODE (r) == VAR_DECL && var_in_constexpr_fn (r)
&& DECL_INITIAL (r))
- r = cxx_eval_constant_expression (call, DECL_INITIAL (r),
+ r = cxx_eval_constant_expression (ctx, DECL_INITIAL (r),
allow_non_constant, false,
non_constant_p, overflow_p);
+ if (TREE_CODE (r) == VAR_DECL)
+ if (tree *p = ctx->values->get (r))
+ r = *p;
if (DECL_P (r))
{
if (!allow_non_constant)
@@ -2247,18 +2379,8 @@ cxx_eval_constant_expression (const constexpr_call *call, tree t,
return t;
case PARM_DECL:
- if (call && DECL_CONTEXT (t) == call->fundef->decl)
- {
- if (DECL_ARTIFICIAL (t) && DECL_CONSTRUCTOR_P (DECL_CONTEXT (t)))
- {
- if (!allow_non_constant)
- sorry ("use of the value of the object being constructed "
- "in a constant expression");
- *non_constant_p = true;
- }
- else
- r = lookup_parameter_binding (call, t);
- }
+ if (ctx && ctx->call && DECL_CONTEXT (t) == ctx->call->fundef->decl)
+ r = lookup_parameter_binding (ctx->call, t);
else if (addr)
/* Defer in case this is only used for its type. */;
else
@@ -2271,7 +2393,7 @@ cxx_eval_constant_expression (const constexpr_call *call, tree t,
case CALL_EXPR:
case AGGR_INIT_EXPR:
- r = cxx_eval_call_expression (call, t, allow_non_constant, addr,
+ r = cxx_eval_call_expression (ctx, t, allow_non_constant, addr,
non_constant_p, overflow_p);
break;
@@ -2287,11 +2409,23 @@ cxx_eval_constant_expression (const constexpr_call *call, tree t,
*non_constant_p = true;
break;
}
+ if ((AGGREGATE_TYPE_P (TREE_TYPE (t)) || VECTOR_TYPE_P (TREE_TYPE (t))))
+ {
+ /* We're being expanded without an explicit target, so start
+ initializing a new object; expansion with an explicit target
+ 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;
+ new_ctx.object = TARGET_EXPR_SLOT (t);
+ ctx->values->put (new_ctx.object, new_ctx.ctor);
+ ctx = &new_ctx;
+ }
/* else fall through. */
case INIT_EXPR:
/* Pass false for 'addr' because these codes indicate
initialization of a temporary. */
- r = cxx_eval_constant_expression (call, TREE_OPERAND (t, 1),
+ r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
allow_non_constant, false,
non_constant_p, overflow_p);
if (!*non_constant_p)
@@ -2300,7 +2434,7 @@ cxx_eval_constant_expression (const constexpr_call *call, tree t,
break;
case SCOPE_REF:
- r = cxx_eval_constant_expression (call, TREE_OPERAND (t, 1),
+ r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
allow_non_constant, addr,
non_constant_p, overflow_p);
break;
@@ -2311,7 +2445,7 @@ cxx_eval_constant_expression (const constexpr_call *call, tree t,
case CLEANUP_POINT_EXPR:
case MUST_NOT_THROW_EXPR:
case SAVE_EXPR:
- r = cxx_eval_constant_expression (call, TREE_OPERAND (t, 0),
+ r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
allow_non_constant, addr,
non_constant_p, overflow_p);
break;
@@ -2320,14 +2454,14 @@ cxx_eval_constant_expression (const constexpr_call *call, tree t,
check for a constant operand or result; an address can be
constant without its operand being, and vice versa. */
case INDIRECT_REF:
- r = cxx_eval_indirect_ref (call, t, allow_non_constant, addr,
+ r = cxx_eval_indirect_ref (ctx, t, allow_non_constant, addr,
non_constant_p, overflow_p);
break;
case ADDR_EXPR:
{
tree oldop = TREE_OPERAND (t, 0);
- tree op = cxx_eval_constant_expression (call, oldop,
+ tree op = cxx_eval_constant_expression (ctx, oldop,
allow_non_constant,
/*addr*/true,
non_constant_p, overflow_p);
@@ -2351,7 +2485,7 @@ cxx_eval_constant_expression (const constexpr_call *call, tree t,
case BIT_NOT_EXPR:
case TRUTH_NOT_EXPR:
case FIXED_CONVERT_EXPR:
- r = cxx_eval_unary_expression (call, t, allow_non_constant, addr,
+ r = cxx_eval_unary_expression (ctx, t, allow_non_constant, addr,
non_constant_p, overflow_p);
break;
@@ -2380,15 +2514,15 @@ cxx_eval_constant_expression (const constexpr_call *call, tree t,
STRIP_NOPS (op1);
if ((TREE_CODE (op0) == TARGET_EXPR && op1 == TARGET_EXPR_SLOT (op0))
|| TREE_CODE (op1) == EMPTY_CLASS_EXPR)
- r = cxx_eval_constant_expression (call, op0, allow_non_constant,
+ r = cxx_eval_constant_expression (ctx, op0, allow_non_constant,
addr, non_constant_p, overflow_p);
else
{
/* Check that the LHS is constant and then discard it. */
- cxx_eval_constant_expression (call, op0, allow_non_constant,
+ cxx_eval_constant_expression (ctx, op0, allow_non_constant,
false, non_constant_p, overflow_p);
op1 = TREE_OPERAND (t, 1);
- r = cxx_eval_constant_expression (call, op1, allow_non_constant,
+ r = cxx_eval_constant_expression (ctx, op1, allow_non_constant,
addr, non_constant_p, overflow_p);
}
}
@@ -2433,7 +2567,7 @@ cxx_eval_constant_expression (const constexpr_call *call, tree t,
case LTGT_EXPR:
case RANGE_EXPR:
case COMPLEX_EXPR:
- r = cxx_eval_binary_expression (call, t, allow_non_constant, addr,
+ r = cxx_eval_binary_expression (ctx, t, allow_non_constant, addr,
non_constant_p, overflow_p);
break;
@@ -2441,7 +2575,7 @@ cxx_eval_constant_expression (const constexpr_call *call, tree t,
short-circuiting. */
case TRUTH_AND_EXPR:
case TRUTH_ANDIF_EXPR:
- r = cxx_eval_logical_expression (call, t, boolean_false_node,
+ r = cxx_eval_logical_expression (ctx, t, boolean_false_node,
boolean_true_node,
allow_non_constant, addr,
non_constant_p, overflow_p);
@@ -2449,14 +2583,14 @@ cxx_eval_constant_expression (const constexpr_call *call, tree t,
case TRUTH_OR_EXPR:
case TRUTH_ORIF_EXPR:
- r = cxx_eval_logical_expression (call, t, boolean_true_node,
+ r = cxx_eval_logical_expression (ctx, t, boolean_true_node,
boolean_false_node,
allow_non_constant, addr,
non_constant_p, overflow_p);
break;
case ARRAY_REF:
- r = cxx_eval_array_reference (call, t, allow_non_constant, addr,
+ r = cxx_eval_array_reference (ctx, t, allow_non_constant, addr,
non_constant_p, overflow_p);
break;
@@ -2471,23 +2605,23 @@ cxx_eval_constant_expression (const constexpr_call *call, tree t,
*non_constant_p = true;
return t;
}
- r = cxx_eval_component_reference (call, t, allow_non_constant, addr,
+ r = cxx_eval_component_reference (ctx, t, allow_non_constant, addr,
non_constant_p, overflow_p);
break;
case BIT_FIELD_REF:
- r = cxx_eval_bit_field_ref (call, t, allow_non_constant, addr,
+ r = cxx_eval_bit_field_ref (ctx, t, allow_non_constant, addr,
non_constant_p, overflow_p);
break;
case COND_EXPR:
case VEC_COND_EXPR:
- r = cxx_eval_conditional_expression (call, t, allow_non_constant, addr,
+ r = cxx_eval_conditional_expression (ctx, t, allow_non_constant, addr,
non_constant_p, overflow_p);
break;
case CONSTRUCTOR:
- r = cxx_eval_bare_aggregate (call, t, allow_non_constant, addr,
+ r = cxx_eval_bare_aggregate (ctx, t, allow_non_constant, addr,
non_constant_p, overflow_p);
break;
@@ -2497,13 +2631,13 @@ cxx_eval_constant_expression (const constexpr_call *call, tree t,
be NULL, meaning default-initialization, or it will be an lvalue
or xvalue of the same type, meaning direct-initialization from the
corresponding member. */
- r = cxx_eval_vec_init (call, t, allow_non_constant, addr,
+ r = cxx_eval_vec_init (ctx, t, allow_non_constant, addr,
non_constant_p, overflow_p);
break;
case FMA_EXPR:
case VEC_PERM_EXPR:
- r = cxx_eval_trinary_expression (call, t, allow_non_constant, addr,
+ r = cxx_eval_trinary_expression (ctx, t, allow_non_constant, addr,
non_constant_p, overflow_p);
break;
@@ -2512,7 +2646,7 @@ cxx_eval_constant_expression (const constexpr_call *call, tree t,
case NOP_EXPR:
{
tree oldop = TREE_OPERAND (t, 0);
- tree op = cxx_eval_constant_expression (call, oldop,
+ tree op = cxx_eval_constant_expression (ctx, oldop,
allow_non_constant, addr,
non_constant_p, overflow_p);
if (*non_constant_p)
@@ -2573,6 +2707,29 @@ cxx_eval_constant_expression (const constexpr_call *call, tree t,
*non_constant_p = true;
break;
+ case PLACEHOLDER_EXPR:
+ if (!ctx || !ctx->ctor || (addr && !ctx->object))
+ {
+ /* A placeholder without a referent. We can get here when
+ checking whether NSDMIs are noexcept, or in massage_init_elt;
+ just say it's non-constant for now. */
+ gcc_assert (allow_non_constant);
+ *non_constant_p = true;
+ break;
+ }
+ else
+ {
+ /* Use of the value or address of the current object. We could
+ use ctx->object unconditionally, but using ctx->ctor when we
+ can is a minor optimization. */
+ tree ctor = addr ? ctx->object : ctx->ctor;
+ gcc_assert (same_type_ignoring_top_level_qualifiers_p
+ (TREE_TYPE (t), TREE_TYPE (ctor)));
+ return cxx_eval_constant_expression
+ (ctx, ctor, allow_non_constant, addr, non_constant_p, overflow_p);
+ }
+ break;
+
default:
internal_error ("unexpected expression %qE of kind %s", t,
get_tree_code_name (TREE_CODE (t)));
@@ -2590,12 +2747,43 @@ cxx_eval_constant_expression (const constexpr_call *call, tree t,
}
static tree
-cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant)
+cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
+ tree object = NULL_TREE)
{
bool non_constant_p = false;
bool overflow_p = false;
- tree r = cxx_eval_constant_expression (NULL, t, allow_non_constant,
- false, &non_constant_p, &overflow_p);
+ constexpr_ctx ctx = { NULL, NULL, NULL, NULL };
+ hash_map<tree,tree> map;
+ ctx.values = &map;
+ tree type = initialized_type (t);
+ if (!object && TREE_CODE (t) == TARGET_EXPR)
+ object = TARGET_EXPR_SLOT (t);
+ tree r = t;
+ if (AGGREGATE_TYPE_P (type) || VECTOR_TYPE_P (type))
+ {
+ /* In C++14 an NSDMI can participate in aggregate initialization,
+ and can refer to the address of the object being initialized, so
+ we need to pass in the relevant VAR_DECL if we want to do the
+ evaluation in a single pass. The evaluation will dynamically
+ update ctx.values for the VAR_DECL. We use the same strategy
+ 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;
+ ctx.object = object;
+ if (object)
+ gcc_assert (same_type_ignoring_top_level_qualifiers_p
+ (type, TREE_TYPE (object)));
+ if (object && DECL_P (object))
+ map.put (object, ctx.ctor);
+ if (TREE_CODE (r) == TARGET_EXPR)
+ /* Avoid creating another CONSTRUCTOR when we expand the
+ TARGET_EXPR. */
+ r = TARGET_EXPR_INITIAL (r);
+ }
+
+ r = cxx_eval_constant_expression (&ctx, r, allow_non_constant,
+ false, &non_constant_p, &overflow_p);
verify_constant (r, allow_non_constant, &non_constant_p, &overflow_p);
@@ -2607,7 +2795,7 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant)
constexpr variables. */
if (!allow_non_constant)
error ("%qT cannot be the type of a complete constant expression "
- "because it has mutable sub-objects", TREE_TYPE (t));
+ "because it has mutable sub-objects", type);
non_constant_p = true;
}
@@ -2668,7 +2856,17 @@ is_sub_constant_expr (tree t)
{
bool non_constant_p = false;
bool overflow_p = false;
- cxx_eval_constant_expression (NULL, t, true, false, &non_constant_p,
+ constexpr_ctx ctx = { NULL, NULL, NULL, NULL };
+ hash_map <tree, tree> map;
+ ctx.values = &map;
+ tree type = initialized_type (t);
+ if ((AGGREGATE_TYPE_P (type) || VECTOR_TYPE_P (type))
+ && TREE_CODE (t) != TARGET_EXPR)
+ {
+ ctx.ctor = build_constructor (type, NULL);
+ CONSTRUCTOR_NO_IMPLICIT_ZERO (ctx.ctor) = true;
+ }
+ cxx_eval_constant_expression (&ctx, t, true, false, &non_constant_p,
&overflow_p);
return !non_constant_p && !overflow_p;
}
@@ -2678,9 +2876,9 @@ is_sub_constant_expr (tree t)
return NULL. */
tree
-cxx_constant_value (tree t)
+cxx_constant_value (tree t, tree decl)
{
- return cxx_eval_outermost_constant_expr (t, false);
+ return cxx_eval_outermost_constant_expr (t, false, decl);
}
/* If T is a constant expression, returns its reduced value.
@@ -2688,7 +2886,7 @@ cxx_constant_value (tree t)
Otherwise, returns a version of T without TREE_CONSTANT. */
tree
-maybe_constant_value (tree t)
+maybe_constant_value (tree t, tree decl)
{
tree r;
@@ -2705,7 +2903,7 @@ maybe_constant_value (tree t)
return t;
}
- r = cxx_eval_outermost_constant_expr (t, true);
+ r = cxx_eval_outermost_constant_expr (t, true, decl);
#ifdef ENABLE_CHECKING
/* cp_tree_equal looks through NOPs, so allow them. */
gcc_assert (r == t
@@ -2720,14 +2918,14 @@ maybe_constant_value (tree t)
than wrapped in a TARGET_EXPR. */
tree
-maybe_constant_init (tree t)
+maybe_constant_init (tree t, tree decl)
{
if (TREE_CODE (t) == EXPR_STMT)
t = TREE_OPERAND (t, 0);
if (TREE_CODE (t) == CONVERT_EXPR
&& VOID_TYPE_P (TREE_TYPE (t)))
t = TREE_OPERAND (t, 0);
- t = maybe_constant_value (t);
+ t = maybe_constant_value (t, decl);
if (TREE_CODE (t) == TARGET_EXPR)
{
tree init = TARGET_EXPR_INITIAL (t);
@@ -2822,6 +3020,7 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags)
case FIELD_DECL:
case PARM_DECL:
case USING_DECL:
+ case PLACEHOLDER_EXPR:
return true;
case AGGR_INIT_EXPR:
@@ -2861,18 +3060,7 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags)
{
tree x = get_nth_callarg (t, 0);
if (is_this_parameter (x))
- {
- if (DECL_CONTEXT (x) == NULL_TREE
- || DECL_CONSTRUCTOR_P (DECL_CONTEXT (x)))
- {
- if (flags & tf_error)
- sorry ("calling a member function of the "
- "object being constructed in a constant "
- "expression");
- return false;
- }
- /* Otherwise OK. */;
- }
+ return true;
else if (!potential_constant_expression_1 (x, rval, flags))
return false;
i = 1;
@@ -3002,14 +3190,6 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags)
error ("use of %<this%> in a constant expression");
return false;
}
- if (want_rval && DECL_CONTEXT (x)
- && DECL_CONSTRUCTOR_P (DECL_CONTEXT (x)))
- {
- if (flags & tf_error)
- sorry ("use of the value of the object being constructed "
- "in a constant expression");
- return false;
- }
return true;
}
return potential_constant_expression_1 (x, rval, flags);
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index 5275072..e5436bb 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -495,6 +495,10 @@ cp_gimplify_init_expr (tree *expr_p)
TREE_TYPE (from) = void_type_node;
}
+ if (cxx_dialect >= cxx14 && TREE_CODE (sub) == CONSTRUCTOR)
+ /* Handle aggregate NSDMI. */
+ replace_placeholders (sub, to);
+
if (t == sub)
break;
else
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 0923d9f..abc3d6f 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -98,6 +98,7 @@ c-common.h, not after.
DECL_FINAL_P (in FUNCTION_DECL)
QUALIFIED_NAME_IS_TEMPLATE (in SCOPE_REF)
DECLTYPE_FOR_INIT_CAPTURE (in DECLTYPE_TYPE)
+ CONSTRUCTOR_NO_IMPLICIT_ZERO (in CONSTRUCTOR)
2: IDENTIFIER_OPNAME_P (in IDENTIFIER_NODE)
ICS_THIS_FLAG (in _CONV)
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL)
@@ -3479,6 +3480,11 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
B b{1,2}, not B b({1,2}) or B b = {1,2}. */
#define CONSTRUCTOR_IS_DIRECT_INIT(NODE) (TREE_LANG_FLAG_0 (CONSTRUCTOR_CHECK (NODE)))
+/* True if an uninitialized element in NODE should not be treated as
+ implicitly value-initialized. Only used in constexpr evaluation. */
+#define CONSTRUCTOR_NO_IMPLICIT_ZERO(NODE) \
+ (TREE_LANG_FLAG_1 (CONSTRUCTOR_CHECK (NODE)))
+
#define DIRECT_LIST_INIT_P(NODE) \
(BRACE_ENCLOSED_INITIALIZER_P (NODE) && CONSTRUCTOR_IS_DIRECT_INIT (NODE))
@@ -6033,6 +6039,8 @@ extern tree bind_template_template_parm (tree, tree);
extern tree array_type_nelts_total (tree);
extern tree array_type_nelts_top (tree);
extern tree break_out_target_exprs (tree);
+extern tree build_ctor_subob_ref (tree, tree, tree);
+extern tree replace_placeholders (tree, tree);
extern tree get_type_decl (tree);
extern tree decl_namespace_context (tree);
extern bool decl_anon_ns_mem_p (const_tree);
@@ -6320,9 +6328,9 @@ extern bool potential_constant_expression (tree);
extern bool potential_rvalue_constant_expression (tree);
extern bool require_potential_constant_expression (tree);
extern bool require_potential_rvalue_constant_expression (tree);
-extern tree cxx_constant_value (tree);
-extern tree maybe_constant_value (tree);
-extern tree maybe_constant_init (tree);
+extern tree cxx_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 bool is_sub_constant_expr (tree);
extern bool reduced_constant_expression_p (tree);
extern bool is_instantiation_of_constexpr (tree);
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 755bb00..76f86cb 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -2673,6 +2673,10 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
pp_cxx_right_paren (pp);
break;
+ case PLACEHOLDER_EXPR:
+ pp_string (pp, M_("*this"));
+ break;
+
/* This list is incomplete, but should suffice for now.
It is very important that `sorry' does not call
`report_error_function'. That could cause an infinite loop. */
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 6851fe9..5c61107 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -540,7 +540,12 @@ get_nsdmi (tree member, bool in_ctor)
tree save_ccp = current_class_ptr;
tree save_ccr = current_class_ref;
if (!in_ctor)
- inject_this_parameter (DECL_CONTEXT (member), TYPE_UNQUALIFIED);
+ {
+ /* Use a PLACEHOLDER_EXPR when we don't have a 'this' parameter to
+ refer to; constexpr evaluation knows what to do with it. */
+ current_class_ref = build0 (PLACEHOLDER_EXPR, DECL_CONTEXT (member));
+ current_class_ptr = build_address (current_class_ref);
+ }
if (DECL_LANG_SPECIFIC (member) && DECL_TEMPLATE_INFO (member))
{
/* Do deferred instantiation of the NSDMI. */
@@ -560,7 +565,7 @@ get_nsdmi (tree member, bool in_ctor)
error ("constructor required before non-static data member "
"for %qD has been parsed", member);
DECL_INITIAL (member) = error_mark_node;
- init = NULL_TREE;
+ init = error_mark_node;
}
/* Strip redundant TARGET_EXPR so we don't need to remap it, and
so the aggregate init code below will see a CONSTRUCTOR. */
@@ -1723,7 +1728,7 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags,
tree fn = get_callee_fndecl (rval);
if (fn && DECL_DECLARED_CONSTEXPR_P (fn))
{
- tree e = maybe_constant_init (rval);
+ tree e = maybe_constant_init (rval, exp);
if (TREE_CONSTANT (e))
rval = build2 (INIT_EXPR, type, exp, e);
}
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 9008cdb..ef7f675 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -158,6 +158,7 @@ lvalue_kind (const_tree ref)
case ARRAY_NOTATION_REF:
case PARM_DECL:
case RESULT_DECL:
+ case PLACEHOLDER_EXPR:
return clk_ordinary;
/* A scope ref in a template, left as SCOPE_REF to support later
@@ -2450,6 +2451,103 @@ break_out_target_exprs (tree t)
return t;
}
+/* Build an expression for the subobject of OBJ at CONSTRUCTOR index INDEX,
+ which we expect to have type TYPE. */
+
+tree
+build_ctor_subob_ref (tree index, tree type, tree obj)
+{
+ if (index == NULL_TREE)
+ /* Can't refer to a particular member of a vector. */
+ obj = NULL_TREE;
+ else if (TREE_CODE (index) == INTEGER_CST)
+ obj = cp_build_array_ref (input_location, obj, index, tf_none);
+ else
+ obj = build_class_member_access_expr (obj, index, NULL_TREE,
+ /*reference*/false, tf_none);
+ if (obj)
+ gcc_assert (same_type_ignoring_top_level_qualifiers_p (type,
+ TREE_TYPE (obj)));
+ return obj;
+}
+
+/* Like substitute_placeholder_in_expr, but handle C++ tree codes and
+ build up subexpressions as we go deeper. */
+
+struct replace_placeholders_t
+{
+ tree obj;
+ hash_set<tree> *pset;
+};
+
+static tree
+replace_placeholders_r (tree* t, int* walk_subtrees, void* data_)
+{
+ tree obj = static_cast<tree>(data_);
+
+ if (TREE_CONSTANT (*t))
+ {
+ *walk_subtrees = false;
+ return NULL_TREE;
+ }
+
+ switch (TREE_CODE (*t))
+ {
+ case PLACEHOLDER_EXPR:
+ gcc_assert (same_type_ignoring_top_level_qualifiers_p
+ (TREE_TYPE (*t), TREE_TYPE (obj)));
+ *t = obj;
+ *walk_subtrees = false;
+ break;
+
+ case TARGET_EXPR:
+ /* Don't mess with placeholders in an unrelated object. */
+ *walk_subtrees = false;
+ break;
+
+ case CONSTRUCTOR:
+ {
+ constructor_elt *ce;
+ vec<constructor_elt,va_gc> *v = CONSTRUCTOR_ELTS (*t);
+ for (unsigned i = 0; vec_safe_iterate (v, i, &ce); ++i)
+ {
+ tree *valp = &ce->value;
+ tree type = TREE_TYPE (*valp);
+ tree subob = obj;
+
+ if (TREE_CODE (*valp) == CONSTRUCTOR
+ && AGGREGATE_TYPE_P (type))
+ {
+ subob = build_ctor_subob_ref (ce->index, type, obj);
+ if (TREE_CODE (*valp) == TARGET_EXPR)
+ valp = &TARGET_EXPR_INITIAL (*valp);
+ }
+
+ cp_walk_tree (valp, replace_placeholders_r,
+ subob, NULL);
+ }
+ *walk_subtrees = false;
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return NULL_TREE;
+}
+
+tree
+replace_placeholders (tree exp, tree obj)
+{
+ hash_set<tree> pset;
+ tree *tp = &exp;
+ if (TREE_CODE (exp) == TARGET_EXPR)
+ tp = &TARGET_EXPR_INITIAL (exp);
+ cp_walk_tree (tp, replace_placeholders_r, obj, NULL);
+ return exp;
+}
+
/* Similar to `build_nt', but for template definitions of dependent
expressions */
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index ad69668..d57f75d 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -806,15 +806,19 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
&& !require_potential_constant_expression (value))
value = error_mark_node;
else
- value = cxx_constant_value (value);
+ value = cxx_constant_value (value, decl);
}
- value = maybe_constant_init (value);
+ value = maybe_constant_init (value, decl);
const_init = (reduced_constant_expression_p (value)
|| error_operand_p (value));
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = const_init;
TREE_CONSTANT (decl) = const_init && decl_maybe_constant_var_p (decl);
}
+ if (cxx_dialect >= cxx14)
+ /* Handle aggregate NSDMI in non-constant initializers, too. */
+ value = replace_placeholders (value, decl);
+
/* If the initializer is not a constant, fill in DECL_INITIAL with
the bits that are constant, and then return an expression that
will perform the dynamic initialization. */
@@ -1292,9 +1296,8 @@ process_init_constructor_record (tree type, tree init,
tsubst_flags_t complain)
{
vec<constructor_elt, va_gc> *v = NULL;
- int flags = 0;
tree field;
- unsigned HOST_WIDE_INT idx = 0;
+ int skipped = 0;
gcc_assert (TREE_CODE (type) == RECORD_TYPE);
gcc_assert (!CLASSTYPE_VBASECLASSES (type));
@@ -1302,6 +1305,9 @@ process_init_constructor_record (tree type, tree init,
|| !BINFO_N_BASE_BINFOS (TYPE_BINFO (type)));
gcc_assert (!TYPE_POLYMORPHIC_P (type));
+ restart:
+ int flags = 0;
+ unsigned HOST_WIDE_INT idx = 0;
/* Generally, we will always have an index for each initializer (which is
a FIELD_DECL, put by reshape_init), but compound literals don't go trough
reshape_init. So we need to handle both cases. */
@@ -1345,6 +1351,19 @@ process_init_constructor_record (tree type, tree init,
next = massage_init_elt (type, ce->value, complain);
++idx;
}
+ else if (DECL_INITIAL (field))
+ {
+ if (skipped > 0)
+ {
+ /* We're using an NSDMI past a field with implicit
+ zero-init. Go back and make it explicit. */
+ skipped = -1;
+ vec_safe_truncate (v, 0);
+ goto restart;
+ }
+ /* C++14 aggregate NSDMI. */
+ next = get_nsdmi (field, /*ctor*/false);
+ }
else if (type_build_ctor_call (TREE_TYPE (field)))
{
/* If this type needs constructors run for
@@ -1387,13 +1406,17 @@ process_init_constructor_record (tree type, tree init,
warning (OPT_Wmissing_field_initializers,
"missing initializer for member %qD", field);
- if (!zero_init_p (TREE_TYPE (field)))
+ if (!zero_init_p (TREE_TYPE (field))
+ || skipped < 0)
next = build_zero_init (TREE_TYPE (field), /*nelts=*/NULL_TREE,
/*static_storage_p=*/false);
else
- /* The default zero-initialization is fine for us; don't
- add anything to the CONSTRUCTOR. */
- continue;
+ {
+ /* The default zero-initialization is fine for us; don't
+ add anything to the CONSTRUCTOR. */
+ skipped = 1;
+ continue;
+ }
}
/* If this is a bitfield, now convert to the lowered type. */