re PR tree-optimization/29484 (tree-inline.c bug with local static vars)

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.
	* doc/extend.texi (Labels as Values): Document &&foo behaviour
	vs. inlining.

	* gcc.c-torture/execute/20071220-1.c: New test.
	* gcc.c-torture/execute/20071220-2.c: New test.

From-SVN: r131300
This commit is contained in:
Jakub Jelinek 2008-01-03 09:33:57 +01:00 committed by Jakub Jelinek
parent 097392de6b
commit 2092ee7d08
6 changed files with 138 additions and 2 deletions

View File

@ -1,3 +1,12 @@
2008-01-03 Jakub Jelinek <jakub@redhat.com>
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.
* doc/extend.texi (Labels as Values): Document &&foo behaviour
vs. inlining.
2007-12-19 Sebastian Pop <sebastian.pop@amd.com>
PR tree-optimization/34635

View File

@ -370,6 +370,12 @@ This is more friendly to code living in shared libraries, as it reduces
the number of dynamic relocations that are needed, and by consequence,
allows the data to be read-only.
The @code{&&foo} expressions for the same label might have different values
if the containing function is inlined or cloned. If a program relies on
them being always the same, @code{__attribute__((__noinline__))} should
be used to prevent inlining. If @code{&&foo} is used
in a static variable initializer, inlining is forbidden.
@node Nested Functions
@section Nested Functions
@cindex nested functions

View File

@ -1,3 +1,9 @@
2008-01-03 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/29484
* gcc.c-torture/execute/20071220-1.c: New test.
* gcc.c-torture/execute/20071220-2.c: New test.
2007-12-19 Sebastian Pop <sebastian.pop@amd.com>
PR tree-optimization/34635

View File

@ -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;
}

View File

@ -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;
}

View File

@ -1951,6 +1951,27 @@ inline_forbidden_p_1 (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED,
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;