[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 ) ; } } }