2007-10-01 Alexandre Oliva * decl.c (duplicate_decls): Preserve linkage flags for mere redeclarations of gnu_inline definitions. * g++.dg/ext/gnu-inline-global-redecl.C: New. --- gcc/cp/decl.c.orig 2007-09-28 00:02:33.000000000 -0300 +++ gcc/cp/decl.c 2007-10-01 16:33:10.000000000 -0300 @@ -1846,24 +1846,24 @@ duplicate_decls (tree newdecl, tree oldd new_template = NULL_TREE; if (DECL_LANG_SPECIFIC (newdecl) && DECL_LANG_SPECIFIC (olddecl)) { - bool old_decl_gnu_inline; + bool new_redefines_gnu_inline = false; - if ((DECL_INTERFACE_KNOWN (olddecl) - && TREE_CODE (olddecl) == FUNCTION_DECL) - || (TREE_CODE (olddecl) == TEMPLATE_DECL - && TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) == FUNCTION_DECL)) + if (new_defines_function + && ((DECL_INTERFACE_KNOWN (olddecl) + && TREE_CODE (olddecl) == FUNCTION_DECL) + || (TREE_CODE (olddecl) == TEMPLATE_DECL + && (TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) + == FUNCTION_DECL)))) { tree fn = olddecl; if (TREE_CODE (fn) == TEMPLATE_DECL) fn = DECL_TEMPLATE_RESULT (olddecl); - old_decl_gnu_inline = GNU_INLINE_P (fn) && DECL_INITIAL (fn); + new_redefines_gnu_inline = GNU_INLINE_P (fn) && DECL_INITIAL (fn); } - else - old_decl_gnu_inline = false; - if (!old_decl_gnu_inline) + if (!new_redefines_gnu_inline) { DECL_INTERFACE_KNOWN (newdecl) |= DECL_INTERFACE_KNOWN (olddecl); DECL_NOT_REALLY_EXTERN (newdecl) |= DECL_NOT_REALLY_EXTERN (olddecl); --- gcc/testsuite/g++.dg/ext/gnu-inline-global-redecl.C 1970-01-01 00:00:00.000000000 +0000 +++ gcc/testsuite/g++.dg/ext/gnu-inline-global-redecl.C 2007-10-01 16:45:49.000000000 -0300 @@ -0,0 +1,19 @@ +/* Test __attribute__((gnu_inline)). + + Check that we don't get out-of-line definitions for extern inline + gnu_inline functions, regardless of redeclaration. + + */ + +/* { dg-do link } */ +/* { dg-options "-O" } */ // such that static functions are optimized out + +#include "gnu-inline-common.h" + +decl(extern, fn) +gnuindef(fn, 0) +decl(extern, fn) + +int main () { + fn (); +}