On Thu, Nov 22, 2012 at 2:14 AM, Richard Smith <span dir="ltr"><<a href="mailto:richard@metafoo.co.uk" target="_blank">richard@metafoo.co.uk</a>></span> wrote:<br><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="im">On Wed, Nov 21, 2012 at 9:52 PM, Ryan Molden <<a href="mailto:ryanmolden@gmail.com">ryanmolden@gmail.com</a>> wrote:<br>
> Is this the right alias for discussion of Clang implementation specifics? Or<br>
> would that be better over on cfe-commits?<br>
<br>
</div>This is the right place.<br>
<div><div class="h5"><br>
> Assuming this is an appropriate alias (or that I can simply forward this on<br>
> if not), I am fixing some missing compiler intrinsics that Clang doesn't<br>
> provide but the VS 2012 STL headers require for some of their type traits<br>
> implementations.<br>
><br>
> In doing this I have found a couple of things in Clang's current type trait<br>
> support that seem incorrect by my reading of the standards, but I wanted to<br>
> run this by other people before I changed anything.<br>
><br>
> The first issue is this code:<br>
><br>
> struct NotTrivial {<br>
>   NotTrivial() = delete;<br>
> };<br>
><br>
> int main(int,char**)<br>
> {<br>
>     static_assert(!__is_trivial(NotTrivial), "A class with no default<br>
> constructor doesn't meet the definition of a trivial class");<br>
>     return 0;<br>
> }<br>
><br>
> This fires today in Clang trunk.<br>
><br>
> Looking at the standard I see this:<br>
><br>
> The definition of a trivial type is n3376 3.9 [basic.types]/9<br>
><br>
> Arithmetic types (3.9.1), enumeration types, pointer types, pointer to<br>
> member types (3.9.2), std::nullptr_t, and cv-qualified<br>
> versions of these types (3.9.3) are collectively called scalar types. Scalar<br>
> types, POD classes (Clause 9), arrays of such types and cv-qualified<br>
> versions of these types (3.9.3) are collectively called POD types. Scalar<br>
> types, trivially copyable class types (Clause 9), arrays of such types, and<br>
> cv-qualified versions of these types (3.9.3) are collectively called<br>
> trivially copyable types. Scalar types, trivial class types (Clause 9),<br>
> arrays of such types and cv-qualified versions of these types (3.9.3) are<br>
> collectively called trivial types. Scalar types, standard-layout class types<br>
> (Clause 9), arrays of such types and cv-qualified<br>
> versions of these types (3.9.3) are collectively called standard layout<br>
> types.<br>
><br>
> The referenced Clause 9 says (n3376 9 [class]/6):<br>
><br>
> A trivial class is a class that has a trivial default constructor (12.1) and<br>
> is trivially copyable.<br>
> [ Note: In particular, a trivially copyable or trivial class does not have<br>
> virtual functions or virtual base<br>
><br>
> Since NotTrivial has no default constructor it seems it can't meet this<br>
> definition.<br>
<br>
</div></div>Clang is behaving correctly. NotTrivial has a default constructor,<br>
which is deleted, and thus not user-provided. It meets the other<br>
constraints for triviality, so it is a trivial default constructor.<br>
<br>
(Note that deleted functions still exist, and can still be trivial.)<br>
<div class="im"><br>
> The second issue (this one I am less sure about) is in this code (this also<br>
> fires in Clang trunk):<br>
><br>
> struct NotTriviallyCopyable {<br>
>   NotTriviallyCopyable(const NotTriviallyCopyable&) = delete;<br>
>   NotTriviallyCopyable& operator=(const NotTriviallyCopyable&) = delete;<br>
> };<br>
><br>
> int main(int,char**)<br>
> {<br>
>     static_assert(!__is_trivially_copyable(NotTriviallyCopyable), "A class<br>
> with no copy constructor or copy assignment operator is not trivially<br>
> copyable");<br>
>     return 0;<br>
> }<br>
><br>
> This one hinges on the definition of trivially-copyable, which seems like it<br>
> can be read two ways:<br>
><br>
> n3376 9 [class]/6:<br>
><br>
> A trivially copyable class is a class that:<br>
>   — has no non-trivial copy constructors (12.8),<br>
>   — has no non-trivial move constructors (12.8),<br>
>   — has no non-trivial copy assignment operators (13.5.3, 12.8),<br>
>   — has no non-trivial move assignment operators (13.5.3, 12.8), and<br>
>   — has a trivial destructor (12.4).<br>
><br>
> It seems since this class has NO copy constructors or copy assignment<br>
> operators that it shouldn't be considered trivially copyable.<br>
<br>
</div>Clang is correct here too. This class has a trivial (deleted) copy<br>
constructor and a trivial (deleted) copy assignment. It has no move<br>
constructor and no move assignment. It also has a trivial destructor.<br>
Therefore it is trivially copyable.<br>
</blockquote></div><br><div>Interesting. My conceptualization of deleted functions was that they any reference to them in code would be ill-formed. It isn't clear how one uses some of the type traits (like is_default_constructible, is_copy_constructible, etc..) in meaningful ways in the face of deleted functions. It seems like it would lead one down a path of choosing functions/code paths that end up being ill-formed because the thing you tested for and were told existed by the compiler was actually deleted.<br>
</div><div><br></div><div>Another example, I notice that UTT_HasTrivialDefaultConstructor maps to the intrinsic __has_trivial_constructor, which reports true for a class with a deleted default constructor. Wouldn't that naturally lead one to think code like T t; is valid, when it would not be?</div>
<div><br></div><div>Ryan</div>