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;
}