From dfb9470529df202844f4b5dfe757ff07fa9bd27f Mon Sep 17 00:00:00 2001 From: jason Date: Fri, 6 May 2011 21:58:30 +0000 Subject: [PATCH] PR c++/48446 * decl.c (stabilize_save_expr_r, stabilize_vla_size): New. (grokdeclarator): Use stabilize_vla_size. * init.c (get_temp_regvar): No longer static. * cp-tree.h: Declare it. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-4_6-branch@173514 138bc75d-0d04-0410-961f-82ee72b054a4 index 9fbca57..be61dad 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4958,6 +4958,7 @@ extern tree build_offset_ref (tree, tree, bool); 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, diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 6f8bb9f..74bae0b 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -7499,6 +7499,39 @@ check_static_variable_definition (tree decl, tree type) 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. */ @@ -8951,7 +8984,12 @@ grokdeclarator (const cp_declarator *declarator, && (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) { @@ -9026,6 +9064,14 @@ grokdeclarator (const cp_declarator *declarator, } } + /* 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) diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 4798257..ff94b71 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -45,7 +45,6 @@ static void expand_virtual_init (tree, tree); 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 *); @@ -2871,7 +2870,7 @@ create_temporary_var (tree type) 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; new file mode 100644 index 0000000..401c4e0 --- /dev/null +++ b/gcc/testsuite/c-c++-common/vla-1.c @@ -0,0 +1,21 @@ +/* Test that changes to a variable are reflected in a VLA later in the + expression. */ +/* { dg-options "" } */ + +#ifdef __cplusplus +extern "C" +#endif +void abort(); + +int i = 4; +int f() +{ + return i; +} + +int main() +{ + if (i+=2, sizeof(*(int(*)[f()])0) != 6*sizeof(int)) + abort(); + return 0; +} diff --git a/gcc/testsuite/g++.dg/ext/vla10.C b/gcc/testsuite/g++.dg/ext/vla10.C new file mode 100644 index 0000000..17cdb2f --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/vla10.C @@ -0,0 +1,32 @@ +// PR c++/48446 +// { dg-options "" } + +template +struct A +{ + ~A (); + T *operator-> () const; +}; + +struct B +{ + typedef A P; + static P foo (int); +}; + +struct C +{ + typedef A P; + static const int c = 80; +}; + +C::P bar (); + +void +baz () +{ + char z[bar ()->c]; + { + B::P m = B::foo (sizeof (z)); + } +} -- 1.7.0.4