ipa-utils.h (warn_types_mismatch, [...]): Declare.

* ipa-utils.h (warn_types_mismatch, odr_or_derived_type_p,
	odr_types_equivalent_p): Declare.
	(odr_type_p): Use gcc_checking_assert.
	(type_in_anonymous_namespace_p) Declare.
	(type_with_linkage_p): Declare.
	* common.opt (Wlto-type-mismatch): New warning.
	* ipa-devirt.c (compound_type_base): New function.
	(odr_or_derived_type_p): New function.
	(odr_types_equivalent_p): New function.
	(add_type_duplicate): Simplify.
	(type_with_linkage_p): Add hack to prevent false positives on C types
	(type_in_anonymous_namespace_p): Likewise.
	* tree.c (need_assembler_name_p): Use type_with_linkage.
	* tree.h (type_in_anonymous_namespace_p): Remove.
	* doc/invoke.texi (-Wlto-type-mismatch): Document

	* lto-symtab.c (warn_type_compatibility_p): Break out from ...;
	compare ODR types (if available) and function types.
	(lto_symtab_merge): ... here; output ODR violation warnings
	and call warn_types_mismatch.

	* gfortran.dg/lto/20091028-2_1.c: Fix return value.
	* gfortran.dg/lto/pr41576_1.f90: Add interface.
	* gfortran.dg/lto/pr41521_0.f90: Disable lto-type-mismatch
	* gfortran.dg/lto/pr60635_0.f90: Disable lto-type-mismatch.
	* gfortran.dg/lto/20091028-1_1.c: Fix return type.
	* gcc.dg/lto/20120723_0.c: Disbale lto-type-mismatch.

From-SVN: r223258
This commit is contained in:
Jan Hubicka 2015-05-16 23:18:29 +00:00
parent 4d259d334e
commit 259d29e396
16 changed files with 288 additions and 97 deletions

View File

@ -607,6 +607,10 @@ Woverflow
Common Var(warn_overflow) Init(1) Warning
Warn about overflow in arithmetic expressions
Wlto-type-mismatch
Common Var(warn_lto_type_mismatch) Init(1) Warning
During link time optimization warn about mismatched types of global declarations
Wpacked
Common Var(warn_packed) Warning
Warn when the packed attribute has no effect on struct layout

View File

@ -2698,6 +2698,14 @@ In this case, @code{PRId64} is treated as a separate preprocessing token.
This warning is enabled by default.
@item -Wlto-type-mismatch
@opindex Wlto-type-mismatch
@opindex Wno-lto-type-mistmach
During the link-time optimization warn about type mismatches in between
global declarations from different compilation units.
Requires @option{-flto} to be enabled. Enabled by default.
@item -Wnarrowing @r{(C++ and Objective-C++ only)}
@opindex Wnarrowing
@opindex Wno-narrowing

View File

