2007-12-20 Jakub Jelinek PR tree-optimization/29484 * tree-inline.c (inline_forbidden_p_2): New function. (inline_forbidden_p): Disallow inlining if some static var has an address of a local LABEL_DECL in its initializer. * gcc.c-torture/execute/20071220-1.c: New test. * gcc.c-torture/execute/20071220-2.c: New test. --- gcc/tree-inline.c.jj 2007-12-04 16:39:22.000000000 +0100 +++ gcc/tree-inline.c 2007-12-20 13:46:18.000000000 +0100 @@ -1951,6 +1951,27 @@ inline_forbidden_p_1 (tree *nodep, int * return NULL_TREE; } +static tree +inline_forbidden_p_2 (tree *nodep, int *walk_subtrees, + void *fnp) +{ + tree node = *nodep; + tree fn = (tree) fnp; + + if (TREE_CODE (node) == LABEL_DECL && DECL_CONTEXT (node) == fn) + { + inline_forbidden_reason + = G_("function %q+F can never be inlined " + "because it saves address of local label in a static variable"); + return node; + } + + if (TYPE_P (node)) + *walk_subtrees = 0; + + return NULL_TREE; +} + /* Return subexpression representing possible alloca call, if any. */ static tree inline_forbidden_p (tree fndecl) @@ -1959,16 +1980,31 @@ inline_forbidden_p (tree fndecl) block_stmt_iterator bsi; basic_block bb; tree ret = NULL_TREE; + struct function *fun = DECL_STRUCT_FUNCTION (fndecl); + tree step; - FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (fndecl)) + FOR_EACH_BB_FN (bb, fun) for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) { ret = walk_tree_without_duplicates (bsi_stmt_ptr (bsi), - inline_forbidden_p_1, fndecl); + inline_forbidden_p_1, fndecl); if (ret) goto egress; } + for (step = fun->unexpanded_var_list; step; step = TREE_CHAIN (step)) + { + tree decl = TREE_VALUE (step); + if (TREE_CODE (decl) == VAR_DECL + && TREE_STATIC (decl) + && !DECL_EXTERNAL (decl) + && DECL_INITIAL (decl)) + ret = walk_tree_without_duplicates (&DECL_INITIAL (decl), + inline_forbidden_p_2, fndecl); + if (ret) + goto egress; + } + egress: input_location = saved_loc; return ret; --- gcc/testsuite/gcc.c-torture/execute/20071220-1.c.jj 2007-12-20 14:29:04.000000000 +0100 +++ gcc/testsuite/gcc.c-torture/execute/20071220-1.c 2007-12-20 14:28:12.000000000 +0100 @@ -0,0 +1,40 @@ +/* PR tree-optimization/29484 */ + +extern void abort (void); + +void *__attribute__((noinline)) +baz (void **lab) +{ + asm volatile ("" : "+r" (lab)); + return *lab; +} + +static inline +int bar (void) +{ + static void *b[] = { &&addr }; + void *p = baz (b); + goto *p; +addr: + return 17; +} + +int __attribute__((noinline)) +f1 (void) +{ + return bar (); +} + +int __attribute__((noinline)) +f2 (void) +{ + return bar (); +} + +int +main (void) +{ + if (f1 () != 17 || f1 () != 17 || f2 () != 17 || f2 () != 17) + abort (); + return 0; +} --- gcc/testsuite/gcc.c-torture/execute/20071220-2.c.jj 2007-12-20 14:29:13.000000000 +0100 +++ gcc/testsuite/gcc.c-torture/execute/20071220-2.c 2007-12-20 14:28:30.000000000 +0100 @@ -0,0 +1,39 @@ +/* PR tree-optimization/29484 */ + +extern void abort (void); + +void *__attribute__((noinline)) +baz (void **lab) +{ + asm volatile ("" : "+r" (lab)); + return *lab; +} + +static inline +int bar (void) +{ + static void *b[] = { &&addr }; + baz (b); +addr: + return 17; +} + +int __attribute__((noinline)) +f1 (void) +{ + return bar (); +} + +int __attribute__((noinline)) +f2 (void) +{ + return bar (); +} + +int +main (void) +{ + if (f1 () != 17 || f1 () != 17 || f2 () != 17 || f2 () != 17) + abort (); + return 0; +}