From: Jan Hubicka Date: Mon, 23 Mar 2015 00:17:07 +0000 (+0100) Subject: re PR lto/65475 (ICE in odr_vtable_hasher::equal (Segmentation fault)) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=b19058080955faaad5744d69288cb1de24078083;p=gcc.git re PR lto/65475 (ICE in odr_vtable_hasher::equal (Segmentation fault)) PR ipa/65475 * ipa-devirt.c: Include demangle.h (odr_type_d): Add field rtti_broken. (odr_subtypes_equivalent_p): Do not require name to match. (compare_virtual_tables): Fix typo; if type already has ODR violation, bypass the tests; be ready for function referneces in vtables that are not DECL_VIRTUAL; make warnings to be OPT_Wodr. (warn_odr): Give up for nameless types. (warn_types_mismatch): Report mismatch in mangled names; report mismatch in anonymous namespaces; look into component types to give useful error; report when mismatch is dragged in from other ODR type. (odr_types_equivalent_p): Match types for being polymorphic; avoid duplicated diagnostics. (add_type_duplicate): Reorder checks so more informative ones come first; fix typo; do not output "the extra base is defined here" when we did not warn. (BINFO_N_BASE_BINFOS): Relax sanity check. * g++.dg/lto/pr65475b_0.C: New testcase. * g++.dg/lto/pr65475b_1.C: New testcase. * g++.dg/lto/pr65475c_0.C: New testcase. * g++.dg/lto/pr65475c_1.C: New testcase. From-SVN: r221582 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7e05b814765..02562e34e35 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,25 @@ -2015-03-22 Martin Liska +2015-03-22 Jan Hubicka + + PR ipa/65475 + * ipa-devirt.c: Include demangle.h + (odr_type_d): Add field rtti_broken. + (odr_subtypes_equivalent_p): Do not require name to match. + (compare_virtual_tables): Fix typo; if type already has ODR violation, + bypass the tests; be ready for function referneces in vtables that are + not DECL_VIRTUAL; make warnings to be OPT_Wodr. + (warn_odr): Give up for nameless types. + (warn_types_mismatch): Report mismatch in mangled names; + report mismatch in anonymous namespaces; look into component types to + give useful error; report when mismatch is dragged in from other ODR + type. + (odr_types_equivalent_p): Match types for being polymorphic; avoid + duplicated diagnostics. + (add_type_duplicate): Reorder checks so more informative ones come + first; fix typo; do not output "the extra base is defined here" when + we did not warn. + (BINFO_N_BASE_BINFOS): Relax sanity check. +2015-03-22 Martin Liska Jakub Jelinek * config/i386/i386.c (def_builtin): Set deferred_isa_values for diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c index dd4397bbf28..5e08431d427 100644 --- a/gcc/ipa-devirt.c +++ b/gcc/ipa-devirt.c @@ -166,6 +166,7 @@ along with GCC; see the file COPYING3. If not see #include "gimple-pretty-print.h" #include "stor-layout.h" #include "intl.h" +#include "demangle.h" /* Hash based set of pairs of types. */ typedef struct @@ -239,6 +240,8 @@ struct GTY(()) odr_type_d bool all_derivations_known; /* Did we report ODR violation here? */ bool odr_violated; + /* Set when virtual table without RTTI previaled table with. */ + bool rtti_broken; }; /* Return TRUE if all derived types of T are known and thus @@ -673,8 +676,6 @@ odr_subtypes_equivalent_p (tree t1, tree t2, return false; if ((TYPE_NAME (t1) == NULL_TREE) != (TYPE_NAME (t2) == NULL_TREE)) return false; - if (TYPE_NAME (t1) && DECL_NAME (TYPE_NAME (t1)) != DECL_NAME (TYPE_NAME (t2))) - return false; type_pair pair={t1,t2}; if (TYPE_UID (t1) > TYPE_UID (t2)) @@ -694,6 +695,7 @@ void compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable) { int n1, n2; + if (DECL_VIRTUAL_P (prevailing->decl) != DECL_VIRTUAL_P (vtable->decl)) { odr_violation_reported = true; @@ -715,6 +717,17 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable) } if (!prevailing->definition || !vtable->definition) return; + + /* If we do not stream ODR type info, do not bother to do useful compare. */ + if (!TYPE_BINFO (DECL_CONTEXT (vtable->decl)) + || !polymorphic_type_binfo_p (TYPE_BINFO (DECL_CONTEXT (vtable->decl)))) + return; + + odr_type class_type = get_odr_type (DECL_CONTEXT (vtable->decl), true); + + if (class_type->odr_violated) + return; + for (n1 = 0, n2 = 0; true; n1++, n2++) { struct ipa_ref *ref1, *ref2; @@ -730,13 +743,16 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable) && (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)) + && TREE_CODE (ref1->referred->decl) == FUNCTION_DECL)) + && TREE_CODE (ref2->referred->decl) != FUNCTION_DECL) { - 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))) + if (!class_type->rtti_broken + && warning_at (DECL_SOURCE_LOCATION + (TYPE_NAME (DECL_CONTEXT (vtable->decl))), + OPT_Wodr, + "virtual table of type %qD contains RTTI " + "information", + DECL_CONTEXT (vtable->decl))) { inform (DECL_SOURCE_LOCATION (TYPE_NAME (DECL_CONTEXT (prevailing->decl))), @@ -745,6 +761,7 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable) inform (DECL_SOURCE_LOCATION (TYPE_NAME (DECL_CONTEXT (prevailing->decl))), "RTTI will not work on this type"); + class_type->rtti_broken = true; } n2++; end2 = !vtable->iterate_reference (n2, ref2); @@ -753,11 +770,11 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable) && (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)) + && TREE_CODE (ref2->referred->decl) == FUNCTION_DECL)) + && TREE_CODE (ref1->referred->decl) != FUNCTION_DECL) { n1++; - end1 = !vtable->iterate_reference (n1, ref1); + end1 = !prevailing->iterate_reference (n1, ref1); } /* Finished? */ @@ -770,8 +787,10 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable) is not output too often. */ if (DECL_SIZE (prevailing->decl) != DECL_SIZE (vtable->decl)) { + class_type->odr_violated = true; if (warning_at (DECL_SOURCE_LOCATION - (TYPE_NAME (DECL_CONTEXT (vtable->decl))), 0, + (TYPE_NAME (DECL_CONTEXT (vtable->decl))), + OPT_Wodr, "virtual table of type %qD violates " "one definition rule ", DECL_CONTEXT (vtable->decl))) @@ -791,13 +810,16 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable) == DECL_ASSEMBLER_NAME (ref2->referred->decl)) continue; + class_type->odr_violated = true; + /* 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 (TREE_CODE (ref1->referred->decl) != FUNCTION_DECL + && TREE_CODE (ref2->referred->decl) != FUNCTION_DECL) { if (warning_at (DECL_SOURCE_LOCATION - (TYPE_NAME (DECL_CONTEXT (vtable->decl))), 0, + (TYPE_NAME (DECL_CONTEXT (vtable->decl))), + OPT_Wodr, "virtual table of type %qD violates " "one definition rule ", DECL_CONTEXT (vtable->decl))) @@ -813,12 +835,6 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable) 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)) { @@ -829,6 +845,8 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable) } } + class_type->odr_violated = true; + /* Complain about size mismatch. Either we have too many virutal functions or too many virtual table pointers. */ if (end1 || end2) @@ -841,7 +859,8 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable) ref1 = ref2; } if (warning_at (DECL_SOURCE_LOCATION - (TYPE_NAME (DECL_CONTEXT (vtable->decl))), 0, + (TYPE_NAME (DECL_CONTEXT (vtable->decl))), + OPT_Wodr, "virtual table of type %qD violates " "one definition rule", DECL_CONTEXT (vtable->decl))) @@ -871,7 +890,7 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable) /* 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, + (TYPE_NAME (DECL_CONTEXT (vtable->decl))), OPT_Wodr, "virtual table of type %qD violates " "one definition rule ", DECL_CONTEXT (vtable->decl))) @@ -914,8 +933,9 @@ warn_odr (tree t1, tree t2, tree st1, tree st2, if (warned) *warned = false; - if (!warn) + if (!warn || !TYPE_NAME(t1)) return; + if (!warning_at (DECL_SOURCE_LOCATION (TYPE_NAME (t1)), OPT_Wodr, "type %qT violates one definition rule", t1)) @@ -964,7 +984,132 @@ warn_odr (tree t1, tree t2, tree st1, tree st2, void warn_types_mismatch (tree t1, tree t2) { + /* If types have names and they are different, it is most informative to + output those. */ + if (TYPE_NAME (t1) && TYPE_NAME (t2) + && DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (t1)) + && DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (t2)) + && DECL_ASSEMBLER_NAME (TYPE_NAME (t1)) + != DECL_ASSEMBLER_NAME (TYPE_NAME (t2))) + { + char *name1 = xstrdup (cplus_demangle + (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (TYPE_NAME (t1))), + DMGL_PARAMS | DMGL_ANSI | DMGL_TYPES)); + char *name2 = cplus_demangle + (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (TYPE_NAME (t2))), + DMGL_PARAMS | DMGL_ANSI | DMGL_TYPES); + if (name1 && name2 && strcmp (name1, name2)) + { + inform (DECL_SOURCE_LOCATION (TYPE_NAME (t1)), + "type name %<%s%> should match type name %<%s%>", + name1, name2); + inform (DECL_SOURCE_LOCATION (TYPE_NAME (t2)), + "the incompatible type is defined here"); + free (name1); + return; + } + free (name1); + } + /* It is a quite common bug to reference anonymous namespace type in + non-anonymous namespace class. */ + if (type_in_anonymous_namespace_p (t1) + || type_in_anonymous_namespace_p (t2)) + { + if (!type_in_anonymous_namespace_p (t1)) + { + tree tmp = t1;; + t1 = t2; + t2 = tmp; + } + if (TYPE_NAME (t1) && TYPE_NAME (t2)) + { + inform (DECL_SOURCE_LOCATION (TYPE_NAME (t1)), + "type %qT defined in anonymous namespace can not match " + "type %qT", + t1, t2); + inform (DECL_SOURCE_LOCATION (TYPE_NAME (t2)), + "the incompatible type defined in anonymous namespace in " + "another translation unit"); + } + else + inform (UNKNOWN_LOCATION, + "types in anonymous namespace does not match across " + "translation unit boundary"); + return; + } + /* A tricky case are component types. Often they appear the same in source + code and the mismatch is dragged in by type they are build from. + Look for those differences in subtypes and try to be informative. In other + cases just output nothing because the source code is probably different + and in this case we already output a all necessary info. */ if (!TYPE_NAME (t1) || !TYPE_NAME (t2)) + { + if (TREE_CODE (t1) == TREE_CODE (t2)) + { + hash_set visited; + if (TREE_CODE (t1) == ARRAY_TYPE + && COMPLETE_TYPE_P (t1) && COMPLETE_TYPE_P (t2)) + { + tree i1 = TYPE_DOMAIN (t1); + tree i2 = TYPE_DOMAIN (t2); + + if (i1 && i2 + && TYPE_MAX_VALUE (i1) + && TYPE_MAX_VALUE (i2) + && !operand_equal_p (TYPE_MAX_VALUE (i1), + TYPE_MAX_VALUE (i2), 0)) + { + inform (UNKNOWN_LOCATION, + "array types have different bounds"); + return; + } + } + if ((POINTER_TYPE_P (t1) || TREE_CODE (t1) == ARRAY_TYPE) + && !odr_subtypes_equivalent_p (TREE_TYPE (t1), + TREE_TYPE (t2), + &visited)) + warn_types_mismatch (TREE_TYPE (t1), TREE_TYPE (t2)); + else if (TREE_CODE (t1) == METHOD_TYPE + || TREE_CODE (t1) == FUNCTION_TYPE) + { + tree parms1, parms2; + int count = 1; + + if (!odr_subtypes_equivalent_p (TREE_TYPE (t1), TREE_TYPE (t2), + &visited)) + { + inform (UNKNOWN_LOCATION, "return value type mismatch"); + warn_types_mismatch (TREE_TYPE (t1), TREE_TYPE (t2)); + return; + } + for (parms1 = TYPE_ARG_TYPES (t1), parms2 = TYPE_ARG_TYPES (t2); + parms1 && parms2; + parms1 = TREE_CHAIN (parms1), parms2 = TREE_CHAIN (parms2), + count++) + { + if (!odr_subtypes_equivalent_p + (TREE_VALUE (parms1), TREE_VALUE (parms2), &visited)) + { + inform (UNKNOWN_LOCATION, + "type mismatch in parameter %i", count); + warn_types_mismatch (TREE_VALUE (parms1), + TREE_VALUE (parms2)); + return; + } + } + if (parms1 || parms2) + { + inform (UNKNOWN_LOCATION, + "types have different parameter counts"); + return; + } + } + } + return; + } + /* This should not happen but if it does, the warning would not be helpful. + TODO: turn it into assert next stage1. */ + if (TYPE_NAME (t1) == TYPE_NAME (t2)) return; /* In Firefox it is a common bug to have same types but in different namespaces. Be a bit more informative on @@ -979,12 +1124,19 @@ warn_types_mismatch (tree t1, tree t2) "type %qT should match type %qT but is defined " "in different namespace ", t1, t2); + else if (types_odr_comparable (t1, t2, true) + && types_same_for_odr (t1, t2, true)) + inform (DECL_SOURCE_LOCATION (TYPE_NAME (t1)), + "type %qT should match type %qT that itself violate " + "one definition rule", + t1, t2); else inform (DECL_SOURCE_LOCATION (TYPE_NAME (t1)), "type %qT should match type %qT", t1, t2); - inform (DECL_SOURCE_LOCATION (TYPE_NAME (t2)), - "the incompatible type is defined here"); + if (DECL_SOURCE_LOCATION (TYPE_NAME (t2)) > BUILTINS_LOCATION) + inform (DECL_SOURCE_LOCATION (TYPE_NAME (t2)), + "the incompatible type is defined here"); } /* Compare T1 and T2, report ODR violations if WARN is true and set @@ -1232,6 +1384,20 @@ odr_types_equivalent_p (tree t1, tree t2, bool warn, bool *warned, /* For aggregate types, all the fields must be the same. */ if (COMPLETE_TYPE_P (t1) && COMPLETE_TYPE_P (t2)) { + if (TYPE_BINFO (t1) && TYPE_BINFO (t2) + && polymorphic_type_binfo_p (TYPE_BINFO (t1)) + != polymorphic_type_binfo_p (TYPE_BINFO (t2))) + { + if (polymorphic_type_binfo_p (TYPE_BINFO (t1))) + warn_odr (t1, t2, NULL, NULL, warn, warned, + G_("a type defined in another translation unit " + "is not polymorphic")); + else + warn_odr (t1, t2, NULL, NULL, warn, warned, + G_("a type defined in another translation unit " + "is polymorphic")); + return false; + } for (f1 = TYPE_FIELDS (t1), f2 = TYPE_FIELDS (t2); f1 || f2; f1 = TREE_CHAIN (f1), f2 = TREE_CHAIN (f2)) @@ -1303,8 +1469,8 @@ odr_types_equivalent_p (tree t1, tree t2, bool warn, bool *warned, 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))) + else 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")); @@ -1408,6 +1574,7 @@ add_type_duplicate (odr_type val, tree type) { bool build_bases = false; bool prevail = false; + bool odr_must_violate = false; if (!val->types_set) val->types_set = new hash_set; @@ -1469,27 +1636,7 @@ add_type_duplicate (odr_type val, tree type) gcc_assert (in_lto_p); vec_safe_push (val->types, type); - /* First we compare memory layout. */ - if (!odr_types_equivalent_p (val->type, type, - !flag_ltrans && !val->odr_violated, - &warned, &visited)) - { - merge = false; - odr_violation_reported = true; - val->odr_violated = true; - if (symtab->dump_file) - { - fprintf (symtab->dump_file, "ODR violation\n"); - - print_node (symtab->dump_file, "", val->type, 0); - putc ('\n',symtab->dump_file); - print_node (symtab->dump_file, "", type, 0); - putc ('\n',symtab->dump_file); - } - } - - /* Next sanity check that bases are the same. If not, we will end - up producing wrong answers. */ + /* If both are class types, compare the bases. */ if (COMPLETE_TYPE_P (type) && COMPLETE_TYPE_P (val->type) && TREE_CODE (val->type) == RECORD_TYPE && TREE_CODE (type) == RECORD_TYPE @@ -1498,25 +1645,28 @@ add_type_duplicate (odr_type val, tree type) if (BINFO_N_BASE_BINFOS (TYPE_BINFO (type)) != BINFO_N_BASE_BINFOS (TYPE_BINFO (val->type))) { - if (!warned && !val->odr_violated) + if (!flag_ltrans && !warned && !val->odr_violated) { tree extra_base; warn_odr (type, val->type, NULL, NULL, !warned, &warned, "a type with the same name but different " "number of polymorphic bases is " "defined in another translation unit"); - if (BINFO_N_BASE_BINFOS (TYPE_BINFO (type)) - > BINFO_N_BASE_BINFOS (TYPE_BINFO (val->type))) - extra_base = BINFO_BASE_BINFO - (TYPE_BINFO (type), - BINFO_N_BASE_BINFOS (TYPE_BINFO (val->type))); - else - extra_base = BINFO_BASE_BINFO - (TYPE_BINFO (val->type), - BINFO_N_BASE_BINFOS (TYPE_BINFO (type))); - tree extra_base_type = BINFO_TYPE (extra_base); - inform (DECL_SOURCE_LOCATION (TYPE_NAME (extra_base_type)), - "the extra base is defined here"); + if (warned) + { + if (BINFO_N_BASE_BINFOS (TYPE_BINFO (type)) + > BINFO_N_BASE_BINFOS (TYPE_BINFO (val->type))) + extra_base = BINFO_BASE_BINFO + (TYPE_BINFO (type), + BINFO_N_BASE_BINFOS (TYPE_BINFO (val->type))); + else + extra_base = BINFO_BASE_BINFO + (TYPE_BINFO (val->type), + BINFO_N_BASE_BINFOS (TYPE_BINFO (type))); + tree extra_base_type = BINFO_TYPE (extra_base); + inform (DECL_SOURCE_LOCATION (TYPE_NAME (extra_base_type)), + "the extra base is defined here"); + } } base_mismatch = true; } @@ -1570,10 +1720,10 @@ add_type_duplicate (odr_type val, tree type) but not for TYPE2 we possibly missed a base when recording VAL->type earlier. Be sure this does not happen. */ - gcc_assert (TYPE_BINFO (type2) - || !polymorphic_type_binfo_p (TYPE_BINFO (type1)) - || build_bases - || val->odr_violated); + if (TYPE_BINFO (type1) + && polymorphic_type_binfo_p (TYPE_BINFO (type1)) + && !build_bases) + odr_must_violate = true; break; } /* One base is polymorphic and the other not. @@ -1583,38 +1733,15 @@ add_type_duplicate (odr_type val, tree type) && polymorphic_type_binfo_p (TYPE_BINFO (type1)) != polymorphic_type_binfo_p (TYPE_BINFO (type2))) { - gcc_assert (val->odr_violated); + if (!warned && !val->odr_violated) + warn_odr (type, val->type, NULL, NULL, + !warned, &warned, + "a base of the type is polymorphic only in one " + "translation unit"); base_mismatch = true; break; } } -#ifdef ENABLE_CHECKING - /* Sanity check that all bases will be build same way again. */ - if (!base_mismatch && val->bases.length ()) - { - unsigned int num_poly_bases = 0; - unsigned int j; - - for (i = 0; i < BINFO_N_BASE_BINFOS (TYPE_BINFO (type)); i++) - if (polymorphic_type_binfo_p (BINFO_BASE_BINFO - (TYPE_BINFO (type), i))) - num_poly_bases++; - gcc_assert (num_poly_bases == val->bases.length ()); - 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); - gcc_assert (val->bases[j] == base); - j++; - } - } -#endif if (base_mismatch) { merge = false; @@ -1633,6 +1760,59 @@ add_type_duplicate (odr_type val, tree type) } } + /* Next compare memory layout. */ + if (!odr_types_equivalent_p (val->type, type, + !flag_ltrans && !val->odr_violated && !warned, + &warned, &visited)) + { + merge = false; + odr_violation_reported = true; + val->odr_violated = true; + if (symtab->dump_file) + { + fprintf (symtab->dump_file, "ODR violation\n"); + + print_node (symtab->dump_file, "", val->type, 0); + putc ('\n',symtab->dump_file); + print_node (symtab->dump_file, "", type, 0); + putc ('\n',symtab->dump_file); + } + } + gcc_assert (val->odr_violated || !odr_must_violate); + /* Sanity check that all bases will be build same way again. */ +#ifdef ENABLE_CHECKING + 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) + && !val->odr_violated + && !base_mismatch && val->bases.length ()) + { + unsigned int num_poly_bases = 0; + unsigned int j; + + for (i = 0; i < BINFO_N_BASE_BINFOS (TYPE_BINFO (type)); i++) + if (polymorphic_type_binfo_p (BINFO_BASE_BINFO + (TYPE_BINFO (type), i))) + num_poly_bases++; + gcc_assert (num_poly_bases == val->bases.length ()); + 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); + gcc_assert (val->bases[j] == base); + j++; + } + } +#endif + + /* Regularize things a little. During LTO same types may come with different BINFOs. Either because their virtual table was not merged by tree merging and only later at decl merging or @@ -1794,7 +1974,7 @@ get_odr_type (tree type, bool insert) tree binfo = TYPE_BINFO (type); unsigned int i; - gcc_assert (BINFO_TYPE (TYPE_BINFO (val->type)) = type); + gcc_assert (BINFO_TYPE (TYPE_BINFO (val->type)) == type); val->all_derivations_known = type_all_derivations_known_p (type); for (i = 0; i < BINFO_N_BASE_BINFOS (binfo); i++) @@ -1803,10 +1983,9 @@ get_odr_type (tree type, bool insert) determine ODR equivalency of these during LTO. */ if (polymorphic_type_binfo_p (BINFO_BASE_BINFO (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); + tree base_type= BINFO_TYPE (BINFO_BASE_BINFO (binfo, i)); + odr_type base = get_odr_type (base_type, 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) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index bdd0864a787..d9747487b42 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2015-03-22 Jan Hubicka + + PR ipa/65475 + * g++.dg/lto/pr65475b_0.C: New testcase. + * g++.dg/lto/pr65475b_1.C: New testcase. + * g++.dg/lto/pr65475c_0.C: New testcase. + * g++.dg/lto/pr65475c_1.C: New testcase. + 2015-03-21 Tobias Burnus * gfortran.dg/coarray_38.f90: New. diff --git a/gcc/testsuite/g++.dg/lto/pr65475b_0.C b/gcc/testsuite/g++.dg/lto/pr65475b_0.C new file mode 100644 index 00000000000..c29b2e1e5cb --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/pr65475b_0.C @@ -0,0 +1,9 @@ +/* { dg-lto-do link } */ +/* { dg-options "-O2 -Wno-odr" } */ +/* { dg-extra-ld-options { -O2 -Wno-odr -r -nostdlib } } */ +namespace std { +class exception {}; +class runtime_error : exception { + virtual char m_fn1(); +} a; +} diff --git a/gcc/testsuite/g++.dg/lto/pr65475b_1.C b/gcc/testsuite/g++.dg/lto/pr65475b_1.C new file mode 100644 index 00000000000..29cb4619928 --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/pr65475b_1.C @@ -0,0 +1,7 @@ +namespace std { +class exception { + virtual char m_fn1(); +}; +class runtime_error : exception { +} b; +} diff --git a/gcc/testsuite/g++.dg/lto/pr65475c_0.C b/gcc/testsuite/g++.dg/lto/pr65475c_0.C new file mode 100644 index 00000000000..8e1d8bcc83d --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/pr65475c_0.C @@ -0,0 +1,156 @@ +/* { dg-lto-do link } */ +/* { dg-lto-options "-O2 -w" } */ +/* { dg-extra-ld-options { -O2 -Wno-odr -r -nostdlib } } */ +namespace std +{ +template < class > struct char_traits; +typedef long streamsize; +template < typename, typename > class basic_streambuf; +template < typename > class A; +template < typename, typename > class basic_ostream; +template < typename _CharT, typename = + char_traits < _CharT > >class istreambuf_iterator; +template < typename _CharT, typename = + char_traits < _CharT > >class ostreambuf_iterator; +template < typename > class ctype; +template < typename _CharT, typename = + istreambuf_iterator < _CharT > >class num_get; +template < typename _CharT, typename = + ostreambuf_iterator < _CharT > >class num_put; +} +typedef int _Atomic_word; +namespace std +{ +class locale +{ + class facet; + class _Impl; + _Impl *_M_impl; +}; +class locale::facet +{ + _Atomic_word _M_refcount; +protected: + virtual ~ facet (); +}; +enum _Ios_Fmtflags +{ _S_boolalpha = 1, _S_dec, _S_fixed = 1 << 2, _S_hex = + 1 << 3, _S_internal = 1 << 4, _S_left = 1 << 5, _S_oct = + 1 << 6, _S_right = 1 << 7, _S_scientific = 1 << 8, _S_showbase = + 1 << 9, _S_showpoint = 1 << 10, _S_showpos = 1 << 11, _S_skipws = + 1 << 12, _S_unitbuf = 1 << 13, _S_uppercase = 1 << 14, _S_adjustfield = + _S_left | _S_right | _S_internal, _S_basefield = + _S_dec | _S_oct | _S_hex, _S_floatfield = + _S_scientific | _S_fixed, _S_ios_fmtflags_end = 1 << 16 +}; +enum _Ios_Iostate +{ _S_goodbit, _S_badbit, _S_eofbit, _S_failbit = + 1 << 2, _S_ios_iostate_end = 1 << 16 +}; +class ios_base +{ + typedef _Ios_Fmtflags fmtflags; + typedef _Ios_Iostate iostate; + streamsize _M_precision; + streamsize _M_width; + fmtflags _M_flags; + iostate _M_exception; + iostate _M_streambuf_state; + struct _Callback_list; + _Callback_list *_M_callbacks; + struct _Words + { + void *_M_pword; + long _M_iword; + } _M_word_zero; + enum + { _S_local_word_size = 8 }; + _Words _M_local_word[_S_local_word_size]; + int _M_word_size; + _Words *_M_word; + locale _M_ios_locale; + virtual ~ ios_base (); +}; +template < typename, typename > class istreambuf_iterator +{ + typedef A < char_traits < wchar_t > >istream_type; +}; +template < typename, typename > class ostreambuf_iterator +{ + typedef basic_ostream < wchar_t, char_traits < wchar_t > >ostream_type; +}; +template < typename, typename > class num_get:locale::facet +{ +public: + typedef istreambuf_iterator < wchar_t > iter_type; +}; +template < typename, typename > class num_put:locale::facet +{ +public: + typedef ostreambuf_iterator < wchar_t > iter_type; +}; +template < typename, typename > class basic_ios:ios_base +{ + typedef wchar_t char_type; + basic_ostream < wchar_t, char_traits < wchar_t > >*_M_tie; + char_type _M_fill; + bool _M_fill_init; + basic_streambuf < wchar_t, char_traits < wchar_t > >*_M_streambuf; + ctype < wchar_t > *_M_ctype; + num_put < wchar_t > *_M_num_put; + num_get < wchar_t > *_M_num_get; +}; +template < typename, typename > class basic_ostream:virtual basic_ios < wchar_t, + char_traits < wchar_t > + > +{ + typedef basic_ios __ios_type; +}; +template < typename > class A:basic_ios < wchar_t, int > +{ +}; +class B:A < char_traits < wchar_t > >, basic_ostream < wchar_t, + char_traits < wchar_t > > +{ +}; +} + +class C: + std::num_put < + wchar_t > +{ +public: + C (int); + iter_type + do_put_out; +}; +class + D: + std::num_get < + wchar_t > +{ +public: + D (int); + iter_type + do_get_in; +}; +template < typename > void +install_formatting_facets (std::locale, int p2) +{ + (C (p2)); +} + +template < typename > void +install_parsing_facets (std::locale, int p2) +{ + (D (p2)); +} + +std::locale a; +int b; +void +create_formatting () +{ + install_formatting_facets < wchar_t > (a, b); + install_parsing_facets < wchar_t > (a, b); +} diff --git a/gcc/testsuite/g++.dg/lto/pr65475c_1.C b/gcc/testsuite/g++.dg/lto/pr65475c_1.C new file mode 100644 index 00000000000..b63ff9b225b --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/pr65475c_1.C @@ -0,0 +1,234 @@ +namespace std +{ + template < class _CharT > struct char_traits; + typedef long streamsize; + template < typename _CharT, typename _Traits = + char_traits < _CharT > >class basic_ostream; + template < typename _CharT, typename _Traits = + char_traits < _CharT > >class Trans_NS___cxx11_basic_ostringstream; + template < typename _CharT, typename _Traits = + char_traits < _CharT > >class istreambuf_iterator; + template < typename _CharT, typename _Traits = + char_traits < _CharT > >class ostreambuf_iterator; +} +namespace std +{ + template < typename _CharT, typename _InIter = + istreambuf_iterator < _CharT > >class num_get; + template < typename _CharT, typename _OutIter = + ostreambuf_iterator < _CharT > >class num_put; + struct iterator + { + }; +} +typedef int _Atomic_word; +namespace std +{ + class locale + { + public:class facet; + class _Impl; + template < typename _Facet > locale ( const locale & __other, + _Facet * __f ); + private: _Impl * _M_impl; + }; + class locale::facet + { + mutable _Atomic_word _M_refcount; + protected: explicit facet ( void ) throw ( ); + virtual ~ facet ( ); + }; + enum _Ios_Fmtflags + { + _S_boolalpha = 1 << 0, _S_dec, _S_fixed = 1 << 2, _S_hex = + 1 << 3, _S_internal = 1 << 4, _S_left = 1 << 5, _S_oct = + 1 << 6, _S_right = 1 << 7, _S_scientific = 1 << 8, _S_showbase = + 1 << 9, _S_showpoint = 1 << 10, _S_showpos = 1 << 11, _S_skipws = + 1 << 12, _S_unitbuf = 1 << 13, _S_uppercase = 1 << 14, _S_adjustfield = + _S_left | _S_right | _S_internal, _S_basefield = + _S_dec | _S_oct | _S_hex, _S_floatfield = + _S_scientific | _S_fixed, _S_ios_fmtflags_end = 1 << 16 + }; + enum _Ios_Openmode + { + _S_out + }; + enum _Ios_Iostate + { + _S_goodbit, _S_badbit, _S_eofbit, _S_failbit = + 1 << 2, _S_ios_iostate_end = 1 << 16 + }; + class ios_base + { + public:typedef _Ios_Fmtflags fmtflags; + typedef _Ios_Iostate iostate; + protected: streamsize _M_precision; + streamsize _M_width; + fmtflags _M_flags; + iostate _M_exception; + iostate _M_streambuf_state; + struct _Callback_list; + _Callback_list *_M_callbacks; + struct _Words + { + void *_M_pword; + long _M_iword; + }; + _Words _M_word_zero; + enum + { + _S_local_word_size = 8 + }; + _Words _M_local_word[_S_local_word_size]; + int _M_word_size; + _Words *_M_word; + locale _M_ios_locale; + virtual ~ ios_base ( ); + }; + template < typename _CharT, typename _Traits > class basic_streambuf; +template < typename _CharT, typename _Traits > class ostreambuf_iterator:public + iterator + { + typedef basic_ostream < wchar_t, _Traits > ostream_type; + }; + class __ctype_abstract_base:public locale::facet + { + }; +template < typename _CharT > class ctype:public __ctype_abstract_base + { + }; + class Trans_NS___cxx11_numpunct:public locale::facet + { + }; +template < typename _CharT, typename _InIter > class num_get:public locale:: + facet + { + }; +template < typename _CharT, typename _OutIter > class num_put:public locale:: + facet + { + public:typedef int char_type; + typedef std::ostreambuf_iterator < wchar_t, + std::char_traits < wchar_t > >iter_type; + }; +template < typename _CharT, typename _Traits > class basic_ios:public + ios_base + { + public:typedef wchar_t char_type; + typedef num_get < wchar_t, istreambuf_iterator < wchar_t, + _Traits > >__num_get_type; + protected:basic_ostream < wchar_t, _Traits > *_M_tie; + mutable char_type _M_fill; + mutable bool _M_fill_init; + basic_streambuf < wchar_t, _Traits > *_M_streambuf; + const ctype < wchar_t > *_M_ctype; + const num_put < wchar_t, ostreambuf_iterator < wchar_t, + _Traits > >*_M_num_put; + const __num_get_type *_M_num_get; + }; +template < typename _CharT, typename _Traits > class basic_ostream:virtual public basic_ios < wchar_t, + _Traits + > + { + }; +} +typedef enum +{ + posix +} +value_type; +static const unsigned int wchar_t_facet = 1 << 1; +class shared_ptr +{ +}; +namespace std +{ +template < typename _CharT, typename _Traits > class Trans_NS___cxx11_basic_ostringstream:public basic_ostream < wchar_t, + _Traits + > + { + public:explicit Trans_NS___cxx11_basic_ostringstream ( void ); + }; +} +class base_num_format:public + std::num_put < + wchar_t > +{ +public:typedef typename + std::num_put < + wchar_t >::iter_type + iter_type; + typedef wchar_t + char_type; + base_num_format ( unsigned long refs = 0 ); + iter_type + do_put_out; + std::ios_base & + do_put_ios; + char_type + do_put_fill; + unsigned long long + do_put_val; + virtual iter_type + do_put ( void ) const + { + return + do_real_put ( do_put_out, do_put_ios, do_put_fill, do_put_val ); + } +private:template < + typename + ValueType > + iter_type + do_real_put ( iter_type out, std::ios_base & ios, char_type fill, + ValueType val ) const + { + switch ( 0 ) + case posix: + { + typedef + std::Trans_NS___cxx11_basic_ostringstream < + char_type > + sstream_type; + sstream_type + ss; + } + } +}; +class + base_num_parse: + public + std::num_get < + wchar_t > +{ +private:}; +class + num_format: + public + base_num_format +{ +public:typedef wchar_t + iter_type; + num_format ( shared_ptr lc, unsigned long refs = 0 ) + { + } +}; +class + num_punct_posix: + public + std::Trans_NS___cxx11_numpunct +{ +}; +template < typename CharType > + std::locale create_formatting_impl ( std::locale const &in, shared_ptr lc ) +{ + std::locale tmp = std::locale ( tmp, new num_format ( lc ) ); +} +shared_ptr create_formatting_lc; +unsigned int create_formatting_type; +void +create_formatting ( std::locale const &in ) +{ + switch ( create_formatting_type ) + case wchar_t_facet: + create_formatting_impl < wchar_t > ( in, create_formatting_lc ); +}