Fix pr61848, linux kernel miscompile

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
This commit is contained in:
Markus Trippelsdorf 2014-10-17 05:10:07 +00:00
parent d6db0df556
commit 5fcffe51f0
7 changed files with 84 additions and 40 deletions

View 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

View 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;
}

View 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.

View 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;

View 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.

View File

@ -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")));

View File

@ -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")));