rjmccall added inline comments.
================ Comment at: docs/LanguageExtensions.rst:1096 + equivalent to copying the underlying bytes and then dropping the source object + on the floor. * ``__is_destructible`` (MSVC 2013) ---------------- Quuxplusone wrote: > rjmccall wrote: > > Quuxplusone wrote: > > > @rjmccall wrote: > > > > trivial_abi permits annotated types to be passed and returned in > > > > registers, which is ABI-breaking. Skimming the blog post, it looks like > > > > trivially_relocatable does not permit this — it merely signifies that > > > > destruction is a no-op after a move construction or assignment. > > > > > > Not necessarily a "no-op"; my canonical example is a > > > CopyOnlyCXX03SharedPtr which increments a refcount on construction and > > > decrements on destruction. But move-construction plus destruction should > > > "balance out" and result in no observable side effects. > > > > > > > This is usefully different in the design space, since it means you can > > > > safely add the attribute retroactively to e.g. std::unique_ptr, and > > > > other templates can then detect that std::unique_ptr is > > > > trivially-relocatable and optimize themselves to use memcpy or realloc > > > > or whatever it is that they want to do. So in that sense trivial_abi is > > > > a *stronger* attribute, not a *weaker* one: the property it determines > > > > ought to imply trivially_relocatable. > > > > > > `trivial_abi` is an "orthogonal" attribute: you can have `trivial_abi` > > > types with non-trivial constructors and destructors, which can have > > > observable side effects. For example, > > > ``` > > > struct [[clang::trivial_abi]] DestructionAnnouncer { > > > ~DestructionAnnouncer() { puts("hello!"); } > > > }; > > > ``` > > > is `trivial_abi` (because of the annotation) yet not trivially > > > relocatable, because its "move plus destroy" operation has observable > > > side effects. > > > > > > > The only interesting question in the language design that I know of is > > > > what happens if you put the attribute on a template that's instantiated > > > > to contain a sub-object that is definitely not trivially relocatable / > > > > trivial-ABI. For trivial_abi, we decided that the attribute is simply > > > > ignored — it implicitly only applies to specializations where the > > > > attribute would be legal. I haven't dug into the design enough to know > > > > what trivially_relocatable decides in this situation, but the three > > > > basic options are: > > > > > > > > - the attribute always has effect and allows trivial relocation > > > > regardless of the subobject types; this is obviously unsafe, so it > > > > limits the safe applicability of the attribute to templates > > > > - the attribute is ignored, like trivial_abi is > > > > - the attribute is ill-formed, and you'll need to add a > > > > [[trivially_relocatable(bool)]] version to support templates > > > > > > What happens is basically the first thing you said, except that I > > > disagree that it's "obviously unsafe." Right now, conditionally trivial > > > relocation is possible via template metaprogramming; see the libcxx patch > > > at e.g. > > > https://github.com/Quuxplusone/libcxx/commit/6524822c009e#diff-38adc80cec663f2f29c22e9ffc0de912 > > > Since the attribute is an opt-in mechanism, it makes perfect sense to me > > > that if you put it on a class (or class template), then it applies to the > > > class, without any further sanity-checking by the compiler. The compiler > > > has no reason to second-guess the programmer here. > > > > > > However, there's one more interesting case. Suppose the programmer puts > > > the attribute on a class that isn't relocatable at all! (For example, the > > > union case @erichkeane mentioned, or a class type with a deleted > > > destructor.) In that case, this patch *does* give an error... *unless* > > > the class was produced by instantiating a template, in which case we > > > *don't* give an error, because it's not the template-writer's fault. > > > https://p1144.godbolt.org/z/wSZPba > > > trivial_abi is an "orthogonal" attribute: you can have trivial_abi types > > > with non-trivial constructors and destructors, which can have observable > > > side effects. > > > > Let me cut this conversation short. `trivial_abi` is not such an old and > > widely-established attribute that we are unable to revise its definition. > > I am comfortable making the same semantic guarantees for `trivial_abi` that > > you're making for `trivially_relocatable`, because I think it is in the > > language's interest for `trivial_abi` to be strictly stronger than > > `trivially_relocatable`. > > > > > What happens is basically the first thing you said, except that I > > > disagree that it's "obviously unsafe." > > > > Under your semantics, the attribute is an unchecked assertion about all of > > a class's subobjects. A class template which fails to correctly apply the > > template metaprogramming trick to all of its dependently-typed subobjects — > > which can be quite awkward because it creates an extra dimension of partial > > specialization, and which breaks ABI by adding extra template parameters — > > will be silently miscompiled to allow objects to be memcpy'ed when they're > > potentially not legal to memcpy. That is a footgun, and it is indeed > > "obviously unsafe". > > > > Now, it's fair to say that it's unsafe in a useful way: because the > > attribute isn't checked, you can wrap a type you don't control in a > > `trivially_relocatable` struct and thereby get the advantages of triviality > > on the wrapper. The model used by `trivial_abi` doesn't allow that. But I > > feel pretty strongly that that is not the right default behavior for the > > language. > > Under your semantics, the attribute is an unchecked assertion about all of > > a class's subobjects. > > The attribute is an unchecked assertion about the class's //special member > functions//. The attribute doesn't have anything to do with subobjects, > period. > Vice versa, the property currently expressed by > "IsNaturallyTriviallyRelocatable" is deduced from all of the class's > subobjects. The programmer can overrule the "natural" property in an > "unnatural" way by annotating their class with the attribute. > > And we know this is true because it is possible to make a > trivially-relocatable class type containing non-trivially-relocatable members > (e.g. a class having a member of type boost::interprocess::offset_ptr), and > vice versa it is possible to make a non-trivially-relocatable class > containing trivially-relocatable members (e.g. > boost::interprocess::offset_ptr itself, which has only one member, of > integral type). > > > A class template which fails to correctly apply the template > > metaprogramming trick to all of its dependently-typed subobjects — which > > can be quite awkward because it creates an extra dimension of partial > > specialization > > Agreed that it's awkward. The libc++ implementation was awkward, but > definitely not challenging. The only thing that makes it at all tricky in the > STL is that the STL allocator model permits fancy "pointer" types that can > make e.g. std::vector non-trivially relocatable. If it weren't for fancy > pointers, you wouldn't need the extra dimension. > > > and which breaks ABI by adding extra template parameters > > The libc++ implementation does not break ABI. The extra template parameter is > concealed in a private base class. > https://github.com/Quuxplusone/libcxx/commit/6524822c009e#diff-38adc80cec663f2f29c22e9ffc0de912 > > > I feel pretty strongly that that is not the right default behavior for the > > language. > > Can you elaborate on that feeling (maybe in private email)? My intent with > P1144 is that no industry programmer should ever see this attribute; the > right default for industry programmers is to use the Rule of Zero. The reason > we need the attribute is as an opt-in mechanism for the implementor of > `unique_ptr`, `shared_ptr`, `vector`, and so on, //so that// the end-user can > just use the Rule of Zero and everything will work fine. End-users shouldn't > be messing with attributes. > And we know this is true because it is possible to make a > trivially-relocatable class type containing non-trivially-relocatable members > (e.g. a class having a member of type boost::interprocess::offset_ptr), and > vice versa it is possible to make a non-trivially-relocatable class > containing trivially-relocatable members (e.g. > boost::interprocess::offset_ptr itself, which has only one member, of > integral type). Why would a class containing a member of type `boost::interprocess::offset_ptr` be trivially-relocatable? If you actually trivially relocate an object of the class, the pointer will not be rebased and so will be invalidated. It would have to be an `offset_ptr` where you happen to know that the referent will always be copied simultaneously, e.g. because it's a member of the object itself. Of course that's possible, but it's also such a corner case that we shouldn't balk at saying that the programmer ought to be more explicit about recognizing it. > Agreed that it's awkward. The libc++ implementation was awkward, but > definitely not challenging. The only thing that makes it at all tricky in the > STL is that the STL allocator model permits fancy "pointer" types that can > make e.g. std::vector non-trivially relocatable. If it weren't for fancy > pointers, you wouldn't need the extra dimension. Sure. My point about the awkwardness is quite narrow: making the attribute take a `bool` argument is just a superior way of managing this over requiring a partial specialization. Several other language attributes have been heading in this same direction. > The libc++ implementation does not break ABI. The extra template parameter is > concealed in a private base class. Ah, apologies. > My intent with P1144 is that no industry programmer should ever see this > attribute; the right default for industry programmers is to use the Rule of > Zero. ... End-users shouldn't be messing with attributes. Neither of these statements matches my experience. This is an "expert" feature to be sure, but the C++ community is full of experts who write their own rule-of-five types and who will happily use whatever attributes are available to them to make them faster. Also, I assume you are intending for this attribute to be standardized eventually, which will greatly expand its reach. Repository: rC Clang https://reviews.llvm.org/D50119 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits