diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 6360dcc44f15..3143b5c48298 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -499,6 +499,9 @@ public: 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, @@ -514,11 +517,12 @@ public: 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, @@ -856,6 +860,14 @@ public: DeclarationName Name, LookupNameKind NameKind, bool RedeclarationOnly = false); + + typedef llvm::SmallPtrSet AssociatedNamespaceSet; + typedef llvm::SmallPtrSet AssociatedClassSet; + + void FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs, + AssociatedNamespaceSet &AssociatedNamespaces, + AssociatedClassSet &AssociatedClasses); + bool DiagnoseAmbiguousLookup(LookupResult &Result, DeclarationName Name, SourceLocation NameLoc, SourceRange LookupRange = SourceRange()); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 36107e88ddd0..24f7965b63cc 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -1839,7 +1839,6 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, Expr **Args = reinterpret_cast(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. @@ -1851,6 +1850,7 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, 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(), @@ -1880,8 +1880,8 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, 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(Fn->IgnoreParens())) if (isa(MemExpr->getMemberDecl()) || isa(MemExpr->getMemberDecl())) @@ -1889,36 +1889,66 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, 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(Fn)) - DRExpr = dyn_cast(IcExpr->getSubExpr()); - else - DRExpr = dyn_cast(Fn); - - if (DRExpr) { - FDecl = dyn_cast(DRExpr->getDecl()); - Ovl = dyn_cast(DRExpr->getDecl()); + Expr *FnExpr = Fn; + bool ADL = true; + while (true) { + if (ImplicitCastExpr *IcExpr = dyn_cast(FnExpr)) + FnExpr = IcExpr->getSubExpr(); + else if (ParenExpr *PExpr = dyn_cast(FnExpr)) { + // FIXME: Where does the C++ standard say this? + ADL = false; + FnExpr = PExpr->getSubExpr(); + } else if (isa(FnExpr) && + cast(FnExpr)->getOpcode() + == UnaryOperator::AddrOf) { + FnExpr = cast(FnExpr)->getSubExpr(); + } else { + DRExpr = dyn_cast(FnExpr); + break; + } } + + if (DRExpr) + FDecl = dyn_cast(DRExpr->getDecl()); - if (Ovl) { - FDecl = ResolveOverloadedCallFn(Fn, Ovl, LParenLoc, Args, NumArgs, - CommaLocs, RParenLoc); - if (!FDecl) - return ExprError(); + if (getLangOptions().CPlusPlus && DRExpr && + (FDecl || isa(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(DRExpr)) + ADL = false; - // Update Fn to refer to the actual function selected. - Expr *NewFn = 0; - if (QualifiedDeclRefExpr *QDRExpr = dyn_cast(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; + // We don't perform ADL for builtins. + if (FDecl && FDecl->getIdentifier() && + FDecl->getIdentifier()->getBuiltinID()) + ADL = false; + + if ((DRExpr && isa(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(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. diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index c8ecc171fd58..09431492b9c6 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -17,9 +17,11 @@ #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 #include #include @@ -1143,3 +1145,262 @@ bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result, DeclarationName Name, // 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(Ctx)) + AssociatedClasses.insert(EnclosingClass); + + // Add the associated namespace for this class. + while (Ctx->isRecord()) + Ctx = Ctx->getParent(); + if (NamespaceDecl *EnclosingNamespace = dyn_cast(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 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(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(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(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(Ctx)) + AssociatedClasses.insert(EnclosingClass); + + // Add the associated namespace for this class. + while (Ctx->isRecord()) + Ctx = Ctx->getParent(); + if (NamespaceDecl *EnclosingNamespace = dyn_cast(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(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(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(Arg)) { + if (unaryOp->getOpcode() == UnaryOperator::AddrOf) + DRE = dyn_cast(unaryOp->getSubExpr()); + } else + DRE = dyn_cast(Arg); + if (!DRE) + continue; + + OverloadedFunctionDecl *Ovl + = dyn_cast(DRE->getDecl()); + if (!Ovl) + continue; + + for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(), + FuncEnd = Ovl->function_end(); + Func != FuncEnd; ++Func) { + FunctionDecl *FDecl = cast(*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(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); + } + } +} diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 7219f19a97cc..293e9c3c24b1 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -2301,6 +2301,9 @@ void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S, // 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) { @@ -2327,6 +2330,11 @@ void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S, /*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]). @@ -3153,6 +3161,75 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, } } +/// \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 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(*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 @@ -3419,19 +3496,29 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, } /// 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(Callee)) + AddOverloadCandidates(Ovl, Args, NumArgs, CandidateSet); + else if (FunctionDecl *Func = dyn_cast_or_null(Callee)) + AddOverloadCandidate(cast(Func), Args, NumArgs, CandidateSet); + + if (ArgumentDependentLookup) + AddArgumentDependentLookupCandidates(Callee->getDeclName(), Args, NumArgs, + CandidateSet); + OverloadCandidateSet::iterator Best; switch (BestViableFunction(CandidateSet, Best)) { case OR_Success: @@ -3440,14 +3527,14 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, OverloadedFunctionDecl *Ov 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; } diff --git a/clang/test/SemaCXX/basic_lookup_argdep.cpp b/clang/test/SemaCXX/basic_lookup_argdep.cpp new file mode 100644 index 000000000000..67f2b6503391 --- /dev/null +++ b/clang/test/SemaCXX/basic_lookup_argdep.cpp @@ -0,0 +1,45 @@ +// 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); +} diff --git a/clang/test/SemaCXX/convert-to-bool.cpp b/clang/test/SemaCXX/convert-to-bool.cpp index 1b57214d0866..100267c17f7f 100644 --- a/clang/test/SemaCXX/convert-to-bool.cpp +++ b/clang/test/SemaCXX/convert-to-bool.cpp @@ -36,7 +36,7 @@ void test_conv_to_bool(ConvToBool ctb, ConvToInt cti, ExplicitConvToBool ecb) { 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}} @@ -45,7 +45,7 @@ struct ExplicitConvToRef { 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) { diff --git a/clang/test/SemaCXX/converting-constructor.cpp b/clang/test/SemaCXX/converting-constructor.cpp index 0ab8d9313779..edded1758228 100644 --- a/clang/test/SemaCXX/converting-constructor.cpp +++ b/clang/test/SemaCXX/converting-constructor.cpp @@ -12,13 +12,13 @@ public: 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}} } diff --git a/clang/test/SemaCXX/decl-expr-ambiguity.cpp b/clang/test/SemaCXX/decl-expr-ambiguity.cpp index db845393cd01..0cc9d7e05581 100644 --- a/clang/test/SemaCXX/decl-expr-ambiguity.cpp +++ b/clang/test/SemaCXX/decl-expr-ambiguity.cpp @@ -33,11 +33,11 @@ void f() { } 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 } diff --git a/clang/test/SemaCXX/overloaded-operator.cpp b/clang/test/SemaCXX/overloaded-operator.cpp index e558faa8803e..6c7a8d762172 100644 --- a/clang/test/SemaCXX/overloaded-operator.cpp +++ b/clang/test/SemaCXX/overloaded-operator.cpp @@ -195,3 +195,18 @@ struct CopyCon : public CopyConBase { *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); + } +} diff --git a/clang/test/SemaCXX/qualification-conversion.cpp b/clang/test/SemaCXX/qualification-conversion.cpp index 1b818c33927c..689a7b37a563 100644 --- a/clang/test/SemaCXX/qualification-conversion.cpp +++ b/clang/test/SemaCXX/qualification-conversion.cpp @@ -1,23 +1,23 @@ // 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}} } diff --git a/clang/test/SemaCXX/type-dependent-exprs.cpp b/clang/test/SemaCXX/type-dependent-exprs.cpp index 15808c676964..b3bfa8b6018c 100644 --- a/clang/test/SemaCXX/type-dependent-exprs.cpp +++ b/clang/test/SemaCXX/type-dependent-exprs.cpp @@ -4,7 +4,7 @@ public: virtual int f(); }; -void g(int); +void g(int); // expected-note{{candidate function}} template T f(T x) { @@ -18,7 +18,7 @@ T f(T x) { (void)const_cast(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; } diff --git a/clang/test/SemaObjCXX/blocks.mm b/clang/test/SemaObjCXX/blocks.mm index 8aee15266e32..a79200692280 100644 --- a/clang/test/SemaObjCXX/blocks.mm +++ b/clang/test/SemaObjCXX/blocks.mm @@ -11,14 +11,14 @@ void foo2(id (*objectCreationBlock)(void)) { return bar2(objectCreationBlock); // expected-warning{{incompatible pointer types passing 'id (*)(void)', expected 'id (*)(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)) {