Fix pr61848, linux kernel miscompile
authorMarkus Trippelsdorf <trippels@gcc.gnu.org>
Fri, 17 Oct 2014 05:10:07 +0000 (05:10 +0000)
committerMarkus Trippelsdorf <trippels@gcc.gnu.org>
Fri, 17 Oct 2014 05:10:07 +0000 (05:10 +0000)
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.

2014-10-17  Alan Modra  <amodra@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-17  Markus Trippelsdorf  <markus@trippelsdorf.de>

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

From-SVN: r216361

gcc/ChangeLog
gcc/c/c-decl.c
gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/torture/pr61848.C [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/compile/pr61848.c [new file with mode: 0644]

index 8f76145135a6af758807cdf81fcd50f24f920f5b..b55d5d44117c9a7afcfc55666aa99d736f03e9a7 100644 (file)
@@ -1,3 +1,11 @@
+2014-10-17  Alan Modra  <amodra@gmail.com>
+
+       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.
+
 2014-10-16  DJ Delorie  <dj@redhat.com>
 
        * flag-types.h (sanitize_code): Don't assume targets have 32-bit
index fb16be6769c2ea06e10b240cc2409f0884273292..839c67bf7e9147ac8d8397055197b2c56344b13a 100644 (file)
@@ -2297,22 +2297,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);
@@ -2522,6 +2510,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;
        }
 
index 016c8f6f6f139af3a23c835240d17d5191cb291b..1148e9566adb464cb7f64d1abb52ef50a1959047 100644 (file)
@@ -1,3 +1,12 @@
+2014-10-17  Alan Modra  <amodra@gmail.com>
+
+       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  Andrew MacLeod  <amacleod@redhat.com>
 
        * cp-tree.h: Adjust include files.
index 3eba4dcd1d683290cda768d14381a1b9b5dbda10..1b214ab40907db0b18885b913498cc02e7b69337 100644 (file)
@@ -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) || TREE_STATIC (olddecl))
-         && DECL_SECTION_NAME (newdecl) == NULL
-         && DECL_SECTION_NAME (olddecl) != NULL)
-       set_decl_section_name (newdecl, DECL_SECTION_NAME (olddecl));
-
       if (TREE_CODE (newdecl) == FUNCTION_DECL)
        {
          DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl)
@@ -2083,19 +2073,6 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
   /* Merge the storage class information.  */
   merge_weak (newdecl, olddecl);
 
-  if ((TREE_CODE (olddecl) == FUNCTION_DECL || TREE_CODE (olddecl) == VAR_DECL)
-      && (DECL_EXTERNAL (olddecl) || TREE_PUBLIC (olddecl) || TREE_STATIC (olddecl))
-      && DECL_ONE_ONLY (olddecl))
-    {
-      struct symtab_node *symbol;
-      if (TREE_CODE (olddecl) == FUNCTION_DECL)
-       symbol = cgraph_node::get_create (newdecl);
-      else
-       symbol = varpool_node::get_create (newdecl);
-      symbol->set_comdat_group (symtab_node::get
-       (olddecl)->get_comdat_group ());
-    }
-
   DECL_DEFER_OUTPUT (newdecl) |= DECL_DEFER_OUTPUT (olddecl);
   TREE_PUBLIC (newdecl) = TREE_PUBLIC (olddecl);
   TREE_STATIC (olddecl) = TREE_STATIC (newdecl) |= TREE_STATIC (olddecl);
