summaryrefslogtreecommitdiffstats
path: root/clang/lib/AST/ASTContext.cpp
diff options
context:
space:
mode:
authorErich Keane <erich.keane@intel.com>2017-11-30 16:37:02 +0000
committerErich Keane <erich.keane@intel.com>2017-11-30 16:37:02 +0000
commit8a6b7409959f3f6e6d19ac48453c8e9f4a51d829 (patch)
treeb9c9140b22818277b9f318be7fc2754749d9bad7 /clang/lib/AST/ASTContext.cpp
parentc71cced0aae46ab4f27e2ea755819f308661670b (diff)
downloadbcm5719-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.cpp166
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.
OpenPOWER on IntegriCloud