[clang] eb31970 - Add bit-precise overloads for builtin operators (#84755)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Mar 12 04:40:30 PDT 2024
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;
+};
+
More information about the cfe-commits
mailing list