From: Douglas Gregor Date: Wed, 3 Nov 2010 17:00:07 +0000 (+0000) Subject: When producing overload candidates for binary built-in operators, keep X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fec56e7e341cd1d9a861d64bffc80a97aed89802;p=clang When producing overload candidates for binary built-in operators, keep the sets of available conversions for the first and second arguments separate. This is apparently the indent of C++ [over.built], and reduces the number of overload candidates generated, eliminating some ambiguities. Fixes PR8477. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@118178 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index a0251899a5..9fb53c6a18 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -4541,15 +4541,17 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) VisibleTypeConversionsQuals += CollectVRQualifiers(Context, Args[ArgIdx]); - BuiltinCandidateTypeSet CandidateTypes(*this); - for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) - CandidateTypes.AddTypesConvertedFrom(Args[ArgIdx]->getType(), - OpLoc, - true, - (Op == OO_Exclaim || - Op == OO_AmpAmp || - Op == OO_PipePipe), - VisibleTypeConversionsQuals); + llvm::SmallVector 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 @@ -4563,29 +4565,35 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, llvm::DenseSet > UserDefinedBinaryOperators; - if (CandidateTypes.enumeration_begin() != CandidateTypes.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; + /// Set of (canonical) types that we've already handled. + llvm::SmallPtrSet 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))); + // Add this operator to the set of known user-defined operators. + UserDefinedBinaryOperators.insert( + std::make_pair(Context.getCanonicalType(FirstParamType), + Context.getCanonicalType(SecondParamType))); + } } } @@ -4676,8 +4684,10 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // T*VQ& operator--(T*VQ&); // T* operator++(T*VQ&, int); // T* operator--(T*VQ&, int); - for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(); - Ptr != CandidateTypes.pointer_end(); ++Ptr) { + for (BuiltinCandidateTypeSet::iterator + Ptr = CandidateTypes[0].pointer_begin(), + PtrEnd = CandidateTypes[0].pointer_end(); + Ptr != PtrEnd; ++Ptr) { // Skip pointer types that aren't pointers to object types. if (!(*Ptr)->getPointeeType()->isIncompleteOrObjectType()) continue; @@ -4716,8 +4726,10 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // For every function type T, there exist candidate operator // functions of the form // T& operator*(T*); - for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(); - Ptr != CandidateTypes.pointer_end(); ++Ptr) { + 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), @@ -4731,8 +4743,10 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // the form // // T* operator+(T*); - for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(); - Ptr != CandidateTypes.pointer_end(); ++Ptr) { + 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); } @@ -4753,8 +4767,9 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, } // Extension: We also add these operators for vector types. - for (BuiltinCandidateTypeSet::iterator Vec = CandidateTypes.vector_begin(), - VecEnd = CandidateTypes.vector_end(); + for (BuiltinCandidateTypeSet::iterator + Vec = CandidateTypes[0].vector_begin(), + VecEnd = CandidateTypes[0].vector_end(); Vec != VecEnd; ++Vec) { QualType VecTy = *Vec; AddBuiltinCandidate(VecTy, &VecTy, Args, 1, CandidateSet); @@ -4774,8 +4789,9 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, } // Extension: We also add this operator for vector types. - for (BuiltinCandidateTypeSet::iterator Vec = CandidateTypes.vector_begin(), - VecEnd = CandidateTypes.vector_end(); + for (BuiltinCandidateTypeSet::iterator + Vec = CandidateTypes[0].vector_begin(), + VecEnd = CandidateTypes[0].vector_end(); Vec != VecEnd; ++Vec) { QualType VecTy = *Vec; AddBuiltinCandidate(VecTy, &VecTy, Args, 1, CandidateSet); @@ -4806,15 +4822,22 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // // bool operator==(T,T); // bool operator!=(T,T); - for (BuiltinCandidateTypeSet::iterator - MemPtr = CandidateTypes.member_pointer_begin(), - MemPtrEnd = CandidateTypes.member_pointer_end(); - MemPtr != MemPtrEnd; - ++MemPtr) { - QualType ParamTypes[2] = { *MemPtr, *MemPtr }; - AddBuiltinCandidate(Context.BoolTy, ParamTypes, Args, 2, CandidateSet); + for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) { + for (BuiltinCandidateTypeSet::iterator + MemPtr = CandidateTypes[ArgIdx].member_pointer_begin(), + MemPtrEnd = CandidateTypes[ArgIdx].member_pointer_end(); + MemPtr != MemPtrEnd; + ++MemPtr) { + // Don't add the same builtin candidate twice. + if (!AddedTypes.insert(Context.getCanonicalType(*MemPtr))) + continue; + + QualType ParamTypes[2] = { *MemPtr, *MemPtr }; + AddBuiltinCandidate(Context.BoolTy, ParamTypes, Args, 2, CandidateSet); + } } - + AddedTypes.clear(); + // Fall through case OO_Less: @@ -4832,21 +4855,35 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // bool operator>=(T, T); // bool operator==(T, T); // bool operator!=(T, T); - for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(); - Ptr != CandidateTypes.pointer_end(); ++Ptr) { - QualType ParamTypes[2] = { *Ptr, *Ptr }; - AddBuiltinCandidate(Context.BoolTy, ParamTypes, Args, 2, CandidateSet); - } - for (BuiltinCandidateTypeSet::iterator Enum - = CandidateTypes.enumeration_begin(); - Enum != CandidateTypes.enumeration_end(); ++Enum) { - QualType ParamTypes[2] = { *Enum, *Enum }; - CanQualType CanonType = Context.getCanonicalType(*Enum); - if (!UserDefinedBinaryOperators.count( - std::make_pair(CanonType, CanonType))) + for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) { + 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))) + continue; + + QualType ParamTypes[2] = { *Ptr, *Ptr }; AddBuiltinCandidate(Context.BoolTy, ParamTypes, Args, 2, CandidateSet); + } + for (BuiltinCandidateTypeSet::iterator + Enum = CandidateTypes[ArgIdx].enumeration_begin(), + EnumEnd = CandidateTypes[ArgIdx].enumeration_end(); + Enum != EnumEnd; ++Enum) { + // Don't add the same builtin candidate twice. + if (!AddedTypes.insert(Context.getCanonicalType(*Enum))) + 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); + } } - + AddedTypes.clear(); + // Fall through. isComparison = true; @@ -4872,26 +4909,46 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // exist candidate operator functions of the form // // ptrdiff_t operator-(T, T); - for (BuiltinCandidateTypeSet::iterator Ptr - = CandidateTypes.pointer_begin(); - Ptr != CandidateTypes.pointer_end(); ++Ptr) { + 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(); + Ptr != PtrEnd; ++Ptr) { if (Op == OO_Plus) { // T* operator+(ptrdiff_t, T*); - ParamTypes[0] = ParamTypes[1]; - ParamTypes[1] = *Ptr; + QualType ParamTypes[2] = { Context.getPointerDiffType(), *Ptr }; AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet); } else { // ptrdiff_t operator-(T, T); - ParamTypes[1] = *Ptr; + if (!AddedTypes.insert(Context.getCanonicalType(*Ptr))) + continue; + + QualType ParamTypes[2] = { *Ptr, *Ptr }; AddBuiltinCandidate(Context.getPointerDiffType(), ParamTypes, Args, 2, CandidateSet); } - } + } + + AddedTypes.clear(); } // Fall through @@ -4942,12 +4999,13 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // Extension: Add the binary operators ==, !=, <, <=, >=, >, *, /, and the // conditional operator for vector types. - for (BuiltinCandidateTypeSet::iterator Vec1 = CandidateTypes.vector_begin(), - Vec1End = CandidateTypes.vector_end(); + for (BuiltinCandidateTypeSet::iterator + Vec1 = CandidateTypes[0].vector_begin(), + Vec1End = CandidateTypes[0].vector_end(); Vec1 != Vec1End; ++Vec1) for (BuiltinCandidateTypeSet::iterator - Vec2 = CandidateTypes.vector_begin(), - Vec2End = CandidateTypes.vector_end(); + Vec2 = CandidateTypes[1].vector_begin(), + Vec2End = CandidateTypes[1].vector_end(); Vec2 != Vec2End; ++Vec2) { QualType LandR[2] = { *Vec1, *Vec2 }; QualType Result; @@ -5006,18 +5064,30 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // empty, there exist candidate operator functions of the form // // VQ T& operator=(VQ T&, T); - for (BuiltinCandidateTypeSet::iterator - Enum = CandidateTypes.enumeration_begin(), - EnumEnd = CandidateTypes.enumeration_end(); - Enum != EnumEnd; ++Enum) - AddBuiltinAssignmentOperatorCandidates(*this, *Enum, Args, 2, - CandidateSet); - for (BuiltinCandidateTypeSet::iterator - MemPtr = CandidateTypes.member_pointer_begin(), - MemPtrEnd = CandidateTypes.member_pointer_end(); - MemPtr != MemPtrEnd; ++MemPtr) - AddBuiltinAssignmentOperatorCandidates(*this, *MemPtr, Args, 2, - CandidateSet); + for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) { + for (BuiltinCandidateTypeSet::iterator + Enum = CandidateTypes[ArgIdx].enumeration_begin(), + EnumEnd = CandidateTypes[ArgIdx].enumeration_end(); + Enum != EnumEnd; ++Enum) { + if (!AddedTypes.insert(Context.getCanonicalType(*Enum))) + continue; + + AddBuiltinAssignmentOperatorCandidates(*this, *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))) + continue; + + AddBuiltinAssignmentOperatorCandidates(*this, *MemPtr, Args, 2, + CandidateSet); + } + } + AddedTypes.clear(); // Fall through. @@ -5039,11 +5109,17 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // // T*VQ& operator+=(T*VQ&, ptrdiff_t); // T*VQ& operator-=(T*VQ&, ptrdiff_t); - for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(); - Ptr != CandidateTypes.pointer_end(); ++Ptr) { + 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)); + // non-volatile version ParamTypes[0] = Context.getLValueReferenceType(*Ptr); AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, @@ -5058,6 +5134,33 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, /*IsAssigmentOperator=*/Op == OO_Equal); } } + + if (Op == OO_Equal) { + 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))) + continue; + + QualType ParamTypes[2] = { Context.getLValueReferenceType(*Ptr), *Ptr }; + + // non-volatile version + AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + /*IsAssigmentOperator=*/true); + + if (!Context.getCanonicalType(*Ptr).isVolatileQualified() && + VisibleTypeConversionsQuals.hasVolatile()) { + // volatile version + ParamTypes[0] + = Context.getLValueReferenceType(Context.getVolatileType(*Ptr)); + AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + /*IsAssigmentOperator=*/true); + } + } + AddedTypes.clear(); + } // Fall through. case OO_StarEqual: @@ -5096,12 +5199,13 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, } // Extension: Add the binary operators =, +=, -=, *=, /= for vector types. - for (BuiltinCandidateTypeSet::iterator Vec1 = CandidateTypes.vector_begin(), - Vec1End = CandidateTypes.vector_end(); + for (BuiltinCandidateTypeSet::iterator + Vec1 = CandidateTypes[0].vector_begin(), + Vec1End = CandidateTypes[0].vector_end(); Vec1 != Vec1End; ++Vec1) for (BuiltinCandidateTypeSet::iterator - Vec2 = CandidateTypes.vector_begin(), - Vec2End = CandidateTypes.vector_end(); + Vec2 = CandidateTypes[1].vector_begin(), + Vec2End = CandidateTypes[1].vector_end(); Vec2 != Vec2End; ++Vec2) { QualType ParamTypes[2]; ParamTypes[1] = *Vec2; @@ -5200,20 +5304,29 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // T* operator-(T*, ptrdiff_t); [ABOVE] // T* operator+(ptrdiff_t, T*); [ABOVE] // T& operator[](ptrdiff_t, T*); - for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(); - Ptr != CandidateTypes.pointer_end(); ++Ptr) { + for (BuiltinCandidateTypeSet::iterator + Ptr = CandidateTypes[0].pointer_begin(), + PtrEnd = CandidateTypes[0].pointer_end(); + Ptr != PtrEnd; ++Ptr) { QualType ParamTypes[2] = { *Ptr, Context.getPointerDiffType() }; QualType PointeeType = (*Ptr)->getPointeeType(); QualType ResultTy = Context.getLValueReferenceType(PointeeType); // T& operator[](T*, ptrdiff_t) AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet); - - // T& operator[](ptrdiff_t, T*); - ParamTypes[0] = ParamTypes[1]; - ParamTypes[1] = *Ptr; + } + + for (BuiltinCandidateTypeSet::iterator + Ptr = CandidateTypes[1].pointer_begin(), + PtrEnd = CandidateTypes[1].pointer_end(); + Ptr != PtrEnd; ++Ptr) { + QualType ParamTypes[2] = { Context.getPointerDiffType(), *Ptr }; + QualType PointeeType = (*Ptr)->getPointeeType(); + QualType ResultTy = Context.getLValueReferenceType(PointeeType); + + // T& operator[](ptrdiff_t, T*) AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet); - } + } break; case OO_ArrowStar: @@ -5222,12 +5335,15 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // 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::*); + // + // CV12 T& operator->*(CV1 C1*, CV2 T C2::*); + // // where CV12 is the union of CV1 and CV2. { - for (BuiltinCandidateTypeSet::iterator Ptr = - CandidateTypes.pointer_begin(); - Ptr != CandidateTypes.pointer_end(); ++Ptr) { + for (BuiltinCandidateTypeSet::iterator + Ptr = CandidateTypes[0].pointer_begin(), + PtrEnd = CandidateTypes[0].pointer_end(); + Ptr != PtrEnd; ++Ptr) { QualType C1Ty = (*Ptr); QualType C1; QualifierCollector Q1; @@ -5242,8 +5358,8 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, if (!VisibleTypeConversionsQuals.hasRestrict() && Q1.hasRestrict()) continue; for (BuiltinCandidateTypeSet::iterator - MemPtr = CandidateTypes.member_pointer_begin(), - MemPtrEnd = CandidateTypes.member_pointer_end(); + MemPtr = CandidateTypes[1].member_pointer_begin(), + MemPtrEnd = CandidateTypes[1].member_pointer_end(); MemPtr != MemPtrEnd; ++MemPtr) { const MemberPointerType *mptr = cast(*MemPtr); QualType C2 = QualType(mptr->getClass(), 0); @@ -5278,25 +5394,44 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // // T operator?(bool, T, T); // - for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(), - E = CandidateTypes.pointer_end(); Ptr != E; ++Ptr) { - QualType ParamTypes[2] = { *Ptr, *Ptr }; - AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet); - } - for (BuiltinCandidateTypeSet::iterator Ptr = - CandidateTypes.member_pointer_begin(), - E = CandidateTypes.member_pointer_end(); Ptr != E; ++Ptr) { - QualType ParamTypes[2] = { *Ptr, *Ptr }; - AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet); - } - if (getLangOptions().CPlusPlus0x) - for (BuiltinCandidateTypeSet::iterator Enum = - CandidateTypes.enumeration_begin(), - E = CandidateTypes.enumeration_end(); Enum != E; ++Enum) { - if (!(*Enum)->getAs()->getDecl()->isScoped()) - continue; - QualType ParamTypes[2] = { *Enum, *Enum }; - AddBuiltinCandidate(*Enum, ParamTypes, Args, 2, CandidateSet); + for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) { + for (BuiltinCandidateTypeSet::iterator + Ptr = CandidateTypes[ArgIdx].pointer_begin(), + PtrEnd = CandidateTypes[ArgIdx].pointer_end(); + Ptr != PtrEnd; ++Ptr) { + if (!AddedTypes.insert(Context.getCanonicalType(*Ptr))) + continue; + + QualType ParamTypes[2] = { *Ptr, *Ptr }; + AddBuiltinCandidate(*Ptr, ParamTypes, 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))) + continue; + + QualType ParamTypes[2] = { *MemPtr, *MemPtr }; + AddBuiltinCandidate(*MemPtr, ParamTypes, Args, 2, CandidateSet); + } + + if (getLangOptions().CPlusPlus0x) { + for (BuiltinCandidateTypeSet::iterator + Enum = CandidateTypes[ArgIdx].enumeration_begin(), + EnumEnd = CandidateTypes[ArgIdx].enumeration_end(); + Enum != EnumEnd; ++Enum) { + if (!(*Enum)->getAs()->getDecl()->isScoped()) + continue; + + if (!AddedTypes.insert(Context.getCanonicalType(*Enum))) + continue; + + QualType ParamTypes[2] = { *Enum, *Enum }; + AddBuiltinCandidate(*Enum, ParamTypes, Args, 2, CandidateSet); + } + } } goto Conditional; } diff --git a/test/SemaCXX/overloaded-builtin-operators.cpp b/test/SemaCXX/overloaded-builtin-operators.cpp index 8a49671f1a..382f5d973b 100644 --- a/test/SemaCXX/overloaded-builtin-operators.cpp +++ b/test/SemaCXX/overloaded-builtin-operators.cpp @@ -200,3 +200,23 @@ namespace PR7319 { if (e1 > e2) {} } } + +namespace PR8477 { + struct Foo { + operator bool(); + operator const char *(); + }; + + bool doit() { + Foo foo; + long long zero = 0; + (void)(foo + zero); + (void)(foo - zero); + (void)(zero + foo); + (void)(zero[foo]); + (void)(foo - foo); // expected-error{{use of overloaded operator '-' is ambiguous}} \ + // expected-note 4{{built-in candidate operator-}} \ + // expected-note{{candidates omitted}} + return foo[zero] == zero; + } +}