On Tue, 26 May 2015, Jan Hubicka wrote:

> > > Now the change does not really translate to great increase of 
> > > disambiguations
> > > for Firefox (it seems more in noise). The reason is the pointer_type 
> > > globbing
> > > in alias.c.
> > 
> > Yeah, we only get the improvement because of some "hack" in the tree
> > alias oracle which also uses the base object for TBAA.
> 
> Why that is hack? Dereferencing a pointer makes it clear the type of memory 
> location
> pointed to is known, we should use that info.
> > 
> > Yeah, we should fix that.  And in fact, for cross-language LTO I don't
> > see why
> > 
> >   union { int a; char c; };
> > 
> > and
> > 
> >   union { int a; short s; };
> > 
> > should not be compatible - they have a common member after all.  So
> > I'd like to glob all unions that have the same size (and as improvement
> 
> Well, none of language standards I saw so far expect this to happen.
> Going to extremes, you can always put variable sized char array to union
> and by transitivity glob everything with everything.

I'm speaking of cross-language LTO - that leaves the language standards
territorry and requires us to apply common sense.

> > over that, that have at least one compatible member).  That also get's
> > rid of the issue that we'd need to sort union members for the comparison
> > to avoid quadraticness (as long as we don't check for that one compatible
> > member).
> 
> Yeah, sorting is possible by using the hash values.
> > 
> > Oh, and are
> > 
> >   union { int a; };
> > 
> > and
> > 
> >   struct { int a; };
> > 
> > not compatible?  They are layout-wise at least.  Likewise the struct
> > and union { int a; short s; } with the same argument as the two-union
> > case.
> 
> Applying this rule you have
> 
> union { char a[n]; } compatible with every union and thus also
> union {int a;}
> struct { int a;}
> int a;
> 
> Which would disable TBAA completely.

See ;)  At least we have the int a; vs. struct { int a; } issue
with Fortran vs. C compatibility (there is even a PR about this).

> > 
> > >  We also do not compare alignments. This is probably not important)
> > 
> > Correct - alignment doesn't enter TBAA.
> 
> Yep, I think the alignment compare in C standard basically is there to 
> say that structures must have same lyaout.
> > > void f(double (* restrict a)[5]);
> > > void f(double a[restrict][5]);
> > > void f(double a[restrict 3][5]);
> > > void f(double a[restrict static 3][5]);)
> > 
> > Not sure why you get into functions here at all ...
> 
> Basically it matters only if we want to disambiguate function pointers.
> > 
> > >   2  Each enumerated type shall be compatible with char ,  a  signed 
> > > integer
> > >      type, or an unsigned integer type. The choice of type is
> > >      implementation-defined, but  shall be capable of representing the 
> > > values
> > >      of all the members of the enumeration.    The enumerated type is
> > >      incomplete until immediately after the that terminates the list of
> > >      enumerator declarations, and complete thereafter.
> > > 
> > > (we ignore this completely as far as I know, it is easy to fix though, all
> > >  we need is to make ENUMERATION_TYPE pretend to be INTEGER_TYPE)
> > 
> > Yes, we don't make a distinction between ENUMERAL_TYPE and INTEGER_TYPE.
> 
> hstate.add_int (TREE_CODE (type));

in alias.c I mean.

> makes them different.  I think we want to produce "simplified" code that turns
> REFERENCE_TYPE to POINTER_TYPE and ENUMERAL_TYPE to INTEGER_TYPE.
> I will send patch fo that.

Thanks.

