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

Reply via email to