===================================================================
@@ -199,13 +199,19 @@
/* 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. */
+ Bit 0 indicates that types are not compatible in memory representation
+ or by TBAA.
+ Bit 1 indicates that types are not compatible because of C++ ODR rule.
+ We may have false positives for bit 0. We may also output more strict
+ warnings in mismatches between types originating from same compilation
+ units. For example, we may spot qualification differences for C. */
+
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_or_derived_type_p (type)
@@ -245,54 +251,48 @@
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. */
+ more compatible types from other translation units though.
+ For C programs doing so is however valid by WG14
+ as response to DR#314 */
- /* 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))
+ /* Check type compatibility by the canonical type machinery. This only works
+ for complete types. */
+ if (COMPLETE_TYPE_P (type) && COMPLETE_TYPE_P (prevailing_type))
{
- if (TREE_CODE (prevailing_type) == FUNCTION_TYPE
- || TREE_CODE (type) == METHOD_TYPE)
+ /* For mixed C/non-C programs we only can warn if the types are incompatible
+ in their representation.
+ For example it is possible to declare the same variable as C_PTR in
+ Fortran unit and as float * in C unit, because C_PTR (represented as
+ void *) is defined to be interoperable.
+ It is however definitely possible to check more here than what we
+ do currently. */
+ gcc_assert (TYPE_CANONICAL (prevailing_type) && TYPE_CANONICAL (type));
+ if (TYPE_CANONICAL (prevailing_type) != TYPE_CANONICAL (type))
return 1 | lev;
- if (COMPLETE_TYPE_P (type) && COMPLETE_TYPE_P (prevailing_type))
- return 1 | lev;
+ return lev;
+ }
- /* If type is incomplete then avoid warnings in the cases
- that TBAA handles just fine. */
+ /* Incomplete structure is compatible with every other structure.
+ Similarly for unions. For arrays we can do better by recursing
+ on array type and checking the same flags as canonical type machinery
+ does. */
- if (TREE_CODE (prevailing_type) != TREE_CODE (type))
- return 1 | lev;
+ if (tree_code_for_canonical_type_merging (TREE_CODE (prevailing_type))
+ != tree_code_for_canonical_type_merging (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 (TREE_CODE (prevailing_type) == ARRAY_TYPE)
+ {
+ if (TYPE_STRING_FLAG (prevailing_type) != TYPE_STRING_FLAG (type)
+ || TYPE_NONALIASED_COMPONENT (prevailing_type)
+ != TYPE_NONALIASED_COMPONENT (type))
+ return warn_type_compatibility_p (TREE_TYPE (prevailing_type),
+ TREE_TYPE (type)) | lev;
}
- /* ??? We might want to emit a warning here if type qualification
- differences were spotted. Do not do this unconditionally though. */
-
return lev;
}
@@ -325,6 +325,10 @@
return true;
}
+ else if (DECL_SIZE (decl) && DECL_SIZE (prevailing_decl)
+ && !operand_equal_p (DECL_SIZE (decl),
+ DECL_SIZE (prevailing_decl), 0))
+ return false;
if (warn_type_compatibility_p (TREE_TYPE (prevailing_decl),
TREE_TYPE (decl)))
===================================================================
@@ -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
+
===================================================================
@@ -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;
+}
+