Commit b1905808 by Jan Hubicka Committed by Jan Hubicka

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
parent 67e00dab
2015-03-22 Martin Liska <mliska@suse.cz> 2015-03-22 Jan Hubicka <hubicka@ucw.cz>
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 <mliska@suse.cz>
Jakub Jelinek <jakub@redhat.com> Jakub Jelinek <jakub@redhat.com>
* config/i386/i386.c (def_builtin): Set deferred_isa_values for * config/i386/i386.c (def_builtin): Set deferred_isa_values for
......
...@@ -166,6 +166,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -166,6 +166,7 @@ along with GCC; see the file COPYING3. If not see
#include "gimple-pretty-print.h" #include "gimple-pretty-print.h"
#include "stor-layout.h" #include "stor-layout.h"
#include "intl.h" #include "intl.h"
#include "demangle.h"
/* Hash based set of pairs of types. */ /* Hash based set of pairs of types. */
typedef struct typedef struct
...@@ -239,6 +240,8 @@ struct GTY(()) odr_type_d ...@@ -239,6 +240,8 @@ struct GTY(()) odr_type_d
bool all_derivations_known; bool all_derivations_known;
/* Did we report ODR violation here? */ /* Did we report ODR violation here? */
bool odr_violated; 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 /* Return TRUE if all derived types of T are known and thus
...@@ -673,8 +676,6 @@ odr_subtypes_equivalent_p (tree t1, tree t2, ...@@ -673,8 +676,6 @@ odr_subtypes_equivalent_p (tree t1, tree t2,
return false; return false;
if ((TYPE_NAME (t1) == NULL_TREE) != (TYPE_NAME (t2) == NULL_TREE)) if ((TYPE_NAME (t1) == NULL_TREE) != (TYPE_NAME (t2) == NULL_TREE))
return false; return false;
if (TYPE_NAME (t1) && DECL_NAME (TYPE_NAME (t1)) != DECL_NAME (TYPE_NAME (t2)))
return false;
type_pair pair={t1,t2}; type_pair pair={t1,t2};
if (TYPE_UID (t1) > TYPE_UID (t2)) if (TYPE_UID (t1) > TYPE_UID (t2))
...@@ -694,6 +695,7 @@ void ...@@ -694,6 +695,7 @@ void
compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable) compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable)
{ {
int n1, n2; int n1, n2;
if (DECL_VIRTUAL_P (prevailing->decl) != DECL_VIRTUAL_P (vtable->decl)) if (DECL_VIRTUAL_P (prevailing->decl) != DECL_VIRTUAL_P (vtable->decl))
{ {
odr_violation_reported = true; odr_violation_reported = true;
...@@ -715,6 +717,17 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable) ...@@ -715,6 +717,17 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable)
} }
if (!prevailing->definition || !vtable->definition) if (!prevailing->definition || !vtable->definition)
return; 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++) for (n1 = 0, n2 = 0; true; n1++, n2++)
{ {
struct ipa_ref *ref1, *ref2; struct ipa_ref *ref1, *ref2;
...@@ -730,12 +743,15 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable) ...@@ -730,12 +743,15 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable)
&& (end1 && (end1
|| (DECL_ASSEMBLER_NAME (ref1->referred->decl) || (DECL_ASSEMBLER_NAME (ref1->referred->decl)
!= DECL_ASSEMBLER_NAME (ref2->referred->decl) != DECL_ASSEMBLER_NAME (ref2->referred->decl)
&& DECL_VIRTUAL_P (ref1->referred->decl))) && TREE_CODE (ref1->referred->decl) == FUNCTION_DECL))
&& !DECL_VIRTUAL_P (ref2->referred->decl)) && TREE_CODE (ref2->referred->decl) != FUNCTION_DECL)
{ {
if (warning_at (DECL_SOURCE_LOCATION if (!class_type->rtti_broken
(TYPE_NAME (DECL_CONTEXT (vtable->decl))), 0, && warning_at (DECL_SOURCE_LOCATION
"virtual table of type %qD contains RTTI information", (TYPE_NAME (DECL_CONTEXT (vtable->decl))),
OPT_Wodr,
"virtual table of type %qD contains RTTI "
"information",
DECL_CONTEXT (vtable->decl))) DECL_CONTEXT (vtable->decl)))
{ {
inform (DECL_SOURCE_LOCATION inform (DECL_SOURCE_LOCATION
...@@ -745,6 +761,7 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable) ...@@ -745,6 +761,7 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable)
inform (DECL_SOURCE_LOCATION inform (DECL_SOURCE_LOCATION
(TYPE_NAME (DECL_CONTEXT (prevailing->decl))), (TYPE_NAME (DECL_CONTEXT (prevailing->decl))),
"RTTI will not work on this type"); "RTTI will not work on this type");
class_type->rtti_broken = true;
} }
n2++; n2++;
end2 = !vtable->iterate_reference (n2, ref2); end2 = !vtable->iterate_reference (n2, ref2);
...@@ -753,11 +770,11 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable) ...@@ -753,11 +770,11 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable)
&& (end2 && (end2
|| (DECL_ASSEMBLER_NAME (ref2->referred->decl) || (DECL_ASSEMBLER_NAME (ref2->referred->decl)
!= DECL_ASSEMBLER_NAME (ref1->referred->decl) != DECL_ASSEMBLER_NAME (ref1->referred->decl)
&& DECL_VIRTUAL_P (ref2->referred->decl))) && TREE_CODE (ref2->referred->decl) == FUNCTION_DECL))
&& !DECL_VIRTUAL_P (ref1->referred->decl)) && TREE_CODE (ref1->referred->decl) != FUNCTION_DECL)
{ {
n1++; n1++;
end1 = !vtable->iterate_reference (n1, ref1); end1 = !prevailing->iterate_reference (n1, ref1);
} }
/* Finished? */ /* Finished? */
...@@ -770,8 +787,10 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable) ...@@ -770,8 +787,10 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable)
is not output too often. */ is not output too often. */
if (DECL_SIZE (prevailing->decl) != DECL_SIZE (vtable->decl)) if (DECL_SIZE (prevailing->decl) != DECL_SIZE (vtable->decl))
{ {
class_type->odr_violated = true;
if (warning_at (DECL_SOURCE_LOCATION 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 " "virtual table of type %qD violates "
"one definition rule ", "one definition rule ",
DECL_CONTEXT (vtable->decl))) DECL_CONTEXT (vtable->decl)))
...@@ -791,13 +810,16 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable) ...@@ -791,13 +810,16 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable)
== DECL_ASSEMBLER_NAME (ref2->referred->decl)) == DECL_ASSEMBLER_NAME (ref2->referred->decl))
continue; continue;
class_type->odr_violated = true;
/* If the loops above stopped on non-virtual pointer, we have /* If the loops above stopped on non-virtual pointer, we have
mismatch in RTTI information mangling. */ mismatch in RTTI information mangling. */
if (!DECL_VIRTUAL_P (ref1->referred->decl) if (TREE_CODE (ref1->referred->decl) != FUNCTION_DECL
&& !DECL_VIRTUAL_P (ref2->referred->decl)) && TREE_CODE (ref2->referred->decl) != FUNCTION_DECL)
{ {
if (warning_at (DECL_SOURCE_LOCATION 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 " "virtual table of type %qD violates "
"one definition rule ", "one definition rule ",
DECL_CONTEXT (vtable->decl))) DECL_CONTEXT (vtable->decl)))
...@@ -813,12 +835,6 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable) ...@@ -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 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 method we can complain the same way as if one table was shorter
than other pointing out the extra method. */ 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) if (TREE_CODE (ref1->referred->decl)
!= TREE_CODE (ref2->referred->decl)) != TREE_CODE (ref2->referred->decl))
{ {
...@@ -829,6 +845,8 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable) ...@@ -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 /* Complain about size mismatch. Either we have too many virutal
functions or too many virtual table pointers. */ functions or too many virtual table pointers. */
if (end1 || end2) if (end1 || end2)
...@@ -841,7 +859,8 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable) ...@@ -841,7 +859,8 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable)
ref1 = ref2; ref1 = ref2;
} }
if (warning_at (DECL_SOURCE_LOCATION 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 " "virtual table of type %qD violates "
"one definition rule", "one definition rule",
DECL_CONTEXT (vtable->decl))) DECL_CONTEXT (vtable->decl)))
...@@ -871,7 +890,7 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable) ...@@ -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 /* And in the last case we have either mistmatch in between two virtual
methods or two virtual table pointers. */ methods or two virtual table pointers. */
if (warning_at (DECL_SOURCE_LOCATION 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 " "virtual table of type %qD violates "
"one definition rule ", "one definition rule ",
DECL_CONTEXT (vtable->decl))) DECL_CONTEXT (vtable->decl)))
...@@ -914,8 +933,9 @@ warn_odr (tree t1, tree t2, tree st1, tree st2, ...@@ -914,8 +933,9 @@ warn_odr (tree t1, tree t2, tree st1, tree st2,
if (warned) if (warned)
*warned = false; *warned = false;
if (!warn) if (!warn || !TYPE_NAME(t1))
return; return;
if (!warning_at (DECL_SOURCE_LOCATION (TYPE_NAME (t1)), OPT_Wodr, if (!warning_at (DECL_SOURCE_LOCATION (TYPE_NAME (t1)), OPT_Wodr,
"type %qT violates one definition rule", "type %qT violates one definition rule",
t1)) t1))
...@@ -964,7 +984,132 @@ warn_odr (tree t1, tree t2, tree st1, tree st2, ...@@ -964,7 +984,132 @@ warn_odr (tree t1, tree t2, tree st1, tree st2,
void void
warn_types_mismatch (tree t1, tree t2) 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 (!TYPE_NAME (t1) || !TYPE_NAME (t2))
{
if (TREE_CODE (t1) == TREE_CODE (t2))
{
hash_set<type_pair,pair_traits> 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; return;
/* In Firefox it is a common bug to have same types but in /* In Firefox it is a common bug to have same types but in
different namespaces. Be a bit more informative on different namespaces. Be a bit more informative on
...@@ -979,10 +1124,17 @@ warn_types_mismatch (tree t1, tree t2) ...@@ -979,10 +1124,17 @@ warn_types_mismatch (tree t1, tree t2)
"type %qT should match type %qT but is defined " "type %qT should match type %qT but is defined "
"in different namespace ", "in different namespace ",
t1, t2); 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 else
inform (DECL_SOURCE_LOCATION (TYPE_NAME (t1)), inform (DECL_SOURCE_LOCATION (TYPE_NAME (t1)),
"type %qT should match type %qT", "type %qT should match type %qT",
t1, t2); t1, t2);
if (DECL_SOURCE_LOCATION (TYPE_NAME (t2)) > BUILTINS_LOCATION)
inform (DECL_SOURCE_LOCATION (TYPE_NAME (t2)), inform (DECL_SOURCE_LOCATION (TYPE_NAME (t2)),
"the incompatible type is defined here"); "the incompatible type is defined here");
} }
...@@ -1232,6 +1384,20 @@ odr_types_equivalent_p (tree t1, tree t2, bool warn, bool *warned, ...@@ -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. */ /* For aggregate types, all the fields must be the same. */
if (COMPLETE_TYPE_P (t1) && COMPLETE_TYPE_P (t2)) 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); for (f1 = TYPE_FIELDS (t1), f2 = TYPE_FIELDS (t2);
f1 || f2; f1 || f2;
f1 = TREE_CHAIN (f1), f2 = TREE_CHAIN (f2)) f1 = TREE_CHAIN (f1), f2 = TREE_CHAIN (f2))
...@@ -1303,7 +1469,7 @@ odr_types_equivalent_p (tree t1, tree t2, bool warn, bool *warned, ...@@ -1303,7 +1469,7 @@ odr_types_equivalent_p (tree t1, tree t2, bool warn, bool *warned,
warn_odr (t1, t2, NULL, NULL, warn, warned, warn_odr (t1, t2, NULL, NULL, warn, warned,
G_("a type with different virtual table pointers" G_("a type with different virtual table pointers"
" is defined in another translation unit")); " is defined in another translation unit"));
if ((f1 && DECL_ARTIFICIAL (f1)) else if ((f1 && DECL_ARTIFICIAL (f1))
|| (f2 && DECL_ARTIFICIAL (f2))) || (f2 && DECL_ARTIFICIAL (f2)))
warn_odr (t1, t2, NULL, NULL, warn, warned, warn_odr (t1, t2, NULL, NULL, warn, warned,
G_("a type with different bases is defined " G_("a type with different bases is defined "
...@@ -1408,6 +1574,7 @@ add_type_duplicate (odr_type val, tree type) ...@@ -1408,6 +1574,7 @@ add_type_duplicate (odr_type val, tree type)
{ {
bool build_bases = false; bool build_bases = false;
bool prevail = false; bool prevail = false;
bool odr_must_violate = false;
if (!val->types_set) if (!val->types_set)
val->types_set = new hash_set<tree>; val->types_set = new hash_set<tree>;
...@@ -1469,27 +1636,7 @@ add_type_duplicate (odr_type val, tree type) ...@@ -1469,27 +1636,7 @@ add_type_duplicate (odr_type val, tree type)
gcc_assert (in_lto_p); gcc_assert (in_lto_p);
vec_safe_push (val->types, type); vec_safe_push (val->types, type);
/* First we compare memory layout. */ /* If both are class types, compare the bases. */
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 (COMPLETE_TYPE_P (type) && COMPLETE_TYPE_P (val->type) if (COMPLETE_TYPE_P (type) && COMPLETE_TYPE_P (val->type)
&& TREE_CODE (val->type) == RECORD_TYPE && TREE_CODE (val->type) == RECORD_TYPE
&& TREE_CODE (type) == RECORD_TYPE && TREE_CODE (type) == RECORD_TYPE
...@@ -1498,13 +1645,15 @@ add_type_duplicate (odr_type val, tree type) ...@@ -1498,13 +1645,15 @@ add_type_duplicate (odr_type val, tree type)
if (BINFO_N_BASE_BINFOS (TYPE_BINFO (type)) if (BINFO_N_BASE_BINFOS (TYPE_BINFO (type))
!= BINFO_N_BASE_BINFOS (TYPE_BINFO (val->type))) != BINFO_N_BASE_BINFOS (TYPE_BINFO (val->type)))
{ {
if (!warned && !val->odr_violated) if (!flag_ltrans && !warned && !val->odr_violated)
{ {
tree extra_base; tree extra_base;
warn_odr (type, val->type, NULL, NULL, !warned, &warned, warn_odr (type, val->type, NULL, NULL, !warned, &warned,
"a type with the same name but different " "a type with the same name but different "
"number of polymorphic bases is " "number of polymorphic bases is "
"defined in another translation unit"); "defined in another translation unit");
if (warned)
{
if (BINFO_N_BASE_BINFOS (TYPE_BINFO (type)) if (BINFO_N_BASE_BINFOS (TYPE_BINFO (type))
> BINFO_N_BASE_BINFOS (TYPE_BINFO (val->type))) > BINFO_N_BASE_BINFOS (TYPE_BINFO (val->type)))
extra_base = BINFO_BASE_BINFO extra_base = BINFO_BASE_BINFO
...@@ -1518,6 +1667,7 @@ add_type_duplicate (odr_type val, tree type) ...@@ -1518,6 +1667,7 @@ add_type_duplicate (odr_type val, tree type)
inform (DECL_SOURCE_LOCATION (TYPE_NAME (extra_base_type)), inform (DECL_SOURCE_LOCATION (TYPE_NAME (extra_base_type)),
"the extra base is defined here"); "the extra base is defined here");
} }
}
base_mismatch = true; base_mismatch = true;
} }
else else
...@@ -1570,10 +1720,10 @@ add_type_duplicate (odr_type val, tree type) ...@@ -1570,10 +1720,10 @@ add_type_duplicate (odr_type val, tree type)
but not for TYPE2 we possibly missed a base when recording but not for TYPE2 we possibly missed a base when recording
VAL->type earlier. VAL->type earlier.
Be sure this does not happen. */ Be sure this does not happen. */
gcc_assert (TYPE_BINFO (type2) if (TYPE_BINFO (type1)
|| !polymorphic_type_binfo_p (TYPE_BINFO (type1)) && polymorphic_type_binfo_p (TYPE_BINFO (type1))
|| build_bases && !build_bases)
|| val->odr_violated); odr_must_violate = true;
break; break;
} }
/* One base is polymorphic and the other not. /* One base is polymorphic and the other not.
...@@ -1583,14 +1733,60 @@ add_type_duplicate (odr_type val, tree type) ...@@ -1583,14 +1733,60 @@ add_type_duplicate (odr_type val, tree type)
&& polymorphic_type_binfo_p (TYPE_BINFO (type1)) && polymorphic_type_binfo_p (TYPE_BINFO (type1))
!= polymorphic_type_binfo_p (TYPE_BINFO (type2))) != 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; base_mismatch = true;
break; break;
} }
} }
#ifdef ENABLE_CHECKING if (base_mismatch)
{
merge = false;
odr_violation_reported = true;
val->odr_violated = true;
if (symtab->dump_file)
{
fprintf (symtab->dump_file, "ODR base 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 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. */ /* Sanity check that all bases will be build same way again. */
if (!base_mismatch && val->bases.length ()) #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 num_poly_bases = 0;
unsigned int j; unsigned int j;
...@@ -1615,23 +1811,7 @@ add_type_duplicate (odr_type val, tree type) ...@@ -1615,23 +1811,7 @@ add_type_duplicate (odr_type val, tree type)
} }
} }
#endif #endif
if (base_mismatch)
{
merge = false;
odr_violation_reported = true;
val->odr_violated = true;
if (symtab->dump_file)
{
fprintf (symtab->dump_file, "ODR base 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);
}
}
}
/* Regularize things a little. During LTO same types may come with /* Regularize things a little. During LTO same types may come with
different BINFOs. Either because their virtual table was different BINFOs. Either because their virtual table was
...@@ -1794,7 +1974,7 @@ get_odr_type (tree type, bool insert) ...@@ -1794,7 +1974,7 @@ get_odr_type (tree type, bool insert)
tree binfo = TYPE_BINFO (type); tree binfo = TYPE_BINFO (type);
unsigned int i; 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); val->all_derivations_known = type_all_derivations_known_p (type);
for (i = 0; i < BINFO_N_BASE_BINFOS (binfo); i++) for (i = 0; i < BINFO_N_BASE_BINFOS (binfo); i++)
...@@ -1803,10 +1983,9 @@ get_odr_type (tree type, bool insert) ...@@ -1803,10 +1983,9 @@ get_odr_type (tree type, bool insert)
determine ODR equivalency of these during LTO. */ determine ODR equivalency of these during LTO. */
if (polymorphic_type_binfo_p (BINFO_BASE_BINFO (binfo, i))) if (polymorphic_type_binfo_p (BINFO_BASE_BINFO (binfo, i)))
{ {
odr_type base = get_odr_type (BINFO_TYPE (BINFO_BASE_BINFO (binfo, tree base_type= BINFO_TYPE (BINFO_BASE_BINFO (binfo, i));
i)), odr_type base = get_odr_type (base_type, true);
true); gcc_assert (TYPE_MAIN_VARIANT (base_type) == base_type);
gcc_assert (TYPE_MAIN_VARIANT (base->type) == base->type);
base->derived_types.safe_push (val); base->derived_types.safe_push (val);
val->bases.safe_push (base); val->bases.safe_push (base);
if (base->id > base_id) if (base->id > base_id)
......
2015-03-22 Jan Hubicka <hubicka@ucw.cz>
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 <burnus@net-b.de> 2015-03-21 Tobias Burnus <burnus@net-b.de>
* gfortran.dg/coarray_38.f90: New. * gfortran.dg/coarray_38.f90: New.
......
/* { 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;
}
namespace std {
class exception {
virtual char m_fn1();
};
class runtime_error : exception {
} b;
}
/* { 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);
}
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 );
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment