[Release b] <t4m_bug_vt_dtor> Mon Aug 2 17:42:19 WEST 2004 In the current release of tendra4minix (a), after fixing <t4m_bug_pure_virtual>, the program vt_dtor.C makes TenDRA emit the definition of the virtual table for class Alloc<Thread>, thus violating the ARM rule for defining virtual tables (this is done in the module containing the definition of the first non-implicit, non-inline, non-pure virtual function declared in the class). This rule is not contained in the spec X3J16/96-0225 WG21/N1043 (as far as I know), but the compiler is supposed to follow it. It is a nasty bug that causes duplicate definitions of virtual tables. If we place another virtual function before the declaration of Alloc destructor, export template <class N> class Alloc { public: virtual N *get(); virtual ~Alloc(); }; then the bug disappears. It only happens with destructors, never with ordinary virtual member functions. This bug is clearly related to the (supposedly fixed) <t4m_bug_vt>. In fact, this bug is more or less the same bug as <t4m_bug_vt>, that we have fixed only partially. The problem is again the function define_template [instance.c], which marks a template instance Alloc<Thread>::~Alloc() as being defined in the current compilation unit (dspec_defn flag), without knowing if it is really defined. The function in charge of clearing this spurious flag is copy_template [instance.c]. What is happening is that compile_virtual [output/compile.c] is being called before the invocation of copy_template [instance.c] takes place (this invocation is made because the compiler is emitting the virtual table for class ThreadAlloc, and checks if ThreadAlloc has any base class whose virtual table needs to be emitted, but all this is ok). compile_virtual [output/compile.c] thinks that the destructor is defined, and so it is the first non-implicit, non-inline, non-pure virtual function that is declared and defined in this compilation unit, and this means it must emit the virtual table for Alloc<Thread> in this compilation unit. The bug disappears when we add the virtual function Alloc<N>::get because this function is never used, and so define_template does not get called on it. In summary, the problem is the stupid function define_template [instance.c]. Since my patience is exhausting, the only fix I can propose now is to adapt the solution to bug <t4m_bug_vt> in this way: inside define_template, call copy_template unconditionally in the case of functions, that is, we change /* Template functions */ if ( !( ds & dspec_defn ) ) { CONS_id ( id, pending_templates, pending_templates ) ; COPY_dspec ( id_storage ( id ), ( ds | dspec_defn ) ) ; COPY_loc ( id_loc ( id ), crt_loc ) ; if ( all_templates_cleared ) { copy_template ( id, 1 ) ; } } for /* Template functions */ if ( !( ds & dspec_defn ) ) { CONS_id ( id, pending_templates, pending_templates ) ; COPY_dspec ( id_storage ( id ), ( ds | dspec_defn ) ) ; COPY_loc ( id_loc ( id ), crt_loc ) ; copy_template ( id, all_templates_cleared ) ; } This fixes the bug, but I warn that I am not sure about its consequences. PS. As I suspected, this breaks the compilation of S-Lisp in several places, so I have undone this wrong solution. I have also undone the solution to <t4m_bug_vt>, and now I propose this simpler solution to both bugs: in the function compile_virtual [output/compile.c], use the field id_function_etc_defn instead of the dspec_defn flag to check whether a function is defined in the current compilation unit, change line 1579 if ( ds & dspec_defn ) { for EXP e = DEREF_exp ( id_function_etc_defn ( fn ) ) ; if ( !IS_NULL_exp ( e ) ) { This seems to fix both bugs and, until now, it hasn't produced any other consequence.