[PATCH] D50119: Compiler support for P1144R0 "__is_trivially_relocatable(T)"

Arthur O'Dwyer via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Wed Nov 21 10:14:12 PST 2018


Quuxplusone added a comment.

In https://reviews.llvm.org/D50119#1303720, @rjmccall wrote:

> In https://reviews.llvm.org/D50119#1303662, @Quuxplusone wrote:
>
> > >> I still believe it is impossible to implement `std::optional` with only `[[maybe_trivially_relocatable]]`.
> > > 
> > > This might also need elaboration.
> >
> > Because `__optional_destruct_base` contains an anonymous union member, and that union type is not destructible; therefore that union type is not trivially relocatable; therefore `__optional_destruct_base` contains a member of non-trivially-destructible type. However, I'm working on changing my patch to make anonymous unions "see-through" in this respect, so that that union's non-destructibility doesn't interfere with the `[[maybe_trivially_relocatable]]`ity of its enclosing class type, as long as all the members of the //union// are trivially relocatable. This might fix `optional`. I'm not sure yet.
>
>
> Ah, that makes sense.  And yeah, that seems like the right rule for unions.  I really appreciate you putting the effort into exploring this part of the design space.


I think it's part of the right rule, but it's not enough, either. Consider:

  struct [[clang::maybe_trivially_relocatable]] DestroyBase {
      int i;
      DestroyBase(DestroyBase&&) = delete;
      ~DestroyBase();
  };
  struct [[clang::maybe_trivially_relocatable]] MoveBase : DestroyBase {
      MoveBase(MoveBase&&);
  };
  
  static_assert(not std::is_move_constructible_v<DestroyBase>); //, therefore
  static_assert(not std::is_relocatable_v<DestroyBase>); //, therefore
  static_assert(not std::is_trivially_relocatable_v<DestroyBase>); //; and since MoveBase now has a base class of non-trivially-relocatable type,
  static_assert(not std::is_trivially_relocatable_v<MoveBase>);

So maybe you need a notion like "a class is BlahBlah if all of its direct members are BlahBlah, //and// either it is annotated `[[maybe_trivially_relocatable]]` or else it has no non-defaulted move or destroy operations." And then "a move-constructible, destructible class is trivially relocatable if it is BlahBlah, //or// if it is annotated `[[trivially_relocatable]]`." And then a class like `DestroyBase` can be "BlahBlah but not move-constructible," and if it's placed inside `MoveBase`, and `MoveBase` is //both// annotated and move-constructible, then `MoveBase` becomes trivially relocatable.

This does feel like it would be twice as hard to specify in the Standard, because I think I'd have to specify both the rules for BlahBlah //and// the rules for "trivially relocatable."

I'm also extremely concerned about the philosophical correctness of separating BlahBlahness from actual physical relocatability. What does it mean, abstractly, to say that "`DestroyBase` is not even moveable at all, but //if it were//, I'm confident that its relocation operation would be trivial"?  That's some weird counterfactual logic that forces the writer of the class (`DestroyBase` in this case, but also e.g. `lock_guard`) to think about how their class might get used downstream, and what the class's hypothetical invariants might be, under an operation (move+destroy) that it itself does not claim to support.

The benefit of my original "second-level" `[[trivially_relocatable]]` attribute is that it puts all the responsibility in a single very high-level place. `optional` is the thing that knows exactly when it's trivially relocatable (or at least can make a conservative guess, which might boil down to "I'm never trivially relocatable"), so `optional` is the thing that should get the attribute.

If I get time today I'll try adding the boolean argument to the attribute, and do the libc++ patches that way for comparison.


Repository:
  rC Clang

https://reviews.llvm.org/D50119





More information about the cfe-commits mailing list