Opened 8 months ago

Closed 5 days ago

#287 closed defect (fixed)

Incorrect Typeof on Array Index

Reported by: ajbeach Owned by:
Priority: major Component: cfa-cc
Version: 1.0 Keywords:
Cc:

Description

This is a follow up to #286. They exact relation between them is unclear. I discovered them on the same line of code, I believe they were just "hidden" until now in the same way.

Here is the reproduction:

#define SIZE 2
char array[SIZE];

// Passes
_Static_assert(SIZE == sizeof(array) / sizeof(array[0]), "0a");

// Fails 
_Static_assert(SIZE == sizeof(typeof(array)) / sizeof(typeof(array[0])), "1a");

// Fails (second typeof is the one) 
_Static_assert(SIZE == sizeof(array) / sizeof(typeof(array[0])), "2a");

// Passes 
_Static_assert(SIZE == sizeof(typeof(array)) / sizeof(array[0]), "3a");

Having looked at the post translation cases, the sizeof on array[0] does nothing (other than resolving the expression) while adding the typeof reduces it to the resolved type. If the resolved type was correct, this would make no difference, but it is resolved incorrectly to be a pointer to the element type instead of the element type itself.

I believe that making typeof resolve correctly is the only full solution, but delaying the reduction to C will solve this case.

Oh, and here are some extra cases that help show exactly what the error is.

// Here are just the same patterns (0c, 1b, 2b, 3c fail)
_Static_assert(sizeof(char) == sizeof(array[0]), "0b");
_Static_assert(sizeof(void *) == sizeof(array[0]), "0c");
_Static_assert(sizeof(typeof(char)) == sizeof(typeof(array[0])), "1b");
_Static_assert(sizeof(typeof(void *)) == sizeof(typeof(array[0])), "1c");
_Static_assert(sizeof(char) == sizeof(typeof(array[0])), "2b");
_Static_assert(sizeof(void *) == sizeof(typeof(array[0])), "2c");
_Static_assert(sizeof(typeof(char)) == sizeof(array[0]), "3b");
_Static_assert(sizeof(typeof(void *)) == sizeof(array[0]), "3c");

Change History (2)

comment:1 Changed 8 months ago by ajbeach

I think I figured it out while/immediately after writing this.

In the prelude the signature of the function is being called is:

forall(DT & | sized(DT)) DT & ?[?](ptrdiff_t, DT *);

All of the intrinsic index operators look like this (with the possible inclusion of cv qualifiers or an argument order swap). And you may see the problem, the return type is a reference. So the type of the expression (in the examples) in fact "char &". This is then lowered to C via reference to pointer conversion and becomes "char *".

Hence, I think this isn't an implementation bug, but an unnoticed incompatibility with C.

comment:2 Changed 5 days ago by ajbeach

Resolution: fixed
Status: newclosed

This was fixed a while ago.

Cforall behaviour was changed to be compatible with C. As I recall, sizeof/alignof now ignore references and give the size of the underlying type; while typeof still returns a reference type.

Now if you run it the "c" cases are the only ones that fail (void * is not the same size as char so that is fine) and the assertions pass.

Note: See TracTickets for help on using tickets.