{
/* leader type. */
tree type;
- /* All bases. */
+ /* All bases; built only for main variants of types */
vec<odr_type> GTY((skip)) bases;
- /* All derrived types with virtual methods seen in unit. */
+ /* All derrived types with virtual methods seen in unit;
+ built only for main variants oftypes */
vec<odr_type> GTY((skip)) derived_types;
/* All equivalent types, if more than one. */
bool anonymous_namespace;
/* Do we know about all derivations of given type? */
bool all_derivations_known;
+ /* Did we report ODR violation here? */
+ bool odr_violated;
};
static inline void remove (value_type *);
};
+/* Return type that was declared with T's name so that T is an
+ qualified variant of it. */
+
+static inline tree
+main_odr_variant (const_tree t)
+{
+ if (TYPE_NAME (t) && TREE_CODE (TYPE_NAME (t)) == TYPE_DECL)
+ return TREE_TYPE (TYPE_NAME (t));
+ /* Unnamed types and non-C++ produced types can be compared by variants. */
+ else
+ return TYPE_MAIN_VARIANT (t);
+}
+
/* Produce hash based on type name. */
-hashval_t
+static hashval_t
hash_type_name (tree t)
{
- gcc_checking_assert (TYPE_MAIN_VARIANT (t) == t);
+ gcc_checking_assert (main_odr_variant (t) == t);
/* If not in LTO, all main variants are unique, so we can do
pointer hash. */
return htab_hash_pointer (t);
/* For polymorphic types, we can simply hash the virtual table. */
- if (TYPE_BINFO (t) && BINFO_VTABLE (TYPE_BINFO (t)))
+ 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;
return hash_type_name (odr_type->type);
}
+/* For languages with One Definition Rule, work out if
+ types are the same based on their name.
+
+ This is non-trivial for LTO where minnor differences in
+ the type representation may have prevented type merging
+ to merge two copies of otherwise equivalent type.
+
+ Until we start streaming mangled type names, this function works
+ only for polymorphic types. */
+
+bool
+types_same_for_odr (const_tree type1, const_tree type2)
+{
+ gcc_checking_assert (TYPE_P (type1) && TYPE_P (type2));
+
+ type1 = main_odr_variant (type1);
+ type2 = main_odr_variant (type2);
+
+ if (type1 == type2)
+ return true;
+
+ if (!in_lto_p)
+ return false;
+
+ /* 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))
+ return false;
+
+ /* At the moment we have no way to establish ODR equivlaence at LTO
+ other than comparing virtual table pointrs of polymorphic types.
+ Eventually we should start saving mangled names in TYPE_NAME.
+ Then this condition will become non-trivial. */
+
+ if (TREE_CODE (type1) == RECORD_TYPE
+ && TYPE_BINFO (type1) && TYPE_BINFO (type2)
+ && BINFO_VTABLE (TYPE_BINFO (type1))
+ && BINFO_VTABLE (TYPE_BINFO (type2)))
+ {
+ tree v1 = BINFO_VTABLE (TYPE_BINFO (type1));
+ tree v2 = BINFO_VTABLE (TYPE_BINFO (type2));
+ gcc_assert (TREE_CODE (v1) == POINTER_PLUS_EXPR
+ && TREE_CODE (v2) == POINTER_PLUS_EXPR);
+ 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)));
+ }
+ gcc_unreachable ();
+}
+
+
/* Compare types T1 and T2 and return true if they are
equivalent. */
{
tree t2 = const_cast <tree> (ct2);
- gcc_checking_assert (TYPE_MAIN_VARIANT (ct2) == ct2);
+ gcc_checking_assert (main_odr_variant (t2) == t2);
if (t1->type == t2)
return true;
if (!in_lto_p)
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. */
-static void
+static bool
add_type_duplicate (odr_type val, tree type)
{
+ bool build_bases = false;
if (!val->types_set)
val->types_set = pointer_set_create ();
+ /* Always prefer complete type to be the leader. */
+ if (!COMPLETE_TYPE_P (val->type)
+ && COMPLETE_TYPE_P (type))
+ {
+ tree tmp = type;
+
+ build_bases = true;
+ type = val->type;
+ val->type = tmp;
+ }
+
/* See if this duplicate is new. */
if (!pointer_set_insert (val->types_set, type))
{
bool merge = true;
bool base_mismatch = false;
+ bool warned = 0;
+ unsigned int i,j;
+
gcc_assert (in_lto_p);
vec_safe_push (val->types, type);
- unsigned int i,j;
/* First we compare memory layout. */
if (!types_compatible_p (val->type, type))
&& warning_at (DECL_SOURCE_LOCATION (TYPE_NAME (type)), 0,
"type %qD violates one definition rule ",
type))
- inform (DECL_SOURCE_LOCATION (TYPE_NAME (val->type)),
- "a type with the same name but different layout is "
- "defined in another translation unit");
+ {
+ inform (DECL_SOURCE_LOCATION (TYPE_NAME (val->type)),
+ "a type with the same name but different layout is "
+ "defined in another translation unit");
+ warned = true;
+ }
+ val->odr_violated = true;
if (cgraph_dump_file)
{
fprintf (cgraph_dump_file, "ODR violation or merging or ODR type bug?\n");
/* Next sanity check that bases are the same. If not, we will end
up producing wrong answers. */
- for (j = 0, i = 0; i < BINFO_N_BASE_BINFOS (TYPE_BINFO (type)); i++)
- if (polymorphic_type_binfo_p (BINFO_BASE_BINFO (TYPE_BINFO (type), i)))
- {
- odr_type base = get_odr_type
- (BINFO_TYPE
- (BINFO_BASE_BINFO (TYPE_BINFO (type),
- i)),
- true);
- if (val->bases.length () <= j || val->bases[j] != base)
- base_mismatch = true;
- j++;
- }
- if (base_mismatch)
+ if (COMPLETE_TYPE_P (type) && COMPLETE_TYPE_P (val->type)
+ && TREE_CODE (val->type) == RECORD_TYPE
+ && TREE_CODE (type) == RECORD_TYPE
+ && TYPE_BINFO (val->type) && TYPE_BINFO (type))
{
- merge = false;
- odr_violation_reported = true;
-
- if (warning_at (DECL_SOURCE_LOCATION (TYPE_NAME (type)), 0,
- "type %qD violates one definition rule ",
- type))
- inform (DECL_SOURCE_LOCATION (TYPE_NAME (val->type)),
- "a type with the same name but different bases is "
- "defined in another translation unit");
- if (cgraph_dump_file)
+ for (j = 0, i = 0; i < BINFO_N_BASE_BINFOS (TYPE_BINFO (type)); i++)
+ if (polymorphic_type_binfo_p (BINFO_BASE_BINFO (TYPE_BINFO (type), i)))
+ {
+ odr_type base = get_odr_type
+ (BINFO_TYPE
+ (BINFO_BASE_BINFO (TYPE_BINFO (type),
+ i)),
+ true);
+ if (val->bases.length () <= j || val->bases[j] != base)
+ base_mismatch = true;
+ j++;
+ }
+ if (base_mismatch)
{
- fprintf (cgraph_dump_file, "ODR bse violation or merging bug?\n");
-
- print_node (cgraph_dump_file, "", val->type, 0);
- putc ('\n',cgraph_dump_file);
- print_node (cgraph_dump_file, "", type, 0);
- putc ('\n',cgraph_dump_file);
+ merge = false;
+ odr_violation_reported = true;
+
+ if (!warned
+ && warning_at (DECL_SOURCE_LOCATION (TYPE_NAME (type)), 0,
+ "type %qD violates one definition rule ",
+ type))
+ inform (DECL_SOURCE_LOCATION (TYPE_NAME (val->type)),
+ "a type with the same name but different bases is "
+ "defined in another translation unit");
+ val->odr_violated = true;
+ if (cgraph_dump_file)
+ {
+ fprintf (cgraph_dump_file, "ODR bse violation or merging bug?\n");
+
+ print_node (cgraph_dump_file, "", val->type, 0);
+ putc ('\n',cgraph_dump_file);
+ print_node (cgraph_dump_file, "", type, 0);
+ putc ('\n',cgraph_dump_file);
+ }
}
}
merged LTO unit. For this reason we absolutely need to remove
them and replace by internal variants. Not doing so will lead
to incomplete answers from possible_polymorphic_call_targets. */
- if (!flag_ltrans && merge)
+ if (!flag_ltrans && merge
+ && TREE_CODE (val->type) == RECORD_TYPE
+ && TREE_CODE (type) == RECORD_TYPE
+ && TYPE_BINFO (val->type) && TYPE_BINFO (type)
+ && TYPE_MAIN_VARIANT (type) == type
+ && TYPE_MAIN_VARIANT (val->type) == val->type
+ && BINFO_VTABLE (TYPE_BINFO (val->type))
+ && BINFO_VTABLE (TYPE_BINFO (type)))
{
tree master_binfo = TYPE_BINFO (val->type);
tree v1 = BINFO_VTABLE (master_binfo);
set_type_binfo (type, master_binfo);
}
}
+ return build_bases;
}
/* Get ODR type hash entry for TYPE. If INSERT is true, create
odr_type_d **slot;
odr_type val;
hashval_t hash;
+ bool build_bases = false;
+ bool insert_to_odr_array = false;
+ int base_id = -1;
+
+ type = main_odr_variant (type);
- type = TYPE_MAIN_VARIANT (type);
- gcc_checking_assert (TYPE_MAIN_VARIANT (type) == type);
hash = hash_type_name (type);
slot
= odr_hash->find_slot_with_hash (type, hash, insert ? INSERT : NO_INSERT);
/* With LTO we need to support multiple tree representation of
the same ODR type. */
if (val->type != type)
- add_type_duplicate (val, type);
+ build_bases = add_type_duplicate (val, type);
}
else
{
- tree binfo = TYPE_BINFO (type);
- unsigned int i;
val = ggc_cleared_alloc<odr_type_d> ();
val->type = type;
- gcc_assert (BINFO_TYPE (TYPE_BINFO (val->type)) = type);
val->bases = vNULL;
val->derived_types = vNULL;
val->anonymous_namespace = type_in_anonymous_namespace_p (type);
+ build_bases = COMPLETE_TYPE_P (val->type);
+ insert_to_odr_array = true;
+ }
+
+ if (build_bases && TREE_CODE (type) == RECORD_TYPE && TYPE_BINFO (type)
+ && type == TYPE_MAIN_VARIANT (type))
+ {
+ tree binfo = TYPE_BINFO (type);
+ unsigned int i;
+
+ gcc_assert (BINFO_TYPE (TYPE_BINFO (val->type)) = type);
+
val->all_derivations_known = type_all_derivations_known_p (type);
*slot = val;
for (i = 0; i < BINFO_N_BASE_BINFOS (binfo); i++)
odr_type base = get_odr_type (BINFO_TYPE (BINFO_BASE_BINFO (binfo,
i)),
true);
+ gcc_assert (TYPE_MAIN_VARIANT (base->type) == base->type);
base->derived_types.safe_push (val);
val->bases.safe_push (base);
+ if (base->id > base_id)
+ base_id = base->id;
}
- /* First record bases, then add into array so ids are increasing. */
+ }
+ /* Ensure that type always appears after bases. */
+ if (insert_to_odr_array)
+ {
if (odr_types_ptr)
val->id = odr_types.length ();
vec_safe_push (odr_types_ptr, val);
}
+ else if (base_id > val->id)
+ {
+ odr_types[val->id] = 0;
+ /* Be sure we did not recorded any derived types; these may need
+ renumbering too. */
+ gcc_assert (val->derived_types.length() == 0);
+ if (odr_types_ptr)
+ val->id = odr_types.length ();
+ vec_safe_push (odr_types_ptr, val);
+ }
return val;
}
fprintf (f, "\n\nType inheritance graph:\n");
for (i = 0; i < odr_types.length (); i++)
{
- if (odr_types[i]->bases.length () == 0)
+ if (odr_types[i] && odr_types[i]->bases.length () == 0)
dump_odr_type (f, odr_types[i]);
}
for (i = 0; i < odr_types.length (); i++)
{
- if (odr_types[i]->types && odr_types[i]->types->length ())
+ if (odr_types[i] && odr_types[i]->types && odr_types[i]->types->length ())
{
unsigned int j;
fprintf (f, "Duplicate tree types for odr type %i\n", i);
if (is_a <cgraph_node *> (n)
&& DECL_VIRTUAL_P (n->decl)
&& symtab_real_symbol_p (n))
- get_odr_type (method_class_type (TREE_TYPE (n->decl)), true);
+ get_odr_type (TYPE_MAIN_VARIANT (method_class_type (TREE_TYPE (n->decl))),
+ true);
/* Look also for virtual tables of types that do not define any methods.
&& TREE_CODE (DECL_CONTEXT (n->decl)) == RECORD_TYPE
&& TYPE_BINFO (DECL_CONTEXT (n->decl))
&& polymorphic_type_binfo_p (TYPE_BINFO (DECL_CONTEXT (n->decl))))
- get_odr_type (DECL_CONTEXT (n->decl), true);
+ get_odr_type (TYPE_MAIN_VARIANT (DECL_CONTEXT (n->decl)), true);
if (inheritance_dump_file)
{
dump_type_inheritance_graph (inheritance_dump_file);
gcc_assert (in_lto_p || context.maybe_derived_type);
}
- pointer_set_insert (matched_vtables, BINFO_VTABLE (binfo));
+ if (binfo)
+ pointer_set_insert (matched_vtables, BINFO_VTABLE (binfo));
/* Next walk recursively all derived types. */
if (context.maybe_derived_type)
{
vec <cgraph_node *> targets;
bool final;
- odr_type type = get_odr_type (otr_type, false);
+ odr_type type = get_odr_type (TYPE_MAIN_VARIANT (otr_type), false);
unsigned int i;
int nonconstruction;
if (DECL_VIRTUAL_P (n->decl)
&& !n->definition
&& symtab_real_symbol_p (n))
- get_odr_type (method_class_type (TREE_TYPE (n->decl)), true);
+ get_odr_type (method_class_type (TYPE_MAIN_VARIANT (TREE_TYPE (n->decl))),
+ true);
timevar_pop (TV_IPA_INHERITANCE);
}
static int type_hash_marked_p (const void *);
static unsigned int type_hash_list (const_tree, hashval_t);
static unsigned int attribute_hash_list (const_tree, hashval_t);
-static bool decls_same_for_odr (tree decl1, tree decl2);
tree global_trees[TI_MAX];
tree integer_types[itk_none];
return gcc_eh_personality_decl;
}
-/* For languages with One Definition Rule, work out if
- trees are actually the same even if the tree representation
- differs. This handles only decls appearing in TYPE_NAME
- and TYPE_CONTEXT. That is NAMESPACE_DECL, TYPE_DECL,
- RECORD_TYPE and IDENTIFIER_NODE. */
-
-static bool
-same_for_odr (tree t1, tree t2)
-{
- if (t1 == t2)
- return true;
- if (!t1 || !t2)
- return false;
- /* C and C++ FEs differ by using IDENTIFIER_NODE and TYPE_DECL. */
- if (TREE_CODE (t1) == IDENTIFIER_NODE
- && TREE_CODE (t2) == TYPE_DECL
- && DECL_FILE_SCOPE_P (t1))
- {
- t2 = DECL_NAME (t2);
- gcc_assert (TREE_CODE (t2) == IDENTIFIER_NODE);
- }
- if (TREE_CODE (t2) == IDENTIFIER_NODE
- && TREE_CODE (t1) == TYPE_DECL
- && DECL_FILE_SCOPE_P (t2))
- {
- t1 = DECL_NAME (t1);
- gcc_assert (TREE_CODE (t1) == IDENTIFIER_NODE);
- }
- if (TREE_CODE (t1) != TREE_CODE (t2))
- return false;
- if (TYPE_P (t1))
- return types_same_for_odr (t1, t2);
- if (DECL_P (t1))
- return decls_same_for_odr (t1, t2);
- return false;
-}
-
-/* For languages with One Definition Rule, work out if
- decls are actually the same even if the tree representation
- differs. This handles only decls appearing in TYPE_NAME
- and TYPE_CONTEXT. That is NAMESPACE_DECL, TYPE_DECL,
- RECORD_TYPE and IDENTIFIER_NODE. */
-
-static bool
-decls_same_for_odr (tree decl1, tree decl2)
-{
- if (decl1 && TREE_CODE (decl1) == TYPE_DECL
- && DECL_ORIGINAL_TYPE (decl1))
- decl1 = DECL_ORIGINAL_TYPE (decl1);
- if (decl2 && TREE_CODE (decl2) == TYPE_DECL
- && DECL_ORIGINAL_TYPE (decl2))
- decl2 = DECL_ORIGINAL_TYPE (decl2);
- if (decl1 == decl2)
- return true;
- if (!decl1 || !decl2)
- return false;
- gcc_checking_assert (DECL_P (decl1) && DECL_P (decl2));
- if (TREE_CODE (decl1) != TREE_CODE (decl2))
- return false;
- if (TREE_CODE (decl1) == TRANSLATION_UNIT_DECL)
- return true;
- if (TREE_CODE (decl1) != NAMESPACE_DECL
- && TREE_CODE (decl1) != TYPE_DECL)
- return false;
- if (!DECL_NAME (decl1))
- return false;
- gcc_checking_assert (TREE_CODE (DECL_NAME (decl1)) == IDENTIFIER_NODE);
- gcc_checking_assert (!DECL_NAME (decl2)
- || TREE_CODE (DECL_NAME (decl2)) == IDENTIFIER_NODE);
- if (DECL_NAME (decl1) != DECL_NAME (decl2))
- return false;
- return same_for_odr (DECL_CONTEXT (decl1),
- DECL_CONTEXT (decl2));
-}
-
-/* For languages with One Definition Rule, work out if
- types are same even if the tree representation differs.
- This is non-trivial for LTO where minnor differences in
- the type representation may have prevented type merging
- to merge two copies of otherwise equivalent type. */
-
-bool
-types_same_for_odr (tree type1, tree type2)
-{
- gcc_checking_assert (TYPE_P (type1) && TYPE_P (type2));
- type1 = TYPE_MAIN_VARIANT (type1);
- type2 = TYPE_MAIN_VARIANT (type2);
- if (type1 == type2)
- return true;
-
-#ifndef ENABLE_CHECKING
- if (!in_lto_p)
- return false;
-#endif
-
- /* 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))
- return false;
- /* When assembler name of virtual table is available, it is
- easy to compare types for equivalence. */
- if (TYPE_BINFO (type1) && TYPE_BINFO (type2)
- && BINFO_VTABLE (TYPE_BINFO (type1))
- && BINFO_VTABLE (TYPE_BINFO (type2)))
- {
- tree v1 = BINFO_VTABLE (TYPE_BINFO (type1));
- tree v2 = BINFO_VTABLE (TYPE_BINFO (type2));
-
- if (TREE_CODE (v1) == POINTER_PLUS_EXPR)
- {
- if (TREE_CODE (v2) != POINTER_PLUS_EXPR
- || !operand_equal_p (TREE_OPERAND (v1, 1),
- TREE_OPERAND (v2, 1), 0))
- return false;
- v1 = TREE_OPERAND (TREE_OPERAND (v1, 0), 0);
- v2 = TREE_OPERAND (TREE_OPERAND (v2, 0), 0);
- }
- v1 = DECL_ASSEMBLER_NAME (v1);
- v2 = DECL_ASSEMBLER_NAME (v2);
- return (v1 == v2);
- }
-
- /* FIXME: the code comparing type names consider all instantiations of the
- same template to have same name. This is because we have no access
- to template parameters. For types with no virtual method tables
- we thus can return false positives. At the moment we do not need
- to compare types in other scenarios than devirtualization. */
-
- /* If types are not structuraly same, do not bother to contnue.
- Match in the remainder of code would mean ODR violation. */
- if (!types_compatible_p (type1, type2))
- return false;
- if (!TYPE_NAME (type1))
- return false;
- if (!decls_same_for_odr (TYPE_NAME (type1), TYPE_NAME (type2)))
- return false;
- if (!same_for_odr (TYPE_CONTEXT (type1), TYPE_CONTEXT (type2)))
- return false;
- /* When not in LTO the MAIN_VARIANT check should be the same. */
- gcc_assert (in_lto_p);
-
- return true;
-}
-
/* TARGET is a call target of GIMPLE call statement
(obtained by gimple_call_fn). Return true if it is
OBJ_TYPE_REF representing an virtual call of C++ method.
/* Return true if T is in anonymous namespace. */
bool
-type_in_anonymous_namespace_p (tree t)
+type_in_anonymous_namespace_p (const_tree t)
{
return (TYPE_STUB_DECL (t) && !TREE_PUBLIC (TYPE_STUB_DECL (t)));
}