Hi,
the invariant is that DECL_ORIGINAL_TYPE (t) != TREE_TYPE (t) as pointer value
if t is a TYPE_DECL. It's enforced by the DWARF back-end:
if (DECL_ORIGINAL_TYPE (decl))
{
type = DECL_ORIGINAL_TYPE (decl);
if (type == error_mark_node)
return;
gcc_assert (type != TREE_TYPE (decl));
[...]
/* Prevent broken recursion; we can't hand off to the same type. */
gcc_assert (DECL_ORIGINAL_TYPE (TYPE_NAME (type)) != type);
Unfortunately it can be easily broken in remap_decl:
/* Remap types, if necessary. */
TREE_TYPE (t) = remap_type (TREE_TYPE (t), id);
if (TREE_CODE (t) == TYPE_DECL)
DECL_ORIGINAL_TYPE (t) = remap_type (DECL_ORIGINAL_TYPE (t), id);
If TREE_TYPE (t) is for example a pointer to a variably-modified type, then
the types are remapped by means of build_pointer_type_for_mode, which means
that they are also canonicalized, so TREE_TYPE (t) == DECL_ORIGINAL_TYPE (t)
after the remapping. This happens in Ada, but also in C for:
extern void bar (void *) __attribute__((noreturn));
static int foo (int i, unsigned int n)
{
if (i == 0)
{
struct S { int a[n]; };
typedef struct S *ptr;
ptr p = __builtin_malloc (sizeof (struct S));
bar (p);
}
return i > 0 ? 1 : -1;
}
int f1 (int i, unsigned int n)
{
return foo (i, n);
}
int f2 (int i, unsigned int n)
{
return foo (i, n);
}
when foo is split into 2 parts at -O2.
This generally goes unnoticed because the inliner sets DECL_ABSTRACT_ORIGIN on
the remapped TYPE_DECL, so gen_typedef_die skips it:
type_die = new_die (DW_TAG_typedef, context_die, decl);
origin = decl_ultimate_origin (decl);
if (origin != NULL)
add_abstract_origin_attribute (type_die, origin);
else
{
tree type;
add_name_and_src_coords_attributes (type_die, decl);
if (DECL_ORIGINAL_TYPE (decl))
{
type = DECL_ORIGINAL_TYPE (decl);
if (type == error_mark_node)
return;
gcc_assert (type != TREE_TYPE (decl));
equate_type_number_to_die (TREE_TYPE (decl), type_die);
}
But, in LTO mode, DECL_ABSTRACT_ORIGIN is not streamed so it's another story
and this for example breaks the LTO build of the Ada compiler at -O2 -g.
Hence the attached ad-hoc attempt at preserving the invariant in remap_decl,
which appears to work and is sufficient to fix the aforementioned bootstrap.
Tested on x86_64-suse-linux, OK for the mainline?
2016-06-22 Eric Botcazou <ebotca...@adacore.com>
* tree-inline.c (remap_decl): Preserve DECL_ORIGINAL_TYPE invariant.
--
Eric Botcazou
Index: tree-inline.c
===================================================================
--- tree-inline.c (revision 237677)
+++ tree-inline.c (working copy)
@@ -367,7 +367,18 @@ remap_decl (tree decl, copy_body_data *i
/* Remap types, if necessary. */
TREE_TYPE (t) = remap_type (TREE_TYPE (t), id);
if (TREE_CODE (t) == TYPE_DECL)
- DECL_ORIGINAL_TYPE (t) = remap_type (DECL_ORIGINAL_TYPE (t), id);
+ {
+ DECL_ORIGINAL_TYPE (t) = remap_type (DECL_ORIGINAL_TYPE (t), id);
+
+ /* Preserve the invariant that DECL_ORIGINAL_TYPE != TREE_TYPE. */
+ if (DECL_ORIGINAL_TYPE (t) == TREE_TYPE (t))
+ {
+ tree x = build_variant_type_copy (TREE_TYPE (t));
+ TYPE_STUB_DECL (x) = TYPE_STUB_DECL (TREE_TYPE (t));
+ TYPE_NAME (x) = t;
+ DECL_ORIGINAL_TYPE (t) = x;
+ }
+ }
/* Remap sizes as necessary. */
walk_tree (&DECL_SIZE (t), copy_tree_body_r, id, NULL);