On Tue, Oct 24, 2017 at 2:31 PM, Erich Keane via cfe-commits < cfe-commits@lists.llvm.org> wrote:
> Author: erichkeane > Date: Tue Oct 24 14:31:50 2017 > New Revision: 316518 > > URL: http://llvm.org/viewvc/llvm-project?rev=316518&view=rev > Log: > mplement __has_unique_object_representations > > A helper builtin to facilitate implementing the > std::has_unique_object_representations type trait. > > Requested here: https://bugs.llvm.org/show_bug.cgi?id=34942 > Also already exists in GCC and MSVC. > > Differential Revision: https://reviews.llvm.org/D39064 > > Modified: > cfe/trunk/include/clang/AST/Type.h > cfe/trunk/include/clang/Basic/TokenKinds.def > cfe/trunk/include/clang/Basic/TypeTraits.h > cfe/trunk/lib/AST/Type.cpp > cfe/trunk/lib/Parse/ParseExpr.cpp > cfe/trunk/lib/Sema/SemaExprCXX.cpp > cfe/trunk/test/SemaCXX/type-traits.cpp > > Modified: cfe/trunk/include/clang/AST/Type.h > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/ > clang/AST/Type.h?rev=316518&r1=316517&r2=316518&view=diff > ============================================================ > ================== > --- cfe/trunk/include/clang/AST/Type.h (original) > +++ cfe/trunk/include/clang/AST/Type.h Tue Oct 24 14:31:50 2017 > @@ -770,6 +770,10 @@ public: > /// 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. > > @@ -1114,6 +1118,8 @@ public: > 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. > > Modified: cfe/trunk/include/clang/Basic/TokenKinds.def > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/ > clang/Basic/TokenKinds.def?rev=316518&r1=316517&r2=316518&view=diff > ============================================================ > ================== > --- cfe/trunk/include/clang/Basic/TokenKinds.def (original) > +++ cfe/trunk/include/clang/Basic/TokenKinds.def Tue Oct 24 14:31:50 2017 > @@ -455,6 +455,8 @@ TYPE_TRAIT_1(__is_pod, IsPOD, KEYCXX) > 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) > > Modified: cfe/trunk/include/clang/Basic/TypeTraits.h > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/ > clang/Basic/TypeTraits.h?rev=316518&r1=316517&r2=316518&view=diff > ============================================================ > ================== > --- cfe/trunk/include/clang/Basic/TypeTraits.h (original) > +++ cfe/trunk/include/clang/Basic/TypeTraits.h Tue Oct 24 14:31:50 2017 > @@ -70,7 +70,8 @@ namespace clang { > UTT_IsUnsigned, > UTT_IsVoid, > UTT_IsVolatile, > - UTT_Last = UTT_IsVolatile, > + UTT_HasUniqueObjectRepresentations, > + UTT_Last = UTT_HasUniqueObjectRepresentations, > BTT_IsBaseOf, > BTT_IsConvertible, > BTT_IsConvertibleTo, > > Modified: cfe/trunk/lib/AST/Type.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ > Type.cpp?rev=316518&r1=316517&r2=316518&view=diff > ============================================================ > ================== > --- cfe/trunk/lib/AST/Type.cpp (original) > +++ cfe/trunk/lib/AST/Type.cpp Tue Oct 24 14:31:50 2017 > @@ -2166,6 +2166,152 @@ bool QualType::isTriviallyCopyableType(c > 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().structHasUniqueObjectRepresent > ations(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 > This looks like unicode, please replace it with ASCII. > + // 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 > Ditto. > + 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 && > > Modified: cfe/trunk/lib/Parse/ParseExpr.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ > ParseExpr.cpp?rev=316518&r1=316517&r2=316518&view=diff > ============================================================ > ================== > --- cfe/trunk/lib/Parse/ParseExpr.cpp (original) > +++ cfe/trunk/lib/Parse/ParseExpr.cpp Tue Oct 24 14:31:50 2017 > @@ -716,6 +716,7 @@ class CastExpressionIdValidator : public > /// '__is_sealed' [MS] > /// '__is_trivial' > /// '__is_union' > +/// '__has_unique_object_representations' > /// > /// [Clang] unary-type-trait: > /// '__is_aggregate' > > Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/ > SemaExprCXX.cpp?rev=316518&r1=316517&r2=316518&view=diff > ============================================================ > ================== > --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) > +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Tue Oct 24 14:31:50 2017 > @@ -4175,6 +4175,7 @@ static bool CheckUnaryTypeTraitTypeCompl > case UTT_IsDestructible: > case UTT_IsNothrowDestructible: > case UTT_IsTriviallyDestructible: > + case UTT_HasUniqueObjectRepresentations: > if (ArgTy->isIncompleteArrayType() || ArgTy->isVoidType()) > return true; > > @@ -4614,6 +4615,8 @@ static bool EvaluateUnaryTypeTrait(Sema > // 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); > } > } > > > Modified: cfe/trunk/test/SemaCXX/type-traits.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ > SemaCXX/type-traits.cpp?rev=316518&r1=316517&r2=316518&view=diff > ============================================================ > ================== > --- cfe/trunk/test/SemaCXX/type-traits.cpp (original) > +++ cfe/trunk/test/SemaCXX/type-traits.cpp Tue Oct 24 14:31:50 2017 > @@ -2352,3 +2352,236 @@ void is_trivially_destructible_test() { > { 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 InheritsFromNoPadding : NoPadding { > + int c; > + int d; > +}; > + > +static_assert(has_unique_object_representations<InheritsFromNoPadding>::value, > "types without padding are"); > + > +struct VirtuallyInheritsFromNoPadding : virtual NoPadding { > + int c; > + int d; > +}; > + > +static_assert(!has_unique_object_representations< > VirtuallyInheritsFromNoPadding>::value, "No virtual inheritence"); > + > +struct Padding { > + char a; > + int b; > +}; > + > +static_assert(!has_unique_object_representations<Padding>::value, "but > not with padding"); > + > +struct InheritsFromPadding : Padding { > + int c; > + int d; > +}; > + > +static_assert(!has_unique_object_representations<InheritsFromPadding>::value, > "or its subclasses"); > + > +struct TailPadding { > + int a; > + char b; > +}; > + > +static_assert(!has_unique_object_representations<TailPadding>::value, > "even at the end"); > + > +struct TinyStruct { > + char a; > +}; > + > +static_assert(has_unique_object_representations<TinyStruct>::value, > "Should be no padding"); > + > +struct InheritsFromTinyStruct : TinyStruct { > + int b; > +}; > + > +static_assert(!has_unique_object_representations< > InheritsFromTinyStruct>::value, "Inherit causes padding"); > + > +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"); > + > +class EmptyInheritor : Compressed {}; > + > +static_assert(has_unique_object_representations<EmptyInheritor>::value, > "As long as the base has items, empty is ok"); > + > +class Dynamic { > + virtual void A(); > + int i; > +}; > + > +static_assert(!has_unique_object_representations<Dynamic>::value, > "Dynamic types are not valid"); > + > +class InheritsDynamic : Dynamic { > + int j; > +}; > + > +static_assert(!has_unique_object_representations<InheritsDynamic>::value, > "Dynamic types are not valid"); > + > +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 >
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits