[PATCH v2] Fix pr61848, linux kernel miscompile

2014-10-16 Thread Markus Trippelsdorf
(I've taken Alan's patch and added two new testcases.)

This patch cures the linux kernel boot failure when compiled using
trunk gcc. 

At its heart, the problem is caused by merge_decls merging from the
old decl to the new decl, then copying back to the old decl and
discarding the new.  When Jan moved some fields to the symtab,
copying back to the old decl was lost for those fields.  Really,
it would be best if merge_decls was rewritten to merge everything to
the kept decl, but here I'm just doing that for fields accessed via
decl_with_vis.symtab_node.

Tested on powerpc64-unknown-linux-gnu.
OK for trunk?
Thanks.

2014-10-16  Alan Modra  amo...@gmail.com

gcc/c/
PR middle-end/61848
* c-decl.c (merge_decls): Don't merge section name or tls model
to newdecl symtab node, instead merge to olddecl.  Override
existing olddecl section name.  Set tls_model for all thread-local
vars, not just OMP thread-private ones.  Remove incorrect comment.
gcc/cp/
PR middle-end/61848
* decl.c (merge_decls): Don't merge section name, comdat group or
tls model to newdecl symtab node, instead merge to olddecl.
Override existing olddecl section name.  Set tls_model for all
thread-local vars, not just OMP thread-private ones.  Remove
incorrect comment.

2014-10-16  Markus Trippelsdorf  mar...@trippelsdorf.de

PR middle-end/61848
g++.dg/torture/pr61848.C: New testcase.
gcc.c-torture/compile/pr61848.c: New testcase.

---
 gcc/c/c-decl.c| 28 ++--
 gcc/cp/decl.c | 63 +++
 gcc/testsuite/g++.dg/torture/pr61848.C|  5 +++
 gcc/testsuite/gcc.c-torture/compile/pr61848.c |  5 +++
 4 files changed, 61 insertions(+), 40 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/torture/pr61848.C
 create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr61848.c

diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index d9941141041e..18388cb59252 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -2293,22 +2293,10 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, 
tree oldtype)
 
   /* Merge the threadprivate attribute.  */
   if (TREE_CODE (olddecl) == VAR_DECL  C_DECL_THREADPRIVATE_P (olddecl))
-{
-  set_decl_tls_model (newdecl, DECL_TLS_MODEL (olddecl));
-  C_DECL_THREADPRIVATE_P (newdecl) = 1;
-}
+C_DECL_THREADPRIVATE_P (newdecl) = 1;
 
   if (CODE_CONTAINS_STRUCT (TREE_CODE (olddecl), TS_DECL_WITH_VIS))
 {
-  /* Merge the section attribute.
-We want to issue an error if the sections conflict but that
-must be done later in decl_attributes since we are called
-before attributes are assigned.  */
-  if ((DECL_EXTERNAL (olddecl) || TREE_PUBLIC (olddecl) || TREE_STATIC 
(olddecl))
-  DECL_SECTION_NAME (newdecl) == NULL
-  DECL_SECTION_NAME (olddecl))
-   set_decl_section_name (newdecl, DECL_SECTION_NAME (olddecl));
-
   /* Copy the assembler name.
 Currently, it can only be defined in the prototype.  */
   COPY_DECL_ASSEMBLER_NAME (olddecl, newdecl);
@@ -2518,6 +2506,20 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, 
tree oldtype)
  (char *) newdecl + sizeof (struct tree_decl_common),
  tree_code_size (TREE_CODE (olddecl)) - sizeof (struct 
tree_decl_common));
  olddecl-decl_with_vis.symtab_node = snode;
+
+ if ((DECL_EXTERNAL (olddecl)
+  || TREE_PUBLIC (olddecl)
+  || TREE_STATIC (olddecl))
+  DECL_SECTION_NAME (newdecl) != NULL)
+   set_decl_section_name (olddecl, DECL_SECTION_NAME (newdecl));
+
+ /* This isn't quite correct for something like
+   int __thread x attribute ((tls_model (local-exec)));
+   extern int __thread x;
+as we'll lose the local-exec model.  */
+ if (TREE_CODE (olddecl) == VAR_DECL
+  DECL_THREAD_LOCAL_P (newdecl))
+   set_decl_tls_model (olddecl, DECL_TLS_MODEL (newdecl));
  break;
}
 
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 3eba4dcd1d68..1b214ab40907 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -1967,7 +1967,6 @@ duplicate_decls (tree newdecl, tree olddecl, bool 
newdecl_is_friend)
  if (!DECL_LANG_SPECIFIC (newdecl))
retrofit_lang_decl (newdecl);
 
- set_decl_tls_model (newdecl, DECL_TLS_MODEL (olddecl));
  CP_DECL_THREADPRIVATE_P (newdecl) = 1;
}
}
@@ -2030,15 +2029,6 @@ duplicate_decls (tree newdecl, tree olddecl, bool 
newdecl_is_friend)
}
}
 
-  /* Merge the section attribute.
-We want to issue an error if the sections conflict but that must be
-done later in decl_attributes since we are called before attributes
-are assigned.  */
-  if ((DECL_EXTERNAL (olddecl) || TREE_PUBLIC (olddecl) || 

Re: [PATCH v2] Fix pr61848, linux kernel miscompile

2014-10-16 Thread Jeff Law

On 10/16/14 06:40, Markus Trippelsdorf wrote:

(I've taken Alan's patch and added two new testcases.)

This patch cures the linux kernel boot failure when compiled using
trunk gcc.

At its heart, the problem is caused by merge_decls merging from the
old decl to the new decl, then copying back to the old decl and
discarding the new.  When Jan moved some fields to the symtab,
copying back to the old decl was lost for those fields.  Really,
it would be best if merge_decls was rewritten to merge everything to
the kept decl, but here I'm just doing that for fields accessed via
decl_with_vis.symtab_node.

Tested on powerpc64-unknown-linux-gnu.
OK for trunk?
Thanks.

2014-10-16  Alan Modra  amo...@gmail.com

gcc/c/
PR middle-end/61848
* c-decl.c (merge_decls): Don't merge section name or tls model
to newdecl symtab node, instead merge to olddecl.  Override
existing olddecl section name.  Set tls_model for all thread-local
vars, not just OMP thread-private ones.  Remove incorrect comment.
gcc/cp/
PR middle-end/61848
* decl.c (merge_decls): Don't merge section name, comdat group or
tls model to newdecl symtab node, instead merge to olddecl.
Override existing olddecl section name.  Set tls_model for all
thread-local vars, not just OMP thread-private ones.  Remove
incorrect comment.

2014-10-16  Markus Trippelsdorf  mar...@trippelsdorf.de

PR middle-end/61848
g++.dg/torture/pr61848.C: New testcase.
gcc.c-torture/compile/pr61848.c: New testcase.

OK.
Jeff