[cfe-commits] r121623 - /cfe/trunk/lib/Sema/SemaOverload.cpp
Chandler Carruth
chandlerc at gmail.com
Sun Dec 12 00:11:30 PST 2010
Author: chandlerc
Date: Sun Dec 12 02:11:30 2010
New Revision: 121623
URL: http://llvm.org/viewvc/llvm-project?rev=121623&view=rev
Log:
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.
Modified:
cfe/trunk/lib/Sema/SemaOverload.cpp
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=121623&r1=121622&r2=121623&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Sun Dec 12 02:11:30 2010
@@ -4544,23 +4544,17 @@
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 @@
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 @@
// 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 @@
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;
+ // Common instance state available to all overload candidate addition methods.
+ Sema &S;
+ Expr **Args;
+ unsigned NumArgs;
+ Qualifiers VisibleTypeConversionsQuals;
+ llvm::SmallVectorImpl<BuiltinCandidateTypeSet> &CandidateTypes;
+ OverloadCandidateSet &CandidateSet;
- case OO_Star: // '*' is either unary or binary
- if (NumArgs == 1)
- goto UnaryStar;
- else
- goto BinaryStar;
- break;
+ void addPlusPlusMinusMinusStyleOverloads(QualType CandidateTy,
+ bool HasVolatile) {
+ QualType ParamTypes[2] = {
+ S.Context.getLValueReferenceType(CandidateTy),
+ S.Context.IntTy
+ };
- case OO_Plus: // '+' is either unary or binary
+ // Non-volatile version.
if (NumArgs == 1)
- goto UnaryPlus;
+ S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet);
else
- goto BinaryPlus;
- break;
+ S.AddBuiltinCandidate(CandidateTy, ParamTypes, Args, 2, CandidateSet);
- case OO_Minus: // '-' is either unary or binary
- if (NumArgs == 1)
- goto UnaryMinus;
- else
- goto BinaryMinus;
- break;
+ // 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_Amp: // '&' is either unary or binary
- if (NumArgs == 1)
- goto UnaryAmp;
- else
- goto BinaryAmp;
+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");
+ }
- 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);
+ // 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 @@
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);
+ S.AddBuiltinCandidate(S.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);
- }
-
- // 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 @@
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 @@
// 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);
}
}
- break;
+ }
- case OO_Equal:
- // C++ [over.built]p20:
- //
- // For every pair (T, VQ), where T is an enumeration or
- // pointer to member type and VQ is either volatile or
- // empty, there exist candidate operator functions of the form
- //
- // VQ T& operator=(VQ T&, T);
- for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) {
+ // C++ [over.built]p20:
+ //
+ // For every pair (T, VQ), where T is an enumeration or
+ // pointer to member type and VQ is either volatile or
+ // empty, there exist candidate operator functions of the form
+ //
+ // VQ T& operator=(VQ T&, T);
+ void addAssignmentMemberPointerOrEnumeralOverloads() {
+ /// Set of (canonical) types that we've already handled.
+ llvm::SmallPtrSet<QualType, 8> AddedTypes;
+
+ for (unsigned ArgIdx = 0; ArgIdx < 2; ++ArgIdx) {
for (BuiltinCandidateTypeSet::iterator
Enum = CandidateTypes[ArgIdx].enumeration_begin(),
EnumEnd = CandidateTypes[ArgIdx].enumeration_end();
Enum != EnumEnd; ++Enum) {
- if (!AddedTypes.insert(Context.getCanonicalType(*Enum)))
+ if (!AddedTypes.insert(S.Context.getCanonicalType(*Enum)))
continue;
-
- AddBuiltinAssignmentOperatorCandidates(*this, *Enum, Args, 2,
+
+ AddBuiltinAssignmentOperatorCandidates(S, *Enum, Args, 2,
CandidateSet);
}
-
+
for (BuiltinCandidateTypeSet::iterator
MemPtr = CandidateTypes[ArgIdx].member_pointer_begin(),
MemPtrEnd = CandidateTypes[ArgIdx].member_pointer_end();
MemPtr != MemPtrEnd; ++MemPtr) {
- if (!AddedTypes.insert(Context.getCanonicalType(*MemPtr)))
+ if (!AddedTypes.insert(S.Context.getCanonicalType(*MemPtr)))
continue;
-
- AddBuiltinAssignmentOperatorCandidates(*this, *MemPtr, Args, 2,
+
+ AddBuiltinAssignmentOperatorCandidates(S, *MemPtr, Args, 2,
CandidateSet);
}
}
- AddedTypes.clear();
-
- // Fall through.
+ }
- case OO_PlusEqual:
- case OO_MinusEqual:
- // C++ [over.built]p19:
- //
- // For every pair (T, VQ), where T is any type and VQ is either
- // volatile or empty, there exist candidate operator functions
- // of the form
- //
- // T*VQ& operator=(T*VQ&, T*);
- //
- // C++ [over.built]p21:
- //
- // 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&, ptrdiff_t);
- // T*VQ& operator-=(T*VQ&, ptrdiff_t);
- for (BuiltinCandidateTypeSet::iterator
+ // C++ [over.built]p19:
+ //
+ // For every pair (T, VQ), where T is any type and VQ is either
+ // volatile or empty, there exist candidate operator functions
+ // of the form
+ //
+ // T*VQ& operator=(T*VQ&, T*);
+ //
+ // C++ [over.built]p21:
+ //
+ // 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&, ptrdiff_t);
+ // T*VQ& operator-=(T*VQ&, ptrdiff_t);
+ void addAssignmentPointerOverloads(bool isEqualOp) {
+ /// Set of (canonical) types that we've already handled.
+ llvm::SmallPtrSet<QualType, 8> AddedTypes;
+
+ for (BuiltinCandidateTypeSet::iterator
Ptr = CandidateTypes[0].pointer_begin(),
PtrEnd = CandidateTypes[0].pointer_end();
Ptr != PtrEnd; ++Ptr) {
- QualType ParamTypes[2];
- ParamTypes[1] = (Op == OO_Equal)? *Ptr : Context.getPointerDiffType();
-
// If this is operator=, keep track of the builtin candidates we added.
- if (Op == OO_Equal)
- AddedTypes.insert(Context.getCanonicalType(*Ptr));
-
+ if (isEqualOp)
+ AddedTypes.insert(S.Context.getCanonicalType(*Ptr));
+
// non-volatile version
- ParamTypes[0] = Context.getLValueReferenceType(*Ptr);
- AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
- /*IsAssigmentOperator=*/Op == OO_Equal);
+ QualType ParamTypes[2] = {
+ S.Context.getLValueReferenceType(*Ptr),
+ isEqualOp ? *Ptr : S.Context.getPointerDiffType(),
+ };
+ S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
+ /*IsAssigmentOperator=*/ isEqualOp);
- if (!Context.getCanonicalType(*Ptr).isVolatileQualified() &&
+ if (!S.Context.getCanonicalType(*Ptr).isVolatileQualified() &&
VisibleTypeConversionsQuals.hasVolatile()) {
// volatile version
- ParamTypes[0]
- = Context.getLValueReferenceType(Context.getVolatileType(*Ptr));
- AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
- /*IsAssigmentOperator=*/Op == OO_Equal);
+ ParamTypes[0] =
+ S.Context.getLValueReferenceType(S.Context.getVolatileType(*Ptr));
+ S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
+ /*IsAssigmentOperator=*/isEqualOp);
}
}
-
- if (Op == OO_Equal) {
- for (BuiltinCandidateTypeSet::iterator
+
+ if (isEqualOp) {
+ for (BuiltinCandidateTypeSet::iterator
Ptr = CandidateTypes[1].pointer_begin(),
PtrEnd = CandidateTypes[1].pointer_end();
Ptr != PtrEnd; ++Ptr) {
// Make sure we don't add the same candidate twice.
- if (!AddedTypes.insert(Context.getCanonicalType(*Ptr)))
+ if (!AddedTypes.insert(S.Context.getCanonicalType(*Ptr)))
continue;
-
- QualType ParamTypes[2] = { Context.getLValueReferenceType(*Ptr), *Ptr };
-
+
+ QualType ParamTypes[2] = { S.Context.getLValueReferenceType(*Ptr), *Ptr };
+
// non-volatile version
- AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
- /*IsAssigmentOperator=*/true);
-
- if (!Context.getCanonicalType(*Ptr).isVolatileQualified() &&
+ S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
+ /*IsAssigmentOperator=*/true);
+
+ if (!S.Context.getCanonicalType(*Ptr).isVolatileQualified() &&
VisibleTypeConversionsQuals.hasVolatile()) {
// volatile version
- ParamTypes[0]
- = Context.getLValueReferenceType(Context.getVolatileType(*Ptr));
- AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
- /*IsAssigmentOperator=*/true);
+ ParamTypes[0] =
+ S.Context.getLValueReferenceType(S.Context.getVolatileType(*Ptr));
+ S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
+ /*IsAssigmentOperator=*/true);
}
}
- AddedTypes.clear();
}
- // Fall through.
+ }
- case OO_StarEqual:
- case OO_SlashEqual:
- // C++ [over.built]p18:
- //
- // For every triple (L, VQ, R), where L is an arithmetic type,
- // VQ is either volatile or empty, and R is a promoted
- // arithmetic type, there exist candidate operator functions of
- // the form
- //
- // VQ L& operator=(VQ L&, R);
- // VQ L& operator*=(VQ L&, R);
- // VQ L& operator/=(VQ L&, R);
- // VQ L& operator+=(VQ L&, R);
- // VQ L& operator-=(VQ L&, R);
+ // C++ [over.built]p18:
+ //
+ // For every triple (L, VQ, R), where L is an arithmetic type,
+ // VQ is either volatile or empty, and R is a promoted
+ // arithmetic type, there exist candidate operator functions of
+ // the form
+ //
+ // VQ L& operator=(VQ L&, R);
+ // VQ L& operator*=(VQ L&, R);
+ // VQ L& operator/=(VQ L&, R);
+ // VQ L& operator+=(VQ L&, R);
+ // VQ L& operator-=(VQ L&, R);
+ void addAssignmentArithmeticOverloads(bool isEqualOp) {
for (unsigned Left = 0; Left < NumArithmeticTypes; ++Left) {
for (unsigned Right = FirstPromotedArithmeticType;
Right < LastPromotedArithmeticType; ++Right) {
QualType ParamTypes[2];
- ParamTypes[1] = Context.*ArithmeticTypes[Right];
+ ParamTypes[1] = S.Context.*ArithmeticTypes[Right];
// Add this built-in operator as a candidate (VQ is empty).
ParamTypes[0] =
- Context.getLValueReferenceType(Context.*ArithmeticTypes[Left]);
- AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
- /*IsAssigmentOperator=*/Op == OO_Equal);
+ S.Context.getLValueReferenceType(S.Context.*ArithmeticTypes[Left]);
+ S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
+ /*IsAssigmentOperator=*/isEqualOp);
// Add this built-in operator as a candidate (VQ is 'volatile').
if (VisibleTypeConversionsQuals.hasVolatile()) {
ParamTypes[0] =
- Context.getVolatileType(Context.*ArithmeticTypes[Left]);
- ParamTypes[0] = Context.getLValueReferenceType(ParamTypes[0]);
- AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
- /*IsAssigmentOperator=*/Op == OO_Equal);
+ S.Context.getVolatileType(S.Context.*ArithmeticTypes[Left]);
+ ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]);
+ S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
+ /*IsAssigmentOperator=*/isEqualOp);
}
}
}
-
+
// Extension: Add the binary operators =, +=, -=, *=, /= for vector types.
for (BuiltinCandidateTypeSet::iterator
Vec1 = CandidateTypes[0].vector_begin(),
- Vec1End = CandidateTypes[0].vector_end();
- Vec1 != Vec1End; ++Vec1)
- for (BuiltinCandidateTypeSet::iterator
+ Vec1End = CandidateTypes[0].vector_end();
+ Vec1 != Vec1End; ++Vec1) {
+ for (BuiltinCandidateTypeSet::iterator
Vec2 = CandidateTypes[1].vector_begin(),
- Vec2End = CandidateTypes[1].vector_end();
+ Vec2End = CandidateTypes[1].vector_end();
Vec2 != Vec2End; ++Vec2) {
QualType ParamTypes[2];
ParamTypes[1] = *Vec2;
// Add this built-in operator as a candidate (VQ is empty).
- ParamTypes[0] = Context.getLValueReferenceType(*Vec1);
- AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
- /*IsAssigmentOperator=*/Op == OO_Equal);
-
+ ParamTypes[0] = S.Context.getLValueReferenceType(*Vec1);
+ S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
+ /*IsAssigmentOperator=*/isEqualOp);
+
// Add this built-in operator as a candidate (VQ is 'volatile').
if (VisibleTypeConversionsQuals.hasVolatile()) {
- ParamTypes[0] = Context.getVolatileType(*Vec1);
- ParamTypes[0] = Context.getLValueReferenceType(ParamTypes[0]);
- AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
- /*IsAssigmentOperator=*/Op == OO_Equal);
+ ParamTypes[0] = S.Context.getVolatileType(*Vec1);
+ ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]);
+ S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
+ /*IsAssigmentOperator=*/isEqualOp);
}
}
- break;
+ }
+ }
- case OO_PercentEqual:
- case OO_LessLessEqual:
- case OO_GreaterGreaterEqual:
- case OO_AmpEqual:
- case OO_CaretEqual:
- case OO_PipeEqual:
- // C++ [over.built]p22:
- //
- // For every triple (L, VQ, R), where L is an integral type, VQ
- // is either volatile or empty, and R is a promoted integral
- // type, there exist candidate operator functions of the form
- //
- // VQ L& operator%=(VQ L&, R);
- // VQ L& operator<<=(VQ L&, R);
- // VQ L& operator>>=(VQ L&, R);
- // VQ L& operator&=(VQ L&, R);
- // VQ L& operator^=(VQ L&, R);
- // VQ L& operator|=(VQ L&, R);
+ // C++ [over.built]p22:
+ //
+ // For every triple (L, VQ, R), where L is an integral type, VQ
+ // is either volatile or empty, and R is a promoted integral
+ // type, there exist candidate operator functions of the form
+ //
+ // VQ L& operator%=(VQ L&, R);
+ // VQ L& operator<<=(VQ L&, R);
+ // VQ L& operator>>=(VQ L&, R);
+ // VQ L& operator&=(VQ L&, R);
+ // VQ L& operator^=(VQ L&, R);
+ // VQ L& operator|=(VQ L&, R);
+ void addAssignmentIntegralOverloads() {
for (unsigned Left = FirstIntegralType; Left < LastIntegralType; ++Left) {
for (unsigned Right = FirstPromotedIntegralType;
Right < LastPromotedIntegralType; ++Right) {
QualType ParamTypes[2];
- ParamTypes[1] = Context.*ArithmeticTypes[Right];
+ ParamTypes[1] = S.Context.*ArithmeticTypes[Right];
// Add this built-in operator as a candidate (VQ is empty).
ParamTypes[0] =
- Context.getLValueReferenceType(Context.*ArithmeticTypes[Left]);
- AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet);
+ S.Context.getLValueReferenceType(S.Context.*ArithmeticTypes[Left]);
+ S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet);
if (VisibleTypeConversionsQuals.hasVolatile()) {
// Add this built-in operator as a candidate (VQ is 'volatile').
- ParamTypes[0] = Context.*ArithmeticTypes[Left];
- ParamTypes[0] = Context.getVolatileType(ParamTypes[0]);
- ParamTypes[0] = Context.getLValueReferenceType(ParamTypes[0]);
- AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet);
+ ParamTypes[0] = S.Context.*ArithmeticTypes[Left];
+ ParamTypes[0] = S.Context.getVolatileType(ParamTypes[0]);
+ ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]);
+ S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2,
+ CandidateSet);
}
}
}
- break;
-
- case OO_Exclaim: {
- // C++ [over.operator]p23:
- //
- // There also exist candidate operator functions of the form
- //
- // bool operator!(bool);
- // bool operator&&(bool, bool); [BELOW]
- // bool operator||(bool, bool); [BELOW]
- QualType ParamTy = Context.BoolTy;
- AddBuiltinCandidate(ParamTy, &ParamTy, Args, 1, CandidateSet,
- /*IsAssignmentOperator=*/false,
- /*NumContextualBoolArguments=*/1);
- break;
}
- case OO_AmpAmp:
- case OO_PipePipe: {
- // C++ [over.operator]p23:
- //
- // There also exist candidate operator functions of the form
- //
- // bool operator!(bool); [ABOVE]
- // bool operator&&(bool, bool);
- // bool operator||(bool, bool);
- QualType ParamTypes[2] = { Context.BoolTy, Context.BoolTy };
- AddBuiltinCandidate(Context.BoolTy, ParamTypes, Args, 2, CandidateSet,
- /*IsAssignmentOperator=*/false,
- /*NumContextualBoolArguments=*/2);
- break;
+ // C++ [over.operator]p23:
+ //
+ // There also exist candidate operator functions of the form
+ //
+ // bool operator!(bool);
+ // bool operator&&(bool, bool);
+ // bool operator||(bool, bool);
+ void addExclaimOverload() {
+ QualType ParamTy = S.Context.BoolTy;
+ S.AddBuiltinCandidate(ParamTy, &ParamTy, Args, 1, CandidateSet,
+ /*IsAssignmentOperator=*/false,
+ /*NumContextualBoolArguments=*/1);
+ }
+ void addAmpAmpOrPipePipeOverload() {
+ QualType ParamTypes[2] = { S.Context.BoolTy, S.Context.BoolTy };
+ S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, 2, CandidateSet,
+ /*IsAssignmentOperator=*/false,
+ /*NumContextualBoolArguments=*/2);
}
- case OO_Subscript:
- // 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); [ABOVE]
- // T& operator[](T*, ptrdiff_t);
- // T* operator-(T*, ptrdiff_t); [ABOVE]
- // T* operator+(ptrdiff_t, T*); [ABOVE]
- // T& operator[](ptrdiff_t, T*);
- for (BuiltinCandidateTypeSet::iterator
+ // 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); [ABOVE]
+ // T& operator[](T*, ptrdiff_t);
+ // T* operator-(T*, ptrdiff_t); [ABOVE]
+ // T* operator+(ptrdiff_t, T*); [ABOVE]
+ // T& operator[](ptrdiff_t, T*);
+ void addSubscriptOverloads() {
+ for (BuiltinCandidateTypeSet::iterator
Ptr = CandidateTypes[0].pointer_begin(),
PtrEnd = CandidateTypes[0].pointer_end();
Ptr != PtrEnd; ++Ptr) {
- QualType ParamTypes[2] = { *Ptr, Context.getPointerDiffType() };
+ QualType ParamTypes[2] = { *Ptr, S.Context.getPointerDiffType() };
QualType PointeeType = (*Ptr)->getPointeeType();
- QualType ResultTy = Context.getLValueReferenceType(PointeeType);
+ QualType ResultTy = S.Context.getLValueReferenceType(PointeeType);
// T& operator[](T*, ptrdiff_t)
- AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet);
+ S.AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet);
}
-
- for (BuiltinCandidateTypeSet::iterator
+
+ for (BuiltinCandidateTypeSet::iterator
Ptr = CandidateTypes[1].pointer_begin(),
PtrEnd = CandidateTypes[1].pointer_end();
Ptr != PtrEnd; ++Ptr) {
- QualType ParamTypes[2] = { Context.getPointerDiffType(), *Ptr };
+ QualType ParamTypes[2] = { S.Context.getPointerDiffType(), *Ptr };
QualType PointeeType = (*Ptr)->getPointeeType();
- QualType ResultTy = Context.getLValueReferenceType(PointeeType);
-
+ QualType ResultTy = S.Context.getLValueReferenceType(PointeeType);
+
// T& operator[](ptrdiff_t, T*)
- AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet);
+ S.AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet);
}
- break;
+ }
- case OO_ArrowStar:
- // C++ [over.built]p11:
- // For every quintuple (C1, C2, T, CV1, CV2), where C2 is a class type,
- // C1 is the same type as C2 or is a derived class of C2, T is an object
- // type or a function type, and CV1 and CV2 are cv-qualifier-seqs,
- // there exist candidate operator functions of the form
- //
- // CV12 T& operator->*(CV1 C1*, CV2 T C2::*);
- //
- // where CV12 is the union of CV1 and CV2.
- {
- for (BuiltinCandidateTypeSet::iterator
- Ptr = CandidateTypes[0].pointer_begin(),
- PtrEnd = CandidateTypes[0].pointer_end();
- Ptr != PtrEnd; ++Ptr) {
- QualType C1Ty = (*Ptr);
- QualType C1;
- QualifierCollector Q1;
- C1 = QualType(Q1.strip(C1Ty->getPointeeType()), 0);
- if (!isa<RecordType>(C1))
- continue;
- // heuristic to reduce number of builtin candidates in the set.
- // Add volatile/restrict version only if there are conversions to a
- // volatile/restrict type.
- if (!VisibleTypeConversionsQuals.hasVolatile() && Q1.hasVolatile())
+ // C++ [over.built]p11:
+ // For every quintuple (C1, C2, T, CV1, CV2), where C2 is a class type,
+ // C1 is the same type as C2 or is a derived class of C2, T is an object
+ // type or a function type, and CV1 and CV2 are cv-qualifier-seqs,
+ // there exist candidate operator functions of the form
+ //
+ // CV12 T& operator->*(CV1 C1*, CV2 T C2::*);
+ //
+ // where CV12 is the union of CV1 and CV2.
+ void addArrowStarOverloads() {
+ for (BuiltinCandidateTypeSet::iterator
+ Ptr = CandidateTypes[0].pointer_begin(),
+ PtrEnd = CandidateTypes[0].pointer_end();
+ Ptr != PtrEnd; ++Ptr) {
+ QualType C1Ty = (*Ptr);
+ QualType C1;
+ QualifierCollector Q1;
+ C1 = QualType(Q1.strip(C1Ty->getPointeeType()), 0);
+ if (!isa<RecordType>(C1))
+ continue;
+ // heuristic to reduce number of builtin candidates in the set.
+ // Add volatile/restrict version only if there are conversions to a
+ // volatile/restrict type.
+ if (!VisibleTypeConversionsQuals.hasVolatile() && Q1.hasVolatile())
+ continue;
+ if (!VisibleTypeConversionsQuals.hasRestrict() && Q1.hasRestrict())
+ continue;
+ for (BuiltinCandidateTypeSet::iterator
+ MemPtr = CandidateTypes[1].member_pointer_begin(),
+ MemPtrEnd = CandidateTypes[1].member_pointer_end();
+ MemPtr != MemPtrEnd; ++MemPtr) {
+ const MemberPointerType *mptr = cast<MemberPointerType>(*MemPtr);
+ QualType C2 = QualType(mptr->getClass(), 0);
+ C2 = C2.getUnqualifiedType();
+ if (C1 != C2 && !S.IsDerivedFrom(C1, C2))
+ break;
+ QualType ParamTypes[2] = { *Ptr, *MemPtr };
+ // build CV12 T&
+ QualType T = mptr->getPointeeType();
+ if (!VisibleTypeConversionsQuals.hasVolatile() &&
+ T.isVolatileQualified())
continue;
- if (!VisibleTypeConversionsQuals.hasRestrict() && Q1.hasRestrict())
+ if (!VisibleTypeConversionsQuals.hasRestrict() &&
+ T.isRestrictQualified())
continue;
- for (BuiltinCandidateTypeSet::iterator
- MemPtr = CandidateTypes[1].member_pointer_begin(),
- MemPtrEnd = CandidateTypes[1].member_pointer_end();
- MemPtr != MemPtrEnd; ++MemPtr) {
- const MemberPointerType *mptr = cast<MemberPointerType>(*MemPtr);
- QualType C2 = QualType(mptr->getClass(), 0);
- C2 = C2.getUnqualifiedType();
- if (C1 != C2 && !IsDerivedFrom(C1, C2))
- break;
- QualType ParamTypes[2] = { *Ptr, *MemPtr };
- // build CV12 T&
- QualType T = mptr->getPointeeType();
- if (!VisibleTypeConversionsQuals.hasVolatile() &&
- T.isVolatileQualified())
- continue;
- if (!VisibleTypeConversionsQuals.hasRestrict() &&
- T.isRestrictQualified())
- continue;
- T = Q1.apply(Context, T);
- QualType ResultTy = Context.getLValueReferenceType(T);
- AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet);
- }
+ T = Q1.apply(S.Context, T);
+ QualType ResultTy = S.Context.getLValueReferenceType(T);
+ S.AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet);
}
}
- break;
+ }
- case OO_Conditional:
- // Note that we don't consider the first argument, since it has been
- // contextually converted to bool long ago. The candidates below are
- // therefore added as binary.
- //
- // C++ [over.built]p25:
- // For every type T, where T is a pointer, pointer-to-member, or scoped
- // enumeration type, there exist candidate operator functions of the form
- //
- // T operator?(bool, T, T);
- //
- for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) {
+ // Note that we don't consider the first argument, since it has been
+ // contextually converted to bool long ago. The candidates below are
+ // therefore added as binary.
+ //
+ // C++ [over.built]p25:
+ // For every type T, where T is a pointer, pointer-to-member, or scoped
+ // enumeration type, there exist candidate operator functions of the form
+ //
+ // T operator?(bool, T, T);
+ //
+ void addConditionalOperatorOverloads() {
+ /// Set of (canonical) types that we've already handled.
+ llvm::SmallPtrSet<QualType, 8> AddedTypes;
+
+ for (unsigned ArgIdx = 0; ArgIdx < 2; ++ArgIdx) {
for (BuiltinCandidateTypeSet::iterator
Ptr = CandidateTypes[ArgIdx].pointer_begin(),
PtrEnd = CandidateTypes[ArgIdx].pointer_end();
Ptr != PtrEnd; ++Ptr) {
- if (!AddedTypes.insert(Context.getCanonicalType(*Ptr)))
+ if (!AddedTypes.insert(S.Context.getCanonicalType(*Ptr)))
continue;
-
+
QualType ParamTypes[2] = { *Ptr, *Ptr };
- AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet);
+ S.AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet);
}
-
- for (BuiltinCandidateTypeSet::iterator
+
+ for (BuiltinCandidateTypeSet::iterator
MemPtr = CandidateTypes[ArgIdx].member_pointer_begin(),
- MemPtrEnd = CandidateTypes[ArgIdx].member_pointer_end();
+ MemPtrEnd = CandidateTypes[ArgIdx].member_pointer_end();
MemPtr != MemPtrEnd; ++MemPtr) {
- if (!AddedTypes.insert(Context.getCanonicalType(*MemPtr)))
+ if (!AddedTypes.insert(S.Context.getCanonicalType(*MemPtr)))
continue;
-
+
QualType ParamTypes[2] = { *MemPtr, *MemPtr };
- AddBuiltinCandidate(*MemPtr, ParamTypes, Args, 2, CandidateSet);
+ S.AddBuiltinCandidate(*MemPtr, ParamTypes, Args, 2, CandidateSet);
}
-
- if (getLangOptions().CPlusPlus0x) {
- for (BuiltinCandidateTypeSet::iterator
+
+ if (S.getLangOptions().CPlusPlus0x) {
+ for (BuiltinCandidateTypeSet::iterator
Enum = CandidateTypes[ArgIdx].enumeration_begin(),
- EnumEnd = CandidateTypes[ArgIdx].enumeration_end();
+ EnumEnd = CandidateTypes[ArgIdx].enumeration_end();
Enum != EnumEnd; ++Enum) {
if (!(*Enum)->getAs<EnumType>()->getDecl()->isScoped())
continue;
-
- if (!AddedTypes.insert(Context.getCanonicalType(*Enum)))
+
+ if (!AddedTypes.insert(S.Context.getCanonicalType(*Enum)))
continue;
QualType ParamTypes[2] = { *Enum, *Enum };
- AddBuiltinCandidate(*Enum, ParamTypes, Args, 2, CandidateSet);
+ S.AddBuiltinCandidate(*Enum, ParamTypes, Args, 2, CandidateSet);
}
}
}
+ }
+};
+
+CanQualType ASTContext::* const
+BuiltinOperatorOverloadBuilder::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?
+};
+
+// Accelerator table for performing the usual arithmetic conversions.
+// The rules are basically:
+// - if either is floating-point, use the wider floating-point
+// - if same signedness, use the higher rank
+// - if same size, use unsigned of the higher rank
+// - use the larger type
+// These rules, together with the axiom that higher ranks are
+// never smaller, are sufficient to precompute all of these results
+// *except* when dealing with signed types of higher rank.
+// (we could precompute SLL x UI for all known platforms, but it's
+// better not to make any assumptions).
+BuiltinOperatorOverloadBuilder::PromT
+BuiltinOperatorOverloadBuilder::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 }
+};
+
+} // end anonymous namespace
+
+/// 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) {
+ // 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;
+
+ 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)));
+ }
+ }
+ }
+
+ // Setup an object to manage the common state for building overloads.
+ BuiltinOperatorOverloadBuilder OpBuilder(*this, Args, NumArgs,
+ VisibleTypeConversionsQuals,
+ CandidateTypes, CandidateSet);
+
+ // Dispatch over the operation to add in only those overloads which apply.
+ 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)
+ OpBuilder.addUnaryStarPointerOverloads();
+ else
+ goto BinaryStar;
+ break;
+
+ case OO_Plus: // '+' is either unary or binary
+ if (NumArgs == 1) {
+ OpBuilder.addUnaryPlusPointerOverloads();
+ OpBuilder.addUnaryPlusOrMinusArithmeticOverloads();
+ } else {
+ goto BinaryPlus;
+ }
+ break;
+
+ case OO_Minus: // '-' is either unary or binary
+ if (NumArgs == 1)
+ OpBuilder.addUnaryPlusOrMinusArithmeticOverloads();
+ else
+ goto BinaryMinus;
+ break;
+
+ case OO_Amp: // '&' is either unary or binary
+ if (NumArgs == 1)
+ // C++ [over.match.oper]p3:
+ // -- For the operator ',', the unary operator '&', or the
+ // operator '->', the built-in candidates set is empty.
+ break;
+
+ goto BinaryAmp;
+
+ case OO_PlusPlus:
+ case OO_MinusMinus:
+ OpBuilder.addPlusPlusMinusMinusArithmeticOverloads(Op);
+ OpBuilder.addPlusPlusMinusMinusPointerOverloads();
+ break;
+
+ case OO_Tilde:
+ OpBuilder.addUnaryTildePromotedIntegralOverloads();
+ 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;
+
+ case OO_Comma:
+ 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;
+
+ case OO_EqualEqual:
+ case OO_ExclaimEqual:
+ OpBuilder.addEqualEqualOrNotEqualMemberPointerOverloads();
+
+ // Fall through
+
+ case OO_Less:
+ case OO_Greater:
+ case OO_LessEqual:
+ case OO_GreaterEqual:
+ OpBuilder.addRelationalPointerOrEnumeralOverloads(
+ UserDefinedBinaryOperators);
+
+ // Fall through.
+ isComparison = true;
+
+ BinaryPlus:
+ BinaryMinus:
+ if (!isComparison) {
+ // We didn't fall through, so we must have OO_Plus or OO_Minus.
+ OpBuilder.addBinaryPlusOrMinusPointerOverloads(Op);
+ }
+ // Fall through
+
+ case OO_Slash:
+ BinaryStar:
+ Conditional:
+ OpBuilder.addGenericBinaryArithmeticOverloads(isComparison);
+ break;
+
+ case OO_Percent:
+ BinaryAmp:
+ case OO_Caret:
+ case OO_Pipe:
+ case OO_LessLess:
+ case OO_GreaterGreater:
+ OpBuilder.addBinaryBitwiseArithmeticOverloads(Op);
+ break;
+
+ case OO_Equal:
+ OpBuilder.addAssignmentMemberPointerOrEnumeralOverloads();
+ // Fall through.
+
+ case OO_PlusEqual:
+ case OO_MinusEqual:
+ OpBuilder.addAssignmentPointerOverloads(Op == OO_Equal);
+ // Fall through.
+
+ case OO_StarEqual:
+ case OO_SlashEqual:
+ OpBuilder.addAssignmentArithmeticOverloads(Op == OO_Equal);
+ break;
+
+ case OO_PercentEqual:
+ case OO_LessLessEqual:
+ case OO_GreaterGreaterEqual:
+ case OO_AmpEqual:
+ case OO_CaretEqual:
+ case OO_PipeEqual:
+ OpBuilder.addAssignmentIntegralOverloads();
+ break;
+
+ case OO_Exclaim:
+ OpBuilder.addExclaimOverload();
+ break;
+
+ case OO_AmpAmp:
+ case OO_PipePipe:
+ OpBuilder.addAmpAmpOrPipePipeOverload();
+ break;
+
+ case OO_Subscript:
+ OpBuilder.addSubscriptOverloads();
+ break;
+
+ case OO_ArrowStar:
+ OpBuilder.addArrowStarOverloads();
+ break;
+
+ case OO_Conditional:
+ OpBuilder.addConditionalOperatorOverloads();
goto Conditional;
}
}
More information about the cfe-commits
mailing list