Author: Aaron Ballman Date: 2024-03-12T07:40:27-04:00 New Revision: eb319708dc5371bc560c301742abcf94cc5b3de5
URL: https://github.com/llvm/llvm-project/commit/eb319708dc5371bc560c301742abcf94cc5b3de5 DIFF: https://github.com/llvm/llvm-project/commit/eb319708dc5371bc560c301742abcf94cc5b3de5.diff LOG: Add bit-precise overloads for builtin operators (#84755) We previously were not adding them to the candidate set and so use of a bit-precise integer as a class member could lead to ambiguous overload sets. Fixes https://github.com/llvm/llvm-project/issues/82998 Added: clang/test/SemaCXX/overload-bitint.cpp Modified: clang/docs/ReleaseNotes.rst clang/lib/Sema/SemaOverload.cpp Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 88e552d5c46113..4a08b78d78b69b 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -265,6 +265,9 @@ Bug Fixes in This Version operator. Fixes (#GH83267). +- Clang now correctly generates overloads for bit-precise integer types for + builtin operators in C++. Fixes #GH82998. + Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index b0c693f078efe2..f6bd85bdc64692 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -8516,6 +8516,9 @@ class BuiltinCandidateTypeSet { /// candidates. TypeSet MatrixTypes; + /// The set of _BitInt types that will be used in the built-in candidates. + TypeSet BitIntTypes; + /// A flag indicating non-record types are viable candidates bool HasNonRecordTypes; @@ -8564,6 +8567,7 @@ class BuiltinCandidateTypeSet { } llvm::iterator_range<iterator> vector_types() { return VectorTypes; } llvm::iterator_range<iterator> matrix_types() { return MatrixTypes; } + llvm::iterator_range<iterator> bitint_types() { return BitIntTypes; } bool containsMatrixType(QualType Ty) const { return MatrixTypes.count(Ty); } bool hasNonRecordTypes() { return HasNonRecordTypes; } @@ -8735,6 +8739,9 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, } else if (Ty->isEnumeralType()) { HasArithmeticOrEnumeralTypes = true; EnumerationTypes.insert(Ty); + } else if (Ty->isBitIntType()) { + HasArithmeticOrEnumeralTypes = true; + BitIntTypes.insert(Ty); } else if (Ty->isVectorType()) { // We treat vector types as arithmetic types in many contexts as an // extension. @@ -8913,7 +8920,7 @@ class BuiltinOperatorOverloadBuilder { SmallVectorImpl<BuiltinCandidateTypeSet> &CandidateTypes; OverloadCandidateSet &CandidateSet; - static constexpr int ArithmeticTypesCap = 24; + static constexpr int ArithmeticTypesCap = 26; SmallVector<CanQualType, ArithmeticTypesCap> ArithmeticTypes; // Define some indices used to iterate over the arithmetic types in @@ -8955,6 +8962,20 @@ class BuiltinOperatorOverloadBuilder { (S.Context.getAuxTargetInfo() && S.Context.getAuxTargetInfo()->hasInt128Type())) ArithmeticTypes.push_back(S.Context.UnsignedInt128Ty); + + /// We add candidates for the unique, unqualified _BitInt types present in + /// the candidate type set. The candidate set already handled ensuring the + /// type is unqualified and canonical, but because we're adding from N + /// diff erent sets, we need to do some extra work to unique things. Insert + /// the candidates into a unique set, then move from that set into the list + /// of arithmetic types. + llvm::SmallSetVector<CanQualType, 2> BitIntCandidates; + llvm::for_each(CandidateTypes, [&BitIntCandidates]( + BuiltinCandidateTypeSet &Candidate) { + for (QualType BitTy : Candidate.bitint_types()) + BitIntCandidates.insert(CanQualType::CreateUnsafe(BitTy)); + }); + llvm::move(BitIntCandidates, std::back_inserter(ArithmeticTypes)); LastPromotedIntegralType = ArithmeticTypes.size(); LastPromotedArithmeticType = ArithmeticTypes.size(); // End of promoted types. @@ -8975,7 +8996,11 @@ class BuiltinOperatorOverloadBuilder { // End of integral types. // FIXME: What about complex? What about half? - assert(ArithmeticTypes.size() <= ArithmeticTypesCap && + // We don't know for sure how many bit-precise candidates were involved, so + // we subtract those from the total when testing whether we're under the + // cap or not. + assert(ArithmeticTypes.size() - BitIntCandidates.size() <= + ArithmeticTypesCap && "Enough inline storage for all arithmetic types."); } diff --git a/clang/test/SemaCXX/overload-bitint.cpp b/clang/test/SemaCXX/overload-bitint.cpp new file mode 100644 index 00000000000000..b834a3b01fede6 --- /dev/null +++ b/clang/test/SemaCXX/overload-bitint.cpp @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -std=c++20 %s -verify +// expected-no-diagnostics + +#include "Inputs/std-compare.h" + +struct S { + _BitInt(12) a; + + constexpr operator _BitInt(12)() const { return a; } +}; + +// None of these used to compile because we weren't adding _BitInt types to the +// overload set for builtin operators. See GH82998. +static_assert(S{10} < 11); +static_assert(S{10} <= 11); +static_assert(S{12} > 11); +static_assert(S{12} >= 11); +static_assert(S{10} == 10); +static_assert((S{10} <=> 10) == 0); +static_assert(S{10} != 11); +static_assert(S{10} + 0 == 10); +static_assert(S{10} - 0 == 10); +static_assert(S{10} * 1 == 10); +static_assert(S{10} / 1 == 10); +static_assert(S{10} % 1 == 0); +static_assert(S{10} << 0 == 10); +static_assert(S{10} >> 0 == 10); +static_assert((S{10} | 0) == 10); +static_assert((S{10} & 10) == 10); +static_assert((S{10} ^ 0) == 10); +static_assert(-S{10} == -10); +static_assert(+S{10} == +10); +static_assert(~S{10} == ~10); + +struct A { + _BitInt(12) a; + + bool operator==(const A&) const = default; + bool operator!=(const A&) const = default; + std::strong_ordering operator<=>(const A&) const = default; +}; + _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits