Bug (?) in initialization code.
Brad Lucier
lucier@math.purdue.edu
Mon Mar 20 19:22:00 GMT 2000
The code that needs to be changed to fix this seems to begin at line
4104 of varasm.c; see the analysis below. But I don't know how to fix it.
Ivan Kokshaysky was kind enough to point me to the REFLONG relocations
in the loader, which does what I want, loads the lower 32 bits of a pointer
at load time; see elf64_alpha_howto_table in bfd/elf64-alpha.c in the
binutils source.
Compiling the following program actually bombs at line 5847 in c-typeck.c:
else if (require_constant_elements
&& initializer_constant_valid_p (value, TREE_TYPE (value)) == 0)
{
error_init ("initializer element is not computable at load time");
value = error_mark_node;
}
TREE_TYPE(value) is a union type, but the most likely candidate for the
type seems to be:
common = {
chain = 0x0,
type = 0x0,
code = INTEGER_TYPE,
side_effects_flag = 0,
constant_flag = 0,
permanent_flag = 0,
addressable_flag = 0,
volatile_flag = 0,
readonly_flag = 0,
unsigned_flag = 0,
asm_written_flag = 0,
used_flag = 0,
nothrow_flag = 0,
static_flag = 0,
public_flag = 0,
private_flag = 0,
protected_flag = 0,
lang_flag_0 = 0,
lang_flag_1 = 0,
lang_flag_2 = 0,
lang_flag_3 = 0,
lang_flag_4 = 0,
lang_flag_5 = 0,
lang_flag_6 = 0
},
It seems that value is a pointer to the following union element:
common = {
chain = 0x0,
type = 0x2000002a700,
code = NOP_EXPR,
side_effects_flag = 2,
constant_flag = 2,
permanent_flag = 2,
addressable_flag = 2,
volatile_flag = 2,
readonly_flag = 2,
unsigned_flag = 2,
asm_written_flag = 2,
used_flag = 0,
nothrow_flag = 0,
static_flag = 0,
public_flag = 0,
private_flag = 0,
protected_flag = 0,
lang_flag_0 = 0,
lang_flag_1 = 0,
lang_flag_2 = 0,
lang_flag_3 = 0,
lang_flag_4 = 0,
lang_flag_5 = 0,
lang_flag_6 = 0
},
and the code in varasm.c that handles this case seems to begin at line
4072:
case CONVERT_EXPR:
case NOP_EXPR:
/* Allow conversions between pointer types. */
if (POINTER_TYPE_P (TREE_TYPE (value))
&& POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
/* Allow conversions between real types. */
if (FLOAT_TYPE_P (TREE_TYPE (value))
&& FLOAT_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
/* Allow length-preserving conversions between integer types. */
if (INTEGRAL_TYPE_P (TREE_TYPE (value))
&& INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0)))
&& (TYPE_PRECISION (TREE_TYPE (value))
== TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
/* Allow conversions between other integer types only if
explicit value. */
if (INTEGRAL_TYPE_P (TREE_TYPE (value))
&& INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
{
tree inner = initializer_constant_valid_p (TREE_OPERAND (value, 0),
endtype);
if (inner == null_pointer_node)
return null_pointer_node;
break;
}
/* Allow (int) &foo provided int is as wide as a pointer. */
if (INTEGRAL_TYPE_P (TREE_TYPE (value))
&& POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0)))
&& (TYPE_PRECISION (TREE_TYPE (value))
>= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
return initializer_constant_valid_p (TREE_OPERAND (value, 0),
endtype);
/* Likewise conversions from int to pointers, but also allow
conversions from 0. */
if (POINTER_TYPE_P (TREE_TYPE (value))
&& INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
{
if (integer_zerop (TREE_OPERAND (value, 0)))
return null_pointer_node;
else if (TYPE_PRECISION (TREE_TYPE (value))
<= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0))))
return initializer_constant_valid_p (TREE_OPERAND (value, 0),
endtype);
}
/* Allow conversions to union types if the value inside is okay. */
if (TREE_CODE (TREE_TYPE (value)) == UNION_TYPE)
return initializer_constant_valid_p (TREE_OPERAND (value, 0),
endtype);
break;
So it seems that we should allow (int) &foo for alpha.c even though
int is 32 bits and a pointer is 64, if I will use the -taso switch
with ld (which Kokshaysky says is OK). Also for conversion from
int->pointers.
Brad Lucier
>
> The following program:
>
> /* compile with gcc -c foo.c on alpha */
>
> typedef int int32;
> typedef long int64;
>
> typedef struct { int a; int b; } foo;
>
> extern foo f;
>
> static int32 tbl1[] =
> {
> (int32) &f
> };
>
> static int64 tbl2[] =
> {
> (int64) &f
> };
>
> static foo* tbl3[] =
> {
> &f
> };
>
> compiled on alphaev6 with any gcc version I tried from 2.95.1 on
> bombs and gives the following error message:
>
> foo.c:13: initializer element is not computable at load time
> foo.c:13: (near initialization for `tbl1[0]')
>
> The problem seems to be that gcc thinks the loader cannot stuff
> a 64bit pointer into a 32bit int at load time.
>
> I intend to use the -taso flag with ld 2.9.5.0.27 (H. J. Lu's release).
>
> So, the questions:
>
> 1. Can the loader handle this construct correctly, given the -taso flag?
> 2. Should gcc allow this construct?
More information about the Gcc-bugs
mailing list