void AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet);
+ void AddArgumentDependentLookupCandidates(DeclarationName Name,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet& CandidateSet);
void AddOverloadCandidates(const OverloadedFunctionDecl *Ovl,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool Complain);
void FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn);
- FunctionDecl *ResolveOverloadedCallFn(Expr *Fn, OverloadedFunctionDecl *Ovl,
+ FunctionDecl *ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Func,
SourceLocation LParenLoc,
Expr **Args, unsigned NumArgs,
SourceLocation *CommaLocs,
- SourceLocation RParenLoc);
+ SourceLocation RParenLoc,
+ bool ArgumentDependentLookup);
ExprResult
BuildCallToMemberFunction(Scope *S, Expr *MemExpr,
SourceLocation LParenLoc, Expr **Args,
DeclarationName Name,
LookupNameKind NameKind,
bool RedeclarationOnly = false);
+
+ typedef llvm::SmallPtrSet<NamespaceDecl *, 16> AssociatedNamespaceSet;
+ typedef llvm::SmallPtrSet<CXXRecordDecl *, 16> AssociatedClassSet;
+
+ void FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
+ AssociatedNamespaceSet &AssociatedNamespaces,
+ AssociatedClassSet &AssociatedClasses);
+
bool DiagnoseAmbiguousLookup(LookupResult &Result, DeclarationName Name,
SourceLocation NameLoc,
SourceRange LookupRange = SourceRange());
Expr **Args = reinterpret_cast<Expr**>(args.release());
assert(Fn && "no function call expression");
FunctionDecl *FDecl = NULL;
- OverloadedFunctionDecl *Ovl = NULL;
// Determine whether this is a dependent call inside a C++ template,
// in which case we won't do any semantic analysis now.
else {
// Resolve the CXXDependentNameExpr to an actual identifier;
// it wasn't really a dependent name after all.
+ // FIXME: in the presence of ADL, this resolves too early.
OwningExprResult Resolved
= ActOnDeclarationNameExpr(S, FnName->getLocation(),
FnName->getName(),
return Owned(BuildCallToObjectOfClassType(S, Fn, LParenLoc, Args, NumArgs,
CommaLocs, RParenLoc));
- // Determine whether this is a call to a member function.
if (getLangOptions().CPlusPlus) {
+ // Determine whether this is a call to a member function.
if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(Fn->IgnoreParens()))
if (isa<OverloadedFunctionDecl>(MemExpr->getMemberDecl()) ||
isa<CXXMethodDecl>(MemExpr->getMemberDecl()))
CommaLocs, RParenLoc));
}
- // If we're directly calling a function or a set of overloaded
- // functions, get the appropriate declaration.
+ // If we're directly calling a function, get the appropriate declaration.
DeclRefExpr *DRExpr = NULL;
- if (ImplicitCastExpr *IcExpr = dyn_cast<ImplicitCastExpr>(Fn))
- DRExpr = dyn_cast<DeclRefExpr>(IcExpr->getSubExpr());
- else
- DRExpr = dyn_cast<DeclRefExpr>(Fn);
-
- if (DRExpr) {
- FDecl = dyn_cast<FunctionDecl>(DRExpr->getDecl());
- Ovl = dyn_cast<OverloadedFunctionDecl>(DRExpr->getDecl());
+ Expr *FnExpr = Fn;
+ bool ADL = true;
+ while (true) {
+ if (ImplicitCastExpr *IcExpr = dyn_cast<ImplicitCastExpr>(FnExpr))
+ FnExpr = IcExpr->getSubExpr();
+ else if (ParenExpr *PExpr = dyn_cast<ParenExpr>(FnExpr)) {
+ // FIXME: Where does the C++ standard say this?
+ ADL = false;
+ FnExpr = PExpr->getSubExpr();
+ } else if (isa<UnaryOperator>(FnExpr) &&
+ cast<UnaryOperator>(FnExpr)->getOpcode()
+ == UnaryOperator::AddrOf) {
+ FnExpr = cast<UnaryOperator>(FnExpr)->getSubExpr();
+ } else {
+ DRExpr = dyn_cast<DeclRefExpr>(FnExpr);
+ break;
+ }
}
+
+ if (DRExpr)
+ FDecl = dyn_cast<FunctionDecl>(DRExpr->getDecl());
- if (Ovl) {
- FDecl = ResolveOverloadedCallFn(Fn, Ovl, LParenLoc, Args, NumArgs,
- CommaLocs, RParenLoc);
- if (!FDecl)
- return ExprError();
-
- // Update Fn to refer to the actual function selected.
- Expr *NewFn = 0;
- if (QualifiedDeclRefExpr *QDRExpr = dyn_cast<QualifiedDeclRefExpr>(DRExpr))
- NewFn = new (Context) QualifiedDeclRefExpr(FDecl, FDecl->getType(),
- QDRExpr->getLocation(), false, false,
- QDRExpr->getSourceRange().getBegin());
- else
- NewFn = new (Context) DeclRefExpr(FDecl, FDecl->getType(),
- Fn->getSourceRange().getBegin());
- Fn->Destroy(Context);
- Fn = NewFn;
+ if (getLangOptions().CPlusPlus && DRExpr &&
+ (FDecl || isa<OverloadedFunctionDecl>(DRExpr->getDecl()))) {
+ // C++ [basic.lookup.argdep]p1:
+ // When an unqualified name is used as the postfix-expression in
+ // a function call (5.2.2), other namespaces not considered
+ // during the usual unqualified lookup (3.4.1) may be searched,
+ // and namespace-scope friend func- tion declarations (11.4) not
+ // otherwise visible may be found.
+ if (DRExpr && isa<QualifiedDeclRefExpr>(DRExpr))
+ ADL = false;
+
+ // We don't perform ADL for builtins.
+ if (FDecl && FDecl->getIdentifier() &&
+ FDecl->getIdentifier()->getBuiltinID())
+ ADL = false;
+
+ if ((DRExpr && isa<OverloadedFunctionDecl>(DRExpr->getDecl())) || ADL) {
+ FDecl = ResolveOverloadedCallFn(Fn, DRExpr->getDecl(), LParenLoc, Args,
+ NumArgs, CommaLocs, RParenLoc, ADL);
+ if (!FDecl)
+ return ExprError();
+
+ // Update Fn to refer to the actual function selected.
+ Expr *NewFn = 0;
+ if (QualifiedDeclRefExpr *QDRExpr
+ = dyn_cast<QualifiedDeclRefExpr>(DRExpr))
+ NewFn = new (Context) QualifiedDeclRefExpr(FDecl, FDecl->getType(),
+ QDRExpr->getLocation(),
+ false, false,
+ QDRExpr->getSourceRange().getBegin());
+ else
+ NewFn = new (Context) DeclRefExpr(FDecl, FDecl->getType(),
+ Fn->getSourceRange().getBegin());
+ Fn->Destroy(Context);
+ Fn = NewFn;
+ }
}
// Promote the function operand.
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Basic/LangOptions.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallPtrSet.h"
#include <set>
#include <vector>
#include <iterator>
// We can't reach here.
return true;
}
+
+// \brief Add the associated classes and namespaces for
+// argument-dependent lookup with an argument of class type
+// (C++ [basic.lookup.koenig]p2).
+static void
+addAssociatedClassesAndNamespaces(CXXRecordDecl *Class,
+ ASTContext &Context,
+ Sema::AssociatedNamespaceSet &AssociatedNamespaces,
+ Sema::AssociatedClassSet &AssociatedClasses) {
+ // C++ [basic.lookup.koenig]p2:
+ // [...]
+ // -- If T is a class type (including unions), its associated
+ // classes are: the class itself; the class of which it is a
+ // member, if any; and its direct and indirect base
+ // classes. Its associated namespaces are the namespaces in
+ // which its associated classes are defined.
+
+ // Add the class of which it is a member, if any.
+ DeclContext *Ctx = Class->getDeclContext();
+ if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx))
+ AssociatedClasses.insert(EnclosingClass);
+
+ // Add the associated namespace for this class.
+ while (Ctx->isRecord())
+ Ctx = Ctx->getParent();
+ if (NamespaceDecl *EnclosingNamespace = dyn_cast<NamespaceDecl>(Ctx))
+ AssociatedNamespaces.insert(EnclosingNamespace);
+
+ // Add the class itself. If we've already seen this class, we don't
+ // need to visit base classes.
+ if (!AssociatedClasses.insert(Class))
+ return;
+
+ // FIXME: Handle class template specializations
+
+ // Add direct and indirect base classes along with their associated
+ // namespaces.
+ llvm::SmallVector<CXXRecordDecl *, 32> Bases;
+ Bases.push_back(Class);
+ while (!Bases.empty()) {
+ // Pop this class off the stack.
+ Class = Bases.back();
+ Bases.pop_back();
+
+ // Visit the base classes.
+ for (CXXRecordDecl::base_class_iterator Base = Class->bases_begin(),
+ BaseEnd = Class->bases_end();
+ Base != BaseEnd; ++Base) {
+ const RecordType *BaseType = Base->getType()->getAsRecordType();
+ CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(BaseType->getDecl());
+ if (AssociatedClasses.insert(BaseDecl)) {
+ // Find the associated namespace for this base class.
+ DeclContext *BaseCtx = BaseDecl->getDeclContext();
+ while (BaseCtx->isRecord())
+ BaseCtx = BaseCtx->getParent();
+ if (NamespaceDecl *EnclosingNamespace = dyn_cast<NamespaceDecl>(BaseCtx))
+ AssociatedNamespaces.insert(EnclosingNamespace);
+
+ // Make sure we visit the bases of this base class.
+ if (BaseDecl->bases_begin() != BaseDecl->bases_end())
+ Bases.push_back(BaseDecl);
+ }
+ }
+ }
+}
+
+// \brief Add the associated classes and namespaces for
+// argument-dependent lookup with an argument of type T
+// (C++ [basic.lookup.koenig]p2).
+static void
+addAssociatedClassesAndNamespaces(QualType T,
+ ASTContext &Context,
+ Sema::AssociatedNamespaceSet &AssociatedNamespaces,
+ Sema::AssociatedClassSet &AssociatedClasses) {
+ // C++ [basic.lookup.koenig]p2:
+ //
+ // For each argument type T in the function call, there is a set
+ // of zero or more associated namespaces and a set of zero or more
+ // associated classes to be considered. The sets of namespaces and
+ // classes is determined entirely by the types of the function
+ // arguments (and the namespace of any template template
+ // argument). Typedef names and using-declarations used to specify
+ // the types do not contribute to this set. The sets of namespaces
+ // and classes are determined in the following way:
+ T = Context.getCanonicalType(T).getUnqualifiedType();
+
+ // -- If T is a pointer to U or an array of U, its associated
+ // namespaces and classes are those associated with U.
+ //
+ // We handle this by unwrapping pointer and array types immediately,
+ // to avoid unnecessary recursion.
+ while (true) {
+ if (const PointerType *Ptr = T->getAsPointerType())
+ T = Ptr->getPointeeType();
+ else if (const ArrayType *Ptr = Context.getAsArrayType(T))
+ T = Ptr->getElementType();
+ else
+ break;
+ }
+
+ // -- If T is a fundamental type, its associated sets of
+ // namespaces and classes are both empty.
+ if (T->getAsBuiltinType())
+ return;
+
+ // -- If T is a class type (including unions), its associated
+ // classes are: the class itself; the class of which it is a
+ // member, if any; and its direct and indirect base
+ // classes. Its associated namespaces are the namespaces in
+ // which its associated classes are defined.
+ if (const CXXRecordType *ClassType
+ = dyn_cast_or_null<CXXRecordType>(T->getAsRecordType())) {
+ addAssociatedClassesAndNamespaces(ClassType->getDecl(),
+ Context, AssociatedNamespaces,
+ AssociatedClasses);
+ return;
+ }
+
+ // -- If T is an enumeration type, its associated namespace is
+ // the namespace in which it is defined. If it is class
+ // member, its associated class is the member’s class; else
+ // it has no associated class.
+ if (const EnumType *EnumT = T->getAsEnumType()) {
+ EnumDecl *Enum = EnumT->getDecl();
+
+ DeclContext *Ctx = Enum->getDeclContext();
+ if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx))
+ AssociatedClasses.insert(EnclosingClass);
+
+ // Add the associated namespace for this class.
+ while (Ctx->isRecord())
+ Ctx = Ctx->getParent();
+ if (NamespaceDecl *EnclosingNamespace = dyn_cast<NamespaceDecl>(Ctx))
+ AssociatedNamespaces.insert(EnclosingNamespace);
+
+ return;
+ }
+
+ // -- If T is a function type, its associated namespaces and
+ // classes are those associated with the function parameter
+ // types and those associated with the return type.
+ if (const FunctionType *FunctionType = T->getAsFunctionType()) {
+ // Return type
+ addAssociatedClassesAndNamespaces(FunctionType->getResultType(),
+ Context,
+ AssociatedNamespaces, AssociatedClasses);
+
+ const FunctionTypeProto *Proto = dyn_cast<FunctionTypeProto>(FunctionType);
+ if (!Proto)
+ return;
+
+ // Argument types
+ for (FunctionTypeProto::arg_type_iterator Arg = Proto->arg_type_begin(),
+ ArgEnd = Proto->arg_type_end();
+ Arg != ArgEnd; ++Arg)
+ addAssociatedClassesAndNamespaces(*Arg, Context,
+ AssociatedNamespaces, AssociatedClasses);
+
+ return;
+ }
+
+ // -- If T is a pointer to a member function of a class X, its
+ // associated namespaces and classes are those associated
+ // with the function parameter types and return type,
+ // together with those associated with X.
+ //
+ // -- If T is a pointer to a data member of class X, its
+ // associated namespaces and classes are those associated
+ // with the member type together with those associated with
+ // X.
+ if (const MemberPointerType *MemberPtr = T->getAsMemberPointerType()) {
+ // Handle the type that the pointer to member points to.
+ addAssociatedClassesAndNamespaces(MemberPtr->getPointeeType(),
+ Context,
+ AssociatedNamespaces, AssociatedClasses);
+
+ // Handle the class type into which this points.
+ if (const RecordType *Class = MemberPtr->getClass()->getAsRecordType())
+ addAssociatedClassesAndNamespaces(cast<CXXRecordDecl>(Class->getDecl()),
+ Context,
+ AssociatedNamespaces, AssociatedClasses);
+
+ return;
+ }
+
+ // FIXME: What about block pointers?
+ // FIXME: What about Objective-C message sends?
+}
+
+/// \brief Find the associated classes and namespaces for
+/// argument-dependent lookup for a call with the given set of
+/// arguments.
+///
+/// This routine computes the sets of associated classes and associated
+/// namespaces searched by argument-dependent lookup
+/// (C++ [basic.lookup.argdep]) for a given set of arguments.
+void
+Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
+ AssociatedNamespaceSet &AssociatedNamespaces,
+ AssociatedClassSet &AssociatedClasses) {
+ AssociatedNamespaces.clear();
+ AssociatedClasses.clear();
+
+ // C++ [basic.lookup.koenig]p2:
+ // For each argument type T in the function call, there is a set
+ // of zero or more associated namespaces and a set of zero or more
+ // associated classes to be considered. The sets of namespaces and
+ // classes is determined entirely by the types of the function
+ // arguments (and the namespace of any template template
+ // argument).
+ for (unsigned ArgIdx = 0; ArgIdx != NumArgs; ++ArgIdx) {
+ Expr *Arg = Args[ArgIdx];
+
+ if (Arg->getType() != Context.OverloadTy) {
+ addAssociatedClassesAndNamespaces(Arg->getType(), Context,
+ AssociatedNamespaces, AssociatedClasses);
+ continue;
+ }
+
+ // [...] In addition, if the argument is the name or address of a
+ // set of overloaded functions and/or function templates, its
+ // associated classes and namespaces are the union of those
+ // associated with each of the members of the set: the namespace
+ // in which the function or function template is defined and the
+ // classes and namespaces associated with its (non-dependent)
+ // parameter types and return type.
+ DeclRefExpr *DRE = 0;
+ if (UnaryOperator *unaryOp = dyn_cast<UnaryOperator>(Arg)) {
+ if (unaryOp->getOpcode() == UnaryOperator::AddrOf)
+ DRE = dyn_cast<DeclRefExpr>(unaryOp->getSubExpr());
+ } else
+ DRE = dyn_cast<DeclRefExpr>(Arg);
+ if (!DRE)
+ continue;
+
+ OverloadedFunctionDecl *Ovl
+ = dyn_cast<OverloadedFunctionDecl>(DRE->getDecl());
+ if (!Ovl)
+ continue;
+
+ for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(),
+ FuncEnd = Ovl->function_end();
+ Func != FuncEnd; ++Func) {
+ FunctionDecl *FDecl = cast<FunctionDecl>(*Func);
+
+ // Add the namespace in which this function was defined. Note
+ // that, if this is a member function, we do *not* consider the
+ // enclosing namespace of its class.
+ DeclContext *Ctx = FDecl->getDeclContext();
+ if (NamespaceDecl *EnclosingNamespace = dyn_cast<NamespaceDecl>(Ctx))
+ AssociatedNamespaces.insert(EnclosingNamespace);
+
+ // Add the classes and namespaces associated with the parameter
+ // types and return type of this function.
+ addAssociatedClassesAndNamespaces(FDecl->getType(), Context,
+ AssociatedNamespaces, AssociatedClasses);
+ }
+ }
+}
// of type T2 or “reference to (possibly cv-qualified) T2”,
// when T2 is an enumeration type, are candidate functions.
{
+ // FIXME: Don't use the IdentifierResolver here! We need to
+ // perform proper, unqualified lookup starting with the first
+ // enclosing non-class scope.
IdentifierResolver::iterator I = IdResolver.begin(OpName),
IEnd = IdResolver.end();
for (; I != IEnd; ++I) {
/*SuppressUserConversions=*/false);
}
}
+
+ // Since the set of non-member candidates corresponds to
+ // *unqualified* lookup of the operator name, we also perform
+ // argument-dependent lookup.
+ AddArgumentDependentLookupCandidates(OpName, Args, NumArgs, CandidateSet);
}
// Add builtin overload candidates (C++ [over.built]).
}
}
+/// \brief Add function candidates found via argument-dependent lookup
+/// to the set of overloading candidates.
+///
+/// This routine performs argument-dependent name lookup based on the
+/// given function name (which may also be an operator name) and adds
+/// all of the overload candidates found by ADL to the overload
+/// candidate set (C++ [basic.lookup.argdep]).
+void
+Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet& CandidateSet) {
+ // Find all of the associated namespaces and classes based on the
+ // arguments we have.
+ AssociatedNamespaceSet AssociatedNamespaces;
+ AssociatedClassSet AssociatedClasses;
+ FindAssociatedClassesAndNamespaces(Args, NumArgs,
+ AssociatedNamespaces, AssociatedClasses);
+
+ // 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
+ // lookup (defined as follows). If X contains [...] then Y is
+ // empty. Otherwise Y is the set of declarations found in the
+ // namespaces associated with the argument types as described
+ // below. The set of declarations found by the lookup of the name
+ // is the union of X and Y.
+ //
+ // Here, we compute Y and add its members to the overloaded
+ // candidate set.
+ llvm::SmallPtrSet<FunctionDecl *, 16> KnownCandidates;
+ for (AssociatedNamespaceSet::iterator NS = AssociatedNamespaces.begin(),
+ NSEnd = AssociatedNamespaces.end();
+ NS != NSEnd; ++NS) {
+ // When considering an associated namespace, the lookup is the
+ // same as the lookup performed when the associated namespace is
+ // used as a qualifier (3.4.3.2) except that:
+ //
+ // -- Any using-directives in the associated namespace are
+ // ignored.
+ //
+ // -- FIXME: Any namespace-scope friend functions declared in
+ // associated classes are visible within their respective
+ // namespaces even if they are not visible during an ordinary
+ // lookup (11.4).
+ DeclContext::lookup_iterator I, E;
+ for (llvm::tie(I, E) = (*NS)->lookup(Name); I != E; ++I) {
+ FunctionDecl *Func = dyn_cast<FunctionDecl>(*I);
+ if (!Func)
+ break;
+
+ if (KnownCandidates.empty()) {
+ // Record all of the function candidates that we've already
+ // added to the overload set, so that we don't add those same
+ // candidates a second time.
+ for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
+ CandEnd = CandidateSet.end();
+ Cand != CandEnd; ++Cand)
+ KnownCandidates.insert(Cand->Function);
+ }
+
+ // If we haven't seen this function before, add it as a
+ // candidate.
+ if (KnownCandidates.insert(Func))
+ AddOverloadCandidate(Func, Args, NumArgs, CandidateSet);
+ }
+ }
+}
+
/// AddOverloadCandidates - Add all of the function overloads in Ovl
/// to the candidate set.
void
}
/// ResolveOverloadedCallFn - Given the call expression that calls Fn
-/// (which eventually refers to the set of overloaded functions in
-/// Ovl) and the call arguments Args/NumArgs, attempt to resolve the
-/// function call down to a specific function. If overload resolution
-/// succeeds, returns the function declaration produced by overload
+/// (which eventually refers to the declaration Func) and the call
+/// arguments Args/NumArgs, attempt to resolve the function call down
+/// to a specific function. If overload resolution succeeds, returns
+/// the function declaration produced by overload
/// resolution. Otherwise, emits diagnostics, deletes all of the
/// arguments and Fn, and returns NULL.
-FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, OverloadedFunctionDecl *Ovl,
+FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
SourceLocation LParenLoc,
Expr **Args, unsigned NumArgs,
SourceLocation *CommaLocs,
- SourceLocation RParenLoc) {
+ SourceLocation RParenLoc,
+ bool ArgumentDependentLookup) {
OverloadCandidateSet CandidateSet;
- AddOverloadCandidates(Ovl, Args, NumArgs, CandidateSet);
+ if (OverloadedFunctionDecl *Ovl
+ = dyn_cast_or_null<OverloadedFunctionDecl>(Callee))
+ AddOverloadCandidates(Ovl, Args, NumArgs, CandidateSet);
+ else if (FunctionDecl *Func = dyn_cast_or_null<FunctionDecl>(Callee))
+ AddOverloadCandidate(cast<FunctionDecl>(Func), Args, NumArgs, CandidateSet);
+
+ if (ArgumentDependentLookup)
+ AddArgumentDependentLookupCandidates(Callee->getDeclName(), Args, NumArgs,
+ CandidateSet);
+
OverloadCandidateSet::iterator Best;
switch (BestViableFunction(CandidateSet, Best)) {
case OR_Success:
case OR_No_Viable_Function:
Diag(Fn->getSourceRange().getBegin(),
diag::err_ovl_no_viable_function_in_call)
- << Ovl->getDeclName() << (unsigned)CandidateSet.size()
+ << Callee->getDeclName() << (unsigned)CandidateSet.size()
<< Fn->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
break;
case OR_Ambiguous:
Diag(Fn->getSourceRange().getBegin(), diag::err_ovl_ambiguous_call)
- << Ovl->getDeclName() << Fn->getSourceRange();
+ << Callee->getDeclName() << Fn->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
break;
}
--- /dev/null
+// RUN: clang -fsyntax-only -verify %s
+
+namespace N {
+ struct X { };
+
+ X operator+(X, X);
+
+ void f(X);
+ void g(X);
+
+ void test_multiadd(X x) {
+ (void)(x + x);
+ }
+}
+
+namespace M {
+ struct Y : N::X { };
+}
+
+void f();
+
+void test_operator_adl(N::X x, M::Y y) {
+ (void)(x + x);
+ (void)(y + y);
+}
+
+void test_func_adl(N::X x, M::Y y) {
+ f(x);
+ f(y);
+ (f)(x); // expected-error{{too many arguments to function call}}
+ ::f(x); // expected-error{{too many arguments to function call}}
+}
+
+namespace N {
+ void test_multiadd2(X x) {
+ (void)(x + x);
+ }
+}
+
+
+void test_func_adl_only(N::X x) {
+ // FIXME: here, despite the fact that the name lookup for 'g' fails,
+ // this is well-formed code. The fix will go into Sema::ActOnCallExpr.
+ // g(x);
+}
bool b3 = ctb || ecb;
}
-void accepts_bool(bool) { }
+void accepts_bool(bool) { } // expected-note{{candidate function}}
struct ExplicitConvToRef {
explicit operator int&(); // expected-warning{{explicit conversion functions are a C++0x extension}}
void test_explicit_bool(ExplicitConvToBool ecb) {
bool b1(ecb); // okay
bool b2 = ecb; // expected-error{{incompatible type initializing 'struct ExplicitConvToBool', expected '_Bool'}}
- accepts_bool(ecb); // expected-error{{incompatible type passing 'struct ExplicitConvToBool', expected '_Bool'}}
+ accepts_bool(ecb); // expected-error{{no matching function for call to}}
}
void test_explicit_conv_to_ref(ExplicitConvToRef ecr) {
X(const Y&);
};
-void f(X);
+void f(X); // expected-note{{candidate function}}
void g(short s, Y y, Z z) {
f(s);
f(1.0f);
f(y);
- f(z); // expected-error{{incompatible type passing 'class Z', expected 'class X'}}
+ f(z); // expected-error{{no matching function}}
}
}
class C { };
-void fn(int(C)) { } // void fn(int(*fp)(C c)) { }
+void fn(int(C)) { } // void fn(int(*fp)(C c)) { } expected-note{{candidate function}}
// not: void fn(int C);
int g(C);
void foo() {
- fn(1); // expected-error {{incompatible type passing 'int', expected 'int (*)(class C)'}}
+ fn(1); // expected-error {{no matching function}}
fn(g); // OK
}
*this = *Base;
}
};
+
+namespace N {
+ struct X { };
+}
+
+namespace M {
+ N::X operator+(N::X, N::X);
+}
+
+namespace M {
+ void test_X(N::X x) {
+ // FIXME: this should work! See comment in Sema::AddOperatorCandidates.
+ // (void)(x + x);
+ }
+}
// RUN: clang -fsyntax-only -pedantic -verify %s
int* quals1(int const * p);
int* quals2(int const * const * pp);
-int* quals3(int const * * const * ppp);
+int* quals3(int const * * const * ppp); // expected-note{{candidate function}}
void test_quals(int * p, int * * pp, int * * * ppp) {
int const * const * pp2 = pp;
quals1(p);
quals2(pp);
- quals3(ppp); // expected-error {{ incompatible type passing 'int ***', expected 'int const **const *' }}
+ quals3(ppp); // expected-error {{no matching}}
}
struct A {};
void mquals1(int const A::*p);
void mquals2(int const A::* const A::*pp);
-void mquals3(int const A::* A::* const A::*ppp);
+void mquals3(int const A::* A::* const A::*ppp); // expected-note{{candidate function}}
void test_mquals(int A::*p, int A::* A::*pp, int A::* A::* A::*ppp) {
int const A::* const A::* pp2 = pp;
mquals1(p);
mquals2(pp);
- mquals3(ppp); // expected-error {{ incompatible type passing 'int struct A::*struct A::*struct A::*', expected 'int const struct A::*struct A::*const struct A::*' }}
+ mquals3(ppp); // expected-error {{no matching}}
}
virtual int f();
};
-void g(int);
+void g(int); // expected-note{{candidate function}}
template<typename T>
T f(T x) {
(void)const_cast<int>(x);
return g(x);
h(x); // h is a dependent name
- g(1, 1); // expected-error{{too many arguments to function call}}
+ g(1, 1); // expected-error{{no matching function for call}}
h(1); // expected-error{{use of undeclared identifier 'h'}}
return 0;
}
return bar2(objectCreationBlock); // expected-warning{{incompatible pointer types passing 'id (*)(void)', expected 'id<NSObject> (*)(void)'}}
}
-void bar3(id(*)());
+void bar3(id(*)()); // expected-note{{candidate function}}
void foo3(id (*objectCreationBlock)(int)) {
- return bar3(objectCreationBlock); // expected-error{{incompatible type passing 'id (*)(int)', expected 'id (*)(void)'}}
+ return bar3(objectCreationBlock); // expected-error{{no matching}}
}
-void bar4(id(^)());
+void bar4(id(^)()); // expected-note{{candidate function}}
void foo4(id (^objectCreationBlock)(int)) {
- return bar4(objectCreationBlock); // expected-error{{incompatible type passing 'id (^)(int)', expected 'id (^)(void)'}}
+ return bar4(objectCreationBlock); // expected-error{{no matching}}
}
void foo5(id (^x)(int)) {