]> granicus.if.org Git - clang/commitdiff
Initial implementation of argument dependent lookup (a.k.a. ADL,
authorDouglas Gregor <dgregor@apple.com>
Wed, 4 Feb 2009 00:32:51 +0000 (00:32 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 4 Feb 2009 00:32:51 +0000 (00:32 +0000)
a.k.a. Koenig lookup) in C++. Most of the pieces are in place, but for
two:

  - In an unqualified call g(x), even if the name does not refer to
    anything in the current scope, we can still find functions named
    "g" based on ADL. We don't yet have this ability.
  - ADL will need updating for friend functions and templates.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@63692 91177308-0d34-0410-b5e6-96231b3b80d8

12 files changed:
lib/Sema/Sema.h
lib/Sema/SemaExpr.cpp
lib/Sema/SemaLookup.cpp
lib/Sema/SemaOverload.cpp
test/SemaCXX/basic_lookup_argdep.cpp [new file with mode: 0644]
test/SemaCXX/convert-to-bool.cpp
test/SemaCXX/converting-constructor.cpp
test/SemaCXX/decl-expr-ambiguity.cpp
test/SemaCXX/overloaded-operator.cpp
test/SemaCXX/qualification-conversion.cpp
test/SemaCXX/type-dependent-exprs.cpp
test/SemaObjCXX/blocks.mm

index 6360dcc44f15631b9fbd2513a71f75e923fda4e2..3143b5c48298dad2fb8c3cf1762049acf5a9b90f 100644 (file)
@@ -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<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());
index 36107e88ddd0cf4fd01a6071fb5d4b228325757f..24f7965b63ccf8f872c1df6a489deeabef90f3b2 100644 (file)
@@ -1839,7 +1839,6 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
   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. 
@@ -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<MemberExpr>(Fn->IgnoreParens()))
       if (isa<OverloadedFunctionDecl>(MemExpr->getMemberDecl()) ||
           isa<CXXMethodDecl>(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<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.
index c8ecc171fd587c779dd427b2e6f039f4b46945bc..09431492b9c60ba7168e6ec3278c7d616bd23003 100644 (file)
 #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>
@@ -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<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);
+    }
+  }
+}
index 7219f19a97cc6a9b13e0582f31f94ec6a66af915..293e9c3c24b15bad18e168f709ce1a4675eebb0b 100644 (file)
@@ -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<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 
@@ -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<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:
@@ -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/test/SemaCXX/basic_lookup_argdep.cpp b/test/SemaCXX/basic_lookup_argdep.cpp
new file mode 100644 (file)
index 0000000..67f2b65
--- /dev/null
@@ -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);
+}
index 1b57214d0866b2be981f32473787dd8277b5bd20..100267c17f7fcc9267c67ea56fe36f0cafe7fe4b 100644 (file)
@@ -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) {
index 0ab8d93137795f04f03378ba0ae6d4002e1b80c0..edded175822847fa95ee389abba05fcf72935a66 100644 (file)
@@ -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}}
 }
 
 
index db845393cd01196c73c22649cb689662b0bb0a63..0cc9d7e055811413fb1e50510ec4ac13e9792d22 100644 (file)
@@ -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
 }
index e558faa8803e75bbb69045941299cae52bbbb0a7..6c7a8d762172bc108d2ec1eb99dbb7c6fb09f206 100644 (file)
@@ -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);
+  }
+}
index 1b818c33927c929bc99a2e5bdacfdce114ea63c2..689a7b37a563c56854123dc39f72183274bf549b 100644 (file)
@@ -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}}
 }
index 15808c676964ee0fa0938ee9322af63eee894a92..b3bfa8b6018c4411c75fd6046c3a5e10d6b0b00f 100644 (file)
@@ -4,7 +4,7 @@ public:
   virtual int f();
 };
 
-void g(int);
+void g(int); // expected-note{{candidate function}}
 
 template<typename T>
 T f(T x) {
@@ -18,7 +18,7 @@ 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;
 }
index 8aee15266e32b200ee4cafc920374a8d45e19be3..a792006922803d4a0ef9997444b528564513606b 100644 (file)
@@ -11,14 +11,14 @@ void foo2(id <NSObject>(*objectCreationBlock)(void)) {
     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)) {