[Release a] <t4m_bug_templvirtini> Virtual base pointers are not correctly initialized when some initializer for an intermediate class (not the virtual base) is called with arguments that depend (value-wise or type-wise) on template parameters. Schematically, class B : public virtual A { /* ... */ }; template <int N> class C : public B { C() : A(), B(N) { /* ... */ } }; Note that the initializer B(N) takes an argument that is a template parameter. There is an extra hidden argument that is passed to constructors to tell them whether they must skip (extra = 0) initialization of virtual bases (see add_constr_args, line 608 of src/producers/common/construct/construct.c); this is necessary because the initialization must be performed only once, in the constructor for class C, so that the virtual subobject A can be placed after the end of class C data members. Now, in the present case, this argument is wrong (extra = 1), and the constructor for class B invokes the constructor for class A for a second time, re-initializing its virtual base pointer to A to point to the end of its own data members, which is exactly the place where the data members of C are located, and thus the subobjects A and C lie overlapped in memory. The program AB.C illustrates this problem. The constructor for class A gets called twice, and the data members A::a and C::c[0] both have the same address in memory. The origin of the problem is the static flag in_ctor_base_init (line 597 of src/producers/common/construct/construct.c). This flag is raised by ctor_initialise (line 1685) when it is generating the initializer list for a constructor. But the task of ctor_initialise will not be finished when the initializer depends on template parameters. At line 2607, the function convert_constr (called by init_constr, which is called by init_general, which is called by ctor_initialise) checks if the initializer depends on template parameteres and, in that case, it avoids constructing the call: it converts the initializer to a static cast expression[1] to be evaluated later on, forgetting about the flag in_ctor_base_init. When the template constructor gets instantiated, it is the function apply_nary (line 532, operator.c) who calls convert_constr again, but at this time the flag in_ctor_base_init is totally forgotten, which makes add_constr_args pass the (wrong) argument extra = 1 to the constructor for class B. [1] This is suggested by the spec X3J16/96-0225, section 5.2.9, [expr.static.cast], paragraph 2. To fix this, what I have done is to create a new operator for internal use only, called templ_virtual_init (see MAKE_exp_opn in file src/producers/common/obj_c/exp_ops.h) defined en construct.h. This operator is handled exactly in the same way as lex_static_Hcast except in two places in the code: (1) in function convert_constr, if in_ctor_base_init is true, then the initializer is converted to an expression based on the new operator templ_virtual_init, instead of lex_static_Hcast; (2) in function apply_nary, the operator templ_virtual_init is handled in a manner similar to the way lex_static_Hcast is handled, but raising the flag in_ctor_base_init before calling convert_constr. In this way, the operator templ_virtual_init keeps record of the activation of the flag in_ctor_base_init. In order to implement this idea, the following modifications need to be done (all file names are relative to src/producers/common/construct/): ( ) construct.h, add the macro #define templ_virtual_init 1053 ( ) construct.c, line 2609, inside function convert_constr, change MAKE_exp_opn ( t, lex_static_Hcast, args, e ) ; for MAKE_exp_opn ( t, in_ctor_base_init ? templ_virtual_init : lex_static_Hcast, args, e ) ; ( ) construct.c, line 597, export in_ctor_base_init, change static int in_ctor_base_init = 0 ; for int in_ctor_base_init = 0 ; ( ) operator.c, line 587, inside function apply_nary, add the case case templ_virtual_init : { /* Construct 't2 ( p0, ..., pn )' initializer with virtual bases */ ERROR err = NULL_err ; int icbi = in_ctor_base_init ; in_ctor_base_init = 1 ; if ( cpy ) p = copy_exp_list ( p, t1, t2 ) ; p = convert_args ( p ) ; e = convert_constr ( t2, p, &err, CAST_STATIC ) ; in_ctor_base_init = icbi ; if ( !IS_NULL_err ( err ) ) report ( crt_loc, err ) ; break ; } ( ) operator.c, before function apply_nary (line 530), declare in_ctor_base_init, extern int in_ctor_base_init ; ( ) operator.c, line 346, inside function apply_unary (I am not sure if this is necessary, but it will not hurt), add a fall-through for templ_virtual_init, case templ_virtual_init : case lex_static_Hcast : ( ) cast.c, line 1769, inside function make_new_cast_exp (this is tied to the previous case, and again I am not sure whether it is necessary), add a fall-through for templ_virtual_init, case templ_virtual_init : case lex_static_Hcast : { e = make_static_cast_exp ( t, a, n ) ; break ; } By treating templ_virtual_init in the same way as lex_static_Hcast, we are making sure that we are not introducing new bugs.