erichkeane created this revision.
Corrections done for @rsmith 's comments after-commit
on cfe-commits.
https://reviews.llvm.org/D39347
Files:
include/clang/AST/ASTContext.h
include/clang/AST/Type.h
lib/AST/ASTContext.cpp
lib/AST/Type.cpp
lib/Sema/SemaExprCXX.cpp
test/SemaCXX/type-traits.cpp
Index: lib/AST/Type.cpp
===================================================================
--- lib/AST/Type.cpp
+++ lib/AST/Type.cpp
@@ -2166,151 +2166,6 @@
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 &&
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -2110,6 +2110,146 @@
}
}
+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) {
+ 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;
+}
+
+static bool structHasUniqueObjectRepresentations(const ASTContext &Context,
+ const RecordDecl *RD) {
+ assert((RD->isStruct() || RD->isClass()) && "Must be struct/class type");
+ const auto &Layout = Context.getASTRecordLayout(RD);
+
+ CharUnits CurOffset{};
+ if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RD)) {
+ if (ClassDecl->isDynamicClass() || ClassDecl->getNumVBases() != 0)
+ return false;
+
+ SmallVector<QualType, 4> Bases;
+ for (const auto Base : ClassDecl->bases()) {
+ // Empty types can be inherited from, as long as they are handled
+ // by EBO. This will be checked in the next loop.
+ if (!isStructEmpty(Base.getType()) &&
+ !Context.hasUniqueObjectRepresentations(Base.getType()))
+ return false;
+ Bases.push_back(Base.getType());
+ }
+
+ std::sort(Bases.begin(), Bases.end(),
+ [&](const QualType &L, const QualType &R) {
+ return Layout.getBaseClassOffset(L->getAsCXXRecordDecl()) <
+ Layout.getBaseClassOffset(R->getAsCXXRecordDecl());
+ });
+
+ for (const auto Base : Bases) {
+ CharUnits BaseOffset =
+ Layout.getBaseClassOffset(Base->getAsCXXRecordDecl());
+ CharUnits BaseSize = Context.getTypeSizeInChars(Base);
+ if (BaseOffset != CurOffset)
+ return false;
+ // Empty bases are only allowed in EBO.
+ if (!isStructEmpty(Base))
+ CurOffset = BaseOffset + BaseSize;
+ }
+ }
+
+ int FieldIndex = 0;
+ for (const auto *Field : RD->fields()) {
+ if (!Context.hasUniqueObjectRepresentations(Field->getType()))
+ return false;
+ CharUnits FieldSize = Context.getTypeSizeInChars(Field->getType());
+ CharUnits FieldOffset =
+ Context.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex));
+
+ if (FieldOffset != CurOffset)
+ return false;
+
+ CurOffset = FieldSize + FieldOffset;
+
+ ++FieldIndex;
+ }
+
+ // Handles tail-padding. >= comparision takes care of EBO cases.
+ return CurOffset == Layout.getSize();
+}
+
+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 ]
+ if (Ty.isNull())
+ return false;
+
+ // 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;
+
+ // Functions are not unique.
+ if (Ty->isFunctionType())
+ return false;
+
+ // All integrals and enums are unique.
+ if (Ty->isIntegralOrEnumerationType())
+ return true;
+
+ // All other pointers are unique.
+ if (Ty->isPointerType() || Ty->isMemberPointerType())
+ return true;
+
+ if (Ty->isRecordType()) {
+ const RecordDecl *Record = Ty->getAs<RecordType>()->getDecl();
+
+ if (Record->isUnion())
+ return unionHasUniqueObjectRepresentations(*this, Record);
+ return structHasUniqueObjectRepresentations(*this, Record);
+ }
+
+ return false;
+}
+
unsigned ASTContext::CountNonClassIvars(const ObjCInterfaceDecl *OI) const {
unsigned count = 0;
// Count ivars declared in class extension.
Index: lib/Sema/SemaExprCXX.cpp
===================================================================
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -4616,7 +4616,7 @@
// function call.
return !T->isIncompleteType();
case UTT_HasUniqueObjectRepresentations:
- return T.hasUniqueObjectRepresentations(C);
+ return C.hasUniqueObjectRepresentations(T);
}
}
Index: include/clang/AST/ASTContext.h
===================================================================
--- include/clang/AST/ASTContext.h
+++ include/clang/AST/ASTContext.h
@@ -2109,6 +2109,10 @@
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
//===--------------------------------------------------------------------===//
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h
+++ include/clang/AST/Type.h
@@ -770,10 +770,6 @@
/// 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.
@@ -1118,8 +1114,6 @@
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.
Index: test/SemaCXX/type-traits.cpp
===================================================================
--- test/SemaCXX/type-traits.cpp
+++ test/SemaCXX/type-traits.cpp
@@ -2523,7 +2523,6 @@
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[]>::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,11 @@
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 rues");
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits