aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaOverload.cpp
diff options
context:
space:
mode:
authorChandler Carruth <chandlerc@gmail.com>2010-12-12 08:11:30 +0000
committerChandler Carruth <chandlerc@gmail.com>2010-12-12 08:11:30 +0000
commit3a0f3eff30dfa39ca8f78f98070b888dc8c67e54 (patch)
treeb677a4a7745055a1a418b645880590f0783e8130 /lib/Sema/SemaOverload.cpp
parentc78f684c8e300414956bc1566957a17a48da2fc8 (diff)
Begin the refactoring of how builtin operators are added to the overload
candidate set. This breaks apart a huge switch + goto system into distinct methods on a class. It also places the current mess of tables and other static state used in the process within that class. This is still a work in progress. I did a few simplifications that jumped out at me as I went, but I plan to iterate on this a bit before it's truly clean. However, this is easily the most invasive chunk. I benchmarked it on all-std-headers.cpp and an internal testcase that has a major hotspot in overload resolution and saw no real performance impact. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@121623 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaOverload.cpp')
-rw-r--r--lib/Sema/SemaOverload.cpp1578
1 files changed, 842 insertions, 736 deletions
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 890854b897..266da4e264 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -4544,23 +4544,17 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) {
return VRQuals;
}
-
-/// AddBuiltinOperatorCandidates - Add the appropriate built-in
-/// operator overloads to the candidate set (C++ [over.built]), based
-/// on the operator @p Op and the arguments given. For example, if the
-/// operator is a binary '+', this routine might add "int
-/// operator+(int, int)" to cover integer addition.
-void
-Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
- SourceLocation OpLoc,
- Expr **Args, unsigned NumArgs,
- OverloadCandidateSet& CandidateSet) {
- // Information about arithmetic types useful to builtin-type
- // calculations.
+namespace {
+
+/// \brief Helper class to manage the addition of builtin operator overload
+/// candidates. It provides shared state and utility methods used throughout
+/// the process, as well as a helper method to add each group of builtin
+/// operator overloads from the standard to a candidate set.
+class BuiltinOperatorOverloadBuilder {
+ // FIXME: Clean up and document the static helpers for arithmetic types here.
// The "promoted arithmetic types" are the arithmetic
// types are that preserved by promotion (C++ [over.built]p2).
-
static const unsigned FirstIntegralType = 3;
static const unsigned LastIntegralType = 18;
static const unsigned FirstPromotedIntegralType = 3,
@@ -4569,43 +4563,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
LastPromotedArithmeticType = 9;
static const unsigned NumArithmeticTypes = 18;
- static CanQualType ASTContext::* const ArithmeticTypes[NumArithmeticTypes] = {
- // Start of promoted types.
- &ASTContext::FloatTy,
- &ASTContext::DoubleTy,
- &ASTContext::LongDoubleTy,
-
- // Start of integral types.
- &ASTContext::IntTy,
- &ASTContext::LongTy,
- &ASTContext::LongLongTy,
- &ASTContext::UnsignedIntTy,
- &ASTContext::UnsignedLongTy,
- &ASTContext::UnsignedLongLongTy,
- // End of promoted types.
-
- &ASTContext::BoolTy,
- &ASTContext::CharTy,
- &ASTContext::WCharTy,
- &ASTContext::Char16Ty,
- &ASTContext::Char32Ty,
- &ASTContext::SignedCharTy,
- &ASTContext::ShortTy,
- &ASTContext::UnsignedCharTy,
- &ASTContext::UnsignedShortTy
- // End of integral types.
- };
- // FIXME: What about complex?
- assert(ArithmeticTypes[FirstPromotedIntegralType] == &ASTContext::IntTy &&
- "Invalid first promoted integral type");
- assert(ArithmeticTypes[LastPromotedIntegralType - 1]
- == &ASTContext::UnsignedLongLongTy &&
- "Invalid last promoted integral type");
- assert(ArithmeticTypes[FirstPromotedArithmeticType] == &ASTContext::FloatTy &&
- "Invalid first promoted arithmetic type");
- assert(ArithmeticTypes[LastPromotedArithmeticType - 1]
- == &ASTContext::UnsignedLongLongTy &&
- "Invalid last promoted arithmetic type");
+ static CanQualType ASTContext::* const ArithmeticTypes[NumArithmeticTypes];
// Accelerator table for performing the usual arithmetic conversions.
// The rules are basically:
@@ -4620,17 +4578,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
// better not to make any assumptions).
enum PromT { Flt, Dbl, LDbl, SI, SL, SLL, UI, UL, ULL, Dep=-1 };
static PromT UsualArithmeticConversionsTypes
- [LastPromotedArithmeticType][LastPromotedArithmeticType] = {
- /* Flt*/ { Flt, Dbl, LDbl, Flt, Flt, Flt, Flt, Flt, Flt },
- /* Dbl*/ { Dbl, Dbl, LDbl, Dbl, Dbl, Dbl, Dbl, Dbl, Dbl },
- /*LDbl*/ { LDbl, LDbl, LDbl, LDbl, LDbl, LDbl, LDbl, LDbl, LDbl },
- /* SI*/ { Flt, Dbl, LDbl, SI, SL, SLL, UI, UL, ULL },
- /* SL*/ { Flt, Dbl, LDbl, SL, SL, SLL, Dep, UL, ULL },
- /* SLL*/ { Flt, Dbl, LDbl, SLL, SLL, SLL, Dep, Dep, ULL },
- /* UI*/ { Flt, Dbl, LDbl, UI, Dep, Dep, UI, UL, ULL },
- /* UL*/ { Flt, Dbl, LDbl, UL, UL, Dep, UL, UL, ULL },
- /* ULL*/ { Flt, Dbl, LDbl, ULL, ULL, ULL, ULL, ULL, ULL }
- };
+ [LastPromotedArithmeticType][LastPromotedArithmeticType];
struct UsualArithmeticConversionsType {
static CanQualType find(ASTContext &C, unsigned L, unsigned R) {
assert(L < LastPromotedArithmeticType);
@@ -4655,159 +4603,103 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
return C.UnsignedLongLongTy;
}
};
-
- // Find all of the types that the arguments can convert to, but only
- // if the operator we're looking at has built-in operator candidates
- // that make use of these types.
- Qualifiers VisibleTypeConversionsQuals;
- VisibleTypeConversionsQuals.addConst();
- for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx)
- VisibleTypeConversionsQuals += CollectVRQualifiers(Context, Args[ArgIdx]);
-
- llvm::SmallVector<BuiltinCandidateTypeSet, 2> CandidateTypes;
- for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) {
- CandidateTypes.push_back(BuiltinCandidateTypeSet(*this));
- CandidateTypes[ArgIdx].AddTypesConvertedFrom(Args[ArgIdx]->getType(),
- OpLoc,
- true,
- (Op == OO_Exclaim ||
- Op == OO_AmpAmp ||
- Op == OO_PipePipe),
- VisibleTypeConversionsQuals);
- }
-
- // C++ [over.built]p1:
- // If there is a user-written candidate with the same name and parameter
- // types as a built-in candidate operator function, the built-in operator
- // function is hidden and is not included in the set of candidate functions.
- //
- // The text is actually in a note, but if we don't implement it then we end
- // up with ambiguities when the user provides an overloaded operator for
- // an enumeration type. Note that only enumeration types have this problem,
- // so we track which enumeration types we've seen operators for.
- llvm::DenseSet<std::pair<CanQualType, CanQualType> >
- UserDefinedBinaryOperators;
-
- /// Set of (canonical) types that we've already handled.
- llvm::SmallPtrSet<QualType, 8> AddedTypes;
-
- for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) {
- if (CandidateTypes[ArgIdx].enumeration_begin()
- != CandidateTypes[ArgIdx].enumeration_end()) {
- for (OverloadCandidateSet::iterator C = CandidateSet.begin(),
- CEnd = CandidateSet.end();
- C != CEnd; ++C) {
- if (!C->Viable || !C->Function || C->Function->getNumParams() != 2)
- continue;
-
- // Check if the first parameter is of enumeration type.
- QualType FirstParamType
- = C->Function->getParamDecl(0)->getType().getUnqualifiedType();
- if (!FirstParamType->isEnumeralType())
- continue;
-
- // Check if the second parameter is of enumeration type.
- QualType SecondParamType
- = C->Function->getParamDecl(1)->getType().getUnqualifiedType();
- if (!SecondParamType->isEnumeralType())
- continue;
-
- // Add this operator to the set of known user-defined operators.
- UserDefinedBinaryOperators.insert(
- std::make_pair(Context.getCanonicalType(FirstParamType),
- Context.getCanonicalType(SecondParamType)));
- }
- }
- }
-
- bool isComparison = false;
- switch (Op) {
- case OO_None:
- case NUM_OVERLOADED_OPERATORS:
- assert(false && "Expected an overloaded operator");
- break;
- case OO_Star: // '*' is either unary or binary
- if (NumArgs == 1)
- goto UnaryStar;
- else
- goto BinaryStar;
- break;
-
- case OO_Plus: // '+' is either unary or binary
- if (NumArgs == 1)
- goto UnaryPlus;
- else
- goto BinaryPlus;
- break;
-
- case OO_Minus: // '-' is either unary or binary
- if (NumArgs == 1)
- goto UnaryMinus;
- else
- goto BinaryMinus;
- break;
+ // Common instance state available to all overload candidate addition methods.
+ Sema &S;
+ Expr **Args;
+ unsigned NumArgs;
+ Qualifiers VisibleTypeConversionsQuals;
+ llvm::SmallVectorImpl<BuiltinCandidateTypeSet> &CandidateTypes;
+ OverloadCandidateSet &CandidateSet;
+
+ void addPlusPlusMinusMinusStyleOverloads(QualType CandidateTy,
+ bool HasVolatile) {
+ QualType ParamTypes[2] = {
+ S.Context.getLValueReferenceType(CandidateTy),
+ S.Context.IntTy
+ };
- case OO_Amp: // '&' is either unary or binary
+ // Non-volatile version.
if (NumArgs == 1)
- goto UnaryAmp;
+ S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet);
else
- goto BinaryAmp;
+ S.AddBuiltinCandidate(CandidateTy, ParamTypes, Args, 2, CandidateSet);
+
+ // Use a heuristic to reduce number of builtin candidates in the set:
+ // add volatile version only if there are conversions to a volatile type.
+ if (HasVolatile) {
+ ParamTypes[0] =
+ S.Context.getLValueReferenceType(
+ S.Context.getVolatileType(CandidateTy));
+ if (NumArgs == 1)
+ S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet);
+ else
+ S.AddBuiltinCandidate(CandidateTy, ParamTypes, Args, 2, CandidateSet);
+ }
+ }
- case OO_PlusPlus:
- case OO_MinusMinus:
- // C++ [over.built]p3:
- //
- // For every pair (T, VQ), where T is an arithmetic type, and VQ
- // is either volatile or empty, there exist candidate operator
- // functions of the form
- //
- // VQ T& operator++(VQ T&);
- // T operator++(VQ T&, int);
- //
- // C++ [over.built]p4:
- //
- // For every pair (T, VQ), where T is an arithmetic type other
- // than bool, and VQ is either volatile or empty, there exist
- // candidate operator functions of the form
- //
- // VQ T& operator--(VQ T&);
- // T operator--(VQ T&, int);
+public:
+ BuiltinOperatorOverloadBuilder(
+ Sema &S, Expr **Args, unsigned NumArgs,
+ Qualifiers VisibleTypeConversionsQuals,
+ llvm::SmallVectorImpl<BuiltinCandidateTypeSet> &CandidateTypes,
+ OverloadCandidateSet &CandidateSet)
+ : S(S), Args(Args), NumArgs(NumArgs),
+ VisibleTypeConversionsQuals(VisibleTypeConversionsQuals),
+ CandidateTypes(CandidateTypes),
+ CandidateSet(CandidateSet) {
+ // Validate some of our static helper constants in debug builds.
+ assert(ArithmeticTypes[FirstPromotedIntegralType] == &ASTContext::IntTy &&
+ "Invalid first promoted integral type");
+ assert(ArithmeticTypes[LastPromotedIntegralType - 1]
+ == &ASTContext::UnsignedLongLongTy &&
+ "Invalid last promoted integral type");
+ assert(ArithmeticTypes[FirstPromotedArithmeticType]
+ == &ASTContext::FloatTy &&
+ "Invalid first promoted arithmetic type");
+ assert(ArithmeticTypes[LastPromotedArithmeticType - 1]
+ == &ASTContext::UnsignedLongLongTy &&
+ "Invalid last promoted arithmetic type");
+ }
+
+ // C++ [over.built]p3:
+ //
+ // For every pair (T, VQ), where T is an arithmetic type, and VQ
+ // is either volatile or empty, there exist candidate operator
+ // functions of the form
+ //
+ // VQ T& operator++(VQ T&);
+ // T operator++(VQ T&, int);
+ //
+ // C++ [over.built]p4:
+ //
+ // For every pair (T, VQ), where T is an arithmetic type other
+ // than bool, and VQ is either volatile or empty, there exist
+ // candidate operator functions of the form
+ //
+ // VQ T& operator--(VQ T&);
+ // T operator--(VQ T&, int);
+ void addPlusPlusMinusMinusArithmeticOverloads(OverloadedOperatorKind Op) {
for (unsigned Arith = (Op == OO_PlusPlus? 0 : 1);
Arith < NumArithmeticTypes; ++Arith) {
- QualType ArithTy = Context.*ArithmeticTypes[Arith];
- QualType ParamTypes[2]
- = { Context.getLValueReferenceType(ArithTy), Context.IntTy };
-
- // Non-volatile version.
- if (NumArgs == 1)
- AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet);
- else
- AddBuiltinCandidate(ArithTy, ParamTypes, Args, 2, CandidateSet);
- // heuristic to reduce number of builtin candidates in the set.
- // Add volatile version only if there are conversions to a volatile type.
- if (VisibleTypeConversionsQuals.hasVolatile()) {
- // Volatile version
- ParamTypes[0]
- = Context.getLValueReferenceType(Context.getVolatileType(ArithTy));
- if (NumArgs == 1)
- AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet);
- else
- AddBuiltinCandidate(ArithTy, ParamTypes, Args, 2, CandidateSet);
- }
+ addPlusPlusMinusMinusStyleOverloads(
+ S.Context.*ArithmeticTypes[Arith],
+ VisibleTypeConversionsQuals.hasVolatile());
}
+ }
- // C++ [over.built]p5:
- //
- // For every pair (T, VQ), where T is a cv-qualified or
- // cv-unqualified object type, and VQ is either volatile or
- // empty, there exist candidate operator functions of the form
- //
- // T*VQ& operator++(T*VQ&);
- // T*VQ& operator--(T*VQ&);
- // T* operator++(T*VQ&, int);
- // T* operator--(T*VQ&, int);
- for (BuiltinCandidateTypeSet::iterator
+ // C++ [over.built]p5:
+ //
+ // For every pair (T, VQ), where T is a cv-qualified or
+ // cv-unqualified object type, and VQ is either volatile or
+ // empty, there exist candidate operator functions of the form
+ //
+ // T*VQ& operator++(T*VQ&);
+ // T*VQ& operator--(T*VQ&);
+ // T* operator++(T*VQ&, int);
+ // T* operator--(T*VQ&, int);
+ void addPlusPlusMinusMinusPointerOverloads() {
+ for (BuiltinCandidateTypeSet::iterator
Ptr = CandidateTypes[0].pointer_begin(),
PtrEnd = CandidateTypes[0].pointer_end();
Ptr != PtrEnd; ++Ptr) {
@@ -4815,136 +4707,104 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
if (!(*Ptr)->getPointeeType()->isIncompleteOrObjectType())
continue;
- QualType ParamTypes[2] = {
- Context.getLValueReferenceType(*Ptr), Context.IntTy
- };
-
- // Without volatile
- if (NumArgs == 1)
- AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet);
- else
- AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet);
-
- if (!Context.getCanonicalType(*Ptr).isVolatileQualified() &&
- VisibleTypeConversionsQuals.hasVolatile()) {
- // With volatile
- ParamTypes[0]
- = Context.getLValueReferenceType(Context.getVolatileType(*Ptr));
- if (NumArgs == 1)
- AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet);
- else
- AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet);
- }
+ addPlusPlusMinusMinusStyleOverloads(*Ptr,
+ (!S.Context.getCanonicalType(*Ptr).isVolatileQualified() &&
+ VisibleTypeConversionsQuals.hasVolatile()));
}
- break;
+ }
- UnaryStar:
- // C++ [over.built]p6:
- // For every cv-qualified or cv-unqualified object type T, there
- // exist candidate operator functions of the form
- //
- // T& operator*(T*);
- //
- // C++ [over.built]p7:
- // For every function type T, there exist candidate operator
- // functions of the form
- // T& operator*(T*);
- for (BuiltinCandidateTypeSet::iterator
+ // C++ [over.built]p6:
+ // For every cv-qualified or cv-unqualified object type T, there
+ // exist candidate operator functions of the form
+ //
+ // T& operator*(T*);
+ //
+ // C++ [over.built]p7:
+ // For every function type T, there exist candidate operator
+ // functions of the form
+ // T& operator*(T*);
+ void addUnaryStarPointerOverloads() {
+ for (BuiltinCandidateTypeSet::iterator
Ptr = CandidateTypes[0].pointer_begin(),
PtrEnd = CandidateTypes[0].pointer_end();
Ptr != PtrEnd; ++Ptr) {
QualType ParamTy = *Ptr;
QualType PointeeTy = ParamTy->getPointeeType();
- AddBuiltinCandidate(Context.getLValueReferenceType(PointeeTy),
- &ParamTy, Args, 1, CandidateSet);
- }
- break;
-
- UnaryPlus:
- // C++ [over.built]p8:
- // For every type T, there exist candidate operator functions of
- // the form
- //
- // T* operator+(T*);
- for (BuiltinCandidateTypeSet::iterator
- Ptr = CandidateTypes[0].pointer_begin(),
- PtrEnd = CandidateTypes[0].pointer_end();
- Ptr != PtrEnd; ++Ptr) {
- QualType ParamTy = *Ptr;
- AddBuiltinCandidate(ParamTy, &ParamTy, Args, 1, CandidateSet);
+ S.AddBuiltinCandidate(S.Context.getLValueReferenceType(PointeeTy),
+ &ParamTy, Args, 1, CandidateSet);
}
+ }
- // Fall through
-
- UnaryMinus:
- // C++ [over.built]p9:
- // For every promoted arithmetic type T, there exist candidate
- // operator functions of the form
- //
- // T operator+(T);
- // T operator-(T);
+ // C++ [over.built]p9:
+ // For every promoted arithmetic type T, there exist candidate
+ // operator functions of the form
+ //
+ // T operator+(T);
+ // T operator-(T);
+ void addUnaryPlusOrMinusArithmeticOverloads() {
for (unsigned Arith = FirstPromotedArithmeticType;
Arith < LastPromotedArithmeticType; ++Arith) {
- QualType ArithTy = Context.*ArithmeticTypes[Arith];
- AddBuiltinCandidate(ArithTy, &ArithTy, Args, 1, CandidateSet);
+ QualType ArithTy = S.Context.*ArithmeticTypes[Arith];
+ S.AddBuiltinCandidate(ArithTy, &ArithTy, Args, 1, CandidateSet);
}
-
+
// Extension: We also add these operators for vector types.
for (BuiltinCandidateTypeSet::iterator
Vec = CandidateTypes[0].vector_begin(),
- VecEnd = CandidateTypes[0].vector_end();
+ VecEnd = CandidateTypes[0].vector_end();
Vec != VecEnd; ++Vec) {
QualType VecTy = *Vec;
- AddBuiltinCandidate(VecTy, &VecTy, Args, 1, CandidateSet);
+ S.AddBuiltinCandidate(VecTy, &VecTy, Args, 1, CandidateSet);
}
- break;
+ }
- case OO_Tilde:
- // C++ [over.built]p10:
- // For every promoted integral type T, there exist candidate
- // operator functions of the form
- //
- // T operator~(T);
+ // C++ [over.built]p8:
+ // For every type T, there exist candidate operator functions of
+ // the form
+ //
+ // T* operator+(T*);
+ void addUnaryPlusPointerOverloads() {
+ for (BuiltinCandidateTypeSet::iterator
+ Ptr = CandidateTypes[0].pointer_begin(),
+ PtrEnd = CandidateTypes[0].pointer_end();
+ Ptr != PtrEnd; ++Ptr) {
+ QualType ParamTy = *Ptr;
+ S.AddBuiltinCandidate(ParamTy, &ParamTy, Args, 1, CandidateSet);
+ }
+ }
+
+ // C++ [over.built]p10:
+ // For every promoted integral type T, there exist candidate
+ // operator functions of the form
+ //
+ // T operator~(T);
+ void addUnaryTildePromotedIntegralOverloads() {
for (unsigned Int = FirstPromotedIntegralType;
Int < LastPromotedIntegralType; ++Int) {
- QualType IntTy = Context.*ArithmeticTypes[Int];
- AddBuiltinCandidate(IntTy, &IntTy, Args, 1, CandidateSet);
+ QualType IntTy = S.Context.*ArithmeticTypes[Int];
+ S.AddBuiltinCandidate(IntTy, &IntTy, Args, 1, CandidateSet);
}
-
+
// Extension: We also add this operator for vector types.
for (BuiltinCandidateTypeSet::iterator
Vec = CandidateTypes[0].vector_begin(),
- VecEnd = CandidateTypes[0].vector_end();
+ VecEnd = CandidateTypes[0].vector_end();
Vec != VecEnd; ++Vec) {
QualType VecTy = *Vec;
- AddBuiltinCandidate(VecTy, &VecTy, Args, 1, CandidateSet);
- }
- break;
-
- case OO_New:
- case OO_Delete:
- case OO_Array_New:
- case OO_Array_Delete:
- case OO_Call:
- assert(false && "Special operators don't use AddBuiltinOperatorCandidates");
- break;
+ S.AddBuiltinCandidate(VecTy, &VecTy, Args, 1, CandidateSet);
+ }
+ }
- case OO_Comma:
- UnaryAmp:
- case OO_Arrow:
- // C++ [over.match.oper]p3:
- // -- For the operator ',', the unary operator '&', or the
- // operator '->', the built-in candidates set is empty.
- break;
+ // C++ [over.match.oper]p16:
+ // For every pointer to member type T, there exist candidate operator
+ // functions of the form
+ //
+ // bool operator==(T,T);
+ // bool operator!=(T,T);
+ void addEqualEqualOrNotEqualMemberPointerOverloads() {
+ /// Set of (canonical) types that we've already handled.
+ llvm::SmallPtrSet<QualType, 8> AddedTypes;
- case OO_EqualEqual:
- case OO_ExclaimEqual:
- // C++ [over.match.oper]p16:
- // For every pointer to member type T, there exist candidate operator
- // functions of the form
- //
- // bool operator==(T,T);
- // bool operator!=(T,T);
for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) {
for (BuiltinCandidateTypeSet::iterator
MemPtr = CandidateTypes[ArgIdx].member_pointer_begin(),
@@ -4952,172 +4812,156 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
MemPtr != MemPtrEnd;
++MemPtr) {
// Don't add the same builtin candidate twice.
- if (!AddedTypes.insert(Context.getCanonicalType(*MemPtr)))
+ if (!AddedTypes.insert(S.Context.getCanonicalType(*MemPtr)))
continue;
-
+
QualType ParamTypes[2] = { *MemPtr, *MemPtr };
- AddBuiltinCandidate(Context.BoolTy, ParamTypes, Args, 2, CandidateSet);
+ S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, 2,
+ CandidateSet);
}
}
- AddedTypes.clear();
-
- // Fall through
+ }
+
+ // C++ [over.built]p15:
+ //
+ // For every pointer or enumeration type T, there exist
+ // candidate operator functions of the form
+ //
+ // bool operator<(T, T);
+ // bool operator>(T, T);
+ // bool operator<=(T, T);
+ // bool operator>=(T, T);
+ // bool operator==(T, T);
+ // bool operator!=(T, T);
+ void addRelationalPointerOrEnumeralOverloads(
+ const llvm::DenseSet<std::pair<CanQualType, CanQualType> >
+ &UserDefinedBinaryOperators) {
+ /// Set of (canonical) types that we've already handled.
+ llvm::SmallPtrSet<QualType, 8> AddedTypes;
- case OO_Less:
- case OO_Greater:
- case OO_LessEqual:
- case OO_GreaterEqual:
- // C++ [over.built]p15:
- //
- // For every pointer or enumeration type T, there exist
- // candidate operator functions of the form
- //
- // bool operator<(T, T);
- // bool operator>(T, T);
- // bool operator<=(T, T);
- // bool operator>=(T, T);
- // bool operator==(T, T);
- // bool operator!=(T, T);
for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) {
- for (BuiltinCandidateTypeSet::iterator
+ for (BuiltinCandidateTypeSet::iterator
Ptr = CandidateTypes[ArgIdx].pointer_begin(),
PtrEnd = CandidateTypes[ArgIdx].pointer_end();
Ptr != PtrEnd; ++Ptr) {
// Don't add the same builtin candidate twice.
- if (!AddedTypes.insert(Context.getCanonicalType(*Ptr)))
+ if (!AddedTypes.insert(S.Context.getCanonicalType(*Ptr)))
continue;
-
+
QualType ParamTypes[2] = { *Ptr, *Ptr };
- AddBuiltinCandidate(Context.BoolTy, ParamTypes, Args, 2, CandidateSet);
+ S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, 2,
+ CandidateSet);
}
- for (BuiltinCandidateTypeSet::iterator
+ for (BuiltinCandidateTypeSet::iterator
Enum = CandidateTypes[ArgIdx].enumeration_begin(),
EnumEnd = CandidateTypes[ArgIdx].enumeration_end();
Enum != EnumEnd; ++Enum) {
+ CanQualType CanonType = S.Context.getCanonicalType(*Enum);
+
// Don't add the same builtin candidate twice.
- if (!AddedTypes.insert(Context.getCanonicalType(*Enum)))
+ if (!AddedTypes.insert(CanonType))
continue;
-
+
QualType ParamTypes[2] = { *Enum, *Enum };
- CanQualType CanonType = Context.getCanonicalType(*Enum);
if (!UserDefinedBinaryOperators.count(
- std::make_pair(CanonType, CanonType)))
- AddBuiltinCandidate(Context.BoolTy, ParamTypes, Args, 2, CandidateSet);
+ std::make_pair(CanonType, CanonType)))
+ S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, 2,
+ CandidateSet);
}
}
- AddedTypes.clear();
-
- // Fall through.
- isComparison = true;
-
- BinaryPlus:
- BinaryMinus:
- if (!isComparison) {
- // We didn't fall through, so we must have OO_Plus or OO_Minus.
-
- // C++ [over.built]p13:
- //
- // For every cv-qualified or cv-unqualified object type T
- // there exist candidate operator functions of the form
- //
- // T* operator+(T*, ptrdiff_t);
- // T& operator[](T*, ptrdiff_t); [BELOW]
- // T* operator-(T*, ptrdiff_t);
- // T* operator+(ptrdiff_t, T*);
- // T& operator[](ptrdiff_t, T*); [BELOW]
- //
- // C++ [over.built]p14:
- //
- // For every T, where T is a pointer to object type, there
- // exist candidate operator functions of the form
- //
- // ptrdiff_t operator-(T, T);
- for (BuiltinCandidateTypeSet::iterator
- Ptr = CandidateTypes[0].pointer_begin(),
- PtrEnd = CandidateTypes[0].pointer_end();
- Ptr != PtrEnd; ++Ptr) {
- QualType ParamTypes[2] = { *Ptr, Context.getPointerDiffType() };
-
- // operator+(T*, ptrdiff_t) or operator-(T*, ptrdiff_t)
- AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet);
+ }
- if (Op == OO_Minus) {
- // ptrdiff_t operator-(T, T);
- if (!AddedTypes.insert(Context.getCanonicalType(*Ptr)))
- continue;
-
- ParamTypes[1] = *Ptr;
- AddBuiltinCandidate(Context.getPointerDiffType(), ParamTypes,
- Args, 2, CandidateSet);
- }
- }
-
- for (BuiltinCandidateTypeSet::iterator
- Ptr = CandidateTypes[1].pointer_begin(),
- PtrEnd = CandidateTypes[1].pointer_end();
+ // C++ [over.built]p13:
+ //
+ // For every cv-qualified or cv-unqualified object type T
+ // there exist candidate operator functions of the form
+ //
+ // T* operator+(T*, ptrdiff_t);
+ // T& operator[](T*, ptrdiff_t); [BELOW]
+ // T* operator-(T*, ptrdiff_t);
+ // T* operator+(ptrdiff_t, T*);
+ // T& operator[](ptrdiff_t, T*); [BELOW]
+ //
+ // C++ [over.built]p14:
+ //
+ // For every T, where T is a pointer to object type, there
+ // exist candidate operator functions of the form
+ //
+ // ptrdiff_t operator-(T, T);
+ void addBinaryPlusOrMinusPointerOverloads(OverloadedOperatorKind Op) {
+ /// Set of (canonical) types that we've already handled.
+ llvm::SmallPtrSet<QualType, 8> AddedTypes;
+
+ for (int Arg = 0; Arg < 2; ++Arg) {
+ QualType AsymetricParamTypes[2] = {
+ S.Context.getPointerDiffType(),
+ S.Context.getPointerDiffType(),
+ };
+ for (BuiltinCandidateTypeSet::iterator
+ Ptr = CandidateTypes[Arg].pointer_begin(),
+ PtrEnd = CandidateTypes[Arg].pointer_end();
Ptr != PtrEnd; ++Ptr) {
- if (Op == OO_Plus) {
+ AsymetricParamTypes[Arg] = *Ptr;
+ if (Arg == 0 || Op == OO_Plus) {
+ // operator+(T*, ptrdiff_t) or operator-(T*, ptrdiff_t)
// T* operator+(ptrdiff_t, T*);
- QualType ParamTypes[2] = { Context.getPointerDiffType(), *Ptr };
- AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet);
- } else {
+ S.AddBuiltinCandidate(*Ptr, AsymetricParamTypes, Args, 2,
+ CandidateSet);
+ }
+ if (Op == OO_Minus) {
// ptrdiff_t operator-(T, T);
- if (!AddedTypes.insert(Context.getCanonicalType(*Ptr)))
+ if (!AddedTypes.insert(S.Context.getCanonicalType(*Ptr)))
continue;
-
+
QualType ParamTypes[2] = { *Ptr, *Ptr };
- AddBuiltinCandidate(Context.getPointerDiffType(), ParamTypes,
- Args, 2, CandidateSet);
+ S.AddBuiltinCandidate(S.Context.getPointerDiffType(), ParamTypes,
+ Args, 2, CandidateSet);
}
- }
-
- AddedTypes.clear();
+ }
}
- // Fall through
+ }
- case OO_Slash:
- BinaryStar:
- Conditional:
- // C++ [over.built]p12:
- //
- // For every pair of promoted arithmetic types L and R, there
- // exist candidate operator functions of the form
- //
- // LR operator*(L, R);
- // LR operator/(L, R);
- // LR operator+(L, R);
- // LR operator-(L, R);
- // bool operator<(L, R);
- // bool operator>(L, R);
- // bool operator<=(L, R);
- // bool operator>=(L, R);
- // bool operator==(L, R);
- // bool operator!=(L, R);
- //
- // where LR is the result of the usual arithmetic conversions
- // between types L and R.
- //
- // C++ [over.built]p24:
- //
- // For every pair of promoted arithmetic types L and R, there exist
- // candidate operator functions of the form
- //
- // LR operator?(bool, L, R);
- //
- // where LR is the result of the usual arithmetic conversions
- // between types L and R.
- // Our candidates ignore the first parameter.
+ // C++ [over.built]p12:
+ //
+ // For every pair of promoted arithmetic types L and R, there
+ // exist candidate operator functions of the form
+ //
+ // LR operator*(L, R);
+ // LR operator/(L, R);
+ // LR operator+(L, R);
+ // LR operator-(L, R);
+ // bool operator<(L, R);
+ // bool operator>(L, R);
+ // bool operator<=(L, R);
+ // bool operator>=(L, R);
+ // bool operator==(L, R);
+ // bool operator!=(L, R);
+ //
+ // where LR is the result of the usual arithmetic conversions
+ // between types L and R.
+ //
+ // C++ [over.built]p24:
+ //
+ // For every pair of promoted arithmetic types L and R, there exist
+ // candidate operator functions of the form
+ //
+ // LR operator?(bool, L, R);
+ //
+ // where LR is the result of the usual arithmetic conversions
+ // between types L and R.
+ // Our candidates ignore the first parameter.
+ void addGenericBinaryArithmeticOverloads(bool isComparison) {
for (unsigned Left = FirstPromotedArithmeticType;
Left < LastPromotedArithmeticType; ++Left) {
for (unsigned Right = FirstPromotedArithmeticType;
Right < LastPromotedArithmeticType; ++Right) {
- QualType LandR[2] = { Context.*ArithmeticTypes[Left],
- Context.*ArithmeticTypes[Right] };
- QualType Result
- = isComparison
- ? Context.BoolTy
- : UsualArithmeticConversionsType::find(Context, Left, Right);
- AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet);
+ QualType LandR[2] = { S.Context.*ArithmeticTypes[Left],
+ S.Context.*ArithmeticTypes[Right] };
+ QualType Result =
+ isComparison ? S.Context.BoolTy
+ : UsualArithmeticConversionsType::find(S.Context, Left,
+ Right);
+ S.AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet);
}
}
@@ -5125,442 +4969,704 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
// conditional operator for vector types.
for (BuiltinCandidateTypeSet::iterator
Vec1 = CandidateTypes[0].vector_begin(),
- Vec1End = CandidateTypes[0].vector_end();
- Vec1 != Vec1End; ++Vec1)
- for (BuiltinCandidateTypeSet::iterator
- Vec2 = CandidateTypes[1].vector_begin(),
- Vec2End = CandidateTypes[1].vector_end();
+ Vec1End = CandidateTypes[0].vector_end();
+ Vec1 != Vec1End; ++Vec1) {
+ for (BuiltinCandidateTypeSet::iterator
+ Vec2 = CandidateTypes[1].vector_begin(),
+ Vec2End = CandidateTypes[1].vector_end();
Vec2 != Vec2End; ++Vec2) {
QualType LandR[2] = { *Vec1, *Vec2 };
- QualType Result;
- if (isComparison)
- Result = Context.BoolTy;
- else {
+ QualType Result = S.Context.BoolTy;
+ if (!isComparison) {
if ((*Vec1)->isExtVectorType() || !(*Vec2)->isExtVectorType())
Result = *Vec1;
else
Result = *Vec2;
}
-
- AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet);
+
+ S.AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet);
}
-
- break;
+ }
+ }
- case OO_Percent:
- BinaryAmp:
- case OO_Caret:
- case OO_Pipe:
- case OO_LessLess:
- case OO_GreaterGreater:
- // C++ [over.built]p17:
- //
- // For every pair of promoted integral types L and R, there
- // exist candidate operator functions of the form
- //
- // LR operator%(L, R);
- // LR operator&(L, R);
- // LR operator^(L, R);
- // LR operator|(L, R);
- // L operator<<(L, R);
- // L operator>>(L, R);
- //
- // where LR is the result of the usual arithmetic conversions
- // between types L and R.
+ // C++ [over.built]p17:
+ //
+ // For every pair of promoted integral types L and R, there
+ // exist candidate operator functions of the form
+ //
+ // LR operator%(L, R);
+ // LR operator&(L, R);
+ // LR operator^(L, R);
+ // LR operator|(L, R);
+ // L operator<<(L, R);
+ // L operator>>(L, R);
+ //
+ // where LR is the result of the usual arithmetic conversions
+ // between types L and R.
+ void addBinaryBitwiseArithmeticOverloads(OverloadedOperatorKind Op) {
for (unsigned Left = FirstPromotedIntegralType;
Left < LastPromotedIntegralType; ++Left) {
for (unsigned Right = FirstPromotedIntegralType;
Right < LastPromotedIntegralType; ++Right) {
- QualType LandR[2] = { Context.*ArithmeticTypes[Left],
- Context.*ArithmeticTypes[Right] };
+ QualType LandR[2] = { S.Context.*ArithmeticTypes[Left],
+ S.Context.*ArithmeticTypes[Right] };
QualType Result = (Op == OO_LessLess || Op == OO_GreaterGreater)
? LandR[0]
- : UsualArithmeticConversionsType::find(Context, Left, Right);
- AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet);
+ : UsualArithmeticConversionsType::find(S.Context, Left, Right);
+ S.AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet);
}
}<