@ -247,9 +247,14 @@ struct GTY(()) odr_type_d
/* Return true if T is a type with linkage defined. */
static bool
bool
type_with_linkage_p (const_tree t)
{
/* Builtin types do not define linkage, their TYPE_CONTEXT is NULL. */
if (!TYPE_CONTEXT (t)
|| !TYPE_NAME (t) || TREE_CODE (TYPE_NAME (t)) != TYPE_DECL)
return false;
return (RECORD_OR_UNION_TYPE_P (t)
|| TREE_CODE (t) == ENUMERAL_TYPE);
}
@ -261,12 +266,21 @@ bool
type_in_anonymous_namespace_p (const_tree t)
{
gcc_assert (type_with_linkage_p (t));
/* TREE_PUBLIC of TYPE_STUB_DECL may not be properly set for
backend produced types (such as va_arg_type); those have CONTEXT NULL
and never are considered anonymoius. */
if (!TYPE_CONTEXT (t))
return false;
return (TYPE_STUB_DECL (t) && !TREE_PUBLIC (TYPE_STUB_DECL (t)));
if (TYPE_STUB_DECL (t) && !TREE_PUBLIC (TYPE_STUB_DECL (t)))
{
tree ctx = DECL_CONTEXT (TYPE_NAME (t));
while (ctx)
{
if (TREE_CODE (ctx) == NAMESPACE_DECL)
return !TREE_PUBLIC (ctx);
if (TREE_CODE (ctx) == BLOCK)
ctx = BLOCK_SUPERCONTEXT (ctx);
else
ctx = get_containing_scope (ctx);
}
}
return false;
}
/* Return true of T is type with One Definition Rule info attached.
@ -589,6 +603,59 @@ types_must_be_same_for_odr (tree t1, tree t2)
return TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2);
}
/* If T is compound type, return type it is based on. */
static tree
compound_type_base (const_tree t)
{
if (TREE_CODE (t) == ARRAY_TYPE
|| POINTER_TYPE_P (t)
|| TREE_CODE (t) == COMPLEX_TYPE
|| VECTOR_TYPE_P (t))
return TREE_TYPE (t);
if (TREE_CODE (t) == METHOD_TYPE)
return TYPE_METHOD_BASETYPE (t);
if (TREE_CODE (t) == OFFSET_TYPE)
return TYPE_OFFSET_BASETYPE (t);
return NULL_TREE;
}
/* Return true if T is either ODR type or compound type based from it.
If the function return true, we know that T is a type originating from C++
source even at link-time. */
bool
odr_or_derived_type_p (const_tree t)
{
do
{
if (odr_type_p (t))
return true;
/* Function type is a tricky one. Basically we can consider it
ODR derived if return type or any of the parameters is.
We need to check all parameters because LTO streaming merges
common types (such as void) and they are not considered ODR then. */
if (TREE_CODE (t) == FUNCTION_TYPE)
{
if (TYPE_METHOD_BASETYPE (t))
t = TYPE_METHOD_BASETYPE (t);
else
{
if (TREE_TYPE (t) && odr_or_derived_type_p (TREE_TYPE (t)))
return true;
for (t = TYPE_ARG_TYPES (t); t; t = TREE_CHAIN (t))
if (odr_or_derived_type_p (TREE_VALUE (t)))
return true;
return false;
}
}
else
t = compound_type_base (t);
}
while (t);
return t;
}
/* Compare types T1 and T2 and return true if they are
equivalent. */
@ -1223,6 +1290,16 @@ odr_types_equivalent_p (tree t1, tree t2, bool warn, bool *warned,
return false;
}
if ((type_with_linkage_p (t1) && type_in_anonymous_namespace_p (t1))
|| (type_with_linkage_p (t2) && type_in_anonymous_namespace_p (t2)))
{
/* We can not trip this when comparing ODR types, only when trying to
match different ODR derivations from different declarations.
So WARN should be always false. */
gcc_assert (!warn);
return false;
}
if (comp_type_attributes (t1, t2) != 1)
{
warn_odr (t1, t2, NULL, NULL, warn, warned,
@ -1625,6 +1702,20 @@ odr_types_equivalent_p (tree t1, tree t2, bool warn, bool *warned,
return true;
}
/* Return true if TYPE1 and TYPE2 are equivalent for One Definition Rule. */
bool
odr_types_equivalent_p (tree type1, tree type2)
{
hash_set<type_pair,pair_traits> visited;
#ifdef ENABLE_CHECKING
gcc_assert (odr_or_derived_type_p (type1) && odr_or_derived_type_p (type2));
#endif
return odr_types_equivalent_p (type1, type2, false, NULL,
&visited);
}
/* TYPE is equivalent to VAL by ODR, but its tree representation differs
from VAL->type. This may happen in LTO where tree merging did not merge
all variants of the same type or due to ODR violation.
@ -1749,12 +1840,8 @@ add_type_duplicate (odr_type val, tree type)
base_mismatch = true;
}
else
{
hash_set<type_pair,pair_traits> visited;
if (!odr_types_equivalent_p (type1, type2, false, NULL,
&visited))
base_mismatch = true;
}
if (!odr_types_equivalent_p (type1, type2))
base_mismatch = true;
if (base_mismatch)
{
if (!warned && !val->odr_violated)

View File

@ -63,7 +63,9 @@ possible_polymorphic_call_targets (tree, HOST_WIDE_INT,
void **cache_token = NULL,
bool speuclative = false);
odr_type get_odr_type (tree, bool insert = false);
bool odr_type_p (const_tree t);
bool type_in_anonymous_namespace_p (const_tree);
bool type_with_linkage_p (const_tree);
bool odr_type_p (const_tree);
bool possible_polymorphic_call_target_p (tree ref, gimple stmt, struct cgraph_node *n);
void dump_possible_polymorphic_call_targets (FILE *, tree, HOST_WIDE_INT,
const ipa_polymorphic_call_context &);
@ -85,6 +87,9 @@ bool types_must_be_same_for_odr (tree, tree);
bool types_odr_comparable (tree, tree, bool strict = false);
cgraph_node *try_speculative_devirtualization (tree, HOST_WIDE_INT,
ipa_polymorphic_call_context);
void warn_types_mismatch (tree t1, tree t2);
bool odr_or_derived_type_p (const_tree t);
bool odr_types_equivalent_p (tree type1, tree type2);
/* Return vector containing possible targets of polymorphic call E.
If COMPLETEP is non-NULL, store true if the list is complete.

View File

@ -1,3 +1,10 @@
2015-05-17 Jan Hubicka <hubicka@ucw.cz>
* lto-symtab.c (warn_type_compatibility_p): Break out from ...;
compare ODR types (if available) and function types.
(lto_symtab_merge): ... here; output ODR violation warnings
and call warn_types_mismatch.
2015-04-29 Jan Hubicka <hubicka@ucw.cz>
* lto.c (lto_fixup_state): Call verify_type.

View File

@ -56,6 +56,7 @@ along with GCC; see the file COPYING3. If not see
#include "ipa-prop.h"
#include "ipa-inline.h"
#include "builtins.h"
#include "print-tree.h"
/* Replace the cgraph node NODE with PREVAILING_NODE in the cgraph, merging
all edges and removing the old node. */
@ -203,6 +204,105 @@ lto_varpool_replace_node (varpool_node *vnode,
vnode->remove ();
}
/* Return non-zero if we want to output waring about T1 and T2.
Return value is a bitmask of reasons of violation:
Bit 0 indicates that types are not compatible of memory layout.
Bot 1 indicates that types are not compatible because of C++ ODR rule. */
static int
warn_type_compatibility_p (tree prevailing_type, tree type)
{
int lev = 0;
/* C++ provide a robust way to check for type compatibility via the ODR
rule. */
if (odr_or_derived_type_p (prevailing_type) && odr_type_p (type)
&& !odr_types_equivalent_p (prevailing_type, type))
lev = 2;
/* Function types needs special care, because types_compatible_p never
thinks prototype is compatible to non-prototype. */
if ((TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE)
&& TREE_CODE (type) == TREE_CODE (prevailing_type))
{
lev |= warn_type_compatibility_p (TREE_TYPE (prevailing_type),
TREE_TYPE (type));
if (TREE_CODE (type) == METHOD_TYPE)
lev |= warn_type_compatibility_p (TYPE_METHOD_BASETYPE (prevailing_type),
TYPE_METHOD_BASETYPE (type));
if (prototype_p (prevailing_type) && prototype_p (type)
&& TYPE_ARG_TYPES (prevailing_type) != TYPE_ARG_TYPES (type))
{
tree parm1, parm2;
for (parm1 = TYPE_ARG_TYPES (prevailing_type),
parm2 = TYPE_ARG_TYPES (type);
parm1 && parm2;
parm1 = TREE_CHAIN (prevailing_type),
parm2 = TREE_CHAIN (type))
lev |= warn_type_compatibility_p (TREE_VALUE (parm1),
TREE_VALUE (parm2));
if (parm1 || parm2)
lev = 3;
}
if (comp_type_attributes (prevailing_type, type) == 0)
lev = 3;
return lev;
}
/* Sharing a global symbol is a strong hint that two types are
compatible. We could use this information to complete
incomplete pointed-to types more aggressively here, ignoring
mismatches in both field and tag names. It's difficult though
to guarantee that this does not have side-effects on merging
more compatible types from other translation units though. */
/* We can tolerate differences in type qualification, the
qualification of the prevailing definition will prevail.
??? In principle we might want to only warn for structurally
incompatible types here, but unless we have protective measures
for TBAA in place that would hide useful information. */
prevailing_type = TYPE_MAIN_VARIANT (prevailing_type);
type = TYPE_MAIN_VARIANT (type);
if (!types_compatible_p (prevailing_type, type))
{
if (TREE_CODE (prevailing_type) == FUNCTION_TYPE
|| TREE_CODE (type) == METHOD_TYPE)
return 1 | lev;
if (COMPLETE_TYPE_P (type) && COMPLETE_TYPE_P (prevailing_type))
return 1 | lev;
/* If type is incomplete then avoid warnings in the cases
that TBAA handles just fine. */
if (TREE_CODE (prevailing_type) != TREE_CODE (type))
return 1 | lev;
if (TREE_CODE (prevailing_type) == ARRAY_TYPE)
{
tree tem1 = TREE_TYPE (prevailing_type);
tree tem2 = TREE_TYPE (type);
while (TREE_CODE (tem1) == ARRAY_TYPE
&& TREE_CODE (tem2) == ARRAY_TYPE)
{
tem1 = TREE_TYPE (tem1);
tem2 = TREE_TYPE (tem2);
}
if (TREE_CODE (tem1) != TREE_CODE (tem2))
return 1 | lev;
if (!types_compatible_p (tem1, tem2))
return 1 | lev;
}
/* Fallthru. Compatible enough. */
}
/* ??? We might want to emit a warning here if type qualification
differences were spotted. Do not do this unconditionally though. */
return lev;
}
/* Merge two variable or function symbol table entries PREVAILING and ENTRY.
Return false if the symbols are not fully compatible and a diagnostic
should be emitted. */
@ -212,7 +312,6 @@ lto_symtab_merge (symtab_node *prevailing, symtab_node *entry)
{
tree prevailing_decl = prevailing->decl;
tree decl = entry->decl;
tree prevailing_type, type;
if (prevailing_decl == decl)
return true;
@ -227,70 +326,16 @@ lto_symtab_merge (symtab_node *prevailing, symtab_node *entry)
if (TREE_CODE (decl) == FUNCTION_DECL)
{
if (!types_compatible_p (TREE_TYPE (prevailing_decl),
TREE_TYPE (decl)))
/* If we don't have a merged type yet...sigh. The linker
wouldn't complain if the types were mismatched, so we
probably shouldn't either. Just use the type from
whichever decl appears to be associated with the
definition. If for some odd reason neither decl is, the
older one wins. */
(void) 0;
if (warn_type_compatibility_p (TREE_TYPE (prevailing_decl),
TREE_TYPE (decl)))
return false;
return true;
}
/* Now we exclusively deal with VAR_DECLs. */
/* Sharing a global symbol is a strong hint that two types are
compatible. We could use this information to complete
incomplete pointed-to types more aggressively here, ignoring
mismatches in both field and tag names. It's difficult though
to guarantee that this does not have side-effects on merging
more compatible types from other translation units though. */
/* We can tolerate differences in type qualification, the
qualification of the prevailing definition will prevail.
??? In principle we might want to only warn for structurally
incompatible types here, but unless we have protective measures
for TBAA in place that would hide useful information. */
prevailing_type = TYPE_MAIN_VARIANT (TREE_TYPE (prevailing_decl));
type = TYPE_MAIN_VARIANT (TREE_TYPE (decl));
if (!types_compatible_p (prevailing_type, type))
{
if (COMPLETE_TYPE_P (type))
return false;
/* If type is incomplete then avoid warnings in the cases
that TBAA handles just fine. */
if (TREE_CODE (prevailing_type) != TREE_CODE (type))
return false;
if (TREE_CODE (prevailing_type) == ARRAY_TYPE)
{
tree tem1 = TREE_TYPE (prevailing_type);
tree tem2 = TREE_TYPE (type);
while (TREE_CODE (tem1) == ARRAY_TYPE
&& TREE_CODE (tem2) == ARRAY_TYPE)
{
tem1 = TREE_TYPE (tem1);
tem2 = TREE_TYPE (tem2);
}
if (TREE_CODE (tem1) != TREE_CODE (tem2))
return false;
if (!types_compatible_p (tem1, tem2))
return false;
}
/* Fallthru. Compatible enough. */
}
/* ??? We might want to emit a warning here if type qualification
differences were spotted. Do not do this unconditionally though. */
if (warn_type_compatibility_p (TREE_TYPE (prevailing_decl),
TREE_TYPE (decl)))
return false;
/* There is no point in comparing too many details of the decls here.
The type compatibility checks or the completing of types has properly
@ -483,24 +528,39 @@ lto_symtab_merge_decls_2 (symtab_node *first, bool diagnosed_p)
/* Diagnose all mismatched re-declarations. */
FOR_EACH_VEC_ELT (mismatches, i, decl)
{
if (!types_compatible_p (TREE_TYPE (prevailing->decl),
TREE_TYPE (decl)))
diagnosed_p |= warning_at (DECL_SOURCE_LOCATION (decl), 0,
"type of %qD does not match original "
"declaration", decl);
int level = warn_type_compatibility_p (TREE_TYPE (prevailing->decl),
TREE_TYPE (decl));
if (level)
{
bool diag = false;
if (level > 1)
diag = warning_at (DECL_SOURCE_LOCATION (decl),
OPT_Wodr,
"%qD violates the C++ One Definition Rule ",
decl);
if (!diag && (level & 1))
diag = warning_at (DECL_SOURCE_LOCATION (decl),
OPT_Wlto_type_mismatch,
"type of %qD does not match original "
"declaration", decl);
if (diag)
warn_types_mismatch (TREE_TYPE (prevailing->decl),
TREE_TYPE (decl));
diagnosed_p |= diag;
}
else if ((DECL_USER_ALIGN (prevailing->decl)
&& DECL_USER_ALIGN (decl))
&& DECL_ALIGN (prevailing->decl) < DECL_ALIGN (decl))
{
diagnosed_p |= warning_at (DECL_SOURCE_LOCATION (decl), 0,
diagnosed_p |= warning_at (DECL_SOURCE_LOCATION (decl),
OPT_Wlto_type_mismatch,
"alignment of %qD is bigger than "
"original declaration", decl);
}
}
if (diagnosed_p)
inform (DECL_SOURCE_LOCATION (prevailing->decl),
"previously declared here");
"%qD was previously declared here", prevailing->decl);
mismatches.release ();
}

View File

@ -1,3 +1,12 @@
2015-05-16 Jan Hubica <hubicka@ucw.cz>
* gfortran.dg/lto/20091028-2_1.c: Fix return value.
* gfortran.dg/lto/pr41576_1.f90: Add interface.
* gfortran.dg/lto/pr41521_0.f90: Disable lto-type-mismatch
* gfortran.dg/lto/pr60635_0.f90: Disable lto-type-mismatch.
* gfortran.dg/lto/20091028-1_1.c: Fix return type.
* gcc.dg/lto/20120723_0.c: Disbale lto-type-mismatch.
2015-05-16 Jerry DeLisle <jvdelisle@gcc.gnu.org>
PR fortran/65903

View File

@ -3,7 +3,7 @@
??? This testcase is invalid C and can only pass on specific platforms. */
/* { dg-lto-do run } */
/* { dg-skip-if "" { { sparc*-*-* } && ilp32 } { "*" } { "" } } */
/* { dg-lto-options { {-O3 -fno-early-inlining -flto}} } */
/* { dg-lto-options { {-O3 -fno-early-inlining -flto -Wno-lto-type-mismatch}} } */
extern void abort (void);

View File

@ -1,9 +1,9 @@
extern void bcopy(const void *, void *, __SIZE_TYPE__ n);
char *p;
int int_gen_ti_header_c_ (char * hdrbuf, int * hdrbufsize,
int * itypesize, int * typesize,
int * DataHandle, char * Data,
int * Count, int * code)
void int_gen_ti_header_c_ (char * hdrbuf, int * hdrbufsize,
int * itypesize, int * typesize,
int * DataHandle, char * Data,
int * Count, int * code)
{
bcopy (typesize, p, sizeof(int)) ;
bcopy (Data, p, *Count * *typesize) ;

View File

@ -1,9 +1,9 @@
extern void *memcpy(void *dest, const void *src, __SIZE_TYPE__ n);
char *p;
int int_gen_ti_header_c_ (char * hdrbuf, int * hdrbufsize,
int * itypesize, int * typesize,
int * DataHandle, char * Data,
int * Count, int * code)
void int_gen_ti_header_c_ (char * hdrbuf, int * hdrbufsize,
int * itypesize, int * typesize,
int * DataHandle, char * Data,
int * Count, int * code)
{
memcpy (typesize, p, sizeof(int)) ;
memcpy (Data, p, *Count * *typesize) ;

View File

@ -1,9 +1,16 @@
! { dg-lto-do link }
! { dg-lto-options {{-g -flto} {-g -O -flto}} }
! { dg-lto-options {{-g -flto -Wno-lto-type-mismatch} {-g -O -flto -Wno-lto-type-mismatch}} }
program species
integer spk(2)
real eval(2)
spk = 2
call atom(1.1,spk,eval)
end program
interface
subroutine atom(sol,k,eval)
real, intent(in) :: sol
integer, intent(in) :: k(2)
real, intent(out) :: eval(2)
end subroutine
end interface

View File

@ -1,5 +1,5 @@
! { dg-lto-do run }
! { dg-lto-options { { -O2 -flto -Werror } } }
! { dg-lto-options { { -O2 -flto -Werror -Wno-lto-type-mismatch } } }
subroutine foo
common /bar/ a, b

View File

@ -5,3 +5,8 @@ program test
if (c/=1 .or. d/=2) call abort
end program test
interface
subroutine foo()
end subroutine
end interface

View File

@ -1,4 +1,5 @@
! { dg-lto-do link }
! { dg-lto-options {{ -Wno-lto-type-mismatch }} }
program test
use iso_fortran_env

View File

@ -5182,8 +5182,7 @@ need_assembler_name_p (tree decl)
&& DECL_NAME (decl)
&& decl == TYPE_NAME (TREE_TYPE (decl))
&& !TYPE_ARTIFICIAL (TREE_TYPE (decl))
&& (((RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl))
|| TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE)
&& ((type_with_linkage_p (TREE_TYPE (decl))
&& !type_in_anonymous_namespace_p (TREE_TYPE (decl)))
|| TREE_CODE (TREE_TYPE (decl)) == INTEGER_TYPE)
&& !variably_modified_type_p (TREE_TYPE (decl), NULL_TREE))

View File

@ -4544,7 +4544,6 @@ extern tree obj_type_ref_class (tree ref);
extern bool types_same_for_odr (const_tree type1, const_tree type2,
bool strict=false);
extern bool contains_bitfld_component_ref_p (const_tree);
extern bool type_in_anonymous_namespace_p (const_tree);
extern bool block_may_fallthru (const_tree);
extern void using_eh_for_cleanups (void);
extern bool using_eh_for_cleanups_p (void);