------- Additional Comments From uweigand at gcc dot gnu dot org  2005-09-29 
23:52 -------
I've found some time to look a bit more into this.  First of all, here's
a much reduced test case:

procedure CXB4005 is
   type Alphanumeric is array (Positive range <>) of Character;
   TC_Alphanumeric : Alphanumeric(1..1);
begin
   TC_Alphanumeric := "A";
   pragma Assert (TC_Alphanumeric = "A");
end CXB4005;

The assertion fails when built with -O2 -gnata.

The comparsion TC_Alphanumeric = "A" gets translated by the front
end into this tree (02.original):

  if (VIEW_CONVERT_EXPR<character[1:1]>(tc_alphanumeric) != "A")

which get gimplified into (03.generic):

  tc_alphanumeric.0 = (character[1:1] *) &tc_alphanumeric;
  tc_alphanumeric.1 = (const <unnamed type> *) tc_alphanumeric.0;
  D.388 = *tc_alphanumeric.1;
  D.389 = (integer) D.388;
  D.390 = (const <unnamed type> *) "A";
  D.391 = *D.390;
  D.392 = (integer) D.391;
  D.393 = D.389 - D.392;
  if (D.393 != 0)

This transformation happens because an NE_EXPR of array types
is handled by gimplify_variable_sized_compare, which converts
it into an implicit call to memcmp.  This call (with length 1)
is then transformed by fold_builtin_memcmp into the computation
of the difference of the two bytes.

This is done in fold_builtin_memcpy by casting the addresses
to an 'const unsigned char *' and dereferencing that expression,
where that type is constructed as a variant of the predefined
unsigned_char_type_node.  (This type shows up in the above
listings as 'const <unnamed type> *'.)

Now, when the so-casted expression is dereferenced, we obviously
get into aliasing issues.  This works fine in C-based languages,
because there 'unsigned char' is explicitly allowed to alias any
other type -- the fold_builtin_memcpy code is correct really only
when making that assumption.

However, in Ada there is no such special case, and the Ada hook
for get_alias_set does not handle unsigned_char_type_node at all.
Thus the type gets assigned a fresh alias set (that aliases 
nothing at all since the type didn't otherwise occur).


I guess this is really a bug in fold_builtin_memcpy, but I'm not
sure what exactly the proper fix would be.  As a workaround, I've
added the "C-style" treatment of 'char' to the Ada get_alias_set,
and this fixes the symptom as well.  The patch for this is:

Index: gcc/ada/misc.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/ada/misc.c,v
retrieving revision 1.106
diff -c -p -r1.106 misc.c
*** gcc/ada/misc.c      4 Jul 2005 13:27:09 -0000       1.106
--- gcc/ada/misc.c      29 Sep 2005 23:34:18 -0000
*************** gnat_get_alias_set (tree type)
*** 713,718 ****
--- 713,725 ----
      return
        get_alias_set (TREE_TYPE (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (type)))));

+   /* ??? The middle end occasionally generates 'char' types by itself
+      and implicitly assumes they are allowed to alias everything.  One
+      example is fold_builtin_memcmp, causing PR 19382.  */
+   if (type == char_type_node
+       || type == signed_char_type_node
+       || type == unsigned_char_type_node)
+     return 0;

    return -1;
  }

-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=19382

Reply via email to