diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -2684,7 +2684,12 @@ if (!RD->isUnion()) return structHasUniqueObjectRepresentations(Context, RD); } - if (!Field->getType()->isReferenceType() && + + // A _BitInt type may not be unique if it has padding bits + // but if it is a bitfield the padding bits are not used + bool IsBitIntType = + !Field->getType()->isReferenceType() && Field->getType()->isBitIntType(); + if (!Field->getType()->isReferenceType() && !IsBitIntType && !Context.hasUniqueObjectRepresentations(Field->getType())) return llvm::None; @@ -2692,9 +2697,17 @@ Context.toBits(Context.getTypeSizeInChars(Field->getType())); if (Field->isBitField()) { int64_t BitfieldSize = Field->getBitWidthValue(Context); - if (BitfieldSize > FieldSizeInBits) + if (IsBitIntType) { + if ((unsigned)BitfieldSize > + cast(Field->getType())->getNumBits()) + return llvm::None; + } else if (BitfieldSize > FieldSizeInBits) { return llvm::None; + } FieldSizeInBits = BitfieldSize; + } else if (IsBitIntType && + !Context.hasUniqueObjectRepresentations(Field->getType())) { + return llvm::None; } return FieldSizeInBits; } @@ -2792,8 +2805,13 @@ return false; // All integrals and enums are unique. - if (Ty->isIntegralOrEnumerationType()) + if (Ty->isIntegralOrEnumerationType()) { + // Except _BitInt types that have padding bits + if (const auto *BIT = dyn_cast(Ty)) + return getTypeSize(BIT) == BIT->getNumBits(); + return true; + } // All other pointers are unique. if (Ty->isPointerType()) diff --git a/clang/test/SemaCXX/has_unique_object_reps_bitint.cpp b/clang/test/SemaCXX/has_unique_object_reps_bitint.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/has_unique_object_reps_bitint.cpp @@ -0,0 +1,76 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -verify -std=c++17 -Wno-bitfield-width %s +// expected-no-diagnostics + +static_assert(__has_unique_object_representations(_BitInt(8))); +static_assert(__has_unique_object_representations(unsigned _BitInt(8))); +static_assert(__has_unique_object_representations(_BitInt(sizeof(int) * 8u))); +static_assert(sizeof(_BitInt(24)) != 4 || !__has_unique_object_representations(_BitInt(24))); + +static_assert(!__has_unique_object_representations(_BitInt(7))); +static_assert(!__has_unique_object_representations(unsigned _BitInt(7))); +static_assert(!__has_unique_object_representations(_BitInt(2))); +static_assert(!__has_unique_object_representations(unsigned _BitInt(1))); + +template +constexpr bool check() { + if constexpr (N <= __BITINT_MAXWIDTH__) { + static_assert(__has_unique_object_representations(_BitInt(N)) == (sizeof(_BitInt(N)) * 8u == N)); + static_assert(__has_unique_object_representations(unsigned _BitInt(N)) == (sizeof(unsigned _BitInt(N)) * 8u == N)); + } + return true; +} + +template +constexpr bool do_check = (check() && ...); + +static_assert(do_check<2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18>); +static_assert(do_check<15, 16, 17, 23, 24, 25, 31, 32, 33>); +static_assert(do_check<39, 40, 41, 47, 48, 49>); +static_assert(do_check<127, 128, 129, 255, 256, 257, 383, 384, 385>); + +template +struct in_struct { + _BitInt(N) x; + static constexpr bool check() { + return __has_unique_object_representations(in_struct) == __has_unique_object_representations(_BitInt(N)); + } +}; + +static_assert(in_struct<8>::check()); +static_assert(in_struct<7>::check()); + +struct bit_fields_1 { + _BitInt(7) x : 7; + unsigned _BitInt(1) y : 1; +}; + +static_assert(__has_unique_object_representations(bit_fields_1) == (sizeof(bit_fields_1) == 1)); + +struct bit_fields_2 { + _BitInt(8) x : 7; +}; + +static_assert(!__has_unique_object_representations(bit_fields_2)); + +struct bit_fields_3 { + _BitInt(15) x : 8; +}; + +static_assert(__has_unique_object_representations(bit_fields_3) == (sizeof(bit_fields_3) == 1)); + +#if __BITINT_MAXWIDTH__ >= 129 +struct bit_fields_4 { + _BitInt(129) x : 128; +}; + +static_assert(__has_unique_object_representations(bit_fields_4) == (sizeof(bit_fields_4) == 128 / 8)); +#endif + +struct bit_fields_5 { + _BitInt(2) x : 8; +}; + +static_assert(!__has_unique_object_representations(bit_fields_5)); + +static_assert(__has_unique_object_representations(_BitInt(7)&) == __has_unique_object_representations(_BitInt(8)&)); +static_assert(__has_unique_object_representations(_BitInt(8)&) == __has_unique_object_representations(int&));