r316518 - mplement __has_unique_object_representations
David Majnemer via cfe-commits
cfe-commits at lists.llvm.org
Tue Oct 24 14:55:12 PDT 2017
On Tue, Oct 24, 2017 at 2:31 PM, Erich Keane via cfe-commits <
cfe-commits at 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 at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20171024/deae2782/attachment-0001.html>
More information about the cfe-commits
mailing list