Re: [PATCH] Fix PR c++/27100

2016-05-31 Thread Jason Merrill
On Mon, May 30, 2016 at 4:19 PM, Patrick Palka  wrote:
> 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.

That gets into undefined behavior; let's go with the first patch.

Jason


[PATCH] Fix PR c++/27100

2016-05-30 Thread Patrick Palka
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 000..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



[PATCH] Fix PR c++/27100

2016-04-16 Thread Patrick Palka
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 000..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