mirror of https://github.com/microsoft/clang.git
Fix __has_unique_object_representations implementation
As rsmith pointed out, the original implementation of this intrinsic missed a number of important situations. This patch fixe a bunch of shortcomings and implementation details to make it work correctly. Differential Revision: https://reviews.llvm.org/D39347 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@319446 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
96c9689f47
commit
c48afae870
|
@ -2149,6 +2149,10 @@ public:
|
|||
void CollectInheritedProtocols(const Decl *CDecl,
|
||||
llvm::SmallPtrSet<ObjCProtocolDecl*, 8> &Protocols);
|
||||
|
||||
/// \brief Return true if the specified type has unique object representations
|
||||
/// according to (C++17 [meta.unary.prop]p9)
|
||||
bool hasUniqueObjectRepresentations(QualType Ty) const;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Type Operators
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
|
|
@ -808,10 +808,6 @@ public:
|
|||
/// Return true if this is a trivially copyable type (C++0x [basic.types]p9)
|
||||
bool isTriviallyCopyableType(const ASTContext &Context) const;
|
||||
|
||||
/// Return true if this has unique object representations according to (C++17
|
||||
/// [meta.unary.prop]p9)
|
||||
bool hasUniqueObjectRepresentations(const ASTContext &Context) const;
|
||||
|
||||
// Don't promise in the API that anything besides 'const' can be
|
||||
// easily added.
|
||||
|
||||
|
@ -1164,9 +1160,6 @@ public:
|
|||
QualType getAtomicUnqualifiedType() const;
|
||||
|
||||
private:
|
||||
bool unionHasUniqueObjectRepresentations(const ASTContext& Context) const;
|
||||
bool structHasUniqueObjectRepresentations(const ASTContext& Context) const;
|
||||
|
||||
// These methods are implemented in a separate translation unit;
|
||||
// "static"-ize them to avoid creating temporary QualTypes in the
|
||||
// caller.
|
||||
|
|
|
@ -1856,7 +1856,9 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
|
|||
break;
|
||||
case Type::MemberPointer: {
|
||||
const MemberPointerType *MPT = cast<MemberPointerType>(T);
|
||||
std::tie(Width, Align) = ABI->getMemberPointerWidthAndAlign(MPT);
|
||||
CXXABI::MemberPointerInfo MPI = ABI->getMemberPointerInfo(MPT);
|
||||
Width = MPI.Width;
|
||||
Align = MPI.Align;
|
||||
break;
|
||||
}
|
||||
case Type::Complex: {
|
||||
|
@ -2138,6 +2140,168 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
|
|||
}
|
||||
}
|
||||
|
||||
static bool unionHasUniqueObjectRepresentations(const ASTContext &Context,
|
||||
const RecordDecl *RD) {
|
||||
assert(RD->isUnion() && "Must be union type");
|
||||
CharUnits UnionSize = Context.getTypeSizeInChars(RD->getTypeForDecl());
|
||||
|
||||
for (const auto *Field : RD->fields()) {
|
||||
if (!Context.hasUniqueObjectRepresentations(Field->getType()))
|
||||
return false;
|
||||
CharUnits FieldSize = Context.getTypeSizeInChars(Field->getType());
|
||||
if (FieldSize != UnionSize)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isStructEmpty(QualType Ty) {
|
||||
const RecordDecl *RD = Ty->castAs<RecordType>()->getDecl();
|
||||
|
||||
if (!RD->field_empty())
|
||||
return false;
|
||||
|
||||
if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RD))
|
||||
return ClassDecl->isEmpty();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static llvm::Optional<int64_t>
|
||||
structHasUniqueObjectRepresentations(const ASTContext &Context,
|
||||
const RecordDecl *RD) {
|
||||
assert(!RD->isUnion() && "Must be struct/class type");
|
||||
const auto &Layout = Context.getASTRecordLayout(RD);
|
||||
|
||||
int64_t CurOffsetInBits = 0;
|
||||
if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RD)) {
|
||||
if (ClassDecl->isDynamicClass())
|
||||
return llvm::None;
|
||||
|
||||
SmallVector<std::pair<QualType, int64_t>, 4> Bases;
|
||||
for (const auto Base : ClassDecl->bases()) {
|
||||
// Empty types can be inherited from, and non-empty types can potentially
|
||||
// have tail padding, so just make sure there isn't an error.
|
||||
if (!isStructEmpty(Base.getType())) {
|
||||
llvm::Optional<int64_t> Size = structHasUniqueObjectRepresentations(
|
||||
Context, Base.getType()->getAs<RecordType>()->getDecl());
|
||||
if (!Size)
|
||||
return llvm::None;
|
||||
Bases.emplace_back(Base.getType(), Size.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(
|
||||
Bases.begin(), Bases.end(), [&](const std::pair<QualType, int64_t> &L,
|
||||
const std::pair<QualType, int64_t> &R) {
|
||||
return Layout.getBaseClassOffset(L.first->getAsCXXRecordDecl()) <
|
||||
Layout.getBaseClassOffset(R.first->getAsCXXRecordDecl());
|
||||
});
|
||||
|
||||
for (const auto Base : Bases) {
|
||||
int64_t BaseOffset = Context.toBits(
|
||||
Layout.getBaseClassOffset(Base.first->getAsCXXRecordDecl()));
|
||||
int64_t BaseSize = Base.second;
|
||||
if (BaseOffset != CurOffsetInBits)
|
||||
return llvm::None;
|
||||
CurOffsetInBits = BaseOffset + BaseSize;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto *Field : RD->fields()) {
|
||||
if (!Field->getType()->isReferenceType() &&
|
||||
!Context.hasUniqueObjectRepresentations(Field->getType()))
|
||||
return llvm::None;
|
||||
|
||||
int64_t FieldSizeInBits =
|
||||
Context.toBits(Context.getTypeSizeInChars(Field->getType()));
|
||||
if (Field->isBitField()) {
|
||||
int64_t BitfieldSize = Field->getBitWidthValue(Context);
|
||||
|
||||
if (BitfieldSize > FieldSizeInBits)
|
||||
return llvm::None;
|
||||
FieldSizeInBits = BitfieldSize;
|
||||
}
|
||||
|
||||
int64_t FieldOffsetInBits = Context.getFieldOffset(Field);
|
||||
|
||||
if (FieldOffsetInBits != CurOffsetInBits)
|
||||
return llvm::None;
|
||||
|
||||
CurOffsetInBits = FieldSizeInBits + FieldOffsetInBits;
|
||||
}
|
||||
|
||||
return CurOffsetInBits;
|
||||
}
|
||||
|
||||
bool ASTContext::hasUniqueObjectRepresentations(QualType Ty) const {
|
||||
// C++17 [meta.unary.prop]:
|
||||
// The predicate condition for a template specialization
|
||||
// has_unique_object_representations<T> shall be
|
||||
// satisfied if and only if:
|
||||
// (9.1) - T is trivially copyable, and
|
||||
// (9.2) - any two objects of type T with the same value have the same
|
||||
// object representation, where two objects
|
||||
// of array or non-union class type are considered to have the same value
|
||||
// if their respective sequences of
|
||||
// direct subobjects have the same values, and two objects of union type
|
||||
// are considered to have the same
|
||||
// value if they have the same active member and the corresponding members
|
||||
// have the same value.
|
||||
// The set of scalar types for which this condition holds is
|
||||
// implementation-defined. [ Note: If a type has padding
|
||||
// bits, the condition does not hold; otherwise, the condition holds true
|
||||
// for unsigned integral types. -- end note ]
|
||||
assert(!Ty.isNull() && "Null QualType sent to unique object rep check");
|
||||
|
||||
// Arrays are unique only if their element type is unique.
|
||||
if (Ty->isArrayType())
|
||||
return hasUniqueObjectRepresentations(getBaseElementType(Ty));
|
||||
|
||||
// (9.1) - T is trivially copyable...
|
||||
if (!Ty.isTriviallyCopyableType(*this))
|
||||
return false;
|
||||
|
||||
// All integrals and enums are unique.
|
||||
if (Ty->isIntegralOrEnumerationType())
|
||||
return true;
|
||||
|
||||
// All other pointers are unique.
|
||||
if (Ty->isPointerType())
|
||||
return true;
|
||||
|
||||
if (Ty->isMemberPointerType()) {
|
||||
const MemberPointerType *MPT = Ty->getAs<MemberPointerType>();
|
||||
return !ABI->getMemberPointerInfo(MPT).HasPadding;
|
||||
}
|
||||
|
||||
if (Ty->isRecordType()) {
|
||||
const RecordDecl *Record = Ty->getAs<RecordType>()->getDecl();
|
||||
|
||||
if (Record->isUnion())
|
||||
return unionHasUniqueObjectRepresentations(*this, Record);
|
||||
|
||||
Optional<int64_t> StructSize =
|
||||
structHasUniqueObjectRepresentations(*this, Record);
|
||||
|
||||
return StructSize &&
|
||||
StructSize.getValue() == static_cast<int64_t>(getTypeSize(Ty));
|
||||
}
|
||||
|
||||
// FIXME: More cases to handle here (list by rsmith):
|
||||
// vectors (careful about, eg, vector of 3 foo)
|
||||
// _Complex int and friends
|
||||
// _Atomic T
|
||||
// Obj-C block pointers
|
||||
// Obj-C object pointers
|
||||
// and perhaps OpenCL's various builtin types (pipe, sampler_t, event_t,
|
||||
// clk_event_t, queue_t, reserve_id_t)
|
||||
// There're also Obj-C class types and the Obj-C selector type, but I think it
|
||||
// makes sense for those to return false here.
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned ASTContext::CountNonClassIvars(const ObjCInterfaceDecl *OI) const {
|
||||
unsigned count = 0;
|
||||
// Count ivars declared in class extension.
|
||||
|
|
|
@ -31,9 +31,16 @@ class CXXABI {
|
|||
public:
|
||||
virtual ~CXXABI();
|
||||
|
||||
/// Returns the width and alignment of a member pointer in bits.
|
||||
virtual std::pair<uint64_t, unsigned>
|
||||
getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const = 0;
|
||||
struct MemberPointerInfo {
|
||||
uint64_t Width;
|
||||
unsigned Align;
|
||||
bool HasPadding;
|
||||
};
|
||||
|
||||
/// Returns the width and alignment of a member pointer in bits, as well as
|
||||
/// whether it has padding.
|
||||
virtual MemberPointerInfo
|
||||
getMemberPointerInfo(const MemberPointerType *MPT) const = 0;
|
||||
|
||||
/// Returns the default calling convention for C++ methods.
|
||||
virtual CallingConv getDefaultMethodCallConv(bool isVariadic) const = 0;
|
||||
|
|
|
@ -101,15 +101,17 @@ protected:
|
|||
public:
|
||||
ItaniumCXXABI(ASTContext &Ctx) : Context(Ctx) { }
|
||||
|
||||
std::pair<uint64_t, unsigned>
|
||||
getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const override {
|
||||
MemberPointerInfo
|
||||
getMemberPointerInfo(const MemberPointerType *MPT) const override {
|
||||
const TargetInfo &Target = Context.getTargetInfo();
|
||||
TargetInfo::IntType PtrDiff = Target.getPtrDiffType(0);
|
||||
uint64_t Width = Target.getTypeWidth(PtrDiff);
|
||||
unsigned Align = Target.getTypeAlign(PtrDiff);
|
||||
MemberPointerInfo MPI;
|
||||
MPI.Width = Target.getTypeWidth(PtrDiff);
|
||||
MPI.Align = Target.getTypeAlign(PtrDiff);
|
||||
MPI.HasPadding = false;
|
||||
if (MPT->isMemberFunctionPointer())
|
||||
Width = 2 * Width;
|
||||
return std::make_pair(Width, Align);
|
||||
MPI.Width *= 2;
|
||||
return MPI;
|
||||
}
|
||||
|
||||
CallingConv getDefaultMethodCallConv(bool isVariadic) const override {
|
||||
|
|
|
@ -76,8 +76,8 @@ class MicrosoftCXXABI : public CXXABI {
|
|||
public:
|
||||
MicrosoftCXXABI(ASTContext &Ctx) : Context(Ctx) { }
|
||||
|
||||
std::pair<uint64_t, unsigned>
|
||||
getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const override;
|
||||
MemberPointerInfo
|
||||
getMemberPointerInfo(const MemberPointerType *MPT) const override;
|
||||
|
||||
CallingConv getDefaultMethodCallConv(bool isVariadic) const override {
|
||||
if (!isVariadic &&
|
||||
|
@ -227,7 +227,7 @@ getMSMemberPointerSlots(const MemberPointerType *MPT) {
|
|||
return std::make_pair(Ptrs, Ints);
|
||||
}
|
||||
|
||||
std::pair<uint64_t, unsigned> MicrosoftCXXABI::getMemberPointerWidthAndAlign(
|
||||
CXXABI::MemberPointerInfo MicrosoftCXXABI::getMemberPointerInfo(
|
||||
const MemberPointerType *MPT) const {
|
||||
// The nominal struct is laid out with pointers followed by ints and aligned
|
||||
// to a pointer width if any are present and an int width otherwise.
|
||||
|
@ -237,22 +237,25 @@ std::pair<uint64_t, unsigned> MicrosoftCXXABI::getMemberPointerWidthAndAlign(
|
|||
|
||||
unsigned Ptrs, Ints;
|
||||
std::tie(Ptrs, Ints) = getMSMemberPointerSlots(MPT);
|
||||
uint64_t Width = Ptrs * PtrSize + Ints * IntSize;
|
||||
unsigned Align;
|
||||
MemberPointerInfo MPI;
|
||||
MPI.HasPadding = false;
|
||||
MPI.Width = Ptrs * PtrSize + Ints * IntSize;
|
||||
|
||||
// When MSVC does x86_32 record layout, it aligns aggregate member pointers to
|
||||
// 8 bytes. However, __alignof usually returns 4 for data memptrs and 8 for
|
||||
// function memptrs.
|
||||
if (Ptrs + Ints > 1 && Target.getTriple().isArch32Bit())
|
||||
Align = 64;
|
||||
MPI.Align = 64;
|
||||
else if (Ptrs)
|
||||
Align = Target.getPointerAlign(0);
|
||||
MPI.Align = Target.getPointerAlign(0);
|
||||
else
|
||||
Align = Target.getIntAlign();
|
||||
MPI.Align = Target.getIntAlign();
|
||||
|
||||
if (Target.getTriple().isArch64Bit())
|
||||
Width = llvm::alignTo(Width, Align);
|
||||
return std::make_pair(Width, Align);
|
||||
if (Target.getTriple().isArch64Bit()) {
|
||||
MPI.Width = llvm::alignTo(MPI.Width, MPI.Align);
|
||||
MPI.HasPadding = MPI.Width != (Ptrs * PtrSize + Ints * IntSize);
|
||||
}
|
||||
return MPI;
|
||||
}
|
||||
|
||||
CXXABI *clang::CreateMicrosoftCXXABI(ASTContext &Ctx) {
|
||||
|
|
144
lib/AST/Type.cpp
144
lib/AST/Type.cpp
|
@ -2201,150 +2201,6 @@ bool QualType::isTriviallyCopyableType(const ASTContext &Context) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool QualType::unionHasUniqueObjectRepresentations(
|
||||
const ASTContext &Context) const {
|
||||
assert((*this)->isUnionType() && "must be union type");
|
||||
CharUnits UnionSize = Context.getTypeSizeInChars(*this);
|
||||
const RecordDecl *Union = getTypePtr()->getAs<RecordType>()->getDecl();
|
||||
|
||||
for (const auto *Field : Union->fields()) {
|
||||
if (!Field->getType().hasUniqueObjectRepresentations(Context))
|
||||
return false;
|
||||
CharUnits FieldSize = Context.getTypeSizeInChars(Field->getType());
|
||||
if (FieldSize != UnionSize)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool isStructEmpty(QualType Ty) {
|
||||
assert(Ty.getTypePtr()->isStructureOrClassType() &&
|
||||
"Must be struct or class");
|
||||
const RecordDecl *RD = Ty.getTypePtr()->getAs<RecordType>()->getDecl();
|
||||
|
||||
if (!RD->field_empty())
|
||||
return false;
|
||||
|
||||
if (const CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RD)) {
|
||||
return ClassDecl->isEmpty();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QualType::structHasUniqueObjectRepresentations(
|
||||
const ASTContext &Context) const {
|
||||
assert((*this)->isStructureOrClassType() && "Must be struct or class");
|
||||
const RecordDecl *RD = getTypePtr()->getAs<RecordType>()->getDecl();
|
||||
|
||||
if (isStructEmpty(*this))
|
||||
return false;
|
||||
|
||||
// Check base types.
|
||||
CharUnits BaseSize{};
|
||||
if (const CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RD)) {
|
||||
for (const auto Base : ClassDecl->bases()) {
|
||||
if (Base.isVirtual())
|
||||
return false;
|
||||
|
||||
// Empty bases are permitted, otherwise ensure base has unique
|
||||
// representation. Also, Empty Base Optimization means that an
|
||||
// Empty base takes up 0 size.
|
||||
if (!isStructEmpty(Base.getType())) {
|
||||
if (!Base.getType().structHasUniqueObjectRepresentations(Context))
|
||||
return false;
|
||||
BaseSize += Context.getTypeSizeInChars(Base.getType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CharUnits StructSize = Context.getTypeSizeInChars(*this);
|
||||
|
||||
// This struct obviously has bases that keep it from being 'empty', so
|
||||
// checking fields is no longer required. Ensure that the struct size
|
||||
// is the sum of the bases.
|
||||
if (RD->field_empty())
|
||||
return StructSize == BaseSize;
|
||||
|
||||
CharUnits CurOffset =
|
||||
Context.toCharUnitsFromBits(Context.getFieldOffset(*RD->field_begin()));
|
||||
|
||||
// If the first field isn't at the sum of the size of the bases, there
|
||||
// is padding somewhere.
|
||||
if (BaseSize != CurOffset)
|
||||
return false;
|
||||
|
||||
for (const auto *Field : RD->fields()) {
|
||||
if (!Field->getType().hasUniqueObjectRepresentations(Context))
|
||||
return false;
|
||||
CharUnits FieldSize = Context.getTypeSizeInChars(Field->getType());
|
||||
CharUnits FieldOffset =
|
||||
Context.toCharUnitsFromBits(Context.getFieldOffset(Field));
|
||||
// Has padding between fields.
|
||||
if (FieldOffset != CurOffset)
|
||||
return false;
|
||||
CurOffset += FieldSize;
|
||||
}
|
||||
// Check for tail padding.
|
||||
return CurOffset == StructSize;
|
||||
}
|
||||
|
||||
bool QualType::hasUniqueObjectRepresentations(const ASTContext &Context) const {
|
||||
// C++17 [meta.unary.prop]:
|
||||
// The predicate condition for a template specialization
|
||||
// has_unique_object_representations<T> shall be
|
||||
// satisfied if and only if:
|
||||
// (9.1) - T is trivially copyable, and
|
||||
// (9.2) - any two objects of type T with the same value have the same
|
||||
// object representation, where two objects
|
||||
// of array or non-union class type are considered to have the same value
|
||||
// if their respective sequences of
|
||||
// direct subobjects have the same values, and two objects of union type
|
||||
// are considered to have the same
|
||||
// value if they have the same active member and the corresponding members
|
||||
// have the same value.
|
||||
// The set of scalar types for which this condition holds is
|
||||
// implementation-defined. [ Note: If a type has padding
|
||||
// bits, the condition does not hold; otherwise, the condition holds true
|
||||
// for unsigned integral types. -- end note ]
|
||||
if (isNull())
|
||||
return false;
|
||||
|
||||
// Arrays are unique only if their element type is unique.
|
||||
if ((*this)->isArrayType())
|
||||
return Context.getBaseElementType(*this).hasUniqueObjectRepresentations(
|
||||
Context);
|
||||
|
||||
// (9.1) - T is trivially copyable, and
|
||||
if (!isTriviallyCopyableType(Context))
|
||||
return false;
|
||||
|
||||
// Functions are not unique.
|
||||
if ((*this)->isFunctionType())
|
||||
return false;
|
||||
|
||||
// All integrals and enums are unique!
|
||||
if ((*this)->isIntegralOrEnumerationType())
|
||||
return true;
|
||||
|
||||
// All pointers are unique, since they're just integrals.
|
||||
if ((*this)->isPointerType() || (*this)->isMemberPointerType())
|
||||
return true;
|
||||
|
||||
if ((*this)->isRecordType()) {
|
||||
const RecordDecl *Record = getTypePtr()->getAs<RecordType>()->getDecl();
|
||||
|
||||
// Lambda types are not unique, so exclude them immediately.
|
||||
if (Record->isLambda())
|
||||
return false;
|
||||
|
||||
if (Record->isUnion())
|
||||
return unionHasUniqueObjectRepresentations(Context);
|
||||
return structHasUniqueObjectRepresentations(Context);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QualType::isNonWeakInMRRWithObjCWeak(const ASTContext &Context) const {
|
||||
return !Context.getLangOpts().ObjCAutoRefCount &&
|
||||
Context.getLangOpts().ObjCWeak &&
|
||||
|
|
|
@ -4616,7 +4616,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
|
|||
// function call.
|
||||
return !T->isIncompleteType();
|
||||
case UTT_HasUniqueObjectRepresentations:
|
||||
return T.hasUniqueObjectRepresentations(C);
|
||||
return C.hasUniqueObjectRepresentations(T);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-linux-pc -DIS64 -fsyntax-only -verify -std=c++17 %s
|
||||
// RUN: %clang_cc1 -triple x86_64-windows-pc -DIS64 -fsyntax-only -verify -std=c++17 %s
|
||||
// RUN: %clang_cc1 -triple i386-linux-pc -fsyntax-only -verify -std=c++17 %s
|
||||
// RUN: %clang_cc1 -triple i386-windows-pc -DW32 -fsyntax-only -verify -std=c++17 %s
|
||||
// expected-no-diagnostics
|
||||
|
||||
struct Base {};
|
||||
struct A : virtual Base {
|
||||
virtual void n() {}
|
||||
};
|
||||
|
||||
auto p = &A::n;
|
||||
static_assert(__has_unique_object_representations(decltype(p)));
|
||||
|
||||
struct B {
|
||||
decltype(p) x;
|
||||
int b;
|
||||
#ifdef IS64
|
||||
// required on 64 bit to fill out the tail padding.
|
||||
int c;
|
||||
#endif
|
||||
};
|
||||
static_assert(__has_unique_object_representations(B));
|
||||
|
||||
struct C { // has padding on Win32, but nothing else.
|
||||
decltype(p) x;
|
||||
};
|
||||
#ifdef W32
|
||||
static_assert(!__has_unique_object_representations(C));
|
||||
#else
|
||||
static_assert(__has_unique_object_representations(C));
|
||||
#endif
|
|
@ -2447,7 +2447,7 @@ struct Padding {
|
|||
int b;
|
||||
};
|
||||
|
||||
static_assert(!has_unique_object_representations<Padding>::value, "but not with padding");
|
||||
//static_assert(!has_unique_object_representations<Padding>::value, "but not with padding");
|
||||
|
||||
struct InheritsFromPadding : Padding {
|
||||
int c;
|
||||
|
@ -2518,12 +2518,11 @@ enum class LLEnumClass : long long { xLongExample,
|
|||
static_assert(has_unique_object_representations<ExampleEnumClass>::value, "Enums are integrals, so unique!");
|
||||
static_assert(has_unique_object_representations<LLEnumClass>::value, "Enums are integrals, so unique!");
|
||||
|
||||
// because reference types aren't object types
|
||||
// because references aren't trivially copyable.
|
||||
static_assert(!has_unique_object_representations<int &>::value, "No references!");
|
||||
static_assert(!has_unique_object_representations<const int &>::value, "No references!");
|
||||
static_assert(!has_unique_object_representations<volatile int &>::value, "No references!");
|
||||
static_assert(!has_unique_object_representations<const volatile int &>::value, "No references!");
|
||||
|
||||
static_assert(!has_unique_object_representations<Empty>::value, "No empty types!");
|
||||
|
||||
class Compressed : Empty {
|
||||
|
@ -2556,6 +2555,16 @@ static_assert(!has_unique_object_representations<double[42]>::value, "So no arra
|
|||
static_assert(!has_unique_object_representations<double[]>::value, "So no array of doubles!");
|
||||
static_assert(!has_unique_object_representations<double[][42]>::value, "So no array of doubles!");
|
||||
|
||||
struct __attribute__((aligned(16))) WeirdAlignment {
|
||||
int i;
|
||||
};
|
||||
union __attribute__((aligned(16))) WeirdAlignmentUnion {
|
||||
int i;
|
||||
};
|
||||
static_assert(!has_unique_object_representations<WeirdAlignment>::value, "Alignment causes padding");
|
||||
static_assert(!has_unique_object_representations<WeirdAlignmentUnion>::value, "Alignment causes padding");
|
||||
static_assert(!has_unique_object_representations<WeirdAlignment[42]>::value, "Also no arrays that have padding");
|
||||
|
||||
static_assert(!has_unique_object_representations<int(int)>::value, "Functions are not unique");
|
||||
static_assert(!has_unique_object_representations<int(int) const>::value, "Functions are not unique");
|
||||
static_assert(!has_unique_object_representations<int(int) volatile>::value, "Functions are not unique");
|
||||
|
@ -2582,6 +2591,73 @@ static_assert(!has_unique_object_representations<int(int, ...) const &&>::value,
|
|||
static_assert(!has_unique_object_representations<int(int, ...) volatile &&>::value, "Functions are not unique");
|
||||
static_assert(!has_unique_object_representations<int(int, ...) const volatile &&>::value, "Functions are not unique");
|
||||
|
||||
static auto lambda = []() {};
|
||||
static_assert(!has_unique_object_representations<decltype(lambda)>::value, "Lambdas are not unique");
|
||||
void foo(){
|
||||
static auto lambda = []() {};
|
||||
static_assert(!has_unique_object_representations<decltype(lambda)>::value, "Lambdas follow struct rules");
|
||||
int i;
|
||||
static auto lambda2 = [i]() {};
|
||||
static_assert(has_unique_object_representations<decltype(lambda2)>::value, "Lambdas follow struct rules");
|
||||
}
|
||||
|
||||
struct PaddedBitfield {
|
||||
char c : 6;
|
||||
char d : 1;
|
||||
};
|
||||
|
||||
struct UnPaddedBitfield {
|
||||
char c : 6;
|
||||
char d : 2;
|
||||
};
|
||||
|
||||
struct AlignedPaddedBitfield {
|
||||
char c : 6;
|
||||
__attribute__((aligned(1)))
|
||||
char d : 2;
|
||||
};
|
||||
|
||||
static_assert(!has_unique_object_representations<PaddedBitfield>::value, "Bitfield padding");
|
||||
static_assert(has_unique_object_representations<UnPaddedBitfield>::value, "Bitfield padding");
|
||||
static_assert(!has_unique_object_representations<AlignedPaddedBitfield>::value, "Bitfield padding");
|
||||
|
||||
struct BoolBitfield {
|
||||
bool b : 8;
|
||||
};
|
||||
|
||||
static_assert(has_unique_object_representations<BoolBitfield>::value, "Bitfield bool");
|
||||
|
||||
struct BoolBitfield2 {
|
||||
bool b : 16;
|
||||
};
|
||||
|
||||
static_assert(!has_unique_object_representations<BoolBitfield2>::value, "Bitfield bool");
|
||||
|
||||
struct GreaterSizeBitfield {
|
||||
//expected-warning@+1 {{width of bit-field 'n'}}
|
||||
int n : 1024;
|
||||
};
|
||||
|
||||
static_assert(sizeof(GreaterSizeBitfield) == 128, "Bitfield Size");
|
||||
static_assert(!has_unique_object_representations<GreaterSizeBitfield>::value, "Bitfield padding");
|
||||
|
||||
struct StructWithRef {
|
||||
int &I;
|
||||
};
|
||||
|
||||
static_assert(has_unique_object_representations<StructWithRef>::value, "References are still unique");
|
||||
|
||||
struct NotUniqueBecauseTailPadding {
|
||||
int &r;
|
||||
char a;
|
||||
};
|
||||
struct CanBeUniqueIfNoPadding : NotUniqueBecauseTailPadding {
|
||||
char b[7];
|
||||
};
|
||||
|
||||
static_assert(!has_unique_object_representations<NotUniqueBecauseTailPadding>::value,
|
||||
"non trivial");
|
||||
// Can be unique on Itanium, since the is child class' data is 'folded' into the
|
||||
// parent's tail padding.
|
||||
static_assert(sizeof(CanBeUniqueIfNoPadding) != 16 ||
|
||||
has_unique_object_representations<CanBeUniqueIfNoPadding>::value,
|
||||
"inherit from std layout");
|
||||
|
||||
|
|
Loading…
Reference in New Issue