Google reference: b/9004260 Test case: class A { }; class B: virtual A { }; class C: virtual B { }; class D: C { void operator= (D &); }; Using current trunk (@r199023): g++ -c t.ii -std=c++11 t.ii:3:7: warning: defaulted move assignment for ‘C’ calls a non-trivial move assignment operator for virtual base ‘B’ [-Wvirtual-move-assign] class C: virtual B { }; ^ Richard Smith writes: The problem is that a defaulted move assignment for a class with two inheritance paths to a virtual base may move-assign that virtual base multiple times (and thus may lose state). However, this particular case *isn't* the problematic case, because (a) this sample code should not trigger the definition of C's move assignment operator, and (b) there is only one inheritance path from C to B, so it won't be move-assigned multiple times, and (c) the issue isn't with *non-trivial* move assignments, it's with *user-provided* move-assignments (for the virtual base or any of its subobjects), which B does not have. => This is a false positive.
(In reply to Paul Pluzhnikov from comment #0) > However, this particular case *isn't* the problematic case, because > (a) this sample code should not trigger the definition of C's move > assignment operator, and True, the warning is given at declaration time; it would be possible to move the warning to when the move assignment is used, but that might mean design errors don't get caught until later. > (b) there is only one inheritance path from C to B, so it won't be > move-assigned multiple times, and True, the warning is given at the point of first virtual derivation rather than when it appears in a diamond-shaped hierarchy. But the purpose of virtual derivation is to support diamond-shaped hierarchies, so again it seems appropriate to warn sooner rather than later. > (c) the issue isn't with *non-trivial* move assignments, it's with > *user-provided* move-assignments (for the virtual base or any of its > subobjects), which B does not have. Agreed, it would definitely be better for the warning to check that none of the subobjects of B have user-provided move-assignments.
Fixed for 4.9 for now.
Thanks for the fix. Confirmed for both the reduced test case, and the original source. Can this be back-ported to 4.8 branch?
(In reply to Paul Pluzhnikov from comment #3) > Can this be back-ported to 4.8 branch? After 4.8.1, I think.
(In reply to Jason Merrill from comment #1) > (In reply to Paul Pluzhnikov from comment #0) > > However, this particular case *isn't* the problematic case, because > > (a) this sample code should not trigger the definition of C's move > > assignment operator, and > > True, the warning is given at declaration time; it would be possible to move > the warning to when the move assignment is used, but that might mean design > errors don't get caught until later. OK, that makes sense. However, delaying the check until the operator= is lazily declared does not fully achieve this goal. Could the check be performed at the end of the definition of class C (rather than, presumably, when looking for a virtual C::operator= for D::operator= to override)? > > (b) there is only one inheritance path from C to B, so it won't be > > move-assigned multiple times, and > > True, the warning is given at the point of first virtual derivation rather > than when it appears in a diamond-shaped hierarchy. But the purpose of > virtual derivation is to support diamond-shaped hierarchies, so again it > seems appropriate to warn sooner rather than later. OK. The class which brings together the diamond may provide a move assignment operator which does not blindly call the move assignment operators on the base classes, so this can still have some false positives even if every virtual base is involved in diamond inheritance.
GCC 4.8.1 has been released.
Fixed for 4.8.2.