[cfe-commits] r63692 - in /cfe/trunk: lib/Sema/Sema.h lib/Sema/SemaExpr.cpp lib/Sema/SemaLookup.cpp lib/Sema/SemaOverload.cpp test/SemaCXX/basic_lookup_argdep.cpp 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

Douglas Gregor dgregor at apple.com
Tue Feb 3 16:32:52 PST 2009


Author: dgregor
Date: Tue Feb  3 18:32:51 2009
New Revision: 63692

URL: http://llvm.org/viewvc/llvm-project?rev=63692&view=rev
Log:
Initial implementation of argument dependent lookup (a.k.a. ADL,
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.


Added:
    cfe/trunk/test/SemaCXX/basic_lookup_argdep.cpp
Modified:
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaLookup.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/test/SemaCXX/convert-to-bool.cpp
    cfe/trunk/test/SemaCXX/converting-constructor.cpp
    cfe/trunk/test/SemaCXX/decl-expr-ambiguity.cpp
    cfe/trunk/test/SemaCXX/overloaded-operator.cpp
    cfe/trunk/test/SemaCXX/qualification-conversion.cpp
    cfe/trunk/test/SemaCXX/type-dependent-exprs.cpp
    cfe/trunk/test/SemaObjCXX/blocks.mm

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=63692&r1=63691&r2=63692&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Feb  3 18:32:51 2009
@@ -499,6 +499,9 @@
   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 @@
                                                    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 @@
                                 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());

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=63692&r1=63691&r2=63692&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Feb  3 18:32:51 2009
@@ -1839,7 +1839,6 @@
   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 @@
       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 @@
     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 @@
                                                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.

Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=63692&r1=63691&r2=63692&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Tue Feb  3 18:32:51 2009
@@ -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 <set>
 #include <vector>
 #include <iterator>
@@ -1143,3 +1145,262 @@
   // 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);
+    }
+  }
+}

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=63692&r1=63691&r2=63692&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Tue Feb  3 18:32:51 2009
@@ -2301,6 +2301,9 @@
   //        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 @@
                                  /*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 @@
   }
 }
 
+/// \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 @@
 }
 
 /// 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 @@
   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;
   }

Added: cfe/trunk/test/SemaCXX/basic_lookup_argdep.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/basic_lookup_argdep.cpp?rev=63692&view=auto

==============================================================================
--- cfe/trunk/test/SemaCXX/basic_lookup_argdep.cpp (added)
+++ cfe/trunk/test/SemaCXX/basic_lookup_argdep.cpp Tue Feb  3 18:32:51 2009
@@ -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);
+}

Modified: cfe/trunk/test/SemaCXX/convert-to-bool.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/convert-to-bool.cpp?rev=63692&r1=63691&r2=63692&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/convert-to-bool.cpp (original)
+++ cfe/trunk/test/SemaCXX/convert-to-bool.cpp Tue Feb  3 18:32:51 2009
@@ -36,7 +36,7 @@
   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 @@
 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) {

Modified: cfe/trunk/test/SemaCXX/converting-constructor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/converting-constructor.cpp?rev=63692&r1=63691&r2=63692&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/converting-constructor.cpp (original)
+++ cfe/trunk/test/SemaCXX/converting-constructor.cpp Tue Feb  3 18:32:51 2009
@@ -12,13 +12,13 @@
   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}}
 }
 
 

Modified: cfe/trunk/test/SemaCXX/decl-expr-ambiguity.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/decl-expr-ambiguity.cpp?rev=63692&r1=63691&r2=63692&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/decl-expr-ambiguity.cpp (original)
+++ cfe/trunk/test/SemaCXX/decl-expr-ambiguity.cpp Tue Feb  3 18:32:51 2009
@@ -33,11 +33,11 @@
 }
 
 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
 }

Modified: cfe/trunk/test/SemaCXX/overloaded-operator.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/overloaded-operator.cpp?rev=63692&r1=63691&r2=63692&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/overloaded-operator.cpp (original)
+++ cfe/trunk/test/SemaCXX/overloaded-operator.cpp Tue Feb  3 18:32:51 2009
@@ -195,3 +195,18 @@
     *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);
+  }
+}

Modified: cfe/trunk/test/SemaCXX/qualification-conversion.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/qualification-conversion.cpp?rev=63692&r1=63691&r2=63692&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/qualification-conversion.cpp (original)
+++ cfe/trunk/test/SemaCXX/qualification-conversion.cpp Tue Feb  3 18:32:51 2009
@@ -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}}
 }

Modified: cfe/trunk/test/SemaCXX/type-dependent-exprs.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/type-dependent-exprs.cpp?rev=63692&r1=63691&r2=63692&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/type-dependent-exprs.cpp (original)
+++ cfe/trunk/test/SemaCXX/type-dependent-exprs.cpp Tue Feb  3 18:32:51 2009
@@ -4,7 +4,7 @@
   virtual int f();
 };
 
-void g(int);
+void g(int); // expected-note{{candidate function}}
 
 template<typename T>
 T f(T x) {
@@ -18,7 +18,7 @@
   (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;
 }

Modified: cfe/trunk/test/SemaObjCXX/blocks.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/blocks.mm?rev=63692&r1=63691&r2=63692&view=diff

==============================================================================
--- cfe/trunk/test/SemaObjCXX/blocks.mm (original)
+++ cfe/trunk/test/SemaObjCXX/blocks.mm Tue Feb  3 18:32:51 2009
@@ -11,14 +11,14 @@
     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)) {





More information about the cfe-commits mailing list