summaryrefslogtreecommitdiff
path: root/lib/AST/Type.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/AST/Type.cpp')
-rw-r--r--lib/AST/Type.cpp146
1 files changed, 146 insertions, 0 deletions
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index cc5a00b584..15af195064 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -2166,6 +2166,152 @@ 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;
+}
+
+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 &&