Here's a more straightforward version of the patch that abuses the fact that the fields DECL_PENDING_INLINE_INFO and DECL_SAVED_FUNCTION_DATA are a union.
Bootstrapped + regtested on x86_64-pc-linux-gnu. Does this look OK to commit? gcc/cp/ChangeLog: PR c++/27100 * decl.c (duplicate_decls): Copy the DECL_PENDING_INLINE_P flag. gcc/testsuite/ChangeLog: PR c++/27100 * g++.dg/other/friend6.C: New test. --- gcc/cp/decl.c | 11 +++++++++-- gcc/testsuite/g++.dg/other/friend6.C | 15 +++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/g++.dg/other/friend6.C diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 90e147c..b26e8ae 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -2351,8 +2351,15 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) } else { - if (DECL_PENDING_INLINE_INFO (newdecl) == 0) - DECL_PENDING_INLINE_INFO (newdecl) = DECL_PENDING_INLINE_INFO (olddecl); + if (DECL_PENDING_INLINE_INFO (newdecl) == NULL) + { + /* This also copies DECL_SAVED_FUNCTION_DATA since the two fields + are a union (tagged by DECL_PENDING_INLINE_P). */ + DECL_PENDING_INLINE_INFO (newdecl) + = DECL_PENDING_INLINE_INFO (olddecl); + DECL_PENDING_INLINE_P (newdecl) + = DECL_PENDING_INLINE_P (olddecl); + } DECL_DECLARED_INLINE_P (newdecl) |= DECL_DECLARED_INLINE_P (olddecl); diff --git a/gcc/testsuite/g++.dg/other/friend6.C b/gcc/testsuite/g++.dg/other/friend6.C new file mode 100644 index 0000000..5f593a1 --- /dev/null +++ b/gcc/testsuite/g++.dg/other/friend6.C @@ -0,0 +1,15 @@ +// PR c++/27100 +// This used to fail at link time with an "undefined reference to 'foo'" error. +// { dg-do link } + +struct A +{ + friend void foo (const A&) { } + friend void foo (const A&); +}; + +int +main () +{ + foo (A ()); +} -- 2.9.0.rc0.29.gabd6606