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

Ryan Molden ryanmolden at gmail.com
Wed Nov 21 21:52:33 PST 2012


Is this the right alias for discussion of Clang implementation specifics?
Or would that be better over on cfe-commits?

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.

I believe the issue lies in clang\lib\AST\DeclCXX.cpp (line 579):

bool UserProvided = Constructor->isUserProvided();

if (Constructor->isDefaultConstructor()) {
  data().DeclaredDefaultConstructor = true;
  if (UserProvided) {
    // C++0x [class.ctor]p5:
    //   A default constructor is trivial if it is not user-provided [...]
    data().HasTrivialDefaultConstructor = false;
    data().UserProvidedDefaultConstructor = true;
  }

In this case isUserProvided is defined as:

/// isUserProvided - True if this method is user-declared and was not
/// deleted or defaulted on its first declaration.
bool isUserProvided() const {
  return !(isDeleted() || getCanonicalDecl()->isDefaulted());
}

so we never fall into the block that would set HasTrivialDefaultConstructor
to false, since UserProvided ends up as false. We also set
DeclaredDefaultConstructor to true even though Constructor->isDeleted()
would return true here.



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.

That said, you could also read this as the fact there are no such operators
means, implicitly, that there are no non-trivial versions of said operators
and thus this class IS trivially copyable. That reading doesn't really seem
to yield interesting type information since you can't actually copy a type
such as this (short of just doing a memcpy). Or is the intention of code
dealing with trivial types WOULD just copy say via std::memcpy?

Thoughts? Am I misreading the standard? Misunderstanding the Clang code
here?

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


More information about the cfe-dev mailing list