> > 
> > >   10 For two qualified types to be compatible, both shall have the 
> > > identically
> > >      qualified version of a compatible type; the order of type qualifiers
> > >      within a list of specifiers or qualifiers does not affect the 
> > > specified type.
> > > 
> > > Now I think in order to get C standard type compatiblity to imply
> > > gimple_canonical_types_compatible we need to implement all the above 
> > > globbing
> > > rules as part of canonical type computation, not only punt at pointers in
> > > alias.c
> > > 
> > > My reading is that for example
> > > 
> > > struct a {char *a;};
> > > 
> > > is compatible with
> > > 
> > > struct a {enum *a;};
> > > 
> > > defined in other compilation unit.
> > 
> > Yes, as said above the TREE_CODE trick in the pointer-type handing is
> > wrong.  We can as well just drop it ...
> 
> struct a {char a;};
> 
> is compatible with
> 
> struct a {enum a;};
> 
> I would say we just want to simplify the codes and peel for
> pointers instead of TREE_TYPE (t) compare look for actual pointed to type
> (peeling out POINTER_TYPE/RECORD_TYPE/ARRAY_TYPEs)
> > >  8) i think to be correct by C language standard we need to glob enum 
> > > with char
> > >     tough I do not quite see how standard conforming program should use 
> > >     it given that standard does not say if it is char/unsigned 
> > >     char/signed char.
> > 
> > I think it depends on the actual enum, no?  So for forward declarations
> > like
> > 
> >  enum Foo;
> >  struct X { enum Foo *p; };
> > 
> > you face the same issue as with void *.
> 
> Well, handling all enums as integers should solve this.

But sizeof (enum Foo) depends on the enum, so no, it won't solve it.
There are no incomplete integer types but incomplete enum types.
(ok, this is probably a GNU extension issue that we have enums larger
than unsigned int).

> > > Overall plan
> > > ============
> > > 
> > > So I propose the following:
> > >  1) we add the incomplete types mode to 
> > > gimple_canonical_types_compatible_p
> > >     as suggested by this patch
> > >  2) I will add the individual globbing rules to the functions one by one
> > >  3) once done, we enable recursion on pointer
> > >  4) we drop the alias.c globing of pointer_type for in_lto_p.
> > 
> > I don't think we want to do 4), especially not only for in_lto_p.  I'm
> > not sure we should spend time on improving accuracy before fixing
> > correctness (on the current precision level).
> 
> Yep, fixing correctness is 2).  I will look into that.
> > > Based on experience, we may switch to C/C++ compliant equivalence when we 
> > > know
> > > that whole unit is C/C++ and we do not have to deal with odd cases from 
> > > other
> > > languages.
> > 
> > I'm not convinced the patch is a step in the right direction.
> > 
> > Can we please first fix pointer handing for TYPE_CANONICAL by dropping
> > the TREE_CODE handling and fix union handling by only looking at
> > union size?
> 
> OK, I will send patch for TYPE_CODE compare.
> I am not quite convinced about the unions as per example abov.
> > 
> > Originally I wanted to make LTO type compatibility really layout-based
> > (thus struct { int i[2]; } and struct { int i; int j; } match for 
> > example).
> > 
> > I wonder if for non-cross-language-LTO we shouldn't simply stream
> > TYPE_CANONICAL, at stream-in record a TYPE_CANONICAL vs. uses vector
> > map and "fix" up canonical types globally (we'd need to stream
> > "local" canonical types in the global trees then).
> 
> Hmm, can you explain bit more what you have in mind?  I did play
> with non-cross-language canonical type streaming for anonymous
> namespace C++ types (that by definition can not be compatible
> with anything from other language).
> I can return to that.

First of all retain TYPE_CANONICAL if we have a single source language
(we still have to merge them I guess, and hopefully tree merging will
do the correct thing here).

Then avoid the transitivity constraint by computing TYPE_CANONICAL
"globally" (thus not requiring incremental compute to work).  That's
going to work only if we record all canonical types and its uses
(&TYPE_CANONICAL) or the main variants that don't have a canonical
type yet (even for cross-language LTO the original type-canonicals
denote minimal coalescing we have to preserve).

That said, eventually we'd want to stream TYPE_CANONICAL for
correctness (at least for verification that in the end for
two types where the original TYPE_CANONICAL was the same the
LTO idea of TYPE_CANONICAL is also the same - possibly that's
ensured by your type verifier checking the LTO compute computes
the same outcome).

Richard.

