> On Jan 2, 2018, at 10:43 PM, Richard Smith <rich...@metafoo.co.uk> wrote: > > On 2 January 2018 at 19:02, John McCall via cfe-commits > <cfe-commits@lists.llvm.org <mailto:cfe-commits@lists.llvm.org>> wrote: > >> On Jan 2, 2018, at 9:15 PM, Akira Hatanaka <ahatan...@apple.com >> <mailto:ahatan...@apple.com>> wrote: >> >> >> >>> On Jan 2, 2018, at 4:56 PM, Richard Smith via cfe-commits >>> <cfe-commits@lists.llvm.org <mailto:cfe-commits@lists.llvm.org>> wrote: >>> >>> On 2 January 2018 at 15:33, John McCall via cfe-commits >>> <cfe-commits@lists.llvm.org <mailto:cfe-commits@lists.llvm.org>> wrote: >>> 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. >>> >>> The current definition in Itanium is: >>> >>> non-trivial for the purposes of calls <> >>> <> >>> A type is considered non-trivial for the purposes of calls if: >>> >>> it has a non-trivial copy constructor, move constructor, or destructor, or >>> <> >>> 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.) >>> all of its copy and move constructors are deleted. >>> <> >>> >>> I'd suggest modifying this to: >>> >>> A type is considered non-trivial for the purposes of calls if: >>> - if has a copy constructor, move constructor, or destructor >>> which is non-trivial for the purposes of calls, or >>> - all of its copy and move constructors are deleted and it does >>> not have the trivial_abi attribute. >>> >>> A copy/move constructor is considered trivial for the purposes of calls >>> if: >>> - it is user-provided and >>> - the class has the trivial_abi attribute and >>> - a defaulted definition of the constructor would be >>> trivial for the purposes of calls; or >>> >>> 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: >>> >>> struct [[clang::trivial_abi]] A { >>> A(A && = make()); >>> }; >>> >>> Here, A::A(A&&) cannot validly be defaulted. Is A trivial for the purpose >>> of calls? Likewise: >>> >>> struct [[clang::trivial_abi]] B { >>> B(...); >>> }; >>> struct C { >>> volatile B b; >>> }; >>> >>> 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...) >>> >>> 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. >>> >>> - it is not user-provided and >>> - the class has no virtual functions and no virtual >>> base classes, and >>> - the constructor used to copy/move each direct base >>> class subobject is trivial for the purposes of calls, and >>> - 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. >>> >>> A destructor is considered trivial for the purposes of calls if: >>> - it is not user-provided or the class has the trivial_abi >>> attribute, and >>> - the destructor is not virtual, and >>> - all of the direct base classes of its class have destructors >>> that are trivial for the purposes of calls, and >>> - 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. >>> >>> These definitions are intended to follow [class.copy.ctor]p11 and >>> [class.dtor]p6 except for the special rules applicable to trivial_abi >>> classes. >>> >>> 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. >>> >>> I think that's a reasonable rule, if we have a satisfactory notion of >>> "defaulted definition". >>> >>> 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. >>> >>> Per the above examples, I don't think you can escape asking about >>> triviality for an arbitrary constructor if you take this path. >>> >>> 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. >>> >> >> It sounds like a class containing a member that has a type annotated with >> “trivial_abi” would not necessarily be considered trivial for the purpose of >> calls according to rule (2)? For example, S1 would not be trivial for the >> purpose of calls because it isn’t annotated with “trivial_abi” in the code >> below: >> >> struct [[clang::trivial_abi]] S0 { >> // user-provided special functions declared here. >> }; >> >> struct S1 { >> S0 f0; >> }; >> >> I thought we wanted containing classes (S1 in this case) to be trivial for >> the purpose of calls too? > > I would like that, yeah. > > OK, I think that's fair. Then we probably need the more complex rule. Which I > think means we're at something equivalent to: > > A type is considered non-trivial for the purposes of calls if: > - if has a copy constructor, move constructor, or destructor > that is not deleted and is non-trivial for the purposes of calls, or > - all of its copy and move constructors are deleted and it does > not have the trivial_abi attribute. > > A copy/move constructor is considered trivial for the purposes of calls > if: > - it is user-provided and > - the class has the trivial_abi attribute and > - a defaulted definition of a constructor with the > signature of the implicit copy/move constructor for the class would be > trivial for the purposes of calls; or > - it is not user-provided and > - the class has no virtual functions and no virtual > base classes, and > - the constructor used to copy/move each direct base > class subobject is trivial for the purposes of calls, and > - 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. > A constructor that is neither a copy constructor nor a move constructor > is considered non-trivial for the purposes of calls.
This clause is there to handle constructors that are copy/move constructors only because of defaulted arguments? I wonder if this is necessary; I think the allocator-like use cases would prefer that we just ignore the non-initial arguments, wouldn't they? > A destructor is considered trivial for the purposes of calls if: > - it is not user-provided or the class has the trivial_abi > attribute, and > - the destructor is not virtual, and > - all of the direct base classes of its class have destructors > that are trivial for the purposes of calls, and > - 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. > > Bolded phrases are changed from John's initial email. Thank you for the revision; this is much improved. John. > > John. > >> >>> 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? >>> >>> 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. >>> _______________________________________________ >>> cfe-commits mailing list >>> cfe-commits@lists.llvm.org <mailto:cfe-commits@lists.llvm.org> >>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits >>> <http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits> > > > _______________________________________________ > cfe-commits mailing list > cfe-commits@lists.llvm.org <mailto:cfe-commits@lists.llvm.org> > http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits > <http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits> > >
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits