aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog10
-rw-r--r--gcc/gimple-fold.c2
-rw-r--r--gcc/tree.c126
-rw-r--r--gcc/tree.h1
4 files changed, 136 insertions, 3 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index e3484bd..c18f056 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,13 @@
+2013-06-20 Jan Hubicka <jh@suse.cz>
+
+ * gimple-fold.c (gimple_extract_devirt_binfo_from_cst): Use
+ types_same_for_odr.
+ * tree.c (decls_same_for_odr): New function.
+ (same_for_edr): New function.
+ (types_same_for_odr): New function.
+ (get_binfo_at_offset): Use it.
+ * tree.h (types_same_for_odr): Declare.
+
2013-06-20 Oleg Endo <oleg.endo@t-online.de>
Jason Merrill <jason@redhat.com>
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index b6d22b3..728d361 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -1038,7 +1038,7 @@ gimple_extract_devirt_binfo_from_cst (tree cst)
HOST_WIDE_INT pos, size;
tree fld;
- if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (expected_type))
+ if (types_same_for_odr (type, expected_type))
break;
if (offset < 0)
return NULL_TREE;
diff --git a/gcc/tree.c b/gcc/tree.c
index 67553b8..ab11735 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -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;
diff --git a/gcc/tree.h b/gcc/tree.h
index cbbdd0b..b444517 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -5974,6 +5974,7 @@ extern location_t tree_nonartificial_location (tree);
extern tree block_ultimate_origin (const_tree);
extern tree get_binfo_at_offset (tree, HOST_WIDE_INT, tree);
+extern bool types_same_for_odr (tree type1, tree type2);
extern tree get_ref_base_and_extent (tree, HOST_WIDE_INT *,
HOST_WIDE_INT *, HOST_WIDE_INT *);
extern bool contains_bitfld_component_ref_p (const_tree);