
[Release b]
<t4m_bug_const_dflt>
Thu Jul 15 10:44:44 WEST 2004
In the current release of tendra4minix (a), after fixing <t4m_bug_usage>,
the program
int m;
void ini(const int n = 7) { m = n; }
produces this assembler output,
.sect .text; .sect .rom; .sect .data; .sect .bss
.sect .data
.extern _m__i
.comm _m__i, 4
.sect .text
.define _ini__Fi
.align 16
_ini__Fi:
mov (_m__i), 7
ret
.sect .text
and this TDF output,
TAG DECLARATIONS
m__i (variable) has access : -
. and signature : -
. and shape : integer(~signed_int*)
ini__Fi (identity) has access : -
. . and signature : -
. . and shape : proc
TAG DEFINITIONS
m__i (variable) is :
access : -
signature : -
make_int(~signed_int*,0)
ini__Fi (identity) is :
signature : -
make_proc(top,
. |make_proc_arg(integer(~signed_int*),
. . |-,
. . |~tag_2),
. |-,
. |sequence(assign(obtain_tag(m__i),
. . . |make_int(~signed_int*,7)),
. . |return(make_top)))
(so it is a problem in the frontend).
This bug happens also with member functions, both virtual and non-virtual,
with member functions of class templates, exported or not, and even in
functions expanded inline (both the expansion and the non-expanded function
body suffer from this `constant propagation'). It also appears when declaring
function ini previously,
int m;
void ini(const int = 7);
int main() { ini(19); return 0; }
void ini(const int n) { m = n; }
Finally it happens even with pointers; this program
int *nptr;
void ini(int *const p = 0) { nptr = p; }
produces this assembler output,
.sect .text; .sect .rom; .sect .data; .sect .bss
.sect .data
.extern _nptr__Pi
.comm _nptr__Pi, 4
.sect .text
.define _ini__FPi
.align 16
_ini__FPi:
xor eax, eax
mov (_nptr__Pi), eax
ret
.sect .text
The problem does not show up with non-const parameters. It is not difficult
to imagine what's going on: the compiler is probably confusing the parameter
'n' with a const-declared variable. Here is a call-trace starting from the
function make_assign_exp [assign.c], called from the parser,
make_assign_exp, a = m :: exp_identifier_tag, b = n :: exp_identifier_tag,c = 0
convert_reference, a = m :: exp_identifier_tag, context = 0
convert_reference: returning d = m :: exp_identifier_tag
convert_reference, a = n :: exp_identifier_tag, context = 2
convert_reference: returning d = n :: exp_identifier_tag
convert_assign, t = int :: type_integer_tag, a = n :: exp_identifier_tag
cast_exp, t = int :: type_integer_tag, a = n :: exp_identifier_tag,cast = 0
convert_lvalue, a = n :: exp_identifier_tag
convert_const, a = n :: exp_identifier_tag
/* Propagate simple constants */
convert_const: returning d = 7 :: exp_int_lit_tag
convert_lvalue: returning d = 7 :: exp_int_lit_tag
cast_int_int, t = int :: type_integer_tag, a = 7, cast = 0, rank = -1
cast_int_int: returning d = 7 :: exp_int_lit_tag
cast_exp: returning d = 7 :: exp_int_lit_tag
convert_assign: returning d = 7 :: exp_int_lit_tag
make_preinc_exp, t = int, a = m :: exp_identifier_tag, b = 7, op = lex_assign
make_preinc_exp: returning d = <exp> :: exp_assign_tag
make_assign_exp: returning d = <exp> :: exp_assign_tag
The problem lies in function convert_lvalue [convert.c]; it calls function
convert_const [convert.c] no matter what sort of identifier it is dealing with
(id_variable_tag, id_parameter_tag, etc.),
/* Lvalue-to-rvalue conversion */
ERROR err ;
if ( qual == ( cv_const | cv_lvalue ) ) {
/* Check for constants at this stage */
if ( IS_exp_identifier ( a ) ) {
e = convert_const ( a ) ;
if ( !EQ_exp ( e, a ) ) return ( e ) ;
}
}
Needless to say, the meaning of the keyword 'const' in function parameters is
not that of a "compilation constant", and its value is not necessarily the
default argument. To fix this bug, it will suffice to replace the lines above
with
/* Lvalue-to-rvalue conversion */
ERROR err ;
if ( qual == ( cv_const | cv_lvalue ) ) {
/* Check for constants at this stage */
if ( IS_exp_identifier ( a ) ) {
IDENTIFIER id = DEREF_id ( exp_identifier_id ( a ) ) ;
/* Exclude const parameters and their default args. */
if ( !IS_id_parameter ( id ) ) {
e = convert_const ( a ) ;
if ( !EQ_exp ( e, a ) ) return ( e ) ;
}
}
}