diff options
author | Chandler Carruth <chandlerc@gmail.com> | 2010-12-12 08:11:30 +0000 |
---|---|---|
committer | Chandler Carruth <chandlerc@gmail.com> | 2010-12-12 08:11:30 +0000 |
commit | 3a0f3eff30dfa39ca8f78f98070b888dc8c67e54 (patch) | |
tree | b677a4a7745055a1a418b645880590f0783e8130 /lib/Sema/SemaOverload.cpp | |
parent | c78f684c8e300414956bc1566957a17a48da2fc8 (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.cpp | 1578 |
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); } }< |