aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaOverload.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaOverload.cpp')
-rw-r--r--lib/Sema/SemaOverload.cpp585
1 files changed, 581 insertions, 4 deletions
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index b60e55492b..9229fa35d2 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -14,8 +14,11 @@
#include "Sema.h"
#include "SemaInherit.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Lex/Preprocessor.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/TypeOrdering.h"
+#include "llvm/ADT/DenseSet.h"
#include "llvm/Support/Compiler.h"
#include <algorithm>
@@ -413,6 +416,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
return false;
// Standard conversions (C++ [conv])
+ SCS.setAsIdentityConversion();
SCS.Deprecated = false;
SCS.FromTypePtr = FromType.getAsOpaquePtr();
SCS.CopyConstructor = 0;
@@ -1530,7 +1534,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
DeclRefExpr ConversionRef(Conversion, Conversion->getType(),
SourceLocation());
ImplicitCastExpr ConversionFn(Context.getPointerType(Conversion->getType()),
- &ConversionRef);
+ &ConversionRef, false);
CallExpr Call(&ConversionFn, 0, 0,
Conversion->getConversionType().getNonReferenceType(),
SourceLocation());
@@ -1550,6 +1554,562 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
}
}
+/// AddBuiltinCandidate - Add a candidate for a built-in
+/// operator. ResultTy and ParamTys are the result and parameter types
+/// of the built-in candidate, respectively. Args and NumArgs are the
+/// arguments being passed to the candidate.
+void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet& CandidateSet) {
+ // Add this candidate
+ CandidateSet.push_back(OverloadCandidate());
+ OverloadCandidate& Candidate = CandidateSet.back();
+ Candidate.Function = 0;
+ Candidate.BuiltinTypes.ResultTy = ResultTy;
+ for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx)
+ Candidate.BuiltinTypes.ParamTypes[ArgIdx] = ParamTys[ArgIdx];
+
+ // Determine the implicit conversion sequences for each of the
+ // arguments.
+ Candidate.Viable = true;
+ Candidate.Conversions.resize(NumArgs);
+ for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) {
+ Candidate.Conversions[ArgIdx]
+ = TryCopyInitialization(Args[ArgIdx], ParamTys[ArgIdx], false);
+ if (Candidate.Conversions[ArgIdx].ConversionKind
+ == ImplicitConversionSequence::BadConversion)
+ Candidate.Viable = false;
+ }
+}
+
+/// BuiltinCandidateTypeSet - A set of types that will be used for the
+/// candidate operator functions for built-in operators (C++
+/// [over.built]). The types are separated into pointer types and
+/// enumeration types.
+class BuiltinCandidateTypeSet {
+ /// TypeSet - A set of types.
+ typedef llvm::DenseSet<QualType> TypeSet;
+
+ /// PointerTypes - The set of pointer types that will be used in the
+ /// built-in candidates.
+ TypeSet PointerTypes;
+
+ /// EnumerationTypes - The set of enumeration types that will be
+ /// used in the built-in candidates.
+ TypeSet EnumerationTypes;
+
+ /// Context - The AST context in which we will build the type sets.
+ ASTContext &Context;
+
+ bool AddWithMoreQualifiedTypeVariants(QualType Ty);
+
+public:
+ /// iterator - Iterates through the types that are part of the set.
+ typedef TypeSet::iterator iterator;
+
+ BuiltinCandidateTypeSet(ASTContext &Context) : Context(Context) { }
+
+ void AddTypesConvertedFrom(QualType Ty, bool AllowUserConversions = true);
+
+ /// pointer_begin - First pointer type found;
+ iterator pointer_begin() { return PointerTypes.begin(); }
+
+ /// pointer_end - Last pointer type found;
+ iterator pointer_end() { return PointerTypes.end(); }
+
+ /// enumeration_begin - First enumeration type found;
+ iterator enumeration_begin() { return EnumerationTypes.begin(); }
+
+ /// enumeration_end - Last enumeration type found;
+ iterator enumeration_end() { return EnumerationTypes.end(); }
+};
+
+/// AddWithMoreQualifiedTypeVariants - Add the pointer type @p Ty to
+/// the set of pointer types along with any more-qualified variants of
+/// that type. For example, if @p Ty is "int const *", this routine
+/// will add "int const *", "int const volatile *", "int const
+/// restrict *", and "int const volatile restrict *" to the set of
+/// pointer types. Returns true if the add of @p Ty itself succeeded,
+/// false otherwise.
+bool BuiltinCandidateTypeSet::AddWithMoreQualifiedTypeVariants(QualType Ty) {
+ // Insert this type.
+ if (!PointerTypes.insert(Ty).second)
+ return false;
+
+ if (const PointerType *PointerTy = Ty->getAsPointerType()) {
+ QualType PointeeTy = PointerTy->getPointeeType();
+ // FIXME: Optimize this so that we don't keep trying to add the same types.
+
+ // FIXME: Do we have to add CVR qualifiers at *all* levels to deal
+ // with all pointer conversions that don't cast away constness?
+ if (!PointeeTy.isConstQualified())
+ AddWithMoreQualifiedTypeVariants
+ (Context.getPointerType(PointeeTy.withConst()));
+ if (!PointeeTy.isVolatileQualified())
+ AddWithMoreQualifiedTypeVariants
+ (Context.getPointerType(PointeeTy.withVolatile()));
+ if (!PointeeTy.isRestrictQualified())
+ AddWithMoreQualifiedTypeVariants
+ (Context.getPointerType(PointeeTy.withRestrict()));
+ }
+
+ return true;
+}
+
+/// AddTypesConvertedFrom - Add each of the types to which the type @p
+/// Ty can be implicit converted to the given set of @p Types. We're
+/// primarily interested in pointer types, enumeration types,
+void BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
+ bool AllowUserConversions) {
+ // Only deal with canonical types.
+ Ty = Context.getCanonicalType(Ty);
+
+ // Look through reference types; they aren't part of the type of an
+ // expression for the purposes of conversions.
+ if (const ReferenceType *RefTy = Ty->getAsReferenceType())
+ Ty = RefTy->getPointeeType();
+
+ // We don't care about qualifiers on the type.
+ Ty = Ty.getUnqualifiedType();
+
+ if (const PointerType *PointerTy = Ty->getAsPointerType()) {
+ QualType PointeeTy = PointerTy->getPointeeType();
+
+ // Insert our type, and its more-qualified variants, into the set
+ // of types.
+ if (!AddWithMoreQualifiedTypeVariants(Ty))
+ return;
+
+ // Add 'cv void*' to our set of types.
+ if (!Ty->isVoidType()) {
+ QualType QualVoid
+ = Context.VoidTy.getQualifiedType(PointeeTy.getCVRQualifiers());
+ AddWithMoreQualifiedTypeVariants(Context.getPointerType(QualVoid));
+ }
+
+ // If this is a pointer to a class type, add pointers to its bases
+ // (with the same level of cv-qualification as the original
+ // derived class, of course).
+ if (const RecordType *PointeeRec = PointeeTy->getAsRecordType()) {
+ CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(PointeeRec->getDecl());
+ for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin();
+ Base != ClassDecl->bases_end(); ++Base) {
+ QualType BaseTy = Context.getCanonicalType(Base->getType());
+ BaseTy = BaseTy.getQualifiedType(PointeeTy.getCVRQualifiers());
+
+ // Add the pointer type, recursively, so that we get all of
+ // the indirect base classes, too.
+ AddTypesConvertedFrom(Context.getPointerType(BaseTy), false);
+ }
+ }
+ } else if (Ty->isEnumeralType()) {
+ EnumerationTypes.insert(Ty);
+ } else if (AllowUserConversions) {
+ if (const RecordType *TyRec = Ty->getAsRecordType()) {
+ CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl());
+ // FIXME: Visit conversion functions in the base classes, too.
+ OverloadedFunctionDecl *Conversions
+ = ClassDecl->getConversionFunctions();
+ for (OverloadedFunctionDecl::function_iterator Func
+ = Conversions->function_begin();
+ Func != Conversions->function_end(); ++Func) {
+ CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func);
+ AddTypesConvertedFrom(Conv->getConversionType(), false);
+ }
+ }
+ }
+}
+
+/// AddBuiltinCandidates - 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::AddBuiltinBinaryOperatorCandidates(OverloadedOperatorKind Op,
+ Expr **Args,
+ OverloadCandidateSet& CandidateSet) {
+ // The set of "promoted arithmetic types", which are the arithmetic
+ // types are that preserved by promotion (C++ [over.built]p2). Note
+ // that the first few of these types are the promoted integral
+ // types; these types need to be first.
+ // FIXME: What about complex?
+ const unsigned FirstIntegralType = 0;
+ const unsigned LastIntegralType = 13;
+ const unsigned FirstPromotedIntegralType = 7,
+ LastPromotedIntegralType = 13;
+ const unsigned FirstPromotedArithmeticType = 7,
+ LastPromotedArithmeticType = 16;
+ const unsigned NumArithmeticTypes = 16;
+ QualType ArithmeticTypes[NumArithmeticTypes] = {
+ Context.BoolTy, Context.CharTy, Context.WCharTy,
+ Context.SignedCharTy, Context.ShortTy,
+ Context.UnsignedCharTy, Context.UnsignedShortTy,
+ Context.IntTy, Context.LongTy, Context.LongLongTy,
+ Context.UnsignedIntTy, Context.UnsignedLongTy, Context.UnsignedLongLongTy,
+ Context.FloatTy, Context.DoubleTy, Context.LongDoubleTy
+ };
+
+ // 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.
+ BuiltinCandidateTypeSet CandidateTypes(Context);
+ if (Op == OO_Less || Op == OO_Greater || Op == OO_LessEqual ||
+ Op == OO_GreaterEqual || Op == OO_EqualEqual || Op == OO_ExclaimEqual ||
+ Op == OO_Plus || Op == OO_Minus || Op == OO_Equal ||
+ Op == OO_PlusEqual || Op == OO_MinusEqual || Op == OO_Subscript ||
+ Op == OO_ArrowStar) {
+ for (unsigned ArgIdx = 0; ArgIdx < 2; ++ArgIdx)
+ CandidateTypes.AddTypesConvertedFrom(Args[ArgIdx]->getType());
+ }
+
+ bool isComparison = false;
+ switch (Op) {
+ case OO_None:
+ case NUM_OVERLOADED_OPERATORS:
+ assert(false && "Expected an overloaded operator");
+ break;
+
+ case OO_New:
+ case OO_Delete:
+ case OO_Array_New:
+ case OO_Array_Delete:
+ case OO_Tilde:
+ case OO_Exclaim:
+ case OO_PlusPlus:
+ case OO_MinusMinus:
+ case OO_Arrow:
+ case OO_Call:
+ assert(false && "Expected a binary operator");
+ break;
+
+ case OO_Comma:
+ // C++ [over.match.oper]p3:
+ // -- For the operator ',', the unary operator '&', or the
+ // operator '->', the built-in candidates set is empty.
+ // We don't check '&' or '->' here, since they are unary operators.
+ break;
+
+ case OO_Less:
+ case OO_Greater:
+ case OO_LessEqual:
+ case OO_GreaterEqual:
+ case OO_EqualEqual:
+ case OO_ExclaimEqual:
+ // 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 (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 };
+ AddBuiltinCandidate(Context.BoolTy, ParamTypes, Args, 2, CandidateSet);
+ }
+
+ // Fall through.
+ isComparison = true;
+
+ case OO_Plus:
+ case OO_Minus:
+ 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.pointer_begin();
+ Ptr != CandidateTypes.pointer_end(); ++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_Plus) {
+ // T* operator+(ptrdiff_t, T*);
+ ParamTypes[0] = ParamTypes[1];
+ ParamTypes[1] = *Ptr;
+ AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet);
+ } else {
+ // ptrdiff_t operator-(T, T);
+ ParamTypes[1] = *Ptr;
+ AddBuiltinCandidate(Context.getPointerDiffType(), ParamTypes,
+ Args, 2, CandidateSet);
+ }
+ }
+ }
+ // Fall through
+
+ case OO_Star:
+ case OO_Slash:
+ // 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.
+ for (unsigned Left = FirstPromotedArithmeticType;
+ Left < LastPromotedArithmeticType; ++Left) {
+ for (unsigned Right = FirstPromotedArithmeticType;
+ Right < LastPromotedArithmeticType; ++Right) {
+ QualType LandR[2] = { ArithmeticTypes[Left], ArithmeticTypes[Right] };
+ QualType Result
+ = isComparison? Context.BoolTy
+ : UsualArithmeticConversionsType(LandR[0], LandR[1]);
+ AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet);
+ }
+ }
+ break;
+
+ case OO_Percent:
+ case OO_Amp:
+ 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.
+ for (unsigned Left = FirstPromotedIntegralType;
+ Left < LastPromotedIntegralType; ++Left) {
+ for (unsigned Right = FirstPromotedIntegralType;
+ Right < LastPromotedIntegralType; ++Right) {
+ QualType LandR[2] = { ArithmeticTypes[Left], ArithmeticTypes[Right] };
+ QualType Result = (Op == OO_LessLess || Op == OO_GreaterGreater)
+ ? LandR[0]
+ : UsualArithmeticConversionsType(LandR[0], LandR[1]);
+ 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
+ // (FIXME:) 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 (BuiltinCandidateTypeSet::iterator Enum
+ = CandidateTypes.enumeration_begin();
+ Enum != CandidateTypes.enumeration_end(); ++Enum) {
+ QualType ParamTypes[2];
+
+ // T& operator=(T&, T)
+ ParamTypes[0] = Context.getReferenceType(*Enum);
+ ParamTypes[1] = *Enum;
+ AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet);
+
+ // volatile T& operator=(volatile T&, T)
+ ParamTypes[0] = Context.getReferenceType(Enum->withVolatile());
+ ParamTypes[1] = *Enum;
+ AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet);
+ }
+ // 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 Ptr = CandidateTypes.pointer_begin();
+ Ptr != CandidateTypes.pointer_end(); ++Ptr) {
+ QualType ParamTypes[2];
+ ParamTypes[1] = (Op == OO_Equal)? *Ptr : Context.getPointerDiffType();
+
+ // non-volatile version
+ ParamTypes[0] = Context.getReferenceType(*Ptr);
+ AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet);
+
+ // volatile version
+ ParamTypes[0] = Context.getReferenceType(Ptr->withVolatile());
+ AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet);
+ }
+ // 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);
+ for (unsigned Left = 0; Left < NumArithmeticTypes; ++Left) {
+ for (unsigned Right = FirstPromotedArithmeticType;
+ Right < LastPromotedArithmeticType; ++Right) {
+ QualType ParamTypes[2];
+ ParamTypes[1] = ArithmeticTypes[Right];
+
+ // Add this built-in operator as a candidate (VQ is empty).
+ ParamTypes[0] = Context.getReferenceType(ArithmeticTypes[Left]);
+ AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet);
+
+ // Add this built-in operator as a candidate (VQ is 'volatile').
+ ParamTypes[0] = ArithmeticTypes[Left].withVolatile();
+ ParamTypes[0] = Context.getReferenceType(ParamTypes[0]);
+ AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet);
+ }
+ }
+ 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);
+ for (unsigned Left = FirstIntegralType; Left < LastIntegralType; ++Left) {
+ for (unsigned Right = FirstPromotedIntegralType;
+ Right < LastPromotedIntegralType; ++Right) {
+ QualType ParamTypes[2];
+ ParamTypes[1] = ArithmeticTypes[Right];
+
+ // Add this built-in operator as a candidate (VQ is empty).
+ // FIXME: We should be caching these declarations somewhere,
+ // rather than re-building them every time.
+ ParamTypes[0] = Context.getReferenceType(ArithmeticTypes[Left]);
+ AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet);
+
+ // Add this built-in operator as a candidate (VQ is 'volatile').
+ ParamTypes[0] = ArithmeticTypes[Left];
+ ParamTypes[0].addVolatile();
+ ParamTypes[0] = Context.getReferenceType(ParamTypes[0]);
+ AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet);
+ }
+ }
+ break;
+
+ case OO_AmpAmp:
+ case OO_PipePipe: {
+ // C++ [over.operator]p23:
+ //
+ // There also exist candidate operator functions of the form
+ //
+ // bool operator!(bool); [In Unary version]
+ // bool operator&&(bool, bool);
+ // bool operator||(bool, bool);
+ QualType ParamTypes[2] = { Context.BoolTy, Context.BoolTy };
+ AddBuiltinCandidate(Context.BoolTy, ParamTypes, Args, 2, CandidateSet);
+ break;
+ }
+
+ 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 Ptr = CandidateTypes.pointer_begin();
+ Ptr != CandidateTypes.pointer_end(); ++Ptr) {
+ QualType ParamTypes[2] = { *Ptr, Context.getPointerDiffType() };
+ QualType PointeeType = (*Ptr)->getAsPointerType()->getPointeeType();
+ QualType ResultTy = Context.getReferenceType(PointeeType);
+
+ // T& operator[](T*, ptrdiff_t)
+ AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet);
+
+ // T& operator[](ptrdiff_t, T*);
+ ParamTypes[0] = ParamTypes[1];
+ ParamTypes[1] = *Ptr;
+ AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet);
+ }
+ break;
+
+ case OO_ArrowStar:
+ // FIXME: No support for pointer-to-members yet.
+ break;
+ }
+}
+
/// AddOverloadCandidates - Add all of the function overloads in Ovl
/// to the candidate set.
void
@@ -1609,7 +2169,8 @@ Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1,
if (HasBetterConversion)
return true;
- // FIXME: Several other bullets in (C++ 13.3.3p1) need to be implemented.
+ // FIXME: Several other bullets in (C++ 13.3.3p1) need to be
+ // implemented, but they require template support.
// C++ [over.match.best]p1b4:
//
@@ -1688,8 +2249,24 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet,
OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
LastCand = CandidateSet.end();
for (; Cand != LastCand; ++Cand) {
- if (Cand->Viable ||!OnlyViable)
- Diag(Cand->Function->getLocation(), diag::err_ovl_candidate);
+ if (Cand->Viable || !OnlyViable) {
+ if (Cand->Function) {
+ // Normal function
+ Diag(Cand->Function->getLocation(), diag::err_ovl_candidate);
+ } else {
+ // FIXME: We need to get the identifier in here
+ // FIXME: Do we want the error message to point at the
+ // operator? (built-ins won't have a location)
+ QualType FnType
+ = Context.getFunctionType(Cand->BuiltinTypes.ResultTy,
+ Cand->BuiltinTypes.ParamTypes,
+ Cand->Conversions.size(),
+ false, 0);
+
+ Diag(SourceLocation(), diag::err_ovl_builtin_candidate,
+ FnType.getAsString());
+ }
+ }
}
}