/// OverloadCandidateSet - A set of overload candidates, used in C++
/// overload resolution (C++ 13.3).
class OverloadCandidateSet {
+ public:
+ enum CandidateSetKind {
+ /// Normal lookup.
+ CSK_Normal,
+ /// Lookup for candidates for a call using operator syntax. Candidates
+ /// that have no parameters of class type will be skipped unless there
+ /// is a parameter of (reference to) enum type and the corresponding
+ /// argument is of the same enum type.
+ CSK_Operator
+ };
+
+ private:
SmallVector<OverloadCandidate, 16> Candidates;
llvm::SmallPtrSet<Decl *, 16> Functions;
llvm::BumpPtrAllocator ConversionSequenceAllocator;
SourceLocation Loc;
+ CandidateSetKind Kind;
unsigned NumInlineSequences;
char InlineSpace[16 * sizeof(ImplicitConversionSequence)];
void destroyCandidates();
public:
- OverloadCandidateSet(SourceLocation Loc) : Loc(Loc), NumInlineSequences(0){}
+ OverloadCandidateSet(SourceLocation Loc, CandidateSetKind CSK)
+ : Loc(Loc), Kind(CSK), NumInlineSequences(0) {}
~OverloadCandidateSet() { destroyCandidates(); }
SourceLocation getLocation() const { return Loc; }
+ CandidateSetKind getKind() const { return Kind; }
/// \brief Determine when this overload candidate will be new to the
/// overload set.
SourceLocation OpLoc, ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet);
void AddArgumentDependentLookupCandidates(DeclarationName Name,
- bool Operator, SourceLocation Loc,
+ SourceLocation Loc,
ArrayRef<Expr *> Args,
TemplateArgumentListInfo *ExplicitTemplateArgs,
OverloadCandidateSet& CandidateSet,
bool AllowStringTemplate);
bool isKnownName(StringRef name);
- void ArgumentDependentLookup(DeclarationName Name, bool Operator,
- SourceLocation Loc,
- ArrayRef<Expr *> Args,
- ADLResult &Functions);
+ void ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc,
+ ArrayRef<Expr *> Args, ADLResult &Functions);
void LookupVisibleDecls(Scope *S, LookupNameKind Kind,
VisibleDeclConsumer &Consumer,
// Build an overload candidate set based on the functions we find.
SourceLocation Loc = Fn->getExprLoc();
- OverloadCandidateSet CandidateSet(Loc);
+ OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal);
// FIXME: What if we're calling something that isn't a function declaration?
// FIXME: What if we're calling a pseudo-destructor?
NamedDecl *ND = Corrected.getCorrectionDecl();
if (ND) {
if (Corrected.isOverloaded()) {
- OverloadCandidateSet OCS(R.getNameLoc());
+ OverloadCandidateSet OCS(R.getNameLoc(),
+ OverloadCandidateSet::CSK_Normal);
OverloadCandidateSet::iterator Best;
for (TypoCorrection::decl_iterator CD = Corrected.begin(),
CDEnd = Corrected.end();
S.getScopeForContext(S.CurContext), NULL, CCC)) {
if (NamedDecl *ND = Corrected.getCorrectionDecl()) {
if (Corrected.isOverloaded()) {
- OverloadCandidateSet OCS(NameLoc);
+ OverloadCandidateSet OCS(NameLoc, OverloadCandidateSet::CSK_Normal);
OverloadCandidateSet::iterator Best;
for (TypoCorrection::decl_iterator CD = Corrected.begin(),
CDEnd = Corrected.end();
R.suppressDiagnostics();
- OverloadCandidateSet Candidates(StartLoc);
+ OverloadCandidateSet Candidates(StartLoc, OverloadCandidateSet::CSK_Normal);
for (LookupResult::iterator Alloc = R.begin(), AllocEnd = R.end();
Alloc != AllocEnd; ++Alloc) {
// Even member operator new/delete are implicitly treated as
static bool FindConditionalOverload(Sema &Self, ExprResult &LHS, ExprResult &RHS,
SourceLocation QuestionLoc) {
Expr *Args[2] = { LHS.get(), RHS.get() };
- OverloadCandidateSet CandidateSet(QuestionLoc);
+ OverloadCandidateSet CandidateSet(QuestionLoc,
+ OverloadCandidateSet::CSK_Operator);
Self.AddBuiltinOperatorCandidates(OO_Conditional, QuestionLoc, Args,
CandidateSet);
const InitializationKind &Kind,
MultiExprArg Args,
bool TopLevelOfInitList)
- : FailedCandidateSet(Kind.getLocation()) {
+ : FailedCandidateSet(Kind.getLocation(), OverloadCandidateSet::CSK_Normal) {
InitializeFrom(S, Entity, Kind, Args, TopLevelOfInitList);
}
// Only consider constructors and constructor templates. Per
// C++0x [dcl.init]p16, second bullet to class types, this initialization
// is direct-initialization.
- OverloadCandidateSet CandidateSet(Loc);
+ OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal);
LookupCopyAndMoveConstructors(S, CandidateSet, Class, CurInitExpr);
bool HadMultipleCandidates = (CandidateSet.size() > 1);
return;
// Find constructors which would have been considered.
- OverloadCandidateSet CandidateSet(Loc);
+ OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal);
LookupCopyAndMoveConstructors(
S, CandidateSet, cast<CXXRecordDecl>(Record->getDecl()), CurInitExpr);
}
}
-/// IsAcceptableNonMemberOperatorCandidate - Determine whether Fn is
-/// an acceptable non-member overloaded operator for a call whose
-/// arguments have types T1 (and, if non-empty, T2). This routine
-/// implements the check in C++ [over.match.oper]p3b2 concerning
-/// enumeration types.
-static bool
-IsAcceptableNonMemberOperatorCandidate(FunctionDecl *Fn,
- QualType T1, QualType T2,
- ASTContext &Context) {
- if (T1->isDependentType() || (!T2.isNull() && T2->isDependentType()))
- return true;
-
- if (T1->isRecordType() || (!T2.isNull() && T2->isRecordType()))
- return true;
-
- const FunctionProtoType *Proto = Fn->getType()->getAs<FunctionProtoType>();
- if (Proto->getNumParams() < 1)
- return false;
-
- if (T1->isEnumeralType()) {
- QualType ArgType = Proto->getParamType(0).getNonReferenceType();
- if (Context.hasSameUnqualifiedType(T1, ArgType))
- return true;
- }
-
- if (Proto->getNumParams() < 2)
- return false;
-
- if (!T2.isNull() && T2->isEnumeralType()) {
- QualType ArgType = Proto->getParamType(1).getNonReferenceType();
- if (Context.hasSameUnqualifiedType(T2, ArgType))
- return true;
- }
-
- return false;
-}
-
NamedDecl *Sema::LookupSingleName(Scope *S, DeclarationName Name,
SourceLocation Loc,
LookupNameKind NameKind,
// unqualified lookup of operator@ in the context of the
// expression according to the usual rules for name lookup in
// unqualified function calls (3.4.2) except that all member
- // functions are ignored. However, if no operand has a class
- // type, only those non-member functions in the lookup set
- // that have a first parameter of type T1 or "reference to
- // (possibly cv-qualified) T1", when T1 is an enumeration
- // type, or (if there is a right operand) a second parameter
- // of type T2 or "reference to (possibly cv-qualified) T2",
- // when T2 is an enumeration type, are candidate functions.
+ // functions are ignored.
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
LookupResult Operators(*this, OpName, SourceLocation(), LookupOperatorName);
LookupName(Operators, S);
assert(!Operators.isAmbiguous() && "Operator lookup cannot be ambiguous");
-
- if (Operators.empty())
- return;
-
- for (auto I = Operators.begin(), E = Operators.end(); I != E; ++I)
- addOverloadedOperatorToUnresolvedSet(Functions, I.getPair(), T1, T2);
-}
-
-void Sema::addOverloadedOperatorToUnresolvedSet(UnresolvedSetImpl &Functions,
- DeclAccessPair Op,
- QualType T1, QualType T2) {
- NamedDecl *Found = Op->getUnderlyingDecl();
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Found)) {
- if (IsAcceptableNonMemberOperatorCandidate(FD, T1, T2, Context))
- Functions.addDecl(Op, Op.getAccess()); // FIXME: canonical FD
- } else if (FunctionTemplateDecl *FunTmpl
- = dyn_cast<FunctionTemplateDecl>(Found)) {
- // FIXME: friend operators?
- // FIXME: do we need to check IsAcceptableNonMemberOperatorCandidate,
- // later?
- if (!FunTmpl->getDeclContext()->isRecord())
- Functions.addDecl(Op, Op.getAccess());
- }
+ Functions.append(Operators.begin(), Operators.end());
}
Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
// Now we perform lookup on the name we computed earlier and do overload
// resolution. Lookup is only performed directly into the class since there
// will always be a (possibly implicit) declaration to shadow any others.
- OverloadCandidateSet OCS(RD->getLocation());
+ OverloadCandidateSet OCS(RD->getLocation(), OverloadCandidateSet::CSK_Normal);
DeclContext::lookup_result R = RD->lookup(Name);
assert(!R.empty() &&
"lookup for a constructor or assignment operator was empty");
Old = New;
}
-void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
- SourceLocation Loc, ArrayRef<Expr *> Args,
- ADLResult &Result) {
+void Sema::ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc,
+ ArrayRef<Expr *> Args, ADLResult &Result) {
// Find all of the associated namespaces and classes based on the
// arguments we have.
AssociatedNamespaceSet AssociatedNamespaces;
AssociatedNamespaces,
AssociatedClasses);
- QualType T1, T2;
- if (Operator) {
- T1 = Args[0]->getType();
- if (Args.size() >= 2)
- T2 = Args[1]->getType();
- }
-
// C++ [basic.lookup.argdep]p3:
// Let X be the lookup set produced by unqualified lookup (3.4.1)
// and let Y be the lookup set produced by argument dependent
if (isa<UsingShadowDecl>(D))
D = cast<UsingShadowDecl>(D)->getTargetDecl();
- if (isa<FunctionDecl>(D)) {
- if (Operator &&
- !IsAcceptableNonMemberOperatorCandidate(cast<FunctionDecl>(D),
- T1, T2, Context))
- continue;
- } else if (!isa<FunctionTemplateDecl>(D))
+ if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D))
continue;
Result.insert(D);
}
// Attempt user-defined conversion.
- OverloadCandidateSet Conversions(From->getExprLoc());
+ OverloadCandidateSet Conversions(From->getExprLoc(),
+ OverloadCandidateSet::CSK_Normal);
OverloadingResult UserDefResult
= IsUserDefinedConversion(S, From, ToType, ICS.UserDefined, Conversions,
AllowExplicit, AllowObjCConversionOnExplicit);
bool
Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) {
ImplicitConversionSequence ICS;
- OverloadCandidateSet CandidateSet(From->getExprLoc());
+ OverloadCandidateSet CandidateSet(From->getExprLoc(),
+ OverloadCandidateSet::CSK_Normal);
OverloadingResult OvResult =
IsUserDefinedConversion(*this, From, ToType, ICS.UserDefined,
CandidateSet, false, false);
CXXRecordDecl *T2RecordDecl
= dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl());
- OverloadCandidateSet CandidateSet(DeclLoc);
+ OverloadCandidateSet CandidateSet(DeclLoc, OverloadCandidateSet::CSK_Normal);
std::pair<CXXRecordDecl::conversion_iterator,
CXXRecordDecl::conversion_iterator>
Conversions = T2RecordDecl->getVisibleConversionFunctions();
// If one unique T is found:
// First, build a candidate set from the previously recorded
// potentially viable conversions.
- OverloadCandidateSet CandidateSet(Loc);
+ OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal);
collectViableConversionCandidates(*this, From, ToType, ViableConversions,
CandidateSet);
return finishContextualImplicitConversion(*this, Loc, From, Converter);
}
+/// IsAcceptableNonMemberOperatorCandidate - Determine whether Fn is
+/// an acceptable non-member overloaded operator for a call whose
+/// arguments have types T1 (and, if non-empty, T2). This routine
+/// implements the check in C++ [over.match.oper]p3b2 concerning
+/// enumeration types.
+static bool IsAcceptableNonMemberOperatorCandidate(ASTContext &Context,
+ FunctionDecl *Fn,
+ ArrayRef<Expr *> Args) {
+ QualType T1 = Args[0]->getType();
+ QualType T2 = Args.size() > 1 ? Args[1]->getType() : QualType();
+
+ if (T1->isDependentType() || (!T2.isNull() && T2->isDependentType()))
+ return true;
+
+ if (T1->isRecordType() || (!T2.isNull() && T2->isRecordType()))
+ return true;
+
+ const FunctionProtoType *Proto = Fn->getType()->getAs<FunctionProtoType>();
+ if (Proto->getNumParams() < 1)
+ return false;
+
+ if (T1->isEnumeralType()) {
+ QualType ArgType = Proto->getParamType(0).getNonReferenceType();
+ if (Context.hasSameUnqualifiedType(T1, ArgType))
+ return true;
+ }
+
+ if (Proto->getNumParams() < 2)
+ return false;
+
+ if (!T2.isNull() && T2->isEnumeralType()) {
+ QualType ArgType = Proto->getParamType(1).getNonReferenceType();
+ if (Context.hasSameUnqualifiedType(T2, ArgType))
+ return true;
+ }
+
+ return false;
+}
+
/// AddOverloadCandidate - Adds the given function to the set of
/// candidate functions, using the given function call arguments. If
/// @p SuppressUserConversions, then don't allow user-defined
if (!CandidateSet.isNewCandidate(Function))
return;
+ // C++ [over.match.oper]p3:
+ // if no operand has a class type, only those non-member functions in the
+ // lookup set that have a first parameter of type T1 or "reference to
+ // (possibly cv-qualified) T1", when T1 is an enumeration type, or (if there
+ // is a right operand) a second parameter of type T2 or "reference to
+ // (possibly cv-qualified) T2", when T2 is an enumeration type, are
+ // candidate functions.
+ if (CandidateSet.getKind() == OverloadCandidateSet::CSK_Operator &&
+ !IsAcceptableNonMemberOperatorCandidate(Context, Function, Args))
+ return;
+
// C++11 [class.copy]p11: [DR1402]
// A defaulted move constructor that is defined as deleted is ignored by
// overload resolution.
/// candidate set (C++ [basic.lookup.argdep]).
void
Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
- bool Operator, SourceLocation Loc,
+ SourceLocation Loc,
ArrayRef<Expr *> Args,
TemplateArgumentListInfo *ExplicitTemplateArgs,
OverloadCandidateSet& CandidateSet,
// we supposed to consider on ADL candidates, anyway?
// FIXME: Pass in the explicit template arguments?
- ArgumentDependentLookup(Name, Operator, Loc, Args, Fns);
+ ArgumentDependentLookup(Name, Loc, Args, Fns);
// Erase all of the candidates we already knew about.
for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
/*KnownValid*/ true);
if (ULE->requiresADL())
- AddArgumentDependentLookupCandidates(ULE->getName(), /*Operator*/ false,
- ULE->getExprLoc(),
+ AddArgumentDependentLookupCandidates(ULE->getName(), ULE->getExprLoc(),
Args, ExplicitTemplateArgs,
CandidateSet, PartialOverloading);
}
static bool
DiagnoseTwoPhaseLookup(Sema &SemaRef, SourceLocation FnLoc,
const CXXScopeSpec &SS, LookupResult &R,
+ OverloadCandidateSet::CandidateSetKind CSK,
TemplateArgumentListInfo *ExplicitTemplateArgs,
ArrayRef<Expr *> Args) {
if (SemaRef.ActiveTemplateInstantiations.empty() || !SS.isEmpty())
return false;
}
- OverloadCandidateSet Candidates(FnLoc);
+ OverloadCandidateSet Candidates(FnLoc, CSK);
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
AddOverloadedCallCandidate(SemaRef, I.getPair(),
ExplicitTemplateArgs, Args,
SemaRef.Context.DeclarationNames.getCXXOperatorName(Op);
LookupResult R(SemaRef, OpName, OpLoc, Sema::LookupOperatorName);
return DiagnoseTwoPhaseLookup(SemaRef, OpLoc, CXXScopeSpec(), R,
+ OverloadCandidateSet::CSK_Operator,
/*ExplicitTemplateArgs=*/0, Args);
}
(CorrectionCandidateCallback*)&Validator :
(CorrectionCandidateCallback*)&RejectAll;
if (!DiagnoseTwoPhaseLookup(SemaRef, Fn->getExprLoc(), SS, R,
+ OverloadCandidateSet::CSK_Normal,
ExplicitTemplateArgs, Args) &&
(!EmptyLookup ||
SemaRef.DiagnoseEmptyLookup(S, SS, R, *CCC,
SourceLocation RParenLoc,
Expr *ExecConfig,
bool AllowTypoCorrection) {
- OverloadCandidateSet CandidateSet(Fn->getExprLoc());
+ OverloadCandidateSet CandidateSet(Fn->getExprLoc(),
+ OverloadCandidateSet::CSK_Normal);
ExprResult result;
if (buildOverloadedCallSet(S, Fn, ULE, Args, LParenLoc, &CandidateSet,
}
// Build an empty overload set.
- OverloadCandidateSet CandidateSet(OpLoc);
+ OverloadCandidateSet CandidateSet(OpLoc, OverloadCandidateSet::CSK_Operator);
// Add the candidates from the given function set.
AddFunctionCandidates(Fns, ArgsArray, CandidateSet, false);
AddMemberOperatorCandidates(Op, OpLoc, ArgsArray, CandidateSet);
// Add candidates from ADL.
- AddArgumentDependentLookupCandidates(OpName, /*Operator*/ true, OpLoc,
- ArgsArray, /*ExplicitTemplateArgs*/ 0,
- CandidateSet);
+ AddArgumentDependentLookupCandidates(OpName, OpLoc, ArgsArray,
+ /*ExplicitTemplateArgs*/0, CandidateSet);
// Add builtin operator candidates.
AddBuiltinOperatorCandidates(Op, OpLoc, ArgsArray, CandidateSet);
return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
// Build an empty overload set.
- OverloadCandidateSet CandidateSet(OpLoc);
+ OverloadCandidateSet CandidateSet(OpLoc, OverloadCandidateSet::CSK_Operator);
// Add the candidates from the given function set.
AddFunctionCandidates(Fns, Args, CandidateSet, false);
AddMemberOperatorCandidates(Op, OpLoc, Args, CandidateSet);
// Add candidates from ADL.
- AddArgumentDependentLookupCandidates(OpName, /*Operator*/ true,
- OpLoc, Args,
+ AddArgumentDependentLookupCandidates(OpName, OpLoc, Args,
/*ExplicitTemplateArgs*/ 0,
CandidateSet);
return ExprError();
// Build an empty overload set.
- OverloadCandidateSet CandidateSet(LLoc);
+ OverloadCandidateSet CandidateSet(LLoc, OverloadCandidateSet::CSK_Operator);
// Subscript can only be overloaded as a member function.
: UnresExpr->getBase()->Classify(Context);
// Add overload candidates
- OverloadCandidateSet CandidateSet(UnresExpr->getMemberLoc());
+ OverloadCandidateSet CandidateSet(UnresExpr->getMemberLoc(),
+ OverloadCandidateSet::CSK_Normal);
// FIXME: avoid copy.
TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = 0;
// operators of T. The function call operators of T are obtained by
// ordinary lookup of the name operator() in the context of
// (E).operator().
- OverloadCandidateSet CandidateSet(LParenLoc);
+ OverloadCandidateSet CandidateSet(LParenLoc,
+ OverloadCandidateSet::CSK_Operator);
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Call);
if (RequireCompleteType(LParenLoc, Object.get()->getType(),
// overload resolution mechanism (13.3).
DeclarationName OpName =
Context.DeclarationNames.getCXXOperatorName(OO_Arrow);
- OverloadCandidateSet CandidateSet(Loc);
+ OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Operator);
const RecordType *BaseRecord = Base->getType()->getAs<RecordType>();
if (RequireCompleteType(Loc, Base->getType(),
TemplateArgumentListInfo *TemplateArgs) {
SourceLocation UDSuffixLoc = SuffixInfo.getCXXLiteralOperatorNameLoc();
- OverloadCandidateSet CandidateSet(UDSuffixLoc);
+ OverloadCandidateSet CandidateSet(UDSuffixLoc,
+ OverloadCandidateSet::CSK_Normal);
AddFunctionCandidates(R.asUnresolvedSet(), Args, CandidateSet, true,
TemplateArgs);
return StmtError();
}
} else {
- OverloadCandidateSet CandidateSet(RangeLoc);
+ OverloadCandidateSet CandidateSet(RangeLoc,
+ OverloadCandidateSet::CSK_Normal);
Sema::BeginEndFunction BEFFailure;
ForRangeStatus RangeStatus =
BuildNonArrayForRange(*this, S, BeginRangeRef.get(),
if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(Callee)) {
assert(ULE->requiresADL());
-
- for (auto I = ULE->decls_begin(), E = ULE->decls_end(); I != E; ++I)
- SemaRef.addOverloadedOperatorToUnresolvedSet(
- Functions, I.getPair(), First->getType(),
- Second ? Second->getType() : QualType());
+ Functions.append(ULE->decls_begin(), ULE->decls_end());
} else {
// If we've resolved this to a particular non-member function, just call
// that function. If we resolved it to a member function,
// candidates.
struct B { template<typename T> B(T); };
-int operator~(B); // expected-note {{declared prior to the call site}}
+int operator~(B);
template<typename T> int operator%(B, T);
enum class E { e };
-// FIXME: This is the wrong diagnostic.
-template<typename T> int f(T t) { return ~t; } // expected-error {{call to}}
-template<typename T, typename U> int f(T t, U u) { return t % u; }
+template<typename T> int f(T t) { return ~t; } // expected-error {{invalid argument type}}
+template<typename T, typename U> int f(T t, U u) { return t % u; } // expected-error {{invalid operands to}}
int b1 = ~E::e; // expected-error {{invalid argument type}}
int b2 = f(E::e); // expected-note {{in instantiation of}}
int b3 = f(0, E::e);
-// FIXME: This should be rejected.
-int b4 = f(E::e, 0);
+int b4 = f(E::e, 0); // expected-note {{in instantiation of}}
}