ipa-devirt.c (type_with_linkage_p): New function.
* ipa-devirt.c (type_with_linkage_p): New function. (type_in_anonymous_namespace_p): Move here from tree.c; assert that type has linkage. (odr_type_p): Move here from ipa-utils.h; use type_with_linkage_p. (can_be_name_hashed_p): Simplify. (hash_odr_name): Check that type has linkage before checking if it is anonymous. (types_same_for_odr): Likewise. (odr_name_hasher::equal): Likewise. (odr_subtypes_equivalent_p): Likewise. (warn_types_mismatch): Likewise. (get_odr_type): Likewise. (odr_types_equivalent_p): Fix checking of TYPE_MAIN_VARIANT. * ipa-utils.h (odr_type_p): Move offline. * tree.c (need_assembler_name_p): Fix handling of types without linkages. (type_in_anonymous_namespace_p): Move to ipa-devirt.c From-SVN: r223094
This commit is contained in:
parent
2162235ef6
commit
e7a677ca1a
@ -1,3 +1,23 @@
|
||||
2015-05-12 Jan Hubicka <hubicka@ucw.cz>
|
||||
|
||||
* ipa-devirt.c (type_with_linkage_p): New function.
|
||||
(type_in_anonymous_namespace_p): Move here from tree.c; assert that
|
||||
type has linkage.
|
||||
(odr_type_p): Move here from ipa-utils.h; use type_with_linkage_p.
|
||||
(can_be_name_hashed_p): Simplify.
|
||||
(hash_odr_name): Check that type has linkage before checking if it is
|
||||
anonymous.
|
||||
(types_same_for_odr): Likewise.
|
||||
(odr_name_hasher::equal): Likewise.
|
||||
(odr_subtypes_equivalent_p): Likewise.
|
||||
(warn_types_mismatch): Likewise.
|
||||
(get_odr_type): Likewise.
|
||||
(odr_types_equivalent_p): Fix checking of TYPE_MAIN_VARIANT.
|
||||
* ipa-utils.h (odr_type_p): Move offline.
|
||||
* tree.c (need_assembler_name_p): Fix handling of types
|
||||
without linkages.
|
||||
(type_in_anonymous_namespace_p): Move to ipa-devirt.c
|
||||
|
||||
2015-05-12 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* timevar.c (timevar_enable): Delete in favor of...
|
||||
|
155
gcc/ipa-devirt.c
155
gcc/ipa-devirt.c
@ -245,6 +245,47 @@ struct GTY(()) odr_type_d
|
||||
bool rtti_broken;
|
||||
};
|
||||
|
||||
/* Return true if T is a type with linkage defined. */
|
||||
|
||||
static bool
|
||||
type_with_linkage_p (const_tree t)
|
||||
{
|
||||
return (RECORD_OR_UNION_TYPE_P (t)
|
||||
|| TREE_CODE (t) == ENUMERAL_TYPE);
|
||||
}
|
||||
|
||||
/* Return true if T is in anonymous namespace.
|
||||
This works only on those C++ types with linkage defined. */
|
||||
|
||||
bool
|
||||
type_in_anonymous_namespace_p (const_tree t)
|
||||
{
|
||||
gcc_assert (type_with_linkage_p (t));
|
||||
/* TREE_PUBLIC of TYPE_STUB_DECL may not be properly set for
|
||||
backend produced types (such as va_arg_type); those have CONTEXT NULL
|
||||
and never are considered anonymoius. */
|
||||
if (!TYPE_CONTEXT (t))
|
||||
return false;
|
||||
return (TYPE_STUB_DECL (t) && !TREE_PUBLIC (TYPE_STUB_DECL (t)));
|
||||
}
|
||||
|
||||
/* Return true of T is type with One Definition Rule info attached.
|
||||
It means that either it is anonymous type or it has assembler name
|
||||
set. */
|
||||
|
||||
bool
|
||||
odr_type_p (const_tree t)
|
||||
{
|
||||
if (type_with_linkage_p (t) && type_in_anonymous_namespace_p (t))
|
||||
return true;
|
||||
/* We do not have this information when not in LTO, but we do not need
|
||||
to care, since it is used only for type merging. */
|
||||
gcc_checking_assert (in_lto_p || flag_lto);
|
||||
|
||||
return (TYPE_NAME (t)
|
||||
&& (DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (t))));
|
||||
}
|
||||
|
||||
/* Return TRUE if all derived types of T are known and thus
|
||||
we may consider the walk of derived type complete.
|
||||
|
||||
@ -341,8 +382,7 @@ main_odr_variant (const_tree t)
|
||||
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))));
|
||||
return (!in_lto_p || odr_type_p (t));
|
||||
}
|
||||
|
||||
/* Hash type by its ODR name. */
|
||||
@ -358,7 +398,7 @@ hash_odr_name (const_tree t)
|
||||
return htab_hash_pointer (t);
|
||||
|
||||
/* Anonymous types are unique. */
|
||||
if (type_in_anonymous_namespace_p (t))
|
||||
if (type_with_linkage_p (t) && type_in_anonymous_namespace_p (t))
|
||||
return htab_hash_pointer (t);
|
||||
|
||||
gcc_checking_assert (TYPE_NAME (t)
|
||||
@ -381,7 +421,7 @@ can_be_vtable_hashed_p (tree t)
|
||||
if (TYPE_MAIN_VARIANT (t) != t)
|
||||
return false;
|
||||
/* Anonymous namespace types are always handled by name hash. */
|
||||
if (type_in_anonymous_namespace_p (t))
|
||||
if (type_with_linkage_p (t) && type_in_anonymous_namespace_p (t))
|
||||
return false;
|
||||
return (TREE_CODE (t) == RECORD_TYPE
|
||||
&& TYPE_BINFO (t) && BINFO_VTABLE (TYPE_BINFO (t)));
|
||||
@ -455,8 +495,8 @@ types_same_for_odr (const_tree type1, const_tree type2, bool strict)
|
||||
|
||||
/* Check for anonymous namespaces. Those have !TREE_PUBLIC
|
||||
on the corresponding TYPE_STUB_DECL. */
|
||||
if (type_in_anonymous_namespace_p (type1)
|
||||
|| type_in_anonymous_namespace_p (type2))
|
||||
if ((type_with_linkage_p (type1) && type_in_anonymous_namespace_p (type1))
|
||||
|| (type_with_linkage_p (type2) && type_in_anonymous_namespace_p (type2)))
|
||||
return false;
|
||||
|
||||
|
||||
@ -565,8 +605,8 @@ odr_name_hasher::equal (const odr_type_d *o1, const tree_node *t2)
|
||||
return false;
|
||||
/* 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))
|
||||
if ((type_with_linkage_p (t1) && type_in_anonymous_namespace_p (t1))
|
||||
|| (type_with_linkage_p (t2) && 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)));
|
||||
@ -642,7 +682,6 @@ static bool
|
||||
odr_subtypes_equivalent_p (tree t1, tree t2,
|
||||
hash_set<type_pair,pair_traits> *visited)
|
||||
{
|
||||
bool an1, an2;
|
||||
|
||||
/* This can happen in incomplete types that should be handled earlier. */
|
||||
gcc_assert (t1 && t2);
|
||||
@ -653,9 +692,8 @@ odr_subtypes_equivalent_p (tree t1, tree t2,
|
||||
return true;
|
||||
|
||||
/* Anonymous namespace types must match exactly. */
|
||||
an1 = type_in_anonymous_namespace_p (t1);
|
||||
an2 = type_in_anonymous_namespace_p (t2);
|
||||
if (an1 != an2 || an1)
|
||||
if ((type_with_linkage_p (t1) && type_in_anonymous_namespace_p (t1))
|
||||
|| (type_with_linkage_p (t2) && type_in_anonymous_namespace_p (t2)))
|
||||
return false;
|
||||
|
||||
/* For ODR types be sure to compare their names.
|
||||
@ -1019,10 +1057,10 @@ warn_types_mismatch (tree t1, tree t2)
|
||||
}
|
||||
/* It is a quite common bug to reference anonymous namespace type in
|
||||
non-anonymous namespace class. */
|
||||
if (type_in_anonymous_namespace_p (t1)
|
||||
|| type_in_anonymous_namespace_p (t2))
|
||||
if ((type_with_linkage_p (t1) && type_in_anonymous_namespace_p (t1))
|
||||
|| (type_with_linkage_p (t2) && type_in_anonymous_namespace_p (t2)))
|
||||
{
|
||||
if (!type_in_anonymous_namespace_p (t1))
|
||||
if (type_with_linkage_p (t1) && !type_in_anonymous_namespace_p (t1))
|
||||
{
|
||||
tree tmp = t1;;
|
||||
t1 = t2;
|
||||
@ -1166,8 +1204,8 @@ odr_types_equivalent_p (tree t1, tree t2, bool warn, bool *warned,
|
||||
/* Check first for the obvious case of pointer identity. */
|
||||
if (t1 == t2)
|
||||
return true;
|
||||
gcc_assert (!type_in_anonymous_namespace_p (t1));
|
||||
gcc_assert (!type_in_anonymous_namespace_p (t2));
|
||||
gcc_assert (!type_with_linkage_p (t1) || !type_in_anonymous_namespace_p (t1));
|
||||
gcc_assert (!type_with_linkage_p (t2) || !type_in_anonymous_namespace_p (t2));
|
||||
|
||||
/* Can't be the same type if the types don't have the same code. */
|
||||
if (TREE_CODE (t1) != TREE_CODE (t2))
|
||||
@ -1498,43 +1536,53 @@ odr_types_equivalent_p (tree t1, tree t2, bool warn, bool *warned,
|
||||
return false;
|
||||
}
|
||||
if ((TYPE_MAIN_VARIANT (t1) == t1 || TYPE_MAIN_VARIANT (t2) == t2)
|
||||
&& COMPLETE_TYPE_P (TYPE_MAIN_VARIANT (t1))
|
||||
&& COMPLETE_TYPE_P (TYPE_MAIN_VARIANT (t2))
|
||||
&& odr_type_p (TYPE_MAIN_VARIANT (t1))
|
||||
&& odr_type_p (TYPE_MAIN_VARIANT (t2))
|
||||
&& (TYPE_METHODS (TYPE_MAIN_VARIANT (t1))
|
||||
!= TYPE_METHODS (TYPE_MAIN_VARIANT (t2))))
|
||||
{
|
||||
for (f1 = TYPE_METHODS (TYPE_MAIN_VARIANT (t1)),
|
||||
f2 = TYPE_METHODS (TYPE_MAIN_VARIANT (t2));
|
||||
f1 && f2 ; f1 = DECL_CHAIN (f1), f2 = DECL_CHAIN (f2))
|
||||
{
|
||||
if (DECL_ASSEMBLER_NAME (f1) != DECL_ASSEMBLER_NAME (f2))
|
||||
{
|
||||
warn_odr (t1, t2, f1, f2, warn, warned,
|
||||
G_("a different method of same type "
|
||||
"is defined in another translation unit"));
|
||||
return false;
|
||||
}
|
||||
if (DECL_VIRTUAL_P (f1) != DECL_VIRTUAL_P (f2))
|
||||
{
|
||||
warn_odr (t1, t2, f1, f2, warn, warned,
|
||||
G_("s definition that differs by virtual "
|
||||
"keyword in another translation unit"));
|
||||
return false;
|
||||
}
|
||||
if (DECL_VINDEX (f1) != DECL_VINDEX (f2))
|
||||
{
|
||||
warn_odr (t1, t2, f1, f2, warn, warned,
|
||||
G_("virtual table layout differs in another "
|
||||
"translation unit"));
|
||||
return false;
|
||||
}
|
||||
if (odr_subtypes_equivalent_p (TREE_TYPE (f1), TREE_TYPE (f2), visited))
|
||||
{
|
||||
warn_odr (t1, t2, f1, f2, warn, warned,
|
||||
G_("method with incompatible type is defined "
|
||||
"in another translation unit"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (f1 || f2)
|
||||
/* Currently free_lang_data sets TYPE_METHODS to error_mark_node
|
||||
if it is non-NULL so this loop will never realy execute. */
|
||||
if (TYPE_METHODS (TYPE_MAIN_VARIANT (t1)) != error_mark_node
|
||||
&& TYPE_METHODS (TYPE_MAIN_VARIANT (t2)) != error_mark_node)
|
||||
for (f1 = TYPE_METHODS (TYPE_MAIN_VARIANT (t1)),
|
||||
f2 = TYPE_METHODS (TYPE_MAIN_VARIANT (t2));
|
||||
f1 && f2 ; f1 = DECL_CHAIN (f1), f2 = DECL_CHAIN (f2))
|
||||
{
|
||||
if (DECL_ASSEMBLER_NAME (f1) != DECL_ASSEMBLER_NAME (f2))
|
||||
{
|
||||
warn_odr (t1, t2, f1, f2, warn, warned,
|
||||
G_("a different method of same type "
|
||||
"is defined in another "
|
||||
"translation unit"));
|
||||
return false;
|
||||
}
|
||||
if (DECL_VIRTUAL_P (f1) != DECL_VIRTUAL_P (f2))
|
||||
{
|
||||
warn_odr (t1, t2, f1, f2, warn, warned,
|
||||
G_("s definition that differs by virtual "
|
||||
"keyword in another translation unit"));
|
||||
return false;
|
||||
}
|
||||
if (DECL_VINDEX (f1) != DECL_VINDEX (f2))
|
||||
{
|
||||
warn_odr (t1, t2, f1, f2, warn, warned,
|
||||
G_("virtual table layout differs "
|
||||
"in another translation unit"));
|
||||
return false;
|
||||
}
|
||||
if (odr_subtypes_equivalent_p (TREE_TYPE (f1),
|
||||
TREE_TYPE (f2), visited))
|
||||
{
|
||||
warn_odr (t1, t2, f1, f2, warn, warned,
|
||||
G_("method with incompatible type is "
|
||||
"defined in another translation unit"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ((f1 == NULL) != (f2 == NULL))
|
||||
{
|
||||
warn_odr (t1, t2, NULL, NULL, warn, warned,
|
||||
G_("a type with different number of methods "
|
||||
@ -1976,7 +2024,10 @@ get_odr_type (tree type, bool insert)
|
||||
val->type = type;
|
||||
val->bases = vNULL;
|
||||
val->derived_types = vNULL;
|
||||
val->anonymous_namespace = type_in_anonymous_namespace_p (type);
|
||||
if (type_with_linkage_p (type))
|
||||
val->anonymous_namespace = type_in_anonymous_namespace_p (type);
|
||||
else
|
||||
val->anonymous_namespace = 0;
|
||||
build_bases = COMPLETE_TYPE_P (val->type);
|
||||
insert_to_odr_array = true;
|
||||
if (slot)
|
||||
|
@ -63,6 +63,7 @@ possible_polymorphic_call_targets (tree, HOST_WIDE_INT,
|
||||
void **cache_token = NULL,
|
||||
bool speuclative = false);
|
||||
odr_type get_odr_type (tree, bool insert = false);
|
||||
bool odr_type_p (const_tree t);
|
||||
bool possible_polymorphic_call_target_p (tree ref, gimple stmt, struct cgraph_node *n);
|
||||
void dump_possible_polymorphic_call_targets (FILE *, tree, HOST_WIDE_INT,
|
||||
const ipa_polymorphic_call_context &);
|
||||
@ -153,23 +154,6 @@ possible_polymorphic_call_target_p (struct cgraph_edge *e,
|
||||
context, n);
|
||||
}
|
||||
|
||||
/* Return true of T is type with One Definition Rule info attached.
|
||||
It means that either it is anonymous type or it has assembler name
|
||||
set. */
|
||||
|
||||
static inline bool
|
||||
odr_type_p (const_tree t)
|
||||
{
|
||||
if (type_in_anonymous_namespace_p (t))
|
||||
return true;
|
||||
/* We do not have this information when not in LTO, but we do not need
|
||||
to care, since it is used only for type merging. */
|
||||
gcc_assert (in_lto_p || flag_lto);
|
||||
|
||||
return (TYPE_NAME (t)
|
||||
&& (DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (t))));
|
||||
}
|
||||
|
||||
/* Return true if BINFO corresponds to a type with virtual methods.
|
||||
|
||||
Every type has several BINFOs. One is the BINFO associated by the type
|
||||
|
50
gcc/tree.c
50
gcc/tree.c
@ -5160,27 +5160,33 @@ free_lang_data_in_type (tree type)
|
||||
static inline bool
|
||||
need_assembler_name_p (tree decl)
|
||||
{
|
||||
/* We use DECL_ASSEMBLER_NAME to hold mangled type names for One Definition Rule
|
||||
merging. */
|
||||
/* We use DECL_ASSEMBLER_NAME to hold mangled type names for One Definition
|
||||
Rule merging. This makes type_odr_p to return true on those types during
|
||||
LTO and by comparing the mangled name, we can say what types are intended
|
||||
to be equivalent across compilation unit.
|
||||
|
||||
We do not store names of type_in_anonymous_namespace_p.
|
||||
|
||||
Record, union and enumeration type have linkage that allows use
|
||||
to check type_in_anonymous_namespace_p. We do not mangle compound types
|
||||
that always can be compared structurally.
|
||||
|
||||
Similarly for builtin types, we compare properties of their main variant.
|
||||
A special case are integer types where mangling do make differences
|
||||
between char/signed char/unsigned char etc. Storing name for these makes
|
||||
e.g. -fno-signed-char/-fsigned-char mismatches to be handled well.
|
||||
See cp/mangle.c:write_builtin_type for details. */
|
||||
|
||||
if (flag_lto_odr_type_mering
|
||||
&& TREE_CODE (decl) == TYPE_DECL
|
||||
&& DECL_NAME (decl)
|
||||
&& decl == TYPE_NAME (TREE_TYPE (decl))
|
||||
&& !is_lang_specific (TREE_TYPE (decl))
|
||||
/* Save some work. Names of builtin types are always derived from
|
||||
properties of its main variant. A special case are integer types
|
||||
where mangling do make differences between char/signed char/unsigned
|
||||
char etc. Storing name for these makes e.g.
|
||||
-fno-signed-char/-fsigned-char mismatches to be handled well.
|
||||
|
||||
See cp/mangle.c:write_builtin_type for details. */
|
||||
&& (TREE_CODE (TREE_TYPE (decl)) != VOID_TYPE
|
||||
&& TREE_CODE (TREE_TYPE (decl)) != BOOLEAN_TYPE
|
||||
&& TREE_CODE (TREE_TYPE (decl)) != REAL_TYPE
|
||||
&& TREE_CODE (TREE_TYPE (decl)) != FIXED_POINT_TYPE)
|
||||
&& !TYPE_ARTIFICIAL (TREE_TYPE (decl))
|
||||
&& !variably_modified_type_p (TREE_TYPE (decl), NULL_TREE)
|
||||
&& !type_in_anonymous_namespace_p (TREE_TYPE (decl)))
|
||||
&& (((RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl))
|
||||
|| TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE)
|
||||
&& !type_in_anonymous_namespace_p (TREE_TYPE (decl)))
|
||||
|| TREE_CODE (TREE_TYPE (decl)) == INTEGER_TYPE)
|
||||
&& !variably_modified_type_p (TREE_TYPE (decl), NULL_TREE))
|
||||
return !DECL_ASSEMBLER_NAME_SET_P (decl);
|
||||
/* Only FUNCTION_DECLs and VAR_DECLs are considered. */
|
||||
if (TREE_CODE (decl) != FUNCTION_DECL
|
||||
@ -12037,18 +12043,6 @@ obj_type_ref_class (tree ref)
|
||||
return TREE_TYPE (ref);
|
||||
}
|
||||
|
||||
/* Return true if T is in anonymous namespace. */
|
||||
|
||||
bool
|
||||
type_in_anonymous_namespace_p (const_tree t)
|
||||
{
|
||||
/* TREE_PUBLIC of TYPE_STUB_DECL may not be properly set for
|
||||
bulitin types; those have CONTEXT NULL. */
|
||||
if (!TYPE_CONTEXT (t))
|
||||
return false;
|
||||
return (TYPE_STUB_DECL (t) && !TREE_PUBLIC (TYPE_STUB_DECL (t)));
|
||||
}
|
||||
|
||||
/* Lookup sub-BINFO of BINFO of TYPE at offset POS. */
|
||||
|
||||
static tree
|
||||
|
Loading…
Reference in New Issue
Block a user