Skip to content

Commit

Permalink
DR1672, DR1813, DR1881, DR2120: Implement recent fixes to "standard
Browse files Browse the repository at this point in the history
layout" rules.

The new rules say that a standard-layout struct has its first non-static
data member and all base classes at offset 0, and consider a class to
not be standard-layout if that would result in multiple subobjects of a
single type having the same address.

We track "is C++11 standard-layout class" separately from "is
standard-layout class" so that the ABIs that need this information can
still use it.

Differential Revision: https://reviews.llvm.org/D45176

llvm-svn: 329332
  • Loading branch information
zygoloid committed Apr 5, 2018
1 parent 367c2ae commit b6070db
Show file tree
Hide file tree
Showing 17 changed files with 419 additions and 63 deletions.
5 changes: 5 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ Non-comprehensive list of changes in this release
For example, the ``clang`` binary will be called ``clang-7``
instead of ``clang-7.0``.

- Clang implements a collection of recent fixes to the C++ standard's definition
of "standard-layout". In particular, a class is only considered to be
standard-layout if all base classes and the first data member (or bit-field)
can be laid out at offset zero.

- ...

New Compiler Flags
Expand Down
35 changes: 28 additions & 7 deletions clang/include/clang/AST/DeclCXX.h
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,12 @@ class CXXRecordDecl : public RecordDecl {
/// one pure virtual function, (that can come from a base class).
unsigned Abstract : 1;

/// \brief True when this class has standard layout.
/// \brief True when this class is standard-layout, per the applicable
/// language rules (including DRs).
unsigned IsStandardLayout : 1;

/// \brief True when this class was standard-layout under the C++11
/// definition.
///
/// C++11 [class]p7. A standard-layout class is a class that:
/// * has no non-static data members of type non-standard-layout class (or
Expand All @@ -362,13 +367,19 @@ class CXXRecordDecl : public RecordDecl {
/// classes with non-static data members, and
/// * has no base classes of the same type as the first non-static data
/// member.
unsigned IsStandardLayout : 1;
unsigned IsCXX11StandardLayout : 1;

/// \brief True when there are no non-empty base classes.
///
/// \brief True when any base class has any declared non-static data
/// members or bit-fields.
/// This is a helper bit of state used to implement IsStandardLayout more
/// efficiently.
unsigned HasNoNonEmptyBases : 1;
unsigned HasBasesWithFields : 1;

/// \brief True when any base class has any declared non-static data
/// members.
/// This is a helper bit of state used to implement IsCXX11StandardLayout
/// more efficiently.
unsigned HasBasesWithNonStaticDataMembers : 1;

/// \brief True when there are private non-static data members.
unsigned HasPrivateFields : 1;
Expand Down Expand Up @@ -696,6 +707,12 @@ class CXXRecordDecl : public RecordDecl {
/// deserializing the friends from an external AST source.
FriendDecl *getFirstFriend() const;

/// Determine whether this class has an empty base class subobject of type X
/// or of one of the types that might be at offset 0 within X (per the C++
/// "standard layout" rules).
bool hasSubobjectAtOffsetZeroOfEmptyBaseType(ASTContext &Ctx,
const CXXRecordDecl *X);

protected:
CXXRecordDecl(Kind K, TagKind TK, const ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
Expand Down Expand Up @@ -1301,10 +1318,14 @@ class CXXRecordDecl : public RecordDecl {
/// not overridden.
bool isAbstract() const { return data().Abstract; }

/// \brief Determine whether this class has standard layout per
/// (C++ [class]p7)
/// \brief Determine whether this class is standard-layout per
/// C++ [class]p7.
bool isStandardLayout() const { return data().IsStandardLayout; }

/// \brief Determine whether this class was standard-layout per
/// C++11 [class]p7, specifically using the C++11 rules without any DRs.
bool isCXX11StandardLayout() const { return data().IsCXX11StandardLayout; }

/// \brief Determine whether this class, or any of its class subobjects,
/// contains a mutable field.
bool hasMutableFields() const { return data().HasMutableFields; }
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -798,7 +798,8 @@ class QualType {

/// Return true if this is a POD type according to the more relaxed rules
/// of the C++11 standard, regardless of the current compilation's language.
/// (C++0x [basic.types]p9)
/// (C++0x [basic.types]p9). Note that, unlike
/// CXXRecordDecl::isCXX11StandardLayout, this takes DRs into account.
bool isCXX11PODType(const ASTContext &Context) const;

/// Return true if this is a trivial type per (C++0x [basic.types]p9)
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1071,7 +1071,10 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To,
ToData.Polymorphic = FromData.Polymorphic;
ToData.Abstract = FromData.Abstract;
ToData.IsStandardLayout = FromData.IsStandardLayout;
ToData.HasNoNonEmptyBases = FromData.HasNoNonEmptyBases;
ToData.IsCXX11StandardLayout = FromData.IsCXX11StandardLayout;
ToData.HasBasesWithFields = FromData.HasBasesWithFields;
ToData.HasBasesWithNonStaticDataMembers =
FromData.HasBasesWithNonStaticDataMembers;
ToData.HasPrivateFields = FromData.HasPrivateFields;
ToData.HasProtectedFields = FromData.HasProtectedFields;
ToData.HasPublicFields = FromData.HasPublicFields;
Expand Down

0 comments on commit b6070db

Please sign in to comment.