The problem here is that duplicate_decls doesn't preserve the DECL_PENDING_INLINE_P flag of the old decl in the new decl. This happens only when a friend function is defined inside a class and then redeclared. The initial definition sets the DECL_PENDING_INLINE_P flag, but the subsequent redeclaration doesn't retain the flag.
This patch makes duplicate_decls retain the DECL_PENDING_INLINE_P flag from the old decl to the new decl. Bootstrapped + regtested on x86_64-pc-linux-gnu. Does this look OK to commit? gcc/cp/ChangeLog: PR c++/27100 * decl.c (duplicate_decls): Properly copy the DECL_PENDING_INLINE_P, DECL_PENDING_INLINE_INFO and DECL_SAVED_FUNCTION_DATA fields from OLDDECL to NEWDECL. gcc/testsuite/ChangeLog: PR c++/27100 * g++.dg/other/friend6.C: New test. --- gcc/cp/decl.c | 13 +++++++++++-- gcc/testsuite/g++.dg/other/friend6.C | 15 +++++++++++++++ 2 files changed, 26 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 c1ad52f..4f79c71 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -2375,8 +2375,17 @@ 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_P (olddecl)) + { + DECL_PENDING_INLINE_P (newdecl) = 1; + DECL_PENDING_INLINE_INFO (newdecl) + = DECL_PENDING_INLINE_INFO (olddecl); + } + else if (DECL_PENDING_INLINE_P (newdecl)) + ; + else if (DECL_SAVED_FUNCTION_DATA (newdecl) == NULL) + DECL_SAVED_FUNCTION_DATA (newdecl) + = DECL_SAVED_FUNCTION_DATA (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.8.1.231.g95ac767