[cfe-dev] Standards interpretation question wrt to Clang trunk

Ryan Molden ryanmolden at gmail.com
Fri Nov 23 11:42:22 PST 2012


On Thu, Nov 22, 2012 at 9:18 AM, Howard Hinnant <hhinnant at apple.com> wrote:

> On Nov 22, 2012, at 11:27 AM, Ryan Molden <ryanmolden at gmail.com> wrote:
>
> > On Thu, Nov 22, 2012 at 2:14 AM, Richard Smith <richard at metafoo.co.uk>
> wrote:
> > On Wed, Nov 21, 2012 at 9:52 PM, Ryan Molden <ryanmolden at gmail.com>
> wrote:
> > > Is this the right alias for discussion of Clang implementation
> specifics? Or
> > > would that be better over on cfe-commits?
> >
> > This is the right place.
> >
> > > Assuming this is an appropriate alias (or that I can simply forward
> this on
> > > if not), I am fixing some missing compiler intrinsics that Clang
> doesn't
> > > provide but the VS 2012 STL headers require for some of their type
> traits
> > > implementations.
> > >
> > > In doing this I have found a couple of things in Clang's current type
> trait
> > > support that seem incorrect by my reading of the standards, but I
> wanted to
> > > run this by other people before I changed anything.
> > >
> > > The first issue is this code:
> > >
> > > struct NotTrivial {
> > >   NotTrivial() = delete;
> > > };
> > >
> > > int main(int,char**)
> > > {
> > >     static_assert(!__is_trivial(NotTrivial), "A class with no default
> > > constructor doesn't meet the definition of a trivial class");
> > >     return 0;
> > > }
> > >
> > > This fires today in Clang trunk.
> > >
> > > Looking at the standard I see this:
> > >
> > > The definition of a trivial type is n3376 3.9 [basic.types]/9
> > >
> > > Arithmetic types (3.9.1), enumeration types, pointer types, pointer to
> > > member types (3.9.2), std::nullptr_t, and cv-qualified
> > > versions of these types (3.9.3) are collectively called scalar types.
> Scalar
> > > types, POD classes (Clause 9), arrays of such types and cv-qualified
> > > versions of these types (3.9.3) are collectively called POD types.
> Scalar
> > > types, trivially copyable class types (Clause 9), arrays of such
> types, and
> > > cv-qualified versions of these types (3.9.3) are collectively called
> > > trivially copyable types. Scalar types, trivial class types (Clause 9),
> > > arrays of such types and cv-qualified versions of these types (3.9.3)
> are
> > > collectively called trivial types. Scalar types, standard-layout class
> types
> > > (Clause 9), arrays of such types and cv-qualified
> > > versions of these types (3.9.3) are collectively called standard layout
> > > types.
> > >
> > > The referenced Clause 9 says (n3376 9 [class]/6):
> > >
> > > A trivial class is a class that has a trivial default constructor
> (12.1) and
> > > is trivially copyable.
> > > [ Note: In particular, a trivially copyable or trivial class does not
> have
> > > virtual functions or virtual base
> > >
> > > Since NotTrivial has no default constructor it seems it can't meet this
> > > definition.
> >
> > Clang is behaving correctly. NotTrivial has a default constructor,
> > which is deleted, and thus not user-provided. It meets the other
> > constraints for triviality, so it is a trivial default constructor.
> >
> > (Note that deleted functions still exist, and can still be trivial.)
> >
> > > The second issue (this one I am less sure about) is in this code (this
> also
> > > fires in Clang trunk):
> > >
> > > struct NotTriviallyCopyable {
> > >   NotTriviallyCopyable(const NotTriviallyCopyable&) = delete;
> > >   NotTriviallyCopyable& operator=(const NotTriviallyCopyable&) =
> delete;
> > > };
> > >
> > > int main(int,char**)
> > > {
> > >     static_assert(!__is_trivially_copyable(NotTriviallyCopyable), "A
> class
> > > with no copy constructor or copy assignment operator is not trivially
> > > copyable");
> > >     return 0;
> > > }
> > >
> > > This one hinges on the definition of trivially-copyable, which seems
> like it
> > > can be read two ways:
> > >
> > > n3376 9 [class]/6:
> > >
> > > A trivially copyable class is a class that:
> > >   — has no non-trivial copy constructors (12.8),
> > >   — has no non-trivial move constructors (12.8),
> > >   — has no non-trivial copy assignment operators (13.5.3, 12.8),
> > >   — has no non-trivial move assignment operators (13.5.3, 12.8), and
> > >   — has a trivial destructor (12.4).
> > >
> > > It seems since this class has NO copy constructors or copy assignment
> > > operators that it shouldn't be considered trivially copyable.
> >
> > Clang is correct here too. This class has a trivial (deleted) copy
> > constructor and a trivial (deleted) copy assignment. It has no move
> > constructor and no move assignment. It also has a trivial destructor.
> > Therefore it is trivially copyable.
> >
> > 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.
> >
> > 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?
>
> Some traits are more useful than others.  I recommend
> std::is_trivially_default_constructible,
> std::is_trivially_copy_constructible and std::is_trivially_copy_assignable
> for answering the questions you are asking.
>
> Howard
>
>
Thanks to both of you for the clarifications.

Ryan
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20121123/c7e6a678/attachment.html>


More information about the cfe-dev mailing list