@@ -2449,12 +2426,12 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
     }
   else
     {
-      size_t size = tree_code_size (TREE_CODE (olddecl));
+      size_t size = tree_code_size (TREE_CODE (newdecl));
 
       memcpy ((char *) olddecl + sizeof (struct tree_common),
              (char *) newdecl + sizeof (struct tree_common),
              sizeof (struct tree_decl_common) - sizeof (struct tree_common));
-      switch (TREE_CODE (olddecl))
+      switch (TREE_CODE (newdecl))
        {
        case LABEL_DECL:
        case VAR_DECL:
@@ -2466,14 +2443,14 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
          {
             struct symtab_node *snode = NULL;
 
-            if (TREE_CODE (olddecl) == VAR_DECL
+            if (TREE_CODE (newdecl) == VAR_DECL
                && (TREE_STATIC (olddecl) || TREE_PUBLIC (olddecl) || DECL_EXTERNAL (olddecl)))
              snode = symtab_node::get (olddecl);
            memcpy ((char *) olddecl + sizeof (struct tree_decl_common),
                    (char *) newdecl + sizeof (struct tree_decl_common),
                    size - sizeof (struct tree_decl_common)
                    + TREE_CODE_LENGTH (TREE_CODE (newdecl)) * sizeof (char *));
-            if (TREE_CODE (olddecl) == VAR_DECL)
+            if (TREE_CODE (newdecl) == VAR_DECL)
              olddecl->decl_with_vis.symtab_node = snode;
          }
          break;
@@ -2485,6 +2462,38 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
          break;
        }
     }
+
+  if (TREE_CODE (newdecl) == FUNCTION_DECL
+      || TREE_CODE (newdecl) == VAR_DECL)
+    {
+      if (DECL_EXTERNAL (olddecl)
+         || TREE_PUBLIC (olddecl)
+         || TREE_STATIC (olddecl))
+       {
+         /* 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_SECTION_NAME (newdecl) != NULL)
+           set_decl_section_name (olddecl, DECL_SECTION_NAME (newdecl));
+
+         if (DECL_ONE_ONLY (newdecl))
+           {
+             struct symtab_node *oldsym, *newsym;
+             if (TREE_CODE (olddecl) == FUNCTION_DECL)
+               oldsym = cgraph_node::get_create (olddecl);
+             else
+               oldsym = varpool_node::get_create (olddecl);
+             newsym = symtab_node::get (newdecl);
+             oldsym->set_comdat_group (newsym->get_comdat_group ());
+           }
+       }
+
+      if (TREE_CODE (newdecl) == VAR_DECL
+         && DECL_THREAD_LOCAL_P (newdecl))
+       set_decl_tls_model (olddecl, DECL_TLS_MODEL (newdecl));
+    }
+
   DECL_UID (olddecl) = olddecl_uid;
   if (olddecl_friend)
     DECL_FRIEND_P (olddecl) = 1;
index 7f159c65e7f93bc9278d68bb19739ec9ab53173a..e24b295a826b97752ca30f04f707990bb527fd73 100644 (file)
@@ -1,3 +1,9 @@
+2014-10-17  Markus Trippelsdorf  <markus@trippelsdorf.de>
+
+       PR middle-end/61848
+       * g++.dg/torture/pr61848.C: New testcase.
+       * gcc.c-torture/compile/pr61848.c: New testcase.
+
 2014-10-16  Oleg Endo  <olegendo@gcc.gnu.org>
 
        * gcc.target/sh/cmpstr.c: Fix excess failures caused by switch to GNU11.
diff --git a/gcc/testsuite/g++.dg/torture/pr61848.C b/gcc/testsuite/g++.dg/torture/pr61848.C
new file mode 100644 (file)
index 0000000..beb490c
--- /dev/null
@@ -0,0 +1,5 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target named_sections } */
+/* { dg-final { scan-assembler "mysection" } } */
+extern char foo;
+char foo __attribute__ ((__section__(".mysection")));
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr61848.c b/gcc/testsuite/gcc.c-torture/compile/pr61848.c
new file mode 100644 (file)
index 0000000..beb490c
--- /dev/null
@@ -0,0 +1,5 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target named_sections } */
+/* { dg-final { scan-assembler "mysection" } } */
+extern char foo;
+char foo __attribute__ ((__section__(".mysection")));