<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On 2 January 2018 at 15:33, John McCall via cfe-commits <span dir="ltr"><<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word">Hey, Richard et al.  Akira and I were talking about the right ABI rule for deciding can-pass-in-registers-ness for structs in the presence of trivial_abi, and I think I like Akira's approach but wanted to get your input.<div><br></div><div>The current definition in Itanium is:<div><div><br></div><div>  <a name="m_4763064200015128419_non-trivial" style="font-family:-webkit-standard"><i>non-trivial for the purposes of calls</i></a></div><dt style="font-family:-webkit-standard"><a name="m_4763064200015128419_non-trivial"></a></dt><dd style="font-family:-webkit-standard"><a name="m_4763064200015128419_non-trivial"><p>A type is considered non-trivial for the purposes of calls if:</p><ul><li>it has a non-trivial copy constructor, move constructor, or destructor, or</li></ul></a></dd></div></div></div></blockquote><div>I'm assuming we're implicitly excluding deleted functions here. (I'd prefer to make that explicit; this has been the source of a number of ABI mismatches.)</div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><div><div><dd style="font-family:-webkit-standard"><a name="m_4763064200015128419_non-trivial"><ul><li>all of its copy and move constructors are deleted.</li></ul></a></dd><div><br></div><div>I'd suggest modifying this to:</div></div></div><div><br></div><div><span class="gmail-m_4763064200015128419Apple-tab-span" style="white-space:pre-wrap">        </span>A type is considered non-trivial for the purposes of calls if:</div><div><span class="gmail-m_4763064200015128419Apple-tab-span" style="white-space:pre-wrap">               </span>- if has a copy constructor, move constructor, or destructor which is non-trivial for the purposes of calls, or</div><div><span class="gmail-m_4763064200015128419Apple-tab-span" style="white-space:pre-wrap">             </span>- all of its copy and move constructors are deleted and it does not have the trivial_abi attribute.</div><div><br></div><div><span class="gmail-m_4763064200015128419Apple-tab-span" style="white-space:pre-wrap">        </span>A copy/move constructor is considered trivial for the purposes of calls if:</div><div><span class="gmail-m_4763064200015128419Apple-tab-span" style="white-space:pre-wrap">          </span>- it is user-provided and</div><div><span class="gmail-m_4763064200015128419Apple-tab-span" style="white-space:pre-wrap">                    </span>- the class has the trivial_abi attribute and</div><div><span class="gmail-m_4763064200015128419Apple-tab-span" style="white-space:pre-wrap">                       </span>- a defaulted definition of the constructor would be trivial for the purposes of calls; or</div></div></blockquote><div><br></div><div>We'd need to say what happens if the function in question cannot validly be defaulted for any of the reasons in [dcl.fct.def.default]. Do we try to infer whether it's a copy or move constructor, and use the rules for a defaulted copy or move constructor? Or do we just say that's never trivial for the purposes of calls? Or something else? Eg:</div><div><br></div><div>struct [[clang::trivial_abi]] A {</div><div>  A(A && = make());</div><div>};</div><div><br></div><div>Here, A::A(A&&) cannot validly be defaulted. Is A trivial for the purpose of calls? Likewise:</div><div><br></div><div>struct [[clang::trivial_abi]] B {</div><div>  B(...);</div><div>};</div><div>struct C {</div><div>  volatile B b;</div><div>};</div><div><br></div><div>Here, C's copy constructor calls B::B(...). Is C trivial for the purpose of calls? (OK, Clang crashes on that example today. But still...)</div><div><br></div><div>I'd be uncomfortable making the rules in [dcl.fct.def.default] part of the ABI; they seem to be changing relatively frequently. Perhaps we could say "if the function is a copy constructor ([class.copy.ctor]/1), then consider what an implicitly-declared defaulted copy constructor would do; if it's a move constructor ([class.copy.ctor]/2), then consider what an implicitly-declared defaulted move constructor would do; otherwise, it's not trivial for the purpose of calls". That'd mean A is trivial for the purpose of calls and C is not, which I think is probably the right answer.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><div><span class="gmail-m_4763064200015128419Apple-tab-span" style="white-space:pre-wrap">              </span>- it is not user-provided and</div><div><span class="gmail-m_4763064200015128419Apple-tab-span" style="white-space:pre-wrap">                        </span>- the class has no virtual functions and no virtual base classes, and</div><div><span class="gmail-m_4763064200015128419Apple-tab-span" style="white-space:pre-wrap">                        </span>- the constructor used to copy/move each direct base class subobject is trivial for the purposes of calls, and</div><div><span class="gmail-m_4763064200015128419Apple-tab-span" style="white-space:pre-wrap">                       </span>- for each non-static data member that is of class type (or array thereof), the constructor selected to copy/move that member is trivial for the purposes of calls.</div><div><br></div><div><span class="gmail-m_4763064200015128419Apple-tab-span" style="white-space:pre-wrap">       </span>A destructor is considered trivial for the purposes of calls if:</div><div><span class="gmail-m_4763064200015128419Apple-tab-span" style="white-space:pre-wrap">             </span>- it is not user-provided or the class has the trivial_abi attribute, and</div><div><div><span class="gmail-m_4763064200015128419Apple-tab-span" style="white-space:pre-wrap">         </span>- the destructor is not virtual, and</div><div><span class="gmail-m_4763064200015128419Apple-tab-span" style="white-space:pre-wrap">               </span>- all of the direct base classes of its class have destructors that are trivial for the purposes of calls, and</div><div><span class="gmail-m_4763064200015128419Apple-tab-span" style="white-space:pre-wrap">              </span>- for all of the non-static data members of its class that are of class type (or array thereof), each such class is trivial for the purposes of calls.</div></div><div><br></div><div><span class="gmail-m_4763064200015128419Apple-tab-span" style="white-space:pre-wrap"> </span>These definitions are intended to follow [class.copy.ctor]p11 and [class.dtor]p6 except for the special rules applicable to trivial_abi classes.</div></div></blockquote><div><br></div><div>If I could rephrase: a *tor is considered trivial for for the purposes of calls if it is either defaulted or the class has the trivial_abi attribute, and the defaulted definition would satisfy the language rule for being trivial but with the word "trivial" replaced by "trivial for the purposes of calls". So only effect of the trivial_abi attribute is to "undo" the non-triviality implied by a user-provided *tor when computing triviality for the purpose of calls.</div><div><br></div><div>I think that's a reasonable rule, if we have a satisfactory notion of "defaulted definition".</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><div>I'm not sure about the "defaulted definition" rule for copy/move constructors in trivial_abi classes.  The intent is to allow class temploids with trivial_abi that are instantiated to contain non-trivial classes to just silently become non-trivial.  I was thinking at first that it would be nice to have a general rule that trivial_abi classes only contain trivial_abi subobjects, but unfortunately that's not consistent with the standard triviality rule in some silly corner cases: a trivially-copyable class can have a non-trivially-copyable subobject if it happens to copy that subobject with a trivial copy constructor.  I couldn't think of a better way of capturing this than the "defaulted definition" rule.  I considered using the actual initializers used by the constructor, but that would introduce a lot of new complexity: suddenly we'd be asking about triviality for an arbitrary constructor, and copy/move elision make the question somewhat ambiguous anyway.</div></div></blockquote><div><br></div><div>Per the above examples, I don't think you can escape asking about triviality for an arbitrary constructor if you take this path.</div><div><br></div><div>Another option, similar to your general rule, would be to say that a type is considered trivial for the purpose of calls if either: (1) it is trivial for the purpose of calls under the current Itanium ABI rule, or (2) it has the trivial_abi attribute and all members and base classes have types that are trivial for the purpose of calls. That would sidestep the "defaulted definition" complexity entirely, and while it differs from the way that the language computes triviality normally, it doesn't seem fundamentally unreasonable: when we're thinking about triviality for the purpose of calls, there's notionally a call to the trivial copy/move ctor being elided, not a call to an arbitrary ctor selected by overload resolution, and we'd just be pushing that effect from the class itself to its subobjects with this attribute.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><div>I'm also not sure about the right rules about virtual methods.  Should we allow polymorphic classes to be made trivial by application of the attribute?</div></div></blockquote><div><br></div><div>I think that it probably doesn't make much sense to pass dynamic classes indirectly unless we can avoid passing the vptr; otherwise I'd expect we'd use too many registers for it to be worthwhile. Perhaps as a compromise, we could make the attribute ill-formed if used on a class definition that introduces any virtual bases or explicitly declares any member functions as 'virtual'. That gives us the room to make this decision later if we find we want to.</div></div></div></div>