diff options
Diffstat (limited to 'gcc/tree.c')
-rw-r--r-- | gcc/tree.c | 126 |
1 files changed, 124 insertions, 2 deletions
@@ -218,6 +218,7 @@ static void print_value_expr_statistics (void); 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]; @@ -11711,6 +11712,127 @@ lhd_gcc_personality (void) 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; + + /* 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; + +#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_STUB_DECL (type1) != TYPE_STUB_DECL (type2) + && (!TYPE_STUB_DECL (type1) + || !TYPE_STUB_DECL (type2) + || !TREE_PUBLIC (TYPE_STUB_DECL (type1)) + || !TREE_PUBLIC (TYPE_STUB_DECL (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; +} + /* Try to find a base info of BINFO that would have its field decl at offset OFFSET within the BINFO type and which is of EXPECTED_TYPE. If it can be found, return, otherwise return NULL_TREE. */ @@ -11726,7 +11848,7 @@ get_binfo_at_offset (tree binfo, HOST_WIDE_INT offset, tree expected_type) tree fld; int i; - if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (expected_type)) + if (types_same_for_odr (type, expected_type)) return binfo; if (offset < 0) return NULL_TREE; @@ -11756,7 +11878,7 @@ get_binfo_at_offset (tree binfo, HOST_WIDE_INT offset, tree expected_type) { tree base_binfo, found_binfo = NULL_TREE; for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) - if (TREE_TYPE (base_binfo) == TREE_TYPE (fld)) + if (types_same_for_odr (TREE_TYPE (base_binfo), TREE_TYPE (fld))) { found_binfo = base_binfo; break; |