https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88114
Tobias Burnus <burnus at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |jason at gcc dot gnu.org --- Comment #1 from Tobias Burnus <burnus at gcc dot gnu.org> --- The reason that the presence of a single virtual ... = 0; will remove the 'virtual ~One() = default' seems to be the following code in cp/class.c's build_vtbl_initializer (added in r208845 in 2014): /* Don't refer to a virtual destructor from a constructor vtable or a vtable for an abstract class, since destroying an object under construction is undefined behavior and we don't want it to be considered a candidate for speculative devirtualization. But do create the thunk for ABI compliance. */ if (DECL_DESTRUCTOR_P (fn_original) && (CLASSTYPE_PURE_VIRTUALS (DECL_CONTEXT (fn_original)) || orig_binfo != binfo)) init = size_zero_node; That affects the code generation via cp/decl2.c's maybe_emit_vtables() which calls mark_needed() for all non-size_zero_node items. In principle, that's also called for inline virtual ~One() {} such that the vtable seems to contain a NULL -- but the destructor function itself is emitted. My feeling is that something marks the tree as needed and, hence, the symbol is produced. [Probably via somehow via parser.c's cp_parser_save_member_function_body().] Finally, the reason that the One::~One() works without "#pragma interface" is not that it is generated when compiling "test.cc" but it will be generated when compiling "test3.cc".