mirror of git://gcc.gnu.org/git/gcc.git
re PR lto/65316 (LTO: Uninitialized memory / ICE with -g -fno-lto-odr-type-merging: in types_same_for_odr, at ipa-devirt.c:465)
PR lto/65316 * ipa-utils.h (types_odr_comparable): Add strict argument. * ipa-devirt.c: Fix whitespace; (odr_hasher): Remove. (odr_name_hasher, odr_vtable_hasher): New hashers. (can_be_name_hashed_p): New predicate. (hash_type_name): remove. (hash_odr_name): New. (odr_name_hasher::hash): new. (can_be_vtable_hashed_p): New. (hash_odr_vtable): New. (odr_vtable_hasher::hash): New. (types_same_for_odr): Add strict parameter. (types_odr_comparable): Likewise. (odr_name_hasher::equal): New. (odr_vtable_hasher::equal): New. (odr_name_hasher::remove): New. (odr_hash_type): Change to hash_table<odr_name_hasher>. (odr_vtable_hash_type): New. (odr_vtable_hash): New. (odr_subtypes_equivalent_p): Do strict comparsion. (add_type_duplicate): Merge type names; cleanup; avoid type duplicates. (register_odr_type): Initialize vtable hash. (build_type_inheritance_graph): Likewise (get_odr_type): Reorg to use two hashes. (dump_possible_polymorphic_call_targets): Move sanity check after debug output. (ipa_devirt): Dump type_inheritance_graph. (types_same_for_odr): Add strict mode. * g++.dg/lto/pr65316_0.C: New testcase. * g++.dg/lto/pr65316_1.C: New testcase. From-SVN: r221275
This commit is contained in:
parent
e1e8e374f4
commit
609570b49e
|
|
@ -1,3 +1,36 @@
|
|||
2015-03-08 Jan Hubicka <hubicka@ucw.cz>
|
||||
|
||||
PR lto/65316
|
||||
* ipa-utils.h (types_odr_comparable): Add strict argument.
|
||||
* ipa-devirt.c: Fix whitespace;
|
||||
(odr_hasher): Remove.
|
||||
(odr_name_hasher, odr_vtable_hasher): New hashers.
|
||||
(can_be_name_hashed_p): New predicate.
|
||||
(hash_type_name): remove.
|
||||
(hash_odr_name): New.
|
||||
(odr_name_hasher::hash): new.
|
||||
(can_be_vtable_hashed_p): New.
|
||||
(hash_odr_vtable): New.
|
||||
(odr_vtable_hasher::hash): New.
|
||||
(types_same_for_odr): Add strict parameter.
|
||||
(types_odr_comparable): Likewise.
|
||||
(odr_name_hasher::equal): New.
|
||||
(odr_vtable_hasher::equal): New.
|
||||
(odr_name_hasher::remove): New.
|
||||
(odr_hash_type): Change to hash_table<odr_name_hasher>.
|
||||
(odr_vtable_hash_type): New.
|
||||
(odr_vtable_hash): New.
|
||||
(odr_subtypes_equivalent_p): Do strict comparsion.
|
||||
(add_type_duplicate): Merge type names; cleanup; avoid type
|
||||
duplicates.
|
||||
(register_odr_type): Initialize vtable hash.
|
||||
(build_type_inheritance_graph): Likewise
|
||||
(get_odr_type): Reorg to use two hashes.
|
||||
(dump_possible_polymorphic_call_targets): Move sanity check after debug
|
||||
output.
|
||||
(ipa_devirt): Dump type_inheritance_graph.
|
||||
(types_same_for_odr): Add strict mode.
|
||||
|
||||
2015-03-05 Jan Hubicka <hubicka@ucw.cz>
|
||||
|
||||
PR ipa/65334
|
||||
|
|
|
|||
322
gcc/ipa-devirt.c
322
gcc/ipa-devirt.c
|
|
@ -299,9 +299,10 @@ type_possibly_instantiated_p (tree t)
|
|||
return vnode && vnode->definition;
|
||||
}
|
||||
|
||||
/* One Definition Rule hashtable helpers. */
|
||||
/* Hash used to unify ODR types based on their mangled name and for anonymous
|
||||
namespace types. */
|
||||
|
||||
struct odr_hasher
|
||||
struct odr_name_hasher
|
||||
{
|
||||
typedef odr_type_d value_type;
|
||||
typedef union tree_node compare_type;
|
||||
|
|
@ -310,6 +311,16 @@ struct odr_hasher
|
|||
static inline void remove (value_type *);
|
||||
};
|
||||
|
||||
/* Has used to unify ODR types based on their associated virtual table.
|
||||
This hash is needed to keep -fno-lto-odr-type-merging to work and contains
|
||||
only polymorphic types. Types with mangled names are inserted to both. */
|
||||
|
||||
struct odr_vtable_hasher:odr_name_hasher
|
||||
{
|
||||
static inline hashval_t hash (const value_type *);
|
||||
static inline bool equal (const value_type *, const compare_type *);
|
||||
};
|
||||
|
||||
/* Return type that was declared with T's name so that T is an
|
||||
qualified variant of it. */
|
||||
|
||||
|
|
@ -323,10 +334,17 @@ main_odr_variant (const_tree t)
|
|||
return TYPE_MAIN_VARIANT (t);
|
||||
}
|
||||
|
||||
/* Produce hash based on type name. */
|
||||
static bool
|
||||
can_be_name_hashed_p (tree t)
|
||||
{
|
||||
return (!in_lto_p || type_in_anonymous_namespace_p (t)
|
||||
|| (TYPE_NAME (t) && DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (t))));
|
||||
}
|
||||
|
||||
/* Hash type by its ODR name. */
|
||||
|
||||
static hashval_t
|
||||
hash_type_name (tree t)
|
||||
hash_odr_name (const_tree t)
|
||||
{
|
||||
gcc_checking_assert (main_odr_variant (t) == t);
|
||||
|
||||
|
|
@ -339,46 +357,62 @@ hash_type_name (tree t)
|
|||
if (type_in_anonymous_namespace_p (t))
|
||||
return htab_hash_pointer (t);
|
||||
|
||||
/* ODR types have name specified. */
|
||||
if (TYPE_NAME (t)
|
||||
&& DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (t)))
|
||||
gcc_checking_assert (TYPE_NAME (t)
|
||||
&& DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (t)));
|
||||
return IDENTIFIER_HASH_VALUE (DECL_ASSEMBLER_NAME (TYPE_NAME (t)));
|
||||
|
||||
/* For polymorphic types that was compiled with -fno-lto-odr-type-merging
|
||||
we can simply hash the virtual table. */
|
||||
if (TREE_CODE (t) == RECORD_TYPE
|
||||
&& TYPE_BINFO (t) && BINFO_VTABLE (TYPE_BINFO (t)))
|
||||
{
|
||||
tree v = BINFO_VTABLE (TYPE_BINFO (t));
|
||||
hashval_t hash = 0;
|
||||
|
||||
if (TREE_CODE (v) == POINTER_PLUS_EXPR)
|
||||
{
|
||||
hash = TREE_INT_CST_LOW (TREE_OPERAND (v, 1));
|
||||
v = TREE_OPERAND (TREE_OPERAND (v, 0), 0);
|
||||
}
|
||||
|
||||
v = DECL_ASSEMBLER_NAME (v);
|
||||
hash = iterative_hash_hashval_t (hash, htab_hash_pointer (v));
|
||||
return hash;
|
||||
}
|
||||
|
||||
/* Builtin types may appear as main variants of ODR types and are unique.
|
||||
Sanity check we do not get anything that looks non-builtin. */
|
||||
gcc_checking_assert (TREE_CODE (t) == INTEGER_TYPE
|
||||
|| TREE_CODE (t) == VOID_TYPE
|
||||
|| TREE_CODE (t) == COMPLEX_TYPE
|
||||
|| TREE_CODE (t) == REAL_TYPE
|
||||
|| TREE_CODE (t) == POINTER_TYPE);
|
||||
return htab_hash_pointer (t);
|
||||
}
|
||||
|
||||
/* Return the computed hashcode for ODR_TYPE. */
|
||||
|
||||
inline hashval_t
|
||||
odr_hasher::hash (const value_type *odr_type)
|
||||
odr_name_hasher::hash (const value_type *odr_type)
|
||||
{
|
||||
return hash_type_name (odr_type->type);
|
||||
return hash_odr_name (odr_type->type);
|
||||
}
|
||||
|
||||
static bool
|
||||
can_be_vtable_hashed_p (tree t)
|
||||
{
|
||||
/* vtable hashing can distinguish only main variants. */
|
||||
if (TYPE_MAIN_VARIANT (t) != t)
|
||||
return false;
|
||||
/* Anonymous namespace types are always handled by name hash. */
|
||||
if (type_in_anonymous_namespace_p (t))
|
||||
return false;
|
||||
return (TREE_CODE (t) == RECORD_TYPE
|
||||
&& TYPE_BINFO (t) && BINFO_VTABLE (TYPE_BINFO (t)));
|
||||
}
|
||||
|
||||
/* Hash type by assembler name of its vtable. */
|
||||
|
||||
static hashval_t
|
||||
hash_odr_vtable (const_tree t)
|
||||
{
|
||||
tree v = BINFO_VTABLE (TYPE_BINFO (TYPE_MAIN_VARIANT (t)));
|
||||
inchash::hash hstate;
|
||||
|
||||
gcc_checking_assert (in_lto_p);
|
||||
gcc_checking_assert (!type_in_anonymous_namespace_p (t));
|
||||
gcc_checking_assert (TREE_CODE (t) == RECORD_TYPE
|
||||
&& TYPE_BINFO (t) && BINFO_VTABLE (TYPE_BINFO (t)));
|
||||
gcc_checking_assert (main_odr_variant (t) == t);
|
||||
|
||||
if (TREE_CODE (v) == POINTER_PLUS_EXPR)
|
||||
{
|
||||
add_expr (TREE_OPERAND (v, 1), hstate);
|
||||
v = TREE_OPERAND (TREE_OPERAND (v, 0), 0);
|
||||
}
|
||||
|
||||
hstate.add_wide_int (IDENTIFIER_HASH_VALUE (DECL_ASSEMBLER_NAME (v)));
|
||||
return hstate.end ();
|
||||
}
|
||||
|
||||
/* Return the computed hashcode for ODR_TYPE. */
|
||||
|
||||
inline hashval_t
|
||||
odr_vtable_hasher::hash (const value_type *odr_type)
|
||||
{
|
||||
return hash_odr_vtable (odr_type->type);
|
||||
}
|
||||
|
||||
/* For languages with One Definition Rule, work out if
|
||||
|
|
@ -389,15 +423,25 @@ odr_hasher::hash (const value_type *odr_type)
|
|||
to merge two copies of otherwise equivalent type.
|
||||
|
||||
Until we start streaming mangled type names, this function works
|
||||
only for polymorphic types. */
|
||||
only for polymorphic types.
|
||||
|
||||
When STRICT is true, we compare types by their names for purposes of
|
||||
ODR violation warnings. When strict is false, we consider variants
|
||||
equivalent, becuase it is all that matters for devirtualization machinery.
|
||||
*/
|
||||
|
||||
bool
|
||||
types_same_for_odr (const_tree type1, const_tree type2)
|
||||
types_same_for_odr (const_tree type1, const_tree type2, bool strict)
|
||||
{
|
||||
gcc_checking_assert (TYPE_P (type1) && TYPE_P (type2));
|
||||
|
||||
type1 = main_odr_variant (type1);
|
||||
type2 = main_odr_variant (type2);
|
||||
if (!strict)
|
||||
{
|
||||
type1 = TYPE_MAIN_VARIANT (type1);
|
||||
type2 = TYPE_MAIN_VARIANT (type2);
|
||||
}
|
||||
|
||||
if (type1 == type2)
|
||||
return true;
|
||||
|
|
@ -434,7 +478,8 @@ types_same_for_odr (const_tree type1, const_tree type2)
|
|||
if (TREE_CODE (type1) != TREE_CODE (type2))
|
||||
return false;
|
||||
if (TREE_CODE (type1) == RECORD_TYPE
|
||||
&& (TYPE_BINFO (type1) == NULL_TREE) != (TYPE_BINFO (type1) == NULL_TREE))
|
||||
&& (TYPE_BINFO (type1) == NULL_TREE)
|
||||
!= (TYPE_BINFO (type1) == NULL_TREE))
|
||||
return false;
|
||||
if (TREE_CODE (type1) == RECORD_TYPE && TYPE_BINFO (type1)
|
||||
&& (BINFO_VTABLE (TYPE_BINFO (type1)) == NULL_TREE)
|
||||
|
|
@ -471,13 +516,16 @@ types_same_for_odr (const_tree type1, const_tree type2)
|
|||
/* Return true if we can decide on ODR equivalency.
|
||||
|
||||
In non-LTO it is always decide, in LTO however it depends in the type has
|
||||
ODR info attached. */
|
||||
ODR info attached.
|
||||
|
||||
When STRICT is false, compare main variants. */
|
||||
|
||||
bool
|
||||
types_odr_comparable (tree t1, tree t2)
|
||||
types_odr_comparable (tree t1, tree t2, bool strict)
|
||||
{
|
||||
return (!in_lto_p
|
||||
|| main_odr_variant (t1) == main_odr_variant (t2)
|
||||
|| (strict ? main_odr_variant (t1) == main_odr_variant (t2)
|
||||
: TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
|
||||
|| (odr_type_p (t1) && odr_type_p (t2))
|
||||
|| (TREE_CODE (t1) == RECORD_TYPE && TREE_CODE (t2) == RECORD_TYPE
|
||||
&& TYPE_BINFO (t1) && TYPE_BINFO (t2)
|
||||
|
|
@ -494,29 +542,63 @@ types_must_be_same_for_odr (tree t1, tree t2)
|
|||
if (types_odr_comparable (t1, t2))
|
||||
return types_same_for_odr (t1, t2);
|
||||
else
|
||||
return main_odr_variant (t1) == main_odr_variant (t2);
|
||||
return TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2);
|
||||
}
|
||||
|
||||
/* Compare types T1 and T2 and return true if they are
|
||||
equivalent. */
|
||||
|
||||
inline bool
|
||||
odr_hasher::equal (const value_type *t1, const compare_type *ct2)
|
||||
odr_name_hasher::equal (const value_type *o1, const compare_type *t2)
|
||||
{
|
||||
tree t2 = const_cast <tree> (ct2);
|
||||
tree t1 = o1->type;
|
||||
|
||||
gcc_checking_assert (main_odr_variant (t2) == t2);
|
||||
if (t1->type == t2)
|
||||
gcc_checking_assert (main_odr_variant (t1) == t1);
|
||||
if (t1 == t2)
|
||||
return true;
|
||||
if (!in_lto_p)
|
||||
return false;
|
||||
return types_same_for_odr (t1->type, t2);
|
||||
/* Check for anonymous namespaces. Those have !TREE_PUBLIC
|
||||
on the corresponding TYPE_STUB_DECL. */
|
||||
if (type_in_anonymous_namespace_p (t1)
|
||||
|| type_in_anonymous_namespace_p (t2))
|
||||
return false;
|
||||
gcc_checking_assert (DECL_ASSEMBLER_NAME (TYPE_NAME (t1)));
|
||||
gcc_checking_assert (DECL_ASSEMBLER_NAME (TYPE_NAME (t2)));
|
||||
return (DECL_ASSEMBLER_NAME (TYPE_NAME (t1))
|
||||
== DECL_ASSEMBLER_NAME (TYPE_NAME (t2)));
|
||||
}
|
||||
|
||||
/* Compare types T1 and T2 and return true if they are
|
||||
equivalent. */
|
||||
|
||||
inline bool
|
||||
odr_vtable_hasher::equal (const value_type *o1, const compare_type *t2)
|
||||
{
|
||||
tree t1 = o1->type;
|
||||
|
||||
gcc_checking_assert (main_odr_variant (t2) == t2);
|
||||
gcc_checking_assert (main_odr_variant (t1) == t1);
|
||||
gcc_checking_assert (in_lto_p);
|
||||
t1 = TYPE_MAIN_VARIANT (t1);
|
||||
t2 = TYPE_MAIN_VARIANT (t2);
|
||||
if (t1 == t2)
|
||||
return true;
|
||||
tree v1 = BINFO_VTABLE (TYPE_BINFO (t1));
|
||||
tree v2 = BINFO_VTABLE (TYPE_BINFO (t2));
|
||||
return (operand_equal_p (TREE_OPERAND (v1, 1),
|
||||
TREE_OPERAND (v2, 1), 0)
|
||||
&& DECL_ASSEMBLER_NAME
|
||||
(TREE_OPERAND (TREE_OPERAND (v1, 0), 0))
|
||||
== DECL_ASSEMBLER_NAME
|
||||
(TREE_OPERAND (TREE_OPERAND (v2, 0), 0)));
|
||||
}
|
||||
|
||||
/* Free ODR type V. */
|
||||
|
||||
inline void
|
||||
odr_hasher::remove (value_type *v)
|
||||
odr_name_hasher::remove (value_type *v)
|
||||
{
|
||||
v->bases.release ();
|
||||
v->derived_types.release ();
|
||||
|
|
@ -527,8 +609,10 @@ odr_hasher::remove (value_type *v)
|
|||
|
||||
/* ODR type hash used to look up ODR type based on tree type node. */
|
||||
|
||||
typedef hash_table<odr_hasher> odr_hash_type;
|
||||
typedef hash_table<odr_name_hasher> odr_hash_type;
|
||||
static odr_hash_type *odr_hash;
|
||||
typedef hash_table<odr_vtable_hasher> odr_vtable_hash_type;
|
||||
static odr_vtable_hash_type *odr_vtable_hash;
|
||||
|
||||
/* ODR types are also stored into ODR_TYPE vector to allow consistent
|
||||
walking. Bases appear before derived types. Vector is garbage collected
|
||||
|
|
@ -573,9 +657,9 @@ odr_subtypes_equivalent_p (tree t1, tree t2,
|
|||
/* For ODR types be sure to compare their names.
|
||||
To support -wno-odr-type-merging we allow one type to be non-ODR
|
||||
and other ODR even though it is a violation. */
|
||||
if (types_odr_comparable (t1, t2))
|
||||
if (types_odr_comparable (t1, t2, true))
|
||||
{
|
||||
if (!types_same_for_odr (t1, t2))
|
||||
if (!types_same_for_odr (t1, t2, true))
|
||||
return false;
|
||||
/* Limit recursion: If subtypes are ODR types and we know
|
||||
that they are same, be happy. */
|
||||
|
|
@ -721,7 +805,7 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable)
|
|||
inform (DECL_SOURCE_LOCATION
|
||||
(TYPE_NAME (DECL_CONTEXT (prevailing->decl))),
|
||||
"the conflicting type defined in another translation "
|
||||
"unit virtual table with different RTTI information");
|
||||
"unit with different RTTI information");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -1312,32 +1396,45 @@ odr_types_equivalent_p (tree t1, tree t2, bool warn, bool *warned,
|
|||
|
||||
/* TYPE is equivalent to VAL by ODR, but its tree representation differs
|
||||
from VAL->type. This may happen in LTO where tree merging did not merge
|
||||
all variants of the same type. It may or may not mean the ODR violation.
|
||||
Add it to the list of duplicates and warn on some violations. */
|
||||
all variants of the same type or due to ODR violation.
|
||||
|
||||
Analyze and report ODR violations and add type to duplicate list.
|
||||
If TYPE is more specified than VAL->type, prevail VAL->type. Also if
|
||||
this is first time we see definition of a class return true so the
|
||||
base types are analyzed. */
|
||||
|
||||
static bool
|
||||
add_type_duplicate (odr_type val, tree type)
|
||||
{
|
||||
bool build_bases = false;
|
||||
bool prevail = false;
|
||||
|
||||
if (!val->types_set)
|
||||
val->types_set = new hash_set<tree>;
|
||||
|
||||
/* Always prefer complete type to be the leader. */
|
||||
|
||||
if (!COMPLETE_TYPE_P (val->type) && COMPLETE_TYPE_P (type))
|
||||
build_bases = true;
|
||||
{
|
||||
prevail = true;
|
||||
build_bases = TYPE_BINFO (type);
|
||||
}
|
||||
else if (COMPLETE_TYPE_P (val->type) && !COMPLETE_TYPE_P (type))
|
||||
;
|
||||
else if (TREE_CODE (val->type) == ENUMERAL_TYPE
|
||||
&& TREE_CODE (type) == ENUMERAL_TYPE
|
||||
&& !TYPE_VALUES (val->type) && TYPE_VALUES (type))
|
||||
build_bases = true;
|
||||
prevail = true;
|
||||
else if (TREE_CODE (val->type) == RECORD_TYPE
|
||||
&& TREE_CODE (type) == RECORD_TYPE
|
||||
&& TYPE_BINFO (type) && !TYPE_BINFO (val->type))
|
||||
{
|
||||
gcc_assert (!val->bases.length ());
|
||||
build_bases = true;
|
||||
prevail = true;
|
||||
}
|
||||
|
||||
if (build_bases)
|
||||
if (prevail)
|
||||
{
|
||||
tree tmp = type;
|
||||
|
||||
|
|
@ -1345,9 +1442,15 @@ add_type_duplicate (odr_type val, tree type)
|
|||
val->type = tmp;
|
||||
}
|
||||
|
||||
/* See if this duplicate is new. */
|
||||
if (!val->types_set->add (type))
|
||||
{
|
||||
val->types_set->add (type);
|
||||
|
||||
/* If we now have a mangled name, be sure to record it to val->type
|
||||
so ODR hash can work. */
|
||||
|
||||
if (can_be_name_hashed_p (type) && !can_be_name_hashed_p (val->type))
|
||||
SET_DECL_ASSEMBLER_NAME (TYPE_NAME (val->type),
|
||||
DECL_ASSEMBLER_NAME (TYPE_NAME (type)));
|
||||
|
||||
bool merge = true;
|
||||
bool base_mismatch = false;
|
||||
unsigned int i;
|
||||
|
|
@ -1451,14 +1554,26 @@ add_type_duplicate (odr_type val, tree type)
|
|||
"layout is defined in another translation unit");
|
||||
break;
|
||||
}
|
||||
/* One of bases is not of complete type. */
|
||||
if (!TYPE_BINFO (type1) != !TYPE_BINFO (type2))
|
||||
{
|
||||
/* If we have a polymorphic type info specified for TYPE1
|
||||
but not for TYPE2 we possibly missed a base when recording
|
||||
VAL->type earlier.
|
||||
Be sure this does not happen. */
|
||||
gcc_assert (TYPE_BINFO (type2)
|
||||
|| !polymorphic_type_binfo_p (TYPE_BINFO (type1))
|
||||
|| build_bases);
|
||||
break;
|
||||
}
|
||||
/* One base is polymorphic and the other not.
|
||||
This ought to be diagnosed earlier, but do not ICE in the
|
||||
checking bellow. */
|
||||
if (!TYPE_BINFO (type1) != !TYPE_BINFO (type2)
|
||||
|| (TYPE_BINFO (type1)
|
||||
else if (TYPE_BINFO (type1)
|
||||
&& polymorphic_type_binfo_p (TYPE_BINFO (type1))
|
||||
!= polymorphic_type_binfo_p (TYPE_BINFO (type2))))
|
||||
!= polymorphic_type_binfo_p (TYPE_BINFO (type2)))
|
||||
{
|
||||
gcc_assert (val->odr_violated);
|
||||
base_mismatch = true;
|
||||
break;
|
||||
}
|
||||
|
|
@ -1566,7 +1681,6 @@ add_type_duplicate (odr_type val, tree type)
|
|||
else
|
||||
set_type_binfo (type, master_binfo);
|
||||
}
|
||||
}
|
||||
return build_bases;
|
||||
}
|
||||
|
||||
|
|
@ -1576,8 +1690,9 @@ add_type_duplicate (odr_type val, tree type)
|
|||
odr_type
|
||||
get_odr_type (tree type, bool insert)
|
||||
{
|
||||
odr_type_d **slot;
|
||||
odr_type val;
|
||||
odr_type_d **slot = NULL;
|
||||
odr_type_d **vtable_slot = NULL;
|
||||
odr_type val = NULL;
|
||||
hashval_t hash;
|
||||
bool build_bases = false;
|
||||
bool insert_to_odr_array = false;
|
||||
|
|
@ -1585,22 +1700,69 @@ get_odr_type (tree type, bool insert)
|
|||
|
||||
type = main_odr_variant (type);
|
||||
|
||||
hash = hash_type_name (type);
|
||||
gcc_checking_assert (can_be_name_hashed_p (type)
|
||||
|| can_be_vtable_hashed_p (type));
|
||||
|
||||
/* Lookup entry, first try name hash, fallback to vtable hash. */
|
||||
if (can_be_name_hashed_p (type))
|
||||
{
|
||||
hash = hash_odr_name (type);
|
||||
slot = odr_hash->find_slot_with_hash (type, hash,
|
||||
insert ? INSERT : NO_INSERT);
|
||||
if (!slot)
|
||||
}
|
||||
if ((!slot || !*slot) && in_lto_p && can_be_vtable_hashed_p (type))
|
||||
{
|
||||
hash = hash_odr_vtable (type);
|
||||
vtable_slot = odr_vtable_hash->find_slot_with_hash (type, hash,
|
||||
insert ? INSERT : NO_INSERT);
|
||||
}
|
||||
|
||||
if (!slot && !vtable_slot)
|
||||
return NULL;
|
||||
|
||||
/* See if we already have entry for type. */
|
||||
if (*slot)
|
||||
if ((slot && *slot) || (vtable_slot && *vtable_slot))
|
||||
{
|
||||
if (slot && *slot)
|
||||
{
|
||||
val = *slot;
|
||||
#ifdef ENABLE_CHECKING
|
||||
if (in_lto_p && can_be_vtable_hashed_p (type))
|
||||
{
|
||||
hash = hash_odr_vtable (type);
|
||||
vtable_slot = odr_vtable_hash->find_slot_with_hash (type, hash,
|
||||
NO_INSERT);
|
||||
gcc_assert (!vtable_slot || *vtable_slot == *slot);
|
||||
vtable_slot = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if (*vtable_slot)
|
||||
val = *vtable_slot;
|
||||
|
||||
/* With LTO we need to support multiple tree representation of
|
||||
the same ODR type. */
|
||||
if (val->type != type)
|
||||
if (val->type != type
|
||||
&& (!val->types_set || !val->types_set->add (type)))
|
||||
{
|
||||
gcc_assert (insert);
|
||||
/* We have type duplicate, but it may introduce vtable name or
|
||||
mangled name; be sure to keep hashes in sync. */
|
||||
if (in_lto_p && can_be_vtable_hashed_p (type)
|
||||
&& (!vtable_slot || !*vtable_slot))
|
||||
{
|
||||
if (!vtable_slot)
|
||||
{
|
||||
hash = hash_odr_vtable (type);
|
||||
vtable_slot = odr_vtable_hash->find_slot_with_hash
|
||||
(type, hash, INSERT);
|
||||
gcc_checking_assert (!*vtable_slot || *vtable_slot == val);
|
||||
}
|
||||
*vtable_slot = val;
|
||||
}
|
||||
if (slot && !*slot)
|
||||
*slot = val;
|
||||
build_bases = add_type_duplicate (val, type);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
val = ggc_cleared_alloc<odr_type_d> ();
|
||||
|
|
@ -1610,7 +1772,10 @@ get_odr_type (tree type, bool insert)
|
|||
val->anonymous_namespace = type_in_anonymous_namespace_p (type);
|
||||
build_bases = COMPLETE_TYPE_P (val->type);
|
||||
insert_to_odr_array = true;
|
||||
if (slot)
|
||||
*slot = val;
|
||||
if (vtable_slot)
|
||||
*vtable_slot = val;
|
||||
}
|
||||
|
||||
if (build_bases && TREE_CODE (type) == RECORD_TYPE && TYPE_BINFO (type)
|
||||
|
|
@ -1664,7 +1829,11 @@ void
|
|||
register_odr_type (tree type)
|
||||
{
|
||||
if (!odr_hash)
|
||||
{
|
||||
odr_hash = new odr_hash_type (23);
|
||||
if (in_lto_p)
|
||||
odr_vtable_hash = new odr_vtable_hash_type (23);
|
||||
}
|
||||
/* Arrange things to be nicer and insert main variants first. */
|
||||
if (odr_type_p (TYPE_MAIN_VARIANT (type)))
|
||||
get_odr_type (TYPE_MAIN_VARIANT (type), true);
|
||||
|
|
@ -1784,6 +1953,8 @@ build_type_inheritance_graph (void)
|
|||
timevar_push (TV_IPA_INHERITANCE);
|
||||
inheritance_dump_file = dump_begin (TDI_inheritance, &flags);
|
||||
odr_hash = new odr_hash_type (23);
|
||||
if (in_lto_p)
|
||||
odr_vtable_hash = new odr_vtable_hash_type (23);
|
||||
|
||||
/* We reconstruct the graph starting of types of all methods seen in the
|
||||
the unit. */
|
||||
|
|
@ -2839,12 +3010,12 @@ dump_possible_polymorphic_call_targets (FILE *f,
|
|||
targets = possible_polymorphic_call_targets (otr_type, otr_token,
|
||||
ctx,
|
||||
&final, NULL, true);
|
||||
gcc_assert (targets.length () <= len);
|
||||
if (targets.length () != len)
|
||||
{
|
||||
fprintf (f, " Speculative targets:");
|
||||
dump_targets (f, targets);
|
||||
}
|
||||
gcc_assert (targets.length () <= len);
|
||||
fprintf (f, "\n");
|
||||
}
|
||||
|
||||
|
|
@ -3044,6 +3215,9 @@ ipa_devirt (void)
|
|||
if (!odr_types_ptr)
|
||||
return 0;
|
||||
|
||||
if (dump_file)
|
||||
dump_type_inheritance_graph (dump_file);
|
||||
|
||||
/* We can output -Wsuggest-final-methods and -Wsuggest-final-types warnings.
|
||||
This is implemented by setting up final_warning_records that are updated
|
||||
by get_polymorphic_call_targets.
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ bool type_known_to_have_no_deriavations_p (tree);
|
|||
bool contains_polymorphic_type_p (const_tree);
|
||||
void register_odr_type (tree);
|
||||
bool types_must_be_same_for_odr (tree, tree);
|
||||
bool types_odr_comparable (tree, tree);
|
||||
bool types_odr_comparable (tree, tree, bool strict = false);
|
||||
cgraph_node *try_speculative_devirtualization (tree, HOST_WIDE_INT,
|
||||
ipa_polymorphic_call_context);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
2015-03-08 Jan Hubicka <hubicka@ucw.cz>
|
||||
|
||||
PR lto/65316
|
||||
* g++.dg/lto/pr65316_0.C: New testcase.
|
||||
* g++.dg/lto/pr65316_1.C: New testcase.
|
||||
|
||||
2015-03-08 John David Anglin <danglin@gcc.gnu.org>
|
||||
|
||||
PR target/62247
|
||||
|
|
|
|||
|
|
@ -0,0 +1,142 @@
|
|||
// { dg-lto-do link }
|
||||
// { dg-lto-options { { -flto -std=c++11 -g2 -fno-lto-odr-type-merging -O2 } } }
|
||||
// { dg-extra-ld-options "-r -nostdlib -O2 -fno-lto-odr-type-merging" }
|
||||
namespace std
|
||||
{
|
||||
typedef long unsigned int size_t;
|
||||
}
|
||||
extern "C"
|
||||
{
|
||||
typedef struct
|
||||
{
|
||||
} __mbstate_t;
|
||||
}
|
||||
namespace std __attribute__ ((__visibility__ ("default")))
|
||||
{
|
||||
template < class _CharT > struct char_traits;
|
||||
}
|
||||
|
||||
typedef __mbstate_t mbstate_t;
|
||||
namespace std __attribute__ ((__visibility__ ("default")))
|
||||
{
|
||||
template < typename _CharT, typename _Traits =
|
||||
char_traits < _CharT > >class basic_ostream;
|
||||
typedef basic_ostream < char >ostream;
|
||||
}
|
||||
|
||||
using namespace std;
|
||||
class Cstring
|
||||
{
|
||||
public:
|
||||
Cstring (const char *str, int l = 0);
|
||||
};
|
||||
extern ostream & operator << (ostream & os, const Cstring & string);
|
||||
class Foo_Log_Handler
|
||||
{
|
||||
virtual int write_message (const char *msg, size_t msg_len, int channel,
|
||||
int level) = 0;
|
||||
};
|
||||
class Foo_Log_Handler_Stream:public Foo_Log_Handler
|
||||
{
|
||||
virtual int write_message (const char *msg, size_t msg_len, int channel,
|
||||
int level) override;
|
||||
Cstring m_filename;
|
||||
};
|
||||
namespace std __attribute__ ((__visibility__ ("default")))
|
||||
{
|
||||
template <> struct char_traits <char >
|
||||
{
|
||||
typedef mbstate_t state_type;
|
||||
};
|
||||
enum _Ios_Fmtflags
|
||||
{
|
||||
};
|
||||
enum _Ios_Iostate
|
||||
{
|
||||
};
|
||||
class ios_base
|
||||
{
|
||||
public:
|
||||
typedef _Ios_Iostate iostate;
|
||||
};
|
||||
}
|
||||
|
||||
namespace std __attribute__ ((__visibility__ ("default")))
|
||||
{
|
||||
template < typename _CharT > class __ctype_abstract_base
|
||||
{
|
||||
};
|
||||
template < typename _CharT > class ctype
|
||||
{
|
||||
public:
|
||||
typedef char char_type;
|
||||
mutable char _M_widen_ok;
|
||||
char_type widen (char __c) const
|
||||
{
|
||||
if (_M_widen_ok)
|
||||
return this->do_widen (__c);
|
||||
}
|
||||
virtual char_type do_widen (char __c) const
|
||||
{
|
||||
}
|
||||
};
|
||||
template < typename _Facet >
|
||||
inline const _Facet & __check_facet (const _Facet * __f)
|
||||
{
|
||||
}
|
||||
template < typename _CharT, typename _Traits > class basic_ios:public
|
||||
ios_base
|
||||
{
|
||||
typedef _CharT char_type;
|
||||
typedef ctype < _CharT > __ctype_type;
|
||||
const __ctype_type *_M_ctype;
|
||||
public:
|
||||
iostate rdstate ()const
|
||||
{
|
||||
}
|
||||
bool good () const
|
||||
{
|
||||
}
|
||||
char_type widen (char __c) const
|
||||
{
|
||||
return __check_facet (_M_ctype).widen (__c);
|
||||
}
|
||||
};
|
||||
template < typename _CharT, typename _Traits > class basic_ostream:virtual public basic_ios < _CharT,
|
||||
_Traits
|
||||
>
|
||||
{
|
||||
public:
|
||||
typedef _CharT char_type;
|
||||
typedef _Traits traits_type;
|
||||
typedef basic_ostream < _CharT, _Traits > __ostream_type;
|
||||
__ostream_type & operator<< (__ostream_type & (*__pf) (__ostream_type &))
|
||||
{
|
||||
return __pf (*this);
|
||||
}
|
||||
__ostream_type & put (char_type __c);
|
||||
};
|
||||
template < typename _CharT,
|
||||
typename _Traits > inline basic_ostream < _CharT,
|
||||
_Traits > &endl (basic_ostream < _CharT, _Traits > &__os)
|
||||
{
|
||||
return flush (__os.put (__os.widen ('\n')));
|
||||
}
|
||||
template < typename _CharT,
|
||||
typename _Traits > inline basic_ostream < _CharT,
|
||||
_Traits > &flush (basic_ostream < _CharT, _Traits > &__os)
|
||||
{
|
||||
}
|
||||
extern ostream cerr;
|
||||
}
|
||||
|
||||
int
|
||||
Foo_Log_Handler_Stream::write_message (const char *msg, size_t msg_len, int,
|
||||
int level)
|
||||
{
|
||||
{
|
||||
{
|
||||
cerr << "FATAL: cannot write into log file: " << m_filename << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4470,7 +4470,8 @@ extern tree block_ultimate_origin (const_tree);
|
|||
extern tree get_binfo_at_offset (tree, HOST_WIDE_INT, tree);
|
||||
extern bool virtual_method_call_p (tree);
|
||||
extern tree obj_type_ref_class (tree ref);
|
||||
extern bool types_same_for_odr (const_tree type1, const_tree type2);
|
||||
extern bool types_same_for_odr (const_tree type1, const_tree type2,
|
||||
bool strict=false);
|
||||
extern bool contains_bitfld_component_ref_p (const_tree);
|
||||
extern bool type_in_anonymous_namespace_p (const_tree);
|
||||
extern bool block_may_fallthru (const_tree);
|
||||
|
|
|
|||
Loading…
Reference in New Issue