erichkeane updated this revision to Diff 119533. erichkeane marked 3 inline comments as done.
https://reviews.llvm.org/D39064 Files: include/clang/AST/Type.h include/clang/Basic/TokenKinds.def include/clang/Basic/TypeTraits.h lib/AST/Type.cpp lib/Parse/ParseExpr.cpp lib/Sema/SemaExprCXX.cpp test/SemaCXX/type-traits.cpp
Index: lib/Parse/ParseExpr.cpp =================================================================== --- lib/Parse/ParseExpr.cpp +++ lib/Parse/ParseExpr.cpp @@ -716,6 +716,7 @@ /// '__is_sealed' [MS] /// '__is_trivial' /// '__is_union' +/// '__has_unique_object_representations' /// /// [Clang] unary-type-trait: /// '__is_aggregate' Index: lib/AST/Type.cpp =================================================================== --- lib/AST/Type.cpp +++ lib/AST/Type.cpp @@ -2166,6 +2166,89 @@ return false; } +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; + + // Empty types are not unique. + if (Record->field_empty()) + return false; + + CharUnits RecordSize = Context.getTypeSizeInChars(*this); + CharUnits CurOffset = Context.toCharUnitsFromBits( + Context.getFieldOffset(*Record->field_begin())); + for (const auto *Field : Record->fields()) { + if (!Field->getType().hasUniqueObjectRepresentations(Context)) + return false; + + // Check for padding. + CharUnits FieldSize = Context.getTypeSizeInChars(Field->getType()); + if (Record->isUnion() && FieldSize != RecordSize) + return false; + else if (!Record->isUnion()) { + CharUnits FieldOffset = + Context.toCharUnitsFromBits(Context.getFieldOffset(Field)); + if (FieldOffset != CurOffset) + return false; + CurOffset += FieldSize; + } + } + + // struct/class with tail padding. + if (!Record->isUnion() && CurOffset != RecordSize) + return false; + + return true; + } + return false; +} + bool QualType::isNonWeakInMRRWithObjCWeak(const ASTContext &Context) const { return !Context.getLangOpts().ObjCAutoRefCount && Context.getLangOpts().ObjCWeak && Index: lib/Sema/SemaExprCXX.cpp =================================================================== --- lib/Sema/SemaExprCXX.cpp +++ lib/Sema/SemaExprCXX.cpp @@ -4175,6 +4175,7 @@ case UTT_IsDestructible: case UTT_IsNothrowDestructible: case UTT_IsTriviallyDestructible: + case UTT_HasUniqueObjectRepresentations: if (ArgTy->isIncompleteArrayType() || ArgTy->isVoidType()) return true; @@ -4614,6 +4615,8 @@ // Returns True if and only if T is a complete type at the point of the // function call. return !T->isIncompleteType(); + case UTT_HasUniqueObjectRepresentations: + return T.hasUniqueObjectRepresentations(C); } } Index: include/clang/AST/Type.h =================================================================== --- include/clang/AST/Type.h +++ include/clang/AST/Type.h @@ -770,6 +770,10 @@ /// 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. Index: include/clang/Basic/TokenKinds.def =================================================================== --- include/clang/Basic/TokenKinds.def +++ include/clang/Basic/TokenKinds.def @@ -455,6 +455,8 @@ TYPE_TRAIT_1(__is_polymorphic, IsPolymorphic, KEYCXX) TYPE_TRAIT_1(__is_trivial, IsTrivial, KEYCXX) TYPE_TRAIT_1(__is_union, IsUnion, KEYCXX) +TYPE_TRAIT_1(__has_unique_object_representations, + HasUniqueObjectRepresentations, KEYCXX) // Clang-only C++ Type Traits TYPE_TRAIT_N(__is_trivially_constructible, IsTriviallyConstructible, KEYCXX) Index: include/clang/Basic/TypeTraits.h =================================================================== --- include/clang/Basic/TypeTraits.h +++ include/clang/Basic/TypeTraits.h @@ -70,7 +70,8 @@ UTT_IsUnsigned, UTT_IsVoid, UTT_IsVolatile, - UTT_Last = UTT_IsVolatile, + UTT_HasUniqueObjectRepresentations, + UTT_Last = UTT_HasUniqueObjectRepresentations, BTT_IsBaseOf, BTT_IsConvertible, BTT_IsConvertibleTo, Index: test/SemaCXX/type-traits.cpp =================================================================== --- test/SemaCXX/type-traits.cpp +++ test/SemaCXX/type-traits.cpp @@ -2352,3 +2352,186 @@ { int arr[F(__is_trivially_destructible(void))]; } { int arr[F(__is_trivially_destructible(const volatile void))]; } } + +// Instantiation of __has_unique_object_representations +template <typename T> +struct has_unique_object_representations { + static const bool value = __has_unique_object_representations(T); +}; + +static_assert(!has_unique_object_representations<void>::value, "void is never unique"); +static_assert(!has_unique_object_representations<const void>::value, "void is never unique"); +static_assert(!has_unique_object_representations<volatile void>::value, "void is never unique"); +static_assert(!has_unique_object_representations<const volatile void>::value, "void is never unique"); + +static_assert(has_unique_object_representations<int>::value, "integrals are"); +static_assert(has_unique_object_representations<const int>::value, "integrals are"); +static_assert(has_unique_object_representations<volatile int>::value, "integrals are"); +static_assert(has_unique_object_representations<const volatile int>::value, "integrals are"); + +static_assert(has_unique_object_representations<void *>::value, "as are pointers"); +static_assert(has_unique_object_representations<const void *>::value, "as are pointers"); +static_assert(has_unique_object_representations<volatile void *>::value, "are pointers"); +static_assert(has_unique_object_representations<const volatile void *>::value, "as are pointers"); + +static_assert(has_unique_object_representations<int *>::value, "as are pointers"); +static_assert(has_unique_object_representations<const int *>::value, "as are pointers"); +static_assert(has_unique_object_representations<volatile int *>::value, "as are pointers"); +static_assert(has_unique_object_representations<const volatile int *>::value, "as are pointers"); + +class C {}; +using FP = int (*)(int); +using PMF = int (C::*)(int); +using PMD = int C::*; + +static_assert(has_unique_object_representations<FP>::value, "even function pointers"); +static_assert(has_unique_object_representations<const FP>::value, "even function pointers"); +static_assert(has_unique_object_representations<volatile FP>::value, "even function pointers"); +static_assert(has_unique_object_representations<const volatile FP>::value, "even function pointers"); + +static_assert(has_unique_object_representations<PMF>::value, "and pointer to members"); +static_assert(has_unique_object_representations<const PMF>::value, "and pointer to members"); +static_assert(has_unique_object_representations<volatile PMF>::value, "and pointer to members"); +static_assert(has_unique_object_representations<const volatile PMF>::value, "and pointer to members"); + +static_assert(has_unique_object_representations<PMD>::value, "and pointer to members"); +static_assert(has_unique_object_representations<const PMD>::value, "and pointer to members"); +static_assert(has_unique_object_representations<volatile PMD>::value, "and pointer to members"); +static_assert(has_unique_object_representations<const volatile PMD>::value, "and pointer to members"); + +static_assert(has_unique_object_representations<bool>::value, "yes, all integral types"); +static_assert(has_unique_object_representations<char>::value, "yes, all integral types"); +static_assert(has_unique_object_representations<signed char>::value, "yes, all integral types"); +static_assert(has_unique_object_representations<unsigned char>::value, "yes, all integral types"); +static_assert(has_unique_object_representations<short>::value, "yes, all integral types"); +static_assert(has_unique_object_representations<unsigned short>::value, "yes, all integral types"); +static_assert(has_unique_object_representations<int>::value, "yes, all integral types"); +static_assert(has_unique_object_representations<unsigned int>::value, "yes, all integral types"); +static_assert(has_unique_object_representations<long>::value, "yes, all integral types"); +static_assert(has_unique_object_representations<unsigned long>::value, "yes, all integral types"); +static_assert(has_unique_object_representations<long long>::value, "yes, all integral types"); +static_assert(has_unique_object_representations<unsigned long long>::value, "yes, all integral types"); +static_assert(has_unique_object_representations<wchar_t>::value, "yes, all integral types"); +static_assert(has_unique_object_representations<char16_t>::value, "yes, all integral types"); +static_assert(has_unique_object_representations<char32_t>::value, "yes, all integral types"); + +static_assert(!has_unique_object_representations<void>::value, "but not void!"); +static_assert(!has_unique_object_representations<decltype(nullptr)>::value, "or nullptr_t"); +static_assert(!has_unique_object_representations<float>::value, "definitely not Floating Point"); +static_assert(!has_unique_object_representations<double>::value, "definitely not Floating Point"); +static_assert(!has_unique_object_representations<long double>::value, "definitely not Floating Point"); + +struct NoPadding { + int a; + int b; +}; + +static_assert(has_unique_object_representations<NoPadding>::value, "types without padding are"); + +struct Padding { + char a; + int b; +}; + +static_assert(!has_unique_object_representations<Padding>::value, "but not with padding"); + +struct TailPadding { + int a; + char b; +}; + +static_assert(!has_unique_object_representations<TailPadding>::value, "even at the end"); + +union NoPaddingUnion { + int a; + unsigned int b; +}; + +static_assert(has_unique_object_representations<NoPaddingUnion>::value, "unions follow the same rules as structs"); + +union PaddingUnion { + int a; + long long b; +}; + +static_assert(!has_unique_object_representations<PaddingUnion>::value, "unions follow the same rules as structs"); + +struct NotTriviallyCopyable { + int x; + NotTriviallyCopyable(const NotTriviallyCopyable &) {} +}; + +static_assert(!has_unique_object_representations<NotTriviallyCopyable>::value, "must be trivially copyable"); + +struct HasNonUniqueMember { + float x; +}; + +static_assert(!has_unique_object_representations<HasNonUniqueMember>::value, "all members must be unique"); + +enum ExampleEnum { xExample, + yExample }; +enum LLEnum : long long { xLongExample, + yLongExample }; + +static_assert(has_unique_object_representations<ExampleEnum>::value, "Enums are integrals, so unique!"); +static_assert(has_unique_object_representations<LLEnum>::value, "Enums are integrals, so unique!"); + +enum class ExampleEnumClass { xExample, + yExample }; +enum class LLEnumClass : long long { xLongExample, + yLongExample }; + +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 +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 { + int x; +}; + +static_assert(has_unique_object_representations<Compressed>::value, "But inheriting from one is ok"); + +static_assert(has_unique_object_representations<int[42]>::value, "Arrays are fine, as long as their value type is"); +static_assert(has_unique_object_representations<int[]>::value, "Arrays are fine, as long as their value type is"); +static_assert(has_unique_object_representations<int[][42]>::value, "Arrays are fine, as long as their value type is"); +static_assert(!has_unique_object_representations<double[42]>::value, "So no array of doubles!"); +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!"); + +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"); +static_assert(!has_unique_object_representations<int(int) const volatile>::value, "Functions are not unique"); +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"); +static_assert(!has_unique_object_representations<int(int) const volatile &>::value, "Functions are not unique"); +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"); +static_assert(!has_unique_object_representations<int(int) const volatile &&>::value, "Functions are not unique"); + +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"); +static_assert(!has_unique_object_representations<int(int, ...) const volatile>::value, "Functions are not unique"); +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"); +static_assert(!has_unique_object_representations<int(int, ...) const volatile &>::value, "Functions are not unique"); +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"); +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"); +
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits