extern tree build_new (VEC(tree,gc) **, tree, tree,
VEC(tree,gc) **, int,
tsubst_flags_t);
+extern tree get_temp_regvar (tree, tree);
extern tree build_vec_init (tree, tree, tree, bool, int,
tsubst_flags_t);
extern tree build_delete (tree, tree,
return 0;
}
+/* *expr_p is part of the TYPE_SIZE of a variably-sized array. If any
+ SAVE_EXPRs in *expr_p wrap expressions with side-effects, break those
+ expressions out into temporary variables so that walk_tree doesn't
+ step into them (c++/15764). */
+
+static tree
+stabilize_save_expr_r (tree *expr_p, int *walk_subtrees, void *data)
+{
+ struct pointer_set_t *pset = (struct pointer_set_t *)data;
+ tree expr = *expr_p;
+ if (TREE_CODE (expr) == SAVE_EXPR)
+ {
+ tree op = TREE_OPERAND (expr, 0);
+ cp_walk_tree (&op, stabilize_save_expr_r, data, pset);
+ if (TREE_SIDE_EFFECTS (op))
+ TREE_OPERAND (expr, 0) = get_temp_regvar (TREE_TYPE (op), op);
+ *walk_subtrees = 0;
+ }
+ else if (!EXPR_P (expr) || !TREE_SIDE_EFFECTS (expr))
+ *walk_subtrees = 0;
+ return NULL;
+}
+
+/* Entry point for the above. */
+
+static void
+stabilize_vla_size (tree size)
+{
+ struct pointer_set_t *pset = pointer_set_create ();
+ /* Break out any function calls into temporary variables. */
+ cp_walk_tree (&size, stabilize_save_expr_r, pset, pset);
+}
+
/* Given the SIZE (i.e., number of elements) in an array, compute an
appropriate index type for the array. If non-NULL, NAME is the
name of the thing being declared. */
&& (decl_context == NORMAL || decl_context == FIELD)
&& at_function_scope_p ()
&& variably_modified_type_p (type, NULL_TREE))
- finish_expr_stmt (TYPE_SIZE (type));
+ {
+ /* First break out any side-effects. */
+ stabilize_vla_size (TYPE_SIZE (type));
+ /* And then force evaluation of the SAVE_EXPR. */
+ finish_expr_stmt (TYPE_SIZE (type));
+ }
if (declarator->kind == cdk_reference)
{
}
}
+ /* We need to stabilize side-effects in VLA sizes for regular array
+ declarations too, not just pointers to arrays. */
+ if (type != error_mark_node && !TYPE_NAME (type)
+ && (decl_context == NORMAL || decl_context == FIELD)
+ && at_function_scope_p ()
+ && variably_modified_type_p (type, NULL_TREE))
+ stabilize_vla_size (TYPE_SIZE (type));
+
/* A `constexpr' specifier used in an object declaration declares
the object as `const'. */
if (constexpr_p && innermost_code != cdk_function)
static tree sort_mem_initializers (tree, tree);
static tree initializing_context (tree);
static void expand_cleanup_for_base (tree, tree);
-static tree get_temp_regvar (tree, tree);
static tree dfs_initialize_vtbl_ptrs (tree, void *);
static tree build_dtor_call (tree, special_function_kind, int);
static tree build_field_list (tree, tree, int *);
things when it comes time to do final cleanups (which take place
"outside" the binding contour of the function). */
-static tree
+tree
get_temp_regvar (tree type, tree init)
{
tree decl;