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".