From 88b1650888ad7645e65eb7401c6ab4ef194649c3 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Wed, 18 Feb 2015 17:12:52 +0100 Subject: [PATCH] ipa-devirt.c (odr_subtypes_equivalent_p): Fix formating. * ipa-devirt.c (odr_subtypes_equivalent_p): Fix formating. (compare_virtual_tables): Be smarter about skipping typeinfos; do sane output on virtual table table mismatch. (warn_odr): Be ready for forward declarations of enums; output sane info on base mismatch and virtual table mismatch. (add_type_duplicate): Fix code choosing prevailing type; do not ICE when only one type is polymorphic. (get_odr_type): Fix hashtable corruption. (dump_odr_type): Dump mangled names. From-SVN: r220790 --- gcc/ChangeLog | 12 +++ gcc/ipa-devirt.c | 273 ++++++++++++++++++++++++++++++++++++----------- 2 files changed, 222 insertions(+), 63 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9523db04827..edf5a059322 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2015-02-18 Jan Hubicka + + * ipa-devirt.c (odr_subtypes_equivalent_p): Fix formating. + (compare_virtual_tables): Be smarter about skipping typeinfos; + do sane output on virtual table table mismatch. + (warn_odr): Be ready for forward declarations of enums; + output sane info on base mismatch and virtual table mismatch. + (add_type_duplicate): Fix code choosing prevailing type; do not ICE + when only one type is polymorphic. + (get_odr_type): Fix hashtable corruption. + (dump_odr_type): Dump mangled names. + 2015-02-18 Richard Biener PR tree-optimization/65063 diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c index 422d6a4155a..c3f8b156a55 100644 --- a/gcc/ipa-devirt.c +++ b/gcc/ipa-devirt.c @@ -551,7 +551,8 @@ set_type_binfo (tree type, tree binfo) /* Compare T2 and T2 based on name or structure. */ static bool -odr_subtypes_equivalent_p (tree t1, tree t2, hash_set *visited) +odr_subtypes_equivalent_p (tree t1, tree t2, + hash_set *visited) { bool an1, an2; @@ -618,7 +619,8 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable) prevailing = vtable; vtable = tmp; } - if (warning_at (DECL_SOURCE_LOCATION (TYPE_NAME (DECL_CONTEXT (vtable->decl))), + if (warning_at (DECL_SOURCE_LOCATION + (TYPE_NAME (DECL_CONTEXT (vtable->decl))), OPT_Wodr, "virtual table of type %qD violates one definition rule", DECL_CONTEXT (vtable->decl))) @@ -633,39 +635,118 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable) { struct ipa_ref *ref1, *ref2; bool end1, end2; + end1 = !prevailing->iterate_reference (n1, ref1); end2 = !vtable->iterate_reference (n2, ref2); - if (end1 && end2) - return; - if (!end1 && !end2 - && DECL_ASSEMBLER_NAME (ref1->referred->decl) - != DECL_ASSEMBLER_NAME (ref2->referred->decl) - && !n2 - && !DECL_VIRTUAL_P (ref2->referred->decl) - && DECL_VIRTUAL_P (ref1->referred->decl)) + + /* !DECL_VIRTUAL_P means RTTI entry; + We warn when RTTI is lost because non-RTTI previals; we silently + accept the other case. */ + while (!end2 + && (end1 + || (DECL_ASSEMBLER_NAME (ref1->referred->decl) + != DECL_ASSEMBLER_NAME (ref2->referred->decl) + && DECL_VIRTUAL_P (ref1->referred->decl))) + && !DECL_VIRTUAL_P (ref2->referred->decl)) { - if (warning_at (DECL_SOURCE_LOCATION (TYPE_NAME (DECL_CONTEXT (vtable->decl))), 0, + if (warning_at (DECL_SOURCE_LOCATION + (TYPE_NAME (DECL_CONTEXT (vtable->decl))), 0, "virtual table of type %qD contains RTTI information", DECL_CONTEXT (vtable->decl))) { - inform (DECL_SOURCE_LOCATION (TYPE_NAME (DECL_CONTEXT (prevailing->decl))), - "but is prevailed by one without from other translation unit"); - inform (DECL_SOURCE_LOCATION (TYPE_NAME (DECL_CONTEXT (prevailing->decl))), + inform (DECL_SOURCE_LOCATION + (TYPE_NAME (DECL_CONTEXT (prevailing->decl))), + "but is prevailed by one without from other translation " + "unit"); + inform (DECL_SOURCE_LOCATION + (TYPE_NAME (DECL_CONTEXT (prevailing->decl))), "RTTI will not work on this type"); } n2++; end2 = !vtable->iterate_reference (n2, ref2); } - if (!end1 && !end2 - && DECL_ASSEMBLER_NAME (ref1->referred->decl) - != DECL_ASSEMBLER_NAME (ref2->referred->decl) - && !n1 - && !DECL_VIRTUAL_P (ref1->referred->decl) - && DECL_VIRTUAL_P (ref2->referred->decl)) + while (!end1 + && (end2 + || (DECL_ASSEMBLER_NAME (ref2->referred->decl) + != DECL_ASSEMBLER_NAME (ref1->referred->decl) + && DECL_VIRTUAL_P (ref2->referred->decl))) + && !DECL_VIRTUAL_P (ref1->referred->decl)) { n1++; end1 = !vtable->iterate_reference (n1, ref1); } + + /* Finished? */ + if (end1 && end2) + { + /* Extra paranoia; compare the sizes. We do not have information + about virtual inheritance offsets, so just be sure that these + match. + Do this as very last check so the not very informative error + is not output too often. */ + if (DECL_SIZE (prevailing->decl) != DECL_SIZE (vtable->decl)) + { + if (warning_at (DECL_SOURCE_LOCATION + (TYPE_NAME (DECL_CONTEXT (vtable->decl))), 0, + "virtual table of type %qD violates " + "one definition rule ", + DECL_CONTEXT (vtable->decl))) + { + inform (DECL_SOURCE_LOCATION + (TYPE_NAME (DECL_CONTEXT (prevailing->decl))), + "the conflicting type defined in another translation " + "unit has virtual table of different size"); + } + } + return; + } + + if (!end1 && !end2) + { + if (DECL_ASSEMBLER_NAME (ref1->referred->decl) + == DECL_ASSEMBLER_NAME (ref2->referred->decl)) + continue; + + /* If the loops above stopped on non-virtual pointer, we have + mismatch in RTTI information mangling. */ + if (!DECL_VIRTUAL_P (ref1->referred->decl) + && !DECL_VIRTUAL_P (ref2->referred->decl)) + { + if (warning_at (DECL_SOURCE_LOCATION + (TYPE_NAME (DECL_CONTEXT (vtable->decl))), 0, + "virtual table of type %qD violates " + "one definition rule ", + DECL_CONTEXT (vtable->decl))) + { + inform (DECL_SOURCE_LOCATION + (TYPE_NAME (DECL_CONTEXT (prevailing->decl))), + "the conflicting type defined in another translation " + "unit virtual table with different RTTI information"); + } + return; + } + /* At this point both REF1 and REF2 points either to virtual table + or virtual method. If one points to virtual table and other to + method we can complain the same way as if one table was shorter + than other pointing out the extra method. */ + gcc_assert (DECL_VIRTUAL_P (ref1->referred->decl) + && (TREE_CODE (ref1->referred->decl) == FUNCTION_DECL + || TREE_CODE (ref1->referred->decl) == VAR_DECL)); + gcc_assert (DECL_VIRTUAL_P (ref2->referred->decl) + && (TREE_CODE (ref2->referred->decl) == FUNCTION_DECL + || TREE_CODE (ref2->referred->decl) == VAR_DECL)); + if (TREE_CODE (ref1->referred->decl) + != TREE_CODE (ref2->referred->decl)) + { + if (TREE_CODE (ref1->referred->decl) == VAR_DECL) + end1 = true; + else if (TREE_CODE (ref2->referred->decl) == VAR_DECL) + end2 = true; + } + } + + /* Complain about size mismatch. Either we have too many virutal + functions or too many virtual table pointers. */ if (end1 || end2) { if (end1) @@ -681,37 +762,56 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable) "one definition rule", DECL_CONTEXT (vtable->decl))) { - inform (DECL_SOURCE_LOCATION - (TYPE_NAME (DECL_CONTEXT (prevailing->decl))), - "the conflicting type defined in another translation " - "unit"); - inform (DECL_SOURCE_LOCATION - (TYPE_NAME (DECL_CONTEXT (ref1->referring->decl))), - "contains additional virtual method %qD", - ref1->referred->decl); + if (TREE_CODE (ref1->referring->decl) == FUNCTION_DECL) + { + inform (DECL_SOURCE_LOCATION + (TYPE_NAME (DECL_CONTEXT (prevailing->decl))), + "the conflicting type defined in another translation " + "unit"); + inform (DECL_SOURCE_LOCATION + (TYPE_NAME (DECL_CONTEXT (ref1->referring->decl))), + "contains additional virtual method %qD", + ref1->referred->decl); + } + else + { + inform (DECL_SOURCE_LOCATION + (TYPE_NAME (DECL_CONTEXT (prevailing->decl))), + "the conflicting type defined in another translation " + "unit has virtual table table with more entries"); + } } return; } - if (DECL_ASSEMBLER_NAME (ref1->referred->decl) - != DECL_ASSEMBLER_NAME (ref2->referred->decl)) + + /* And in the last case we have either mistmatch in between two virtual + methods or two virtual table pointers. */ + if (warning_at (DECL_SOURCE_LOCATION + (TYPE_NAME (DECL_CONTEXT (vtable->decl))), 0, + "virtual table of type %qD violates " + "one definition rule ", + DECL_CONTEXT (vtable->decl))) { - if (warning_at (DECL_SOURCE_LOCATION - (TYPE_NAME (DECL_CONTEXT (vtable->decl))), 0, - "virtual table of type %qD violates " - "one definition rule ", - DECL_CONTEXT (vtable->decl))) + if (TREE_CODE (ref1->referred->decl) == FUNCTION_DECL) { inform (DECL_SOURCE_LOCATION (TYPE_NAME (DECL_CONTEXT (prevailing->decl))), "the conflicting type defined in another translation " "unit"); + gcc_assert (TREE_CODE (ref2->referred->decl) + == FUNCTION_DECL); inform (DECL_SOURCE_LOCATION (ref1->referred->decl), "virtual method %qD", ref1->referred->decl); inform (DECL_SOURCE_LOCATION (ref2->referred->decl), "ought to match virtual method %qD but does not", ref2->referred->decl); - return; } + else + inform (DECL_SOURCE_LOCATION + (TYPE_NAME (DECL_CONTEXT (prevailing->decl))), + "the conflicting type defined in another translation " + "unit has virtual table table with different contents"); + return; } } } @@ -727,6 +827,8 @@ warn_odr (tree t1, tree t2, tree st1, tree st2, bool warn, bool *warned, const char *reason) { tree decl2 = TYPE_NAME (t2); + if (warned) + *warned = false; if (!warn) return; @@ -840,7 +942,8 @@ odr_types_equivalent_p (tree t1, tree t2, bool warn, bool *warned, return false; } - if (TREE_CODE (t1) == ENUMERAL_TYPE) + if (TREE_CODE (t1) == ENUMERAL_TYPE + && TYPE_VALUES (t1) && TYPE_VALUES (t2)) { tree v1, v2; for (v1 = TYPE_VALUES (t1), v2 = TYPE_VALUES (t2); @@ -1056,8 +1159,20 @@ odr_types_equivalent_p (tree t1, tree t2, bool warn, bool *warned, f2 = TREE_CHAIN (f2); if (!f1 || !f2) break; + if (DECL_VIRTUAL_P (f1) != DECL_VIRTUAL_P (f2)) + { + warn_odr (t1, t2, NULL, NULL, warn, warned, + G_("a type with different virtual table pointers" + " is defined in another translation unit")); + return false; + } if (DECL_ARTIFICIAL (f1) != DECL_ARTIFICIAL (f2)) - break; + { + warn_odr (t1, t2, NULL, NULL, warn, warned, + G_("a type with different bases is defined " + "in another translation unit")); + return false; + } if (DECL_NAME (f1) != DECL_NAME (f2) && !DECL_ARTIFICIAL (f1)) { @@ -1066,10 +1181,11 @@ odr_types_equivalent_p (tree t1, tree t2, bool warn, bool *warned, "in another translation unit")); return false; } - if (!odr_subtypes_equivalent_p (TREE_TYPE (f1), TREE_TYPE (f2), visited)) + if (!odr_subtypes_equivalent_p (TREE_TYPE (f1), + TREE_TYPE (f2), visited)) { - /* Do not warn about artificial fields and just go into generic - field mismatch warning. */ + /* Do not warn about artificial fields and just go into + generic field mismatch warning. */ if (DECL_ARTIFICIAL (f1)) break; @@ -1082,11 +1198,11 @@ odr_types_equivalent_p (tree t1, tree t2, bool warn, bool *warned, } if (!gimple_compare_field_offset (f1, f2)) { - /* Do not warn about artificial fields and just go into generic - field mismatch warning. */ + /* Do not warn about artificial fields and just go into + generic field mismatch warning. */ if (DECL_ARTIFICIAL (f1)) break; - warn_odr (t1, t2, t1, t2, warn, warned, + warn_odr (t1, t2, f1, f2, warn, warned, G_("fields has different layout " "in another translation unit")); return false; @@ -1099,18 +1215,18 @@ odr_types_equivalent_p (tree t1, tree t2, bool warn, bool *warned, are not the same. */ if (f1 || f2) { - if (f1 && DECL_ARTIFICIAL (f1)) - f1 = NULL; - if (f2 && DECL_ARTIFICIAL (f2)) - f2 = NULL; - if (f1 || f2) - warn_odr (t1, t2, f1, f2, warn, warned, - G_("a type with different number of fields " - "is defined in another translation unit")); - /* Ideally we should never get this generic message. */ + if ((f1 && DECL_VIRTUAL_P (f1)) || (f2 && DECL_VIRTUAL_P (f2))) + warn_odr (t1, t2, NULL, NULL, warn, warned, + G_("a type with different virtual table pointers" + " is defined in another translation unit")); + if ((f1 && DECL_ARTIFICIAL (f1)) + || (f2 && DECL_ARTIFICIAL (f2))) + warn_odr (t1, t2, NULL, NULL, warn, warned, + G_("a type with different bases is defined " + "in another translation unit")); else warn_odr (t1, t2, f1, f2, warn, warned, - G_("a type with different memory representation " + G_("a type with different number of fields " "is defined in another translation unit")); return false; @@ -1207,12 +1323,24 @@ add_type_duplicate (odr_type val, tree type) val->types_set = new hash_set; /* Always prefer complete type to be the leader. */ - if ((!COMPLETE_TYPE_P (val->type) || !TYPE_BINFO (val->type)) - && (COMPLETE_TYPE_P (type) && TYPE_BINFO (val->type))) + + if (!COMPLETE_TYPE_P (val->type) && COMPLETE_TYPE_P (type)) + build_bases = true; + else if (COMPLETE_TYPE_P (val->type) && !COMPLETE_TYPE_P (type)) + ; + else if (TREE_CODE (val->type) == ENUMERAL_TYPE + && TREE_CODE (type) == ENUMERAL_TYPE + && !TYPE_VALUES (val->type) && TYPE_VALUES (type)) + build_bases = true; + else if (TREE_CODE (val->type) == RECORD_TYPE + && TREE_CODE (type) == RECORD_TYPE + && TYPE_BINFO (type) && !TYPE_BINFO (val->type)) + build_bases = true; + + if (build_bases) { tree tmp = type; - build_bases = true; type = val->type; val->type = tmp; } @@ -1303,11 +1431,14 @@ add_type_duplicate (odr_type val, tree type) if (base_mismatch) { if (!warned && !val->odr_violated) - warn_odr (type, val->type, NULL, NULL, - !warned, &warned, - "a type with the same name but different base " - "type is defined in another translation unit"); - warn_types_mismatch (type1, type2); + { + warn_odr (type, val->type, NULL, NULL, + !warned, &warned, + "a type with the same name but different base " + "type is defined in another translation unit"); + if (warned) + warn_types_mismatch (type1, type2); + } break; } if (BINFO_OFFSET (base1) != BINFO_OFFSET (base2)) @@ -1320,6 +1451,18 @@ add_type_duplicate (odr_type val, tree type) "layout is defined in another translation unit"); break; } + /* One base is polymorphic and the other not. + This ought to be diagnosed earlier, but do not ICE in the + checking bellow. */ + if (!TYPE_BINFO (type1) != !TYPE_BINFO (type2) + || (TYPE_BINFO (type1) + && polymorphic_type_binfo_p (TYPE_BINFO (type1)) + != polymorphic_type_binfo_p (TYPE_BINFO (type2)))) + { + gcc_assert (val->odr_violated); + base_mismatch = true; + break; + } } #ifdef ENABLE_CHECKING /* Sanity check that all bases will be build same way again. */ @@ -1468,6 +1611,7 @@ get_odr_type (tree type, bool insert) val->anonymous_namespace = type_in_anonymous_namespace_p (type); build_bases = COMPLETE_TYPE_P (val->type); insert_to_odr_array = true; + *slot = val; } if (build_bases && TREE_CODE (type) == RECORD_TYPE && TYPE_BINFO (type) @@ -1479,7 +1623,6 @@ get_odr_type (tree type, bool insert) 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++) /* For now record only polymorphic types. other are pointless for devirtualization and we can not precisely @@ -1557,6 +1700,10 @@ dump_odr_type (FILE *f, odr_type t, int indent=0) fprintf (f, "%*s defined at: %s:%i\n", indent * 2, "", DECL_SOURCE_FILE (TYPE_NAME (t->type)), DECL_SOURCE_LINE (TYPE_NAME (t->type))); + if (DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (t->type))) + fprintf (f, "%*s mangled name: %s\n", indent * 2, "", + IDENTIFIER_POINTER + (DECL_ASSEMBLER_NAME (TYPE_NAME (t->type)))); } if (t->bases.length ()) { -- 2.30.2