This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: aliasing warnings [patch]
- To: law at cygnus dot com
- Subject: Re: aliasing warnings [patch]
- From: Zack Weinberg <zack at bitmover dot com>
- Date: Sat, 25 Sep 1999 13:42:50 -0700
- Cc: egcs at egcs dot cygnus dot com
- References: <5911.938286131@upchuck.cygnus.com>
Jeffrey A Law wrote:
> In message <199909240006.RAA28376@atrus.synopsys.com>you write:
> > Someone mentioned that DEC's compiler issues warnings of this type
> > and that's how the Perl team became aware of the issue. The above
> > approach seems like a clean way to get such warnings, for the case
> > where all the code is in the same function.
> >
> > The RMS variant (sure to be contoversial) would be to put a pointer with
> > this tag into alias set 0 (it can alias everything).
> I haven't thought a lot about the implications of this, but at first glance
> it's not a bad idea.
>
> It should achieve RMS's goal of having old broken code still work without a
> severe impact on most conforming code.
>
> It's behavior should be consistent over time and we should be able to
> document the behavior.
>
> I don't know how difficult this is from a technical standpoint, but it is
> probably worth some investigation.
Hmm... well, check this patch out. It isn't necessary to add another
slot to every tree node, which is a relief. It nails my test case
dead on, but generates a pile of complaints about libgcc which I'm not
sure if they're spurious or not yet.
Patch:
Index: c-typeck.c
===================================================================
RCS file: /cvs/egcs/egcs/gcc/c-typeck.c,v
retrieving revision 1.39
diff -u -p -r1.39 c-typeck.c
--- c-typeck.c 1999/09/22 05:51:44 1.39
+++ c-typeck.c 1999/09/25 20:45:08
@@ -1217,6 +1217,7 @@ build_indirect_ref (ptr, errorstring)
else
{
tree t = TREE_TYPE (type);
+ tree orig_t, field = 0;
register tree ref = build1 (INDIRECT_REF,
TYPE_MAIN_VARIANT (t), pointer);
@@ -1228,16 +1229,44 @@ build_indirect_ref (ptr, errorstring)
if (TREE_CODE (t) == VOID_TYPE && skip_evaluation == 0)
warning ("dereferencing `void *' pointer");
- /* We *must* set TREE_READONLY when dereferencing a pointer to const,
- so that we get the proper error message if the result is used
- to assign to. Also, &* is supposed to be a no-op.
- And ANSI C seems to specify that the type of the result
- should be the const type. */
- /* A de-reference of a pointer to const is not a const. It is valid
- to change it via some other pointer. */
+ /* If we are dereferencing a pointer through a cast to some
+ other type, check that the type of the pointer and the
+ type of the object pointed to are compatible alias-wise. */
+
+ orig_t = pointer;
+ while (TREE_CODE_CLASS (TREE_CODE (orig_t)) == 'e'
+ && TREE_CODE (orig_t) != ADDR_EXPR
+ && TREE_CODE (orig_t) != REFERENCE_EXPR)
+ orig_t = TREE_OPERAND (orig_t, 0);
+
+ orig_t = TREE_TYPE (orig_t);
+
+ if (TREE_CODE (t) == UNION_TYPE && !pedantic)
+ {
+ for (field = TYPE_FIELDS (type); field;
+ field = TREE_CHAIN (field))
+ if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (field)),
+ TYPE_MAIN_VARIANT (TREE_TYPE (orig_t))))
+ break;
+ }
+
+ if (!(get_alias_set (t) == get_alias_set (orig_t)
+ || TYPE_MAIN_VARIANT (t) == char_type_node
+ || TYPE_MAIN_VARIANT (orig_t) == char_type_node
+ || TREE_CODE (orig_t) == VOID_TYPE || field))
+ warning ("dereferencing pointer to type T which points at value of type U");
+
+ /* We *must* set TREE_READONLY when dereferencing a pointer
+ to const, so that we get the proper error message if the
+ result is used to assign to. Also, &* is supposed to be
+ a no-op. And ANSI C seems to specify that the type of
+ the result should be the const type. */
+ /* A de-reference of a pointer to const is not a const. It
+ is valid to change it via some other pointer. */
TREE_READONLY (ref) = TYPE_READONLY (t);
TREE_SIDE_EFFECTS (ref)
- = TYPE_VOLATILE (t) || TREE_SIDE_EFFECTS (pointer) || flag_volatile;
+ = TYPE_VOLATILE (t) || TREE_SIDE_EFFECTS (pointer)
+ || flag_volatile;
TREE_THIS_VOLATILE (ref) = TYPE_VOLATILE (t);
return ref;
}
Test case:
extern int printf(char *, ...);
double foo0(double d)
{
double d2 = d;
((unsigned long *)&d2)[1] |= 0x80000000;
return d2;
}
double foo1(double d)
{
double d2 = d;
unsigned long *l = (unsigned long *)&d2;
l[1] |= 0x80000000;
return d2;
}
double foo2(double d)
{
union u
{
double D;
unsigned long L[2];
};
double d2 = d;
((union u *)&d2)->L[1] |= 0x80000000;
return d2;
}
int main(void)
{
double x = 1.1234;
double a, b, c;
a = foo0(x);
b = foo1(x);
c = foo2(x);
printf("%f %f %f %f\n", x, a, b, c);
return 0;
}
Effect:
$ ./xgcc -B./ -O2 test.c
test.c: In function `foo0':
test.c:6: warning: dereferencing pointer to type T which points at value of type U
test.c: In function `foo1':
test.c:15: warning: dereferencing pointer to type T which points at value of type U
$ ./a.out
1.123400 1.123400 1.123400 -1.123400
$ ./xgcc -B./ -O2 -fno-strict-aliasing test.c
$ ./a.out
1.123400 -1.123400 -1.123400 -1.123400
The text of the warning is lame, but we're not going to be able to do
much better until we make cp/errors.c be usable by the C front end - I
may look at this but no promises.
zw