diff options
author | Erich Keane <erich.keane@intel.com> | 2017-11-30 16:37:02 +0000 |
---|---|---|
committer | Erich Keane <erich.keane@intel.com> | 2017-11-30 16:37:02 +0000 |
commit | 8a6b7409959f3f6e6d19ac48453c8e9f4a51d829 (patch) | |
tree | b9c9140b22818277b9f318be7fc2754749d9bad7 /clang/lib/AST/ASTContext.cpp | |
parent | c71cced0aae46ab4f27e2ea755819f308661670b (diff) | |
download | bcm5719-llvm-8a6b7409959f3f6e6d19ac48453c8e9f4a51d829.tar.gz bcm5719-llvm-8a6b7409959f3f6e6d19ac48453c8e9f4a51d829.zip |
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
llvm-svn: 319446
Diffstat (limited to 'clang/lib/AST/ASTContext.cpp')
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 166 |
1 files changed, 165 insertions, 1 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index d4c94368e68..c16882a7e67 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -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. |