> Honza
> > 
> > Richard.
> > 
> > > Honza
> > > 
> > >   * tree.c (gimple_canonical_types_compatible_p): Turn
> > >   TRUST_TYPE_CANONICAL into FLAGS parameter; support
> > >   comparsion with MATCH_WITH_INCOMPLETE_TYPE.
> > > Index: lto/lto.c
> > > ===================================================================
> > > --- lto/lto.c     (revision 223632)
> > > +++ lto/lto.c     (working copy)
> > > @@ -295,7 +295,9 @@
> > >  static unsigned long num_canonical_type_hash_entries;
> > >  static unsigned long num_canonical_type_hash_queries;
> > >  
> > > -static void iterative_hash_canonical_type (tree type, inchash::hash 
> > > &hstate);
> > > +static void iterative_hash_canonical_type (tree type, inchash::hash 
> > > &hstate,
> > > +                                    unsigned int flags
> > > +                                      = MATCH_TYPE_CANONICAL);
> > >  static hashval_t gimple_canonical_type_hash (const void *p);
> > >  static void gimple_register_canonical_type_1 (tree t, hashval_t hash);
> > >  
> > > @@ -302,26 +304,36 @@
> > >  /* Returning a hash value for gimple type TYPE.
> > >  
> > >     The hash value returned is equal for types considered compatible
> > > -   by gimple_canonical_types_compatible_p.  */
> > > +   by gimple_canonical_types_compatible_p.  FLAGS values are interpretted
> > > +   same way as by this function.  */
> > >  
> > >  static hashval_t
> > > -hash_canonical_type (tree type)
> > > +hash_canonical_type (tree type, unsigned int flags = 
> > > MATCH_TYPE_CANONICAL)
> > >  {
> > >    inchash::hash hstate;
> > >  
> > > -  /* We compute alias sets only for types that needs them.
> > > -     Be sure we do not recurse to something else as we can not hash 
> > > incomplete
> > > -     types in a way they would have same hash value as compatible 
> > > complete
> > > -     types.  */
> > > -  gcc_checking_assert (type_with_alias_set_p (type));
> > > +  /* Check that we encounter incomplete types only with
> > > +     MATCH_WITH_INCOMPLETE_TYPE.
> > >  
> > > +     Also check that no one tries to use hashing in compbination with 
> > > +     !MATCH_TYPE_CANONICAL.  In this case 
> > > gimple_canonical_types_compatible_p
> > > +     is not transitive and thus does not produce equivalence on all 
> > > types.  */
> > > +  gcc_checking_assert ((flags & MATCH_TYPE_CANONICAL)
> > > +                && ((flags & MATCH_WITH_INCOMPLETE_TYPE)
> > > +                    || type_with_alias_set_p (type)));
> > > +
> > >    /* Combine a few common features of types so that types are grouped 
> > > into
> > >       smaller sets; when searching for existing matching types to merge,
> > >       only existing types having the same features as the new type will be
> > >       checked.  */
> > >    hstate.add_int (TREE_CODE (type));
> > > -  hstate.add_int (TYPE_MODE (type));
> > >  
> > > +  /* Incomplete arrays and aggregates do not have TYPE_MODE defined.  */
> > > +  if (!(flags & MATCH_WITH_INCOMPLETE_TYPE)
> > > +      || (TREE_CODE (type) != ARRAY_TYPE
> > > +   && !AGGREGATE_TYPE_P (type)))
> > > +    hstate.add_int (TYPE_MODE (type));
> > > +
> > >    /* Incorporate common features of numerical types.  */
> > >    if (INTEGRAL_TYPE_P (type)
> > >        || SCALAR_FLOAT_TYPE_P (type)
> > > @@ -355,7 +367,8 @@
> > >      hstate.add_int (TYPE_STRING_FLAG (type));
> > >  
> > >    /* For array types hash the domain bounds and the string flag.  */
> > > -  if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type))
> > > +  if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type)
> > > +      && !(flags & MATCH_WITH_INCOMPLETE_TYPE))
> > >      {
> > >        hstate.add_int (TYPE_STRING_FLAG (type));
> > >        /* OMP lowering can introduce error_mark_node in place of
> > > @@ -366,30 +379,35 @@
> > >   inchash::add_expr (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), hstate);
> > >      }
> > >  
> > > -  /* Recurse for aggregates with a single element type.  */
> > > +  /* Recurse for aggregates with a single element type.
> > > +     We are safe to drop MATCH_INCOMPLETE.  There is no way to build
> > > +     an array of incomplete types.   */
> > >    if (TREE_CODE (type) == ARRAY_TYPE
> > >        || TREE_CODE (type) == COMPLEX_TYPE
> > >        || TREE_CODE (type) == VECTOR_TYPE)
> > > -    iterative_hash_canonical_type (TREE_TYPE (type), hstate);
> > > +    iterative_hash_canonical_type (TREE_TYPE (type), hstate,
> > > +                            flags & ~MATCH_WITH_INCOMPLETE_TYPE);
> > >  
> > >    /* Incorporate function return and argument types.  */
> > >    if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == 
> > > METHOD_TYPE)
> > >      {
> > > -      unsigned na;
> > > -      tree p;
> > > +      iterative_hash_canonical_type (TREE_TYPE (type), hstate, flags);
> > >  
> > > -      iterative_hash_canonical_type (TREE_TYPE (type), hstate);
> > > -
> > > -      for (p = TYPE_ARG_TYPES (type), na = 0; p; p = TREE_CHAIN (p))
> > > +      if (!(flags & MATCH_WITH_INCOMPLETE_TYPE)
> > > +   || TREE_CODE (type) == METHOD_TYPE)
> > >   {
> > > -   iterative_hash_canonical_type (TREE_VALUE (p), hstate);
> > > -   na++;
> > > +   unsigned na;
> > > +   tree p;
> > > +   for (p = TYPE_ARG_TYPES (type), na = 0; p; p = TREE_CHAIN (p))
> > > +     {
> > > +       iterative_hash_canonical_type (TREE_VALUE (p), hstate, flags);
> > > +       na++;
> > > +     }
> > > +   hstate.add_int (na);
> > >   }
> > > -
> > > -      hstate.add_int (na);
> > >      }
> > >  
> > > -  if (RECORD_OR_UNION_TYPE_P (type))
> > > +  if (RECORD_OR_UNION_TYPE_P (type) && !(flags & 
> > > MATCH_WITH_INCOMPLETE_TYPE))
> > >      {
> > >        unsigned nf;
> > >        tree f;
> > > @@ -397,7 +415,7 @@
> > >        for (f = TYPE_FIELDS (type), nf = 0; f; f = TREE_CHAIN (f))
> > >   if (TREE_CODE (f) == FIELD_DECL)
> > >     {
> > > -     iterative_hash_canonical_type (TREE_TYPE (f), hstate);
> > > +     iterative_hash_canonical_type (TREE_TYPE (f), hstate, flags);
> > >       nf++;
> > >     }
> > >  
> > > @@ -407,14 +425,22 @@
> > >    return hstate.end();
> > >  }
> > >  
> > > -/* Returning a hash value for gimple type TYPE combined with VAL.  */
> > > +/* Returning a hash value for gimple type TYPE combined with VAL.
> > > +   FLAGS are the same as for gimple_conanical_types_compatible_p.  */
> > >  
> > >  static void
> > > -iterative_hash_canonical_type (tree type, inchash::hash &hstate)
> > > +iterative_hash_canonical_type (tree type, inchash::hash &hstate,
> > > +                        unsigned int flags)
> > >  {
> > >    hashval_t v;
> > > +
> > > +  /* TYPE_CANONICAL reflects equivalence classes with
> > > +     !MATCH_WITH_INCOMPLETE_TYPE.   If we are matching incomplete types,
> > > +     then we need to recurse.  */
> > > +  if (flags & MATCH_WITH_INCOMPLETE_TYPE)
> > > +    v = hash_canonical_type (type, flags);
> > >    /* An already processed type.  */
> > > -  if (TYPE_CANONICAL (type))
> > > +  else if (TYPE_CANONICAL (type))
> > >      {
> > >        type = TYPE_CANONICAL (type);
> > >        v = gimple_canonical_type_hash (type);
> > > @@ -497,6 +523,14 @@
> > >  {
> > >    if (TYPE_CANONICAL (t) || !type_with_alias_set_p (t))
> > >      return;
> > > +  /* Only types that can be handled in memory need canonical types.
> > > +     Function and methods are never accessed. Also we do not need 
> > > canonical
> > > +     types for incomplete types with exception of arrays - structures 
> > > may end
> > > +     with incomplete arrays that may be referenced.  */
> > > +  if (TREE_CODE (t) == FUNCTION_TYPE || TREE_CODE (t) == METHOD_TYPE
> > > +      || (!COMPLETE_TYPE_P (t)
> > > +   && (TREE_CODE (t) != ARRAY_TYPE || !COMPLETE_TYPE_P (TREE_TYPE (t)))))
> > > +    return;
> > >  
> > >    gimple_register_canonical_type_1 (t, hash_canonical_type (t));
> > >  }
> > > Index: tree.c
> > > ===================================================================
> > > --- tree.c        (revision 223633)
> > > +++ tree.c        (working copy)
> > > @@ -12702,12 +12702,24 @@
> > >  /* Return true iff T1 and T2 are structurally identical for what
> > >     TBAA is concerned.  
> > >     This function is used both by lto.c canonical type merging and by the
> > > -   verifier.  If TRUST_TYPE_CANONICAL we do not look into structure of 
> > > types
> > > -   that have TYPE_CANONICAL defined and assume them equivalent.  */
> > > +   verifier.  
> > >  
> > > +   If flags sets MATCH_TYPE_CANONICAL we assume that TYPE_CANONICAL is 
> > > set in a
> > > +   way that two types have the same canonical type if and only if
> > > +   gimple_canonical_types_compatible_p (t1,t2, 0) is true.  This is used
> > > +   to cut down recursion during LTO canonical type comptuation.  When 
> > > this flag
> > > +   is set we also sanity check that we are going to produce equivalence 
> > > relation
> > > +   that is needed to drive the hashtable in lto.c.
> > > +
> > > +   if MATCH_WITH_INCOMPLETE_TYPE is true, then we do not use any 
> > > information
> > > +   from complete types and thus i.e. all RECORD_TYPE are equivlaent to 
> > > other
> > > +   RECORD_TYPEs.  This is the only equivalence possible if one require
> > > +   incomplete type to be in the same equivalence class with all its
> > > +   completetions.  */
> > > +
> > >  bool
> > >  gimple_canonical_types_compatible_p (const_tree t1, const_tree t2,
> > > -                              bool trust_type_canonical)
> > > +                              unsigned int flags)
> > >  {
> > >    /* Before starting to set up the SCC machinery handle simple cases.  */
> > >  
> > > @@ -12719,28 +12731,28 @@
> > >    if (t1 == NULL_TREE || t2 == NULL_TREE)
> > >      return false;
> > >  
> > > -  /* We consider complete types always compatible with incomplete type.
> > > -     This does not make sense for canonical type calculation and thus we
> > > -     need to ensure that we are never called on it.
> > > +  /* Check that either flags allow incomplete types or both types are 
> > > complete.
> > > +     This is necessary to ensure transitivity for canonical type merging.
> > >  
> > > -     FIXME: For more correctness the function probably should have three 
> > > modes
> > > - 1) mode assuming that types are complete mathcing their structure
> > > - 2) mode allowing incomplete types but producing equivalence classes
> > > -    and thus ignoring all info from complete types
> > > - 3) mode allowing incomplete types to match complete but checking
> > > -    compatibility between complete types.
> > > +     FIXME: with !MATCH_TYPE_CANONICAL we probably should allow match 
> > > between
> > > +     incomplete type and complete type as defined by language standards. 
> > >  No
> > > +     one however rely on it so far.  */
> > >  
> > > -     1 and 2 can be used for canonical type calculation. 3 is the real
> > > -     definition of type compatibility that can be used i.e. for warnings 
> > > during
> > > -     declaration merging.  */
> > > -
> > > -  gcc_assert (!trust_type_canonical
> > > +  gcc_assert ((flags & MATCH_WITH_INCOMPLETE_TYPE)
> > > +       || !(flags & MATCH_TYPE_CANONICAL)
> > >         || (type_with_alias_set_p (t1) && type_with_alias_set_p (t2)));
> > >    /* If the types have been previously registered and found equal
> > >       they still are.  */
> > >    if (TYPE_CANONICAL (t1) && TYPE_CANONICAL (t2)
> > > -      && trust_type_canonical)
> > > -    return TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2);
> > > +      && (flags & MATCH_TYPE_CANONICAL))
> > > +    {
> > > +      if (TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2))
> > > + return true;
> > > +      /* TYPE_CANONICAL is always computed with an assumption that the 
> > > type
> > > +  is complete.  */
> > > +      if (!(flags & MATCH_WITH_INCOMPLETE_TYPE))
> > > + return false;
> > > +    }
> > >  
> > >    /* Can't be the same type if the types don't have the same code.  */
> > >    if (TREE_CODE (t1) != TREE_CODE (t2))
> > > @@ -12753,8 +12765,12 @@
> > >        || TREE_CODE (t1) == NULLPTR_TYPE)
> > >      return true;
> > >  
> > > -  /* Can't be the same type if they have different mode.  */
> > > -  if (TYPE_MODE (t1) != TYPE_MODE (t2))
> > > +  /* Can't be the same type if they have different mode.
> > > +     Incomplete arrays and aggregates do not have TYPE_MODE defined.  */
> > > +  if ((!(flags & MATCH_WITH_INCOMPLETE_TYPE)
> > > +       || (TREE_CODE (t1) != ARRAY_TYPE
> > > +           && !AGGREGATE_TYPE_P (t1)))
> > > +      && TYPE_MODE (t1) != TYPE_MODE (t2))
> > >      return false;
> > >  
> > >    /* Non-aggregate types can be handled cheaply.  */
> > > @@ -12783,8 +12799,7 @@
> > >   {
> > >     if (TYPE_ADDR_SPACE (TREE_TYPE (t1))
> > >         != TYPE_ADDR_SPACE (TREE_TYPE (t2)))
> > > -     return false;
> > > -
> > > +             return false;
> > >     if (TREE_CODE (TREE_TYPE (t1)) != TREE_CODE (TREE_TYPE (t2)))
> > >       return false;
> > >   }
> > > @@ -12792,9 +12807,9 @@
> > >        /* Tail-recurse to components.  */
> > >        if (TREE_CODE (t1) == VECTOR_TYPE
> > >     || TREE_CODE (t1) == COMPLEX_TYPE)
> > > - return gimple_canonical_types_compatible_p (TREE_TYPE (t1),
> > > -                                             TREE_TYPE (t2),
> > > -                                             trust_type_canonical);
> > > + return gimple_canonical_types_compatible_p
> > > +          (TREE_TYPE (t1), TREE_TYPE (t2),
> > > +           flags & ~MATCH_WITH_INCOMPLETE_TYPE);
> > >  
> > >        return true;
> > >      }
> > > @@ -12804,12 +12819,20 @@
> > >      {
> > >      case ARRAY_TYPE:
> > >        /* Array types are the same if the element types are the same and
> > > -  the number of elements are the same.  */
> > > -      if (!gimple_canonical_types_compatible_p (TREE_TYPE (t1), 
> > > TREE_TYPE (t2),
> > > -                                         trust_type_canonical)
> > > +  the number of elements are the same.
> > > +
> > > +  When MATCH_WITH_INCOMPLETE_TYPE is set, bypass the check
> > > +  on number of elements.
> > > +  When recursing, clear MATCH_WITH_INCOMPLETE_TYPE because there is
> > > +  no way to make incomplete array of array.  */
> > > +      if (!gimple_canonical_types_compatible_p
> > > +      (TREE_TYPE (t1), TREE_TYPE (t2),
> > > +       flags & ~MATCH_WITH_INCOMPLETE_TYPE)
> > >     || TYPE_STRING_FLAG (t1) != TYPE_STRING_FLAG (t2)
> > >     || TYPE_NONALIASED_COMPONENT (t1) != TYPE_NONALIASED_COMPONENT (t2))
> > >   return false;
> > > +      else if (flags & MATCH_WITH_INCOMPLETE_TYPE)
> > > + return true;
> > >        else
> > >   {
> > >     tree i1 = TYPE_DOMAIN (t1);
> > > @@ -12848,11 +12871,19 @@
> > >      case METHOD_TYPE:
> > >      case FUNCTION_TYPE:
> > >        /* Function types are the same if the return type and arguments 
> > > types
> > > -  are the same.  */
> > > +  are the same.
> > > +  It is possible that function pointers have return values and parameters
> > > +  of incomplete types; permit that by not clearing
> > > +  MATCH_WITH_INCOMPLETE_TYPE  */
> > >        if (!gimple_canonical_types_compatible_p (TREE_TYPE (t1), 
> > > TREE_TYPE (t2),
> > > -                                         trust_type_canonical))
> > > +                                         flags))
> > >   return false;
> > >  
> > > +      /* We must permit a match between !prototype_p and prototype_p for
> > > +  functions; methods are never !prototype_p.  */
> > > +      if ((flags & MATCH_WITH_INCOMPLETE_TYPE)
> > > +   && TREE_CODE (t1) == FUNCTION_TYPE)
> > > + return true;
> > >        if (TYPE_ARG_TYPES (t1) == TYPE_ARG_TYPES (t2))
> > >   return true;
> > >        else
> > > @@ -12864,8 +12895,7 @@
> > >          parms1 = TREE_CHAIN (parms1), parms2 = TREE_CHAIN (parms2))
> > >       {
> > >         if (!gimple_canonical_types_compatible_p
> > > -              (TREE_VALUE (parms1), TREE_VALUE (parms2),
> > > -               trust_type_canonical))
> > > +              (TREE_VALUE (parms1), TREE_VALUE (parms2), flags))
> > >           return false;
> > >       }
> > >  
> > > @@ -12881,6 +12911,15 @@
> > >        {
> > >   tree f1, f2;
> > >  
> > > + /* C standrad require incomplete structures and unions to be
> > > +    considered compatible with complete ones regardless their TYPE_NAME
> > > +    when they come from different translation units.
> > > +    We must consider transitive closure here, so 
> > > +    every structure/union is equivalent to each other.  */
> > > +    
> > > + if (flags & MATCH_WITH_INCOMPLETE_TYPE)
> > > +   return true;
> > > +
> > >   /* For aggregate types, all the fields must be the same.  */
> > >   for (f1 = TYPE_FIELDS (t1), f2 = TYPE_FIELDS (t2);
> > >        f1 || f2;
> > > @@ -12897,8 +12936,7 @@
> > >       if (DECL_NONADDRESSABLE_P (f1) != DECL_NONADDRESSABLE_P (f2)
> > >           || !gimple_compare_field_offset (f1, f2)
> > >           || !gimple_canonical_types_compatible_p
> > > -               (TREE_TYPE (f1), TREE_TYPE (f2),
> > > -                trust_type_canonical))
> > > +               (TREE_TYPE (f1), TREE_TYPE (f2), flags))
> > >         return false;
> > >     }
> > >  
> > > @@ -12961,7 +12999,7 @@
> > >         with variably sized arrays because their sizes possibly
> > >         gimplified to different variables.  */
> > >      && !variably_modified_type_p (ct, NULL)
> > > -    && !gimple_canonical_types_compatible_p (t, ct, false))
> > > +    && !gimple_canonical_types_compatible_p (t, ct, 0))
> > >      {
> > >        error ("TYPE_CANONICAL is not compatible");
> > >        debug_tree (ct);
> > > Index: tree.h
> > > ===================================================================
> > > --- tree.h        (revision 223632)
> > > +++ tree.h        (working copy)
> > > @@ -4569,9 +4569,21 @@
> > >  extern unsigned int tree_map_base_hash (const void *);
> > >  extern int tree_map_base_marked_p (const void *);
> > >  extern void DEBUG_FUNCTION verify_type (const_tree t);
> > > -extern bool gimple_canonical_types_compatible_p (const_tree, const_tree,
> > > -                                          bool trust_type_canonical = 
> > > true);
> > >  
> > > +/* Flags used by gimple_canonical_types_compatible_p.  */
> > > +enum gimple_canonical_types_compatible_flags
> > > +  {
> > > +    /* Asume that TYPE_CANONICAL is set in a way that two types have
> > > +       the same canonical type if and only if
> > > +       gimple_canonical_types_compatible_p (t1,t2, 0) is true.  */
> > > +    MATCH_TYPE_CANONICAL = 1,
> > > +    /* Match all types as if they were incomplete.  */
> > > +    MATCH_WITH_INCOMPLETE_TYPE = 2
> > > +  };
> > > +extern bool gimple_canonical_types_compatible_p
> > > +    (const_tree, const_tree,
> > > +     unsigned int flags = MATCH_TYPE_CANONICAL);
> > > +
> > >  #define tree_map_eq tree_map_base_eq
> > >  extern unsigned int tree_map_hash (const void *);
> > >  #define tree_map_marked_p tree_map_base_marked_p
> > > 
> > > 
> > 
> > -- 
> > Richard Biener <rguent...@suse.de>
> > SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Dilip Upmanyu, 
> > Graham Norton, HRB 21284 (AG Nuernberg)
> 
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Dilip Upmanyu, Graham 
Norton, HRB 21284 (AG Nuernberg)

Reply via email to