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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits