lto-symtab.c: Include alias.h
* lto-symtab.c: Include alias.h (warn_type_compatibility_p): Replace types_compatible_p checks by TBAA and size checks; set bit 2 if locations are TBAA incompatible. (lto_symtab_merge): Compare DECL sizes. (lto_symtab_merge_decls_2): Warn about TBAA in compatibility. * gfortran.dg/lto/bind_c-6_0.f90: New testcase. * gfortran.dg/lto/bind_c-6_1.c: New testcase. From-SVN: r230911
This commit is contained in:
parent
c74f743ae4
commit
22bea0be95
@ -1,3 +1,11 @@
|
||||
2015-11-24 Jan Hubicka <hubicka@ucw.cz>
|
||||
|
||||
* lto-symtab.c: Include alias.h
|
||||
(warn_type_compatibility_p): Replace types_compatible_p checks by
|
||||
TBAA and size checks; set bit 2 if locations are TBAA incompatible.
|
||||
(lto_symtab_merge): Compare DECL sizes.
|
||||
(lto_symtab_merge_decls_2): Warn about TBAA in compatibility.
|
||||
|
||||
2015-11-24 Jan Hubicka <hubicka@ucw.cz>
|
||||
|
||||
* lto.c (iterative_hash_canonical_type): Recruse for all types
|
||||
|
@ -30,6 +30,7 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "lto-streamer.h"
|
||||
#include "ipa-utils.h"
|
||||
#include "builtins.h"
|
||||
#include "alias.h"
|
||||
|
||||
/* Replace the cgraph node NODE with PREVAILING_NODE in the cgraph, merging
|
||||
all edges and removing the old node. */
|
||||
@ -179,39 +180,52 @@ lto_varpool_replace_node (varpool_node *vnode,
|
||||
|
||||
/* 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.
|
||||
Bit 1 indicates that types are not compatible because of C++ ODR rule. */
|
||||
Bit 0 indicates that types are not compatible.
|
||||
Bit 1 indicates that types are not compatible because of C++ ODR rule.
|
||||
If COMMON_OR_EXTERN is true, do not warn on size mismatches of arrays.
|
||||
Bit 2 indicates that types are not ODR compatible
|
||||
|
||||
The interoperability rules are language specific. At present we do only
|
||||
full checking for C++ ODR rule and for other languages we do basic check
|
||||
that data structures are of same size and TBAA compatible. Our TBAA
|
||||
implementation should be coarse enough so all valid type transitions
|
||||
across different languages are allowed.
|
||||
|
||||
In partiucular we thus allow almost arbitrary type changes with
|
||||
-fno-strict-aliasing which may be tough of as a feature rather than bug
|
||||
as it allows to implement dodgy tricks in the language runtimes.
|
||||
|
||||
Naturally this code can be strenghtened significantly if we could track
|
||||
down the language of origin. */
|
||||
|
||||
static int
|
||||
warn_type_compatibility_p (tree prevailing_type, tree type)
|
||||
warn_type_compatibility_p (tree prevailing_type, tree type,
|
||||
bool common_or_extern)
|
||||
{
|
||||
int lev = 0;
|
||||
bool odr_p = odr_or_derived_type_p (prevailing_type)
|
||||
&& odr_or_derived_type_p (type);
|
||||
|
||||
/* Get complete type.
|
||||
??? We might want to emit a warning here if type qualification
|
||||
differences were spotted. Do not do this unconditionally though. */
|
||||
type = TYPE_MAIN_VARIANT (type);
|
||||
prevailing_type = TYPE_MAIN_VARIANT (prevailing_type);
|
||||
if (prevailing_type == type)
|
||||
return 0;
|
||||
|
||||
bool odr_p = odr_or_derived_type_p (prevailing_type)
|
||||
&& odr_or_derived_type_p (type);
|
||||
/* C++ provide a robust way to check for type compatibility via the ODR
|
||||
rule. */
|
||||
if (odr_p && !odr_types_equivalent_p (prevailing_type, type))
|
||||
lev = 2;
|
||||
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 (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE)
|
||||
{
|
||||
if (TREE_CODE (type) != TREE_CODE (prevailing_type))
|
||||
lev |= 1;
|
||||
lev |= warn_type_compatibility_p (TREE_TYPE (prevailing_type),
|
||||
TREE_TYPE (type));
|
||||
if (TREE_CODE (type) == METHOD_TYPE)
|
||||
TREE_TYPE (type), false);
|
||||
if (TREE_CODE (type) == METHOD_TYPE
|
||||
&& TREE_CODE (prevailing_type) == METHOD_TYPE)
|
||||
lev |= warn_type_compatibility_p (TYPE_METHOD_BASETYPE (prevailing_type),
|
||||
TYPE_METHOD_BASETYPE (type));
|
||||
TYPE_METHOD_BASETYPE (type), false);
|
||||
if (prototype_p (prevailing_type) && prototype_p (type)
|
||||
&& TYPE_ARG_TYPES (prevailing_type) != TYPE_ARG_TYPES (type))
|
||||
{
|
||||
@ -222,62 +236,54 @@ warn_type_compatibility_p (tree prevailing_type, tree type)
|
||||
parm1 = TREE_CHAIN (parm1),
|
||||
parm2 = TREE_CHAIN (parm2))
|
||||
lev |= warn_type_compatibility_p (TREE_VALUE (parm1),
|
||||
TREE_VALUE (parm2));
|
||||
TREE_VALUE (parm2), false);
|
||||
if (parm1 || parm2)
|
||||
lev = odr_p ? 3 : 1;
|
||||
lev |= odr_p ? 3 : 1;
|
||||
}
|
||||
if (comp_type_attributes (prevailing_type, type) == 0)
|
||||
lev = odr_p ? 3 : 1;
|
||||
lev |= 1;
|
||||
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. */
|
||||
/* Get complete type. */
|
||||
prevailing_type = TYPE_MAIN_VARIANT (prevailing_type);
|
||||
type = TYPE_MAIN_VARIANT (type);
|
||||
|
||||
if (!types_compatible_p (prevailing_type, type))
|
||||
/* We can not use types_compatible_p because we permit some changes
|
||||
across types. For example unsigned size_t and "signed size_t" may be
|
||||
compatible when merging C and Fortran types. */
|
||||
if (COMPLETE_TYPE_P (prevailing_type)
|
||||
&& COMPLETE_TYPE_P (type)
|
||||
/* While global declarations are never variadic, we can recurse here
|
||||
for function parameter types. */
|
||||
&& TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
|
||||
&& TREE_CODE (TYPE_SIZE (prevailing_type)) == INTEGER_CST
|
||||
&& !tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (prevailing_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;
|
||||
/* As a special case do not warn about merging
|
||||
int a[];
|
||||
and
|
||||
int a[]={1,2,3};
|
||||
here the first declaration is COMMON or EXTERN
|
||||
and sizeof(a) == sizeof (int). */
|
||||
if (!common_or_extern
|
||||
|| TREE_CODE (type) != ARRAY_TYPE
|
||||
|| TYPE_SIZE (type) != TYPE_SIZE (TREE_TYPE (type)))
|
||||
lev |= 1;
|
||||
}
|
||||
|
||||
/* If type is incomplete then avoid warnings in the cases
|
||||
that TBAA handles just fine. */
|
||||
/* Verify TBAA compatibility. Take care of alias set 0 and the fact that
|
||||
we make ptr_type_node to TBAA compatible with every other type. */
|
||||
if (type_with_alias_set_p (type) && type_with_alias_set_p (prevailing_type))
|
||||
{
|
||||
alias_set_type set1 = get_alias_set (type);
|
||||
alias_set_type set2 = get_alias_set (prevailing_type);
|
||||
|
||||
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. */
|
||||
if (set1 && set2 && set1 != set2
|
||||
&& (!POINTER_TYPE_P (type) || !POINTER_TYPE_P (prevailing_type)
|
||||
|| (set1 != TYPE_ALIAS_SET (ptr_type_node)
|
||||
&& set2 != TYPE_ALIAS_SET (ptr_type_node))))
|
||||
lev |= 5;
|
||||
}
|
||||
|
||||
return lev;
|
||||
@ -312,14 +318,17 @@ lto_symtab_merge (symtab_node *prevailing, symtab_node *entry)
|
||||
DECL_POSSIBLY_INLINED (decl) |= DECL_POSSIBLY_INLINED (prevailing_decl);
|
||||
|
||||
if (warn_type_compatibility_p (TREE_TYPE (prevailing_decl),
|
||||
TREE_TYPE (decl)))
|
||||
TREE_TYPE (decl),
|
||||
DECL_COMMON (decl)
|
||||
|| DECL_EXTERNAL (decl)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (warn_type_compatibility_p (TREE_TYPE (prevailing_decl),
|
||||
TREE_TYPE (decl)))
|
||||
TREE_TYPE (decl),
|
||||
DECL_COMMON (decl) || DECL_EXTERNAL (decl)))
|
||||
return false;
|
||||
|
||||
/* There is no point in comparing too many details of the decls here.
|
||||
@ -334,6 +343,20 @@ lto_symtab_merge (symtab_node *prevailing, symtab_node *entry)
|
||||
&& DECL_ALIGN (prevailing_decl) < DECL_ALIGN (decl))
|
||||
return false;
|
||||
|
||||
if (DECL_SIZE (decl) && DECL_SIZE (prevailing_decl)
|
||||
&& !tree_int_cst_equal (DECL_SIZE (decl), DECL_SIZE (prevailing_decl))
|
||||
/* As a special case do not warn about merging
|
||||
int a[];
|
||||
and
|
||||
int a[]={1,2,3};
|
||||
here the first declaration is COMMON
|
||||
and sizeof(a) == sizeof (int). */
|
||||
&& ((!DECL_COMMON (decl) && !DECL_EXTERNAL (decl))
|
||||
|| TREE_CODE (TREE_TYPE (decl)) != ARRAY_TYPE
|
||||
|| TYPE_SIZE (TREE_TYPE (decl))
|
||||
!= TYPE_SIZE (TREE_TYPE (TREE_TYPE (decl)))))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -491,6 +514,7 @@ lto_symtab_merge_decls_2 (symtab_node *first, bool diagnosed_p)
|
||||
vec<tree> mismatches = vNULL;
|
||||
unsigned i;
|
||||
tree decl;
|
||||
bool tbaa_p = false;
|
||||
|
||||
/* Nothing to do for a single entry. */
|
||||
prevailing = first;
|
||||
@ -514,11 +538,12 @@ lto_symtab_merge_decls_2 (symtab_node *first, bool diagnosed_p)
|
||||
FOR_EACH_VEC_ELT (mismatches, i, decl)
|
||||
{
|
||||
int level = warn_type_compatibility_p (TREE_TYPE (prevailing->decl),
|
||||
TREE_TYPE (decl));
|
||||
TREE_TYPE (decl),
|
||||
DECL_COMDAT (decl));
|
||||
if (level)
|
||||
{
|
||||
bool diag = false;
|
||||
if (level > 1)
|
||||
if (level & 2)
|
||||
diag = warning_at (DECL_SOURCE_LOCATION (decl),
|
||||
OPT_Wodr,
|
||||
"%qD violates the C++ One Definition Rule ",
|
||||
@ -529,10 +554,15 @@ lto_symtab_merge_decls_2 (symtab_node *first, bool diagnosed_p)
|
||||
"type of %qD does not match original "
|
||||
"declaration", decl);
|
||||
if (diag)
|
||||
warn_types_mismatch (TREE_TYPE (prevailing->decl),
|
||||
TREE_TYPE (decl),
|
||||
DECL_SOURCE_LOCATION (prevailing->decl),
|
||||
DECL_SOURCE_LOCATION (decl));
|
||||
{
|
||||
warn_types_mismatch (TREE_TYPE (prevailing->decl),
|
||||
TREE_TYPE (decl),
|
||||
DECL_SOURCE_LOCATION (prevailing->decl),
|
||||
DECL_SOURCE_LOCATION (decl));
|
||||
if ((level & 4)
|
||||
&& !TREE_READONLY (prevailing->decl))
|
||||
tbaa_p = true;
|
||||
}
|
||||
diagnosed_p |= diag;
|
||||
}
|
||||
else if ((DECL_USER_ALIGN (prevailing->decl)
|
||||
@ -544,10 +574,19 @@ lto_symtab_merge_decls_2 (symtab_node *first, bool diagnosed_p)
|
||||
"alignment of %qD is bigger than "
|
||||
"original declaration", decl);
|
||||
}
|
||||
else
|
||||
diagnosed_p |= warning_at (DECL_SOURCE_LOCATION (decl),
|
||||
OPT_Wlto_type_mismatch,
|
||||
"size of %qD differ from the size of "
|
||||
"original declaration", decl);
|
||||
}
|
||||
if (diagnosed_p)
|
||||
inform (DECL_SOURCE_LOCATION (prevailing->decl),
|
||||
"%qD was previously declared here", prevailing->decl);
|
||||
if (tbaa_p)
|
||||
inform (DECL_SOURCE_LOCATION (prevailing->decl),
|
||||
"code may be misoptimized unless "
|
||||
"-fno-strict-aliasing is used");
|
||||
|
||||
mismatches.release ();
|
||||
}
|
||||
|
@ -1,3 +1,9 @@
|
||||
2015-11-23 Jan Hubicka <hubicka@ucw.cz>
|
||||
|
||||
* gfortran.dg/lto/bind_c-6_0.f90: New testcase.
|
||||
* gfortran.dg/lto/bind_c-6_1.c: New testcase.
|
||||
* g++.dg/lto/20100603-1_0.C: Add -Wno-lto-type-mismatch.
|
||||
|
||||
2015-11-25 Tom de Vries <tom@codesourcery.com>
|
||||
|
||||
* g++.dg/tree-ssa/copyprop-1.C: Update after adding new dce1.
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* { dg-lto-do link } */
|
||||
/* { dg-extra-ld-options "-Wno-lto-type-mismatch" } */
|
||||
|
||||
extern "C" {
|
||||
typedef struct {} CvImage;
|
||||
|
17
gcc/testsuite/gfortran.dg/lto/bind_c-6_0.f90
Normal file
17
gcc/testsuite/gfortran.dg/lto/bind_c-6_0.f90
Normal file
@ -0,0 +1,17 @@
|
||||
! { dg-lto-do run }
|
||||
! { dg-lto-options {{ -O3 -flto }} }
|
||||
! This testcase will abort if C_FUNPTR is not interoperable with both int *
|
||||
! and float *
|
||||
module lto_type_merge_test
|
||||
use, intrinsic :: iso_c_binding
|
||||
implicit none
|
||||
|
||||
integer(c_size_t), bind(c, name="myVar") :: myVar
|
||||
integer(c_size_t), bind(c, name="myVar2") :: myVar2
|
||||
|
||||
contains
|
||||
subroutine types_test() bind(c)
|
||||
myVar = myVar2
|
||||
end subroutine types_test
|
||||
end module lto_type_merge_test
|
||||
|
29
gcc/testsuite/gfortran.dg/lto/bind_c-6_1.c
Normal file
29
gcc/testsuite/gfortran.dg/lto/bind_c-6_1.c
Normal file
@ -0,0 +1,29 @@
|
||||
#include <stdlib.h>
|
||||
/* declared in the fortran module */
|
||||
extern size_t myVar, myVar2;
|
||||
void types_test(void);
|
||||
|
||||
|
||||
extern void abort(void);
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
size_t *myptr, *myptr2;
|
||||
asm("":"=r"(myptr):"0"(&myVar));
|
||||
asm("":"=r"(myptr2):"0"(&myVar2));
|
||||
*myptr = 1;
|
||||
*myptr2 = 2;
|
||||
types_test();
|
||||
if (*myptr != 2)
|
||||
abort ();
|
||||
if (*myptr2 != 2)
|
||||
abort ();
|
||||
*myptr2 = 3;
|
||||
types_test();
|
||||
if (*myptr != 3)
|
||||
abort ();
|
||||
if (*myptr2 != 3)
|
||||
abort ();
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user