https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87095

--- Comment #3 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
With my very limited understanding of the inheritance and ABI, I think the
testcase is valid.

The problem is I believe in that if there are nearly empty virtual bases that
the ABI requires to reuse the virtual pointers in that case:
  /* A "nearly-empty" virtual base class can be the primary base
     class, if no non-virtual polymorphic base can be found.  Look for
     a nearly-empty virtual dynamic base that is not already a primary
     base of something in the hierarchy.  If there is no such base,
     just pick the first nearly-empty virtual base.  */
the build_clobber_this () handles this by:
  /* If we have virtual bases, clobber the whole object, but only if we're in
     charge.  If we don't have virtual bases, clobber the as-base type so we
     don't mess with tail padding.  */
  bool vbases = CLASSTYPE_VBASECLASSES (current_class_type);
...
  if (vbases)
    exprstmt = build_if_in_charge (exprstmt);

So, to match this it would be just adding
if (CLASSTYPE_VBASECLASSES (current_class_type)) stmt = build_if_in_charge
(stmt);
before finish_decl_cleanup.
Though, if all the virtual bases are non-empty, the sharing of vptr doesn't
occur
in that case and we'd not clear it (e.g. if in the testcase there is int a;
non-static data member in A,
we wouldn't clear B's vptr in not-in-charge B::~B even when A has a different
vptr).

So I wonder if the following is right:

--- gcc/cp/decl.c.jj    2018-08-26 22:41:48.574350447 +0200
+++ gcc/cp/decl.c       2018-08-27 12:59:33.068314097 +0200
@@ -15696,6 +15696,14 @@ begin_destructor_body (void)
            tree stmt = cp_build_modify_expr (input_location, vtbl_ptr,
                                              NOP_EXPR, vtbl,
                                              tf_warning_or_error);
+           /* If the vptr is shared with some virtual nearly empty base,
+              don't clear it if not in charge, the dtor of the virtual
+              nearly empty base will do that later.  */
+           if (CLASSTYPE_VBASECLASSES (current_class_type)
+               && CLASSTYPE_PRIMARY_BINFO (current_class_type)
+               && BINFO_VIRTUAL_P
+                         (CLASSTYPE_PRIMARY_BINFO (current_class_type)))
+             stmt = build_if_in_charge (stmt);
            finish_decl_cleanup (NULL_TREE, stmt);
          }
        else

Reply via email to