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:
Jan Hubicka 2015-05-12 20:30:40 +02:00 committed by Jan Hubicka
parent 2162235ef6
commit e7a677ca1a
4 changed files with 146 additions and 97 deletions

View file

@ -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> 2015-05-12 David Malcolm <dmalcolm@redhat.com>
* timevar.c (timevar_enable): Delete in favor of... * timevar.c (timevar_enable): Delete in favor of...

View file

@ -245,6 +245,47 @@ struct GTY(()) odr_type_d
bool rtti_broken; 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 /* Return TRUE if all derived types of T are known and thus
we may consider the walk of derived type complete. we may consider the walk of derived type complete.
@ -341,8 +382,7 @@ main_odr_variant (const_tree t)
static bool static bool
can_be_name_hashed_p (tree t) can_be_name_hashed_p (tree t)
{ {
return (!in_lto_p || type_in_anonymous_namespace_p (t) return (!in_lto_p || odr_type_p (t));
|| (TYPE_NAME (t) && DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (t))));
} }
/* Hash type by its ODR name. */ /* Hash type by its ODR name. */
@ -358,7 +398,7 @@ hash_odr_name (const_tree t)
return htab_hash_pointer (t); return htab_hash_pointer (t);
/* Anonymous types are unique. */ /* 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); return htab_hash_pointer (t);
gcc_checking_assert (TYPE_NAME (t) gcc_checking_assert (TYPE_NAME (t)
@ -381,7 +421,7 @@ can_be_vtable_hashed_p (tree t)
if (TYPE_MAIN_VARIANT (t) != t) if (TYPE_MAIN_VARIANT (t) != t)
return false; return false;
/* Anonymous namespace types are always handled by name hash. */ /* 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 false;
return (TREE_CODE (t) == RECORD_TYPE return (TREE_CODE (t) == RECORD_TYPE
&& TYPE_BINFO (t) && BINFO_VTABLE (TYPE_BINFO (t))); && 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 /* Check for anonymous namespaces. Those have !TREE_PUBLIC
on the corresponding TYPE_STUB_DECL. */ on the corresponding TYPE_STUB_DECL. */
if (type_in_anonymous_namespace_p (type1) if ((type_with_linkage_p (type1) && type_in_anonymous_namespace_p (type1))
|| type_in_anonymous_namespace_p (type2)) || (type_with_linkage_p (type2) && type_in_anonymous_namespace_p (type2)))
return false; return false;
@ -565,8 +605,8 @@ odr_name_hasher::equal (const odr_type_d *o1, const tree_node *t2)
return false; return false;
/* Check for anonymous namespaces. Those have !TREE_PUBLIC /* Check for anonymous namespaces. Those have !TREE_PUBLIC
on the corresponding TYPE_STUB_DECL. */ on the corresponding TYPE_STUB_DECL. */
if (type_in_anonymous_namespace_p (t1) if ((type_with_linkage_p (t1) && type_in_anonymous_namespace_p (t1))
|| type_in_anonymous_namespace_p (t2)) || (type_with_linkage_p (t2) && type_in_anonymous_namespace_p (t2)))
return false; return false;
gcc_checking_assert (DECL_ASSEMBLER_NAME (TYPE_NAME (t1))); gcc_checking_assert (DECL_ASSEMBLER_NAME (TYPE_NAME (t1)));
gcc_checking_assert (DECL_ASSEMBLER_NAME (TYPE_NAME (t2))); gcc_checking_assert (DECL_ASSEMBLER_NAME (TYPE_NAME (t2)));
@ -642,7 +682,6 @@ static bool
odr_subtypes_equivalent_p (tree t1, tree t2, odr_subtypes_equivalent_p (tree t1, tree t2,
hash_set<type_pair,pair_traits> *visited) hash_set<type_pair,pair_traits> *visited)
{ {
bool an1, an2;
/* This can happen in incomplete types that should be handled earlier. */ /* This can happen in incomplete types that should be handled earlier. */
gcc_assert (t1 && t2); gcc_assert (t1 && t2);
@ -653,9 +692,8 @@ odr_subtypes_equivalent_p (tree t1, tree t2,
return true; return true;
/* Anonymous namespace types must match exactly. */ /* Anonymous namespace types must match exactly. */
an1 = type_in_anonymous_namespace_p (t1); if ((type_with_linkage_p (t1) && type_in_anonymous_namespace_p (t1))
an2 = type_in_anonymous_namespace_p (t2); || (type_with_linkage_p (t2) && type_in_anonymous_namespace_p (t2)))
if (an1 != an2 || an1)
return false; return false;
/* For ODR types be sure to compare their names. /* 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 /* It is a quite common bug to reference anonymous namespace type in
non-anonymous namespace class. */ non-anonymous namespace class. */
if (type_in_anonymous_namespace_p (t1) if ((type_with_linkage_p (t1) && type_in_anonymous_namespace_p (t1))
|| type_in_anonymous_namespace_p (t2)) || (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;; tree tmp = t1;;
t1 = t2; 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. */ /* Check first for the obvious case of pointer identity. */
if (t1 == t2) if (t1 == t2)
return true; return true;
gcc_assert (!type_in_anonymous_namespace_p (t1)); gcc_assert (!type_with_linkage_p (t1) || !type_in_anonymous_namespace_p (t1));
gcc_assert (!type_in_anonymous_namespace_p (t2)); 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. */ /* Can't be the same type if the types don't have the same code. */
if (TREE_CODE (t1) != TREE_CODE (t2)) 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; return false;
} }
if ((TYPE_MAIN_VARIANT (t1) == t1 || TYPE_MAIN_VARIANT (t2) == t2) 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 (t1))
!= TYPE_METHODS (TYPE_MAIN_VARIANT (t2)))) != TYPE_METHODS (TYPE_MAIN_VARIANT (t2))))
{ {
for (f1 = TYPE_METHODS (TYPE_MAIN_VARIANT (t1)), /* Currently free_lang_data sets TYPE_METHODS to error_mark_node
f2 = TYPE_METHODS (TYPE_MAIN_VARIANT (t2)); if it is non-NULL so this loop will never realy execute. */
f1 && f2 ; f1 = DECL_CHAIN (f1), f2 = DECL_CHAIN (f2)) if (TYPE_METHODS (TYPE_MAIN_VARIANT (t1)) != error_mark_node
{ && TYPE_METHODS (TYPE_MAIN_VARIANT (t2)) != error_mark_node)
if (DECL_ASSEMBLER_NAME (f1) != DECL_ASSEMBLER_NAME (f2)) for (f1 = TYPE_METHODS (TYPE_MAIN_VARIANT (t1)),
{ f2 = TYPE_METHODS (TYPE_MAIN_VARIANT (t2));
warn_odr (t1, t2, f1, f2, warn, warned, f1 && f2 ; f1 = DECL_CHAIN (f1), f2 = DECL_CHAIN (f2))
G_("a different method of same type " {
"is defined in another translation unit")); if (DECL_ASSEMBLER_NAME (f1) != DECL_ASSEMBLER_NAME (f2))
return false; {
} warn_odr (t1, t2, f1, f2, warn, warned,
if (DECL_VIRTUAL_P (f1) != DECL_VIRTUAL_P (f2)) G_("a different method of same type "
{ "is defined in another "
warn_odr (t1, t2, f1, f2, warn, warned, "translation unit"));
G_("s definition that differs by virtual " return false;
"keyword in another translation unit")); }
return false; if (DECL_VIRTUAL_P (f1) != DECL_VIRTUAL_P (f2))
} {
if (DECL_VINDEX (f1) != DECL_VINDEX (f2)) warn_odr (t1, t2, f1, f2, warn, warned,
{ G_("s definition that differs by virtual "
warn_odr (t1, t2, f1, f2, warn, warned, "keyword in another translation unit"));
G_("virtual table layout differs in another " return false;
"translation unit")); }
return false; if (DECL_VINDEX (f1) != DECL_VINDEX (f2))
} {
if (odr_subtypes_equivalent_p (TREE_TYPE (f1), TREE_TYPE (f2), visited)) warn_odr (t1, t2, f1, f2, warn, warned,
{ G_("virtual table layout differs "
warn_odr (t1, t2, f1, f2, warn, warned, "in another translation unit"));
G_("method with incompatible type is defined " return false;
"in another translation unit")); }
return false; if (odr_subtypes_equivalent_p (TREE_TYPE (f1),
} TREE_TYPE (f2), visited))
} {
if (f1 || f2) 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, warn_odr (t1, t2, NULL, NULL, warn, warned,
G_("a type with different number of methods " G_("a type with different number of methods "
@ -1976,7 +2024,10 @@ get_odr_type (tree type, bool insert)
val->type = type; val->type = type;
val->bases = vNULL; val->bases = vNULL;
val->derived_types = 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); build_bases = COMPLETE_TYPE_P (val->type);
insert_to_odr_array = true; insert_to_odr_array = true;
if (slot) if (slot)

View file

@ -63,6 +63,7 @@ possible_polymorphic_call_targets (tree, HOST_WIDE_INT,
void **cache_token = NULL, void **cache_token = NULL,
bool speuclative = false); bool speuclative = false);
odr_type get_odr_type (tree, bool insert = 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); 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, void dump_possible_polymorphic_call_targets (FILE *, tree, HOST_WIDE_INT,
const ipa_polymorphic_call_context &); const ipa_polymorphic_call_context &);
@ -153,23 +154,6 @@ possible_polymorphic_call_target_p (struct cgraph_edge *e,
context, n); 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. /* Return true if BINFO corresponds to a type with virtual methods.
Every type has several BINFOs. One is the BINFO associated by the type Every type has several BINFOs. One is the BINFO associated by the type

View file

@ -5160,27 +5160,33 @@ free_lang_data_in_type (tree type)
static inline bool static inline bool
need_assembler_name_p (tree decl) need_assembler_name_p (tree decl)
{ {
/* We use DECL_ASSEMBLER_NAME to hold mangled type names for One Definition Rule /* We use DECL_ASSEMBLER_NAME to hold mangled type names for One Definition
merging. */ 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 if (flag_lto_odr_type_mering
&& TREE_CODE (decl) == TYPE_DECL && TREE_CODE (decl) == TYPE_DECL
&& DECL_NAME (decl) && DECL_NAME (decl)
&& decl == TYPE_NAME (TREE_TYPE (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)) && !TYPE_ARTIFICIAL (TREE_TYPE (decl))
&& !variably_modified_type_p (TREE_TYPE (decl), NULL_TREE) && (((RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl))
&& !type_in_anonymous_namespace_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); return !DECL_ASSEMBLER_NAME_SET_P (decl);
/* Only FUNCTION_DECLs and VAR_DECLs are considered. */ /* Only FUNCTION_DECLs and VAR_DECLs are considered. */
if (TREE_CODE (decl) != FUNCTION_DECL if (TREE_CODE (decl) != FUNCTION_DECL
@ -12037,18 +12043,6 @@ obj_type_ref_class (tree ref)
return TREE_TYPE (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. */ /* Lookup sub-BINFO of BINFO of TYPE at offset POS. */
static tree static tree