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
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
/* 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);
}
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.
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. */
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,
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.
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)
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 &);
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.
+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.
#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. */
vnode->remove ();
}
-/* 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. */
+/* 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 bool
-lto_symtab_merge (symtab_node *prevailing, symtab_node *entry)
+static int
+warn_type_compatibility_p (tree prevailing_type, tree type)
{
- tree prevailing_decl = prevailing->decl;
- tree decl = entry->decl;
- tree prevailing_type, type;
-
- if (prevailing_decl == decl)
- return true;
-
- /* Merge decl state in both directions, we may still end up using
- the new decl. */
- TREE_ADDRESSABLE (prevailing_decl) |= TREE_ADDRESSABLE (decl);
- TREE_ADDRESSABLE (decl) |= TREE_ADDRESSABLE (prevailing_decl);
-
- /* The linker may ask us to combine two incompatible symbols.
- Detect this case and notify the caller of required diagnostics. */
-
- if (TREE_CODE (decl) == FUNCTION_DECL)
+ 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))
{
- 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;
-
- return true;
+ 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;
}
-
- /* 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
??? 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));
+ prevailing_type = TYPE_MAIN_VARIANT (prevailing_type);
+ type = TYPE_MAIN_VARIANT (type);
if (!types_compatible_p (prevailing_type, type))
{
- if (COMPLETE_TYPE_P (type))
- return false;
+ 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 false;
+ return 1 | lev;
if (TREE_CODE (prevailing_type) == ARRAY_TYPE)
{
}
if (TREE_CODE (tem1) != TREE_CODE (tem2))
- return false;
+ return 1 | lev;
if (!types_compatible_p (tem1, tem2))
- return false;
+ 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. */
+
+static bool
+lto_symtab_merge (symtab_node *prevailing, symtab_node *entry)
+{
+ tree prevailing_decl = prevailing->decl;
+ tree decl = entry->decl;
+
+ if (prevailing_decl == decl)
+ return true;
+
+ /* Merge decl state in both directions, we may still end up using
+ the new decl. */
+ TREE_ADDRESSABLE (prevailing_decl) |= TREE_ADDRESSABLE (decl);
+ TREE_ADDRESSABLE (decl) |= TREE_ADDRESSABLE (prevailing_decl);
+
+ /* The linker may ask us to combine two incompatible symbols.
+ Detect this case and notify the caller of required diagnostics. */
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ {
+ if (warn_type_compatibility_p (TREE_TYPE (prevailing_decl),
+ TREE_TYPE (decl)))
+ return false;
+
+ return true;
+ }
+
+ 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
dealt with most issues. */
/* 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 ();
}
+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
??? 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);
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) ;
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) ;
! { 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
! { 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
if (c/=1 .or. d/=2) call abort
end program test
+interface
+ subroutine foo()
+ end subroutine
+end interface
+
! { dg-lto-do link }
+! { dg-lto-options {{ -Wno-lto-type-mismatch }} }
program test
use iso_fortran_env
&& 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))
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);