﻿id	summary	reporter	owner	description	type	status	priority	component	version	resolution	keywords	cc
247	Wrong result type for sizeof(-)	mlbrooks		"The result type of a sizeof(-) expression should be size_t, but it is currently long unsigned int.  The difference is observable on 32-bit builds, including on a plain C example.

Our definition of size_t is taken from the host C installation's <stddef.h> and is, therefore, above reproach.

This definition has:

-m32
typedef unsigned int size_t;

-m64
typedef long unsigned int size_t;

C11 Reference Manual, pg 90 has:
""The value of the result of [sizeof] is implementation-defined, and its type (an unsigned integer type) is size_t, defined in <stddef.h> (and other headers).""

Present state has sizeof(-) returning type long unsigned int, always, which is correct for 64-bit and incorrect for 32-bit:

{{{
// CFA

// expect: collision always
// actual: collision 64-bit only
void f1( size_t ) {}
void f1( typeof( sizeof( 42 ) ) ) {}

// expect: collision 32-bit only
// actual: collision never
void f2( unsigned int ) {}
void f2( typeof( sizeof( 42 ) ) ) {}

// expect: collision 64-bit only
// actual: collision always
void f3( long unsigned int ) {}
void f3( typeof( sizeof( 42 ) ) ) {}
}}}

While it is true that the types unsigned int and long unsigned int are the same size on 32-bit, they are still different types:

{{{
// C

#include <stddef.h>

int main( int argc, char ** argv ) {
    unsigned int val = 0;
    long unsigned int lval = 0;

    unsigned int * p = & lval;
    long unsigned int * lp = &val;
}
}}}
GCC, actual and expected, 32- and 64-bit: initialization of ‘unsigned int *’ from incompatible pointer type ‘long unsigned int *’; initialization of ‘long unsigned int *’ from incompatible pointer type ‘unsigned int *’

Typing the sizeof expression in this way means CFA is unable to compile the following valid C program:

{{{
// C

#include <stddef.h>

int main( int argc, char ** argv ) {
    typeof( sizeof( 42 ) ) val = 0;
    size_t * p = & val;
}
}}}
GCC, 64-bit:  Success
GCC, 32-bit:  Success
CFA, 64-bit:  Success
CFA, 32-bit:  Fail

Typing the sizeof expression in this way means CFA incurs unintuitive conversion costs in sizeof-vs-size_t overloading scenarios, which leads to unexpected ambiguity:

{{{
// CFA

void foo( size_t ) {
    printf(""foo, unsigned\n"");
}

void foo( ptrdiff_t ) {
    printf(""foo, signed\n"");
}

int main(int argc, char** argv) {
    printf(""size of long int: %ld\n"", sizeof(long int));
    foo( sizeof(float) );       // sizeof => size_t
    foo( ""hello"" - ""world"" );   // difference of pointers => ptrdiff_t
}
}}}
CFA, 64-bit, actual and expected:  Compiler success with program output:
{{{
size of long int: 8
foo, unsigned
foo, signed
}}}
CFA, 32-bit, actual:  Compiler error.  Ambiguity at foo(sizeof(float)), having resolved type unsigned long int, between the two declarations, both showing 1 unsafe conversion cost.

CFA, 32-bit, expected:  Compiler success with program output:
{{{
size of long int: 4
foo, unsigned
foo, signed
}}}


Initial investigation into the feasibility of changing the sizeof type found:
- SizeofExpr gets its result type set by its default constructor, and so the ""unsigned int"" decision made at the conclusion of parsing.  It is visible with -XCFA -p -XCFA -P -XCFA ast.
- Validate/FindSpecialDecls.h populates the size_t type into a global variable.
- To fix, consider deferring the result-type decision from parse time until after Validate::findSpecialDecls, and using the type from the global variable.
- There is no equivalent problem with ptrdiff_t being introduced by subtracting pointers, because that operator is given in the prelude, with the expected ptrdiff_t return type.  The difficulty is introduced by the compiler-provided handling of sizeof, taken with the input-provided definition of size_t.
"	defect	closed	minor	cfa-cc	1.0	fixed		
