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