[Release b] <t4m_bug_templ_dflt> Tue Jun 8 21:04:16 WEST 2004 In the current release of tendra4minix (a), after fixing <t4m_bug_nonexport>, the compilation of the file templ_dflt_r.C, template <class T> void g(const T &e = 0) {} int main() { g<int>(); return 0; } produces this error "/usr/local/lib/TenDRA/machines/minix/2.0/80x86/startup/cpp.h", line 2: Error: [Token]: Identifier 'T' used out of scope. The same error is produced with this variant, template <class T> void g(const T &e = 0) {} int main() { g(1); return 0; } It is the error ERR_token_scope, and it is being reported in the function enc_tokdef [common/output/compile.c]. The problem disappears when the default argument is removed. In general, the error is generated in similar programs when the type of the argument 'e' depends on a template parameter, as (for another example) in the program templ_dflt_c.C, template <class T> class H { T h; public: H(const T &t) : h(t) {} }; template <class T> void g(H<T> e = 0) {} template <class T> void f(T t) { g<T>(t); } int main() { f(1); return 0; } "/usr/local/lib/TenDRA/machines/minix/2.0/80x86/startup/cpp.h", line 2: Error: [Token]: Identifier 'T' used out of scope. As before, the problem disappears when the default argument is removed. Note that in this case the function 'g' is called with explicit instantiation. [Note: if we remove the explicit instantiation <T> from the call 'g<T>(t);', then overload resolution fails: "templ_dflt_c.C", line 7: Error: [ISO 14.7.1]: In instantiation of template 'f < int >' (at line 8). [ISO 13.3.2]: None of the overloaded functions 'g' is viable for given call. [ISO 14.8.2]: Template argument deduction failed for 'template < class T > void g ( H < T > = <exp12> )'. but it also fails in the same way with GCC-2.95.3, templ_dflt_c.C: In function `void f<int>(int)': templ_dflt_c.C:8: instantiated from here templ_dflt_c.C:7: no matching function for call to `g (int &)' End note.] I have been making a detailed call trace of the compilation, and the problem lies in the function init_param [initialise.c], which is invoked directly from the parser to build a temporary variable that gets initialized with a cast from the value '0' (of type 'int') to the type 'T' (which is the type of this temporary). A summary of the call tree follows, init_param, id = e, TAG_exp(e) = 4 init_object, id = e, TAG_exp(e) = 4 init_general, t = const T &, e = 0, TAG_exp(e) = 4, id = e, tentative = 0 init_assign, t = const T &, TAG_type(t) = 6, cv = 0, e = 0, TAG_exp(e) = 4 init_assign, t = const T, TAG_type(t) = 13, cv = 0, e = 0, TAG_exp = 4 cast_exp, t = const T, TAG_exp(a) = 4, cast = 0 cast_templ_type, t = const T, TAG_exp(a) = 4, cast = 0 cast_templ_type: returning, TAG_exp = 80 cast_exp: returning, TAG_exp = 80 init_assign: returning, TAG_exp = 80 make_temporary, t = const T, TAG_type(t) = 13, TAG_exp(e) = 80 make_temporary: returning ("templ_dflt_r.C":1), TAG_exp = 0 make_ref_init, t = const T &, e = ("templ_dflt_r.C":1), TAG_exp(e) = 0 make_ref_init: returning ("templ_dflt_r.C":1), TAG_exp(d) = 0 init_assign: returning ("templ_dflt_r.C":1), TAG_exp = 0 init_general: returning ("templ_dflt_r.C":1), TAG_exp = 0 init_object: returning 1 init_param: returning But this initialization can not be done during the template analysis, as usual, since the functions that are in charge of instantiating the templates are not intended to copy the temporary variable and expand its type. The correct initialization will take place afterwards, in the function expand_func_type [token.c], called by expand_type [token.c] during the execution of instance_func [instance.c]. To fix this, we prevent init_param [initialise.c] from calling the function init_object [initialise.c] when either the parameter type or the initializer depend on a parameter of the current template; we change } else { in_default_arg++ ; IGNORE init_object ( id, e ) ; in_default_arg-- ; } for } else if ( in_template_decl && ( is_templ_depend ( DEREF_type ( id_parameter_type ( id ) ) ) || depends_on_exp ( e, any_templ_param, 0 ) ) ) { COPY_exp ( id_parameter_init ( id ), e ) ; } else { in_default_arg++ ; IGNORE init_object ( id, e ) ; in_default_arg-- ; }