SourceForge.net Logo

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