Initial implementation of member name lookup

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@62247 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 899cb4a..eb718f7 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -71,6 +71,7 @@
   class ObjCContainerDecl;
   struct BlockSemaInfo;
   class BasePaths;
+  class MemberLookupCriteria;
 
 /// PragmaPackStack - Simple class to wrap the stack used by #pragma
 /// pack.
@@ -596,6 +597,10 @@
     /// field is determined by the kind of name we're searching for.
     unsigned IDNS;
 
+    LookupCriteria() 
+      : Kind(Ordinary), AllowLazyBuiltinCreation(true), 
+        RedeclarationOnly(false), IDNS(Decl::IDNS_Ordinary) { }
+
     LookupCriteria(NameKind K, bool RedeclarationOnly, bool CPlusPlus);
     
     bool isLookupResult(Decl *D) const;
@@ -620,13 +625,19 @@
     mutable enum {
       /// First is a single declaration (a Decl*), which may be NULL.
       SingleDecl,
+
       /// [First, Last) is an iterator range represented as opaque
       /// pointers used to reconstruct IdentifierResolver::iterators.
       OverloadedDeclFromIdResolver,
+
       /// [First, Last) is an iterator range represented as opaque
       /// pointers used to reconstruct DeclContext::lookup_iterators.
       OverloadedDeclFromDeclContext,
-      /// FIXME: Cope with ambiguous name lookup.
+
+      /// First is a pointer to a BasePaths structure, which is owned
+      /// by the LookupResult. Last is non-zero to indicate that the
+      /// ambiguity is caused by two names found in base class
+      /// subobjects of different types.
       AmbiguousLookup
     } StoredKind;
 
@@ -634,15 +645,16 @@
     /// lookup result. This may be a Decl* (if StoredKind ==
     /// SingleDecl), the opaque pointer from an
     /// IdentifierResolver::iterator (if StoredKind ==
-    /// OverloadedDeclFromIdResolver), or a
-    /// DeclContext::lookup_iterator (if StoredKind ==
-    /// OverloadedDeclFromDeclContext).
+    /// OverloadedDeclFromIdResolver), a DeclContext::lookup_iterator
+    /// (if StoredKind == OverloadedDeclFromDeclContext), or a
+    /// BasePaths pointer (if StoredKind == AmbiguousLookup).
     mutable uintptr_t First;
 
     /// The last lookup result, whose contents depend on the kind of
     /// lookup result. This may be unused (if StoredKind ==
-    /// SingleDecl) or it may have the same type as First (for
-    /// overloaded function declarations).
+    /// SingleDecl), it may have the same type as First (for
+    /// overloaded function declarations), or is may be used as a
+    /// Boolean value (if StoredKind == AmbiguousLookup).
     mutable uintptr_t Last;
 
     /// Context - The context in which we will build any
@@ -655,32 +667,62 @@
     enum LookupKind {
       /// @brief No entity found met the criteria.
       NotFound = 0,
+
       /// @brief Name lookup found a single declaration that met the
-      /// criteria.
+      /// criteria. getAsDecl will return this declaration.
       Found,
+
       /// @brief Name lookup found a set of overloaded functions that
-      /// met the criteria.
+      /// met the criteria. getAsDecl will turn this set of overloaded
+      /// functions into an OverloadedFunctionDecl.
       FoundOverloaded,
-      /// @brief Name lookup resulted in an ambiguity, e.g., because
-      /// the name was found in two different base classes.
-      Ambiguous
+
+      /// Name lookup results in an ambiguity because multiple
+      /// entities that meet the lookup criteria were found in
+      /// subobjects of different types. For example:
+      /// @code
+      /// struct A { void f(int); }
+      /// struct B { void f(double); }
+      /// struct C : A, B { };
+      /// void test(C c) { 
+      ///   c.f(0); // error: A::f and B::f come from subobjects of different
+      ///           // types. overload resolution is not performed.
+      /// }
+      /// @endcode
+      AmbiguousBaseSubobjectTypes,
+
+      /// Name lookup results in an ambiguity because multiple
+      /// nonstatic entities that meet the lookup criteria were found
+      /// in different subobjects of the same type. For example:
+      /// @code
+      /// struct A { int x; };
+      /// struct B : A { };
+      /// struct C : A { };
+      /// struct D : B, C { };
+      /// int test(D d) {
+      ///   return d.x; // error: 'x' is found in two A subobjects (of B and C)
+      /// }
+      /// @endcode
+      AmbiguousBaseSubobjects
     };
 
+    LookupResult() : StoredKind(SingleDecl), First(0), Last(0), Context(0) { }
+
     LookupResult(ASTContext &Context, Decl *D) 
       : StoredKind(SingleDecl), First(reinterpret_cast<uintptr_t>(D)),
         Last(0), Context(&Context) { }
 
     LookupResult(ASTContext &Context, 
-                 IdentifierResolver::iterator F, IdentifierResolver::iterator L)
-      : StoredKind(OverloadedDeclFromIdResolver),
-        First(F.getAsOpaqueValue()), Last(L.getAsOpaqueValue()), 
-        Context(&Context) { }
+                 IdentifierResolver::iterator F, IdentifierResolver::iterator L);
 
     LookupResult(ASTContext &Context, 
-                 DeclContext::lookup_iterator F, DeclContext::lookup_iterator L)
-      : StoredKind(OverloadedDeclFromDeclContext),
-        First(reinterpret_cast<uintptr_t>(F)), 
-        Last(reinterpret_cast<uintptr_t>(L)),
+                 DeclContext::lookup_iterator F, DeclContext::lookup_iterator L);
+
+    LookupResult(ASTContext &Context, BasePaths *Paths, 
+                 bool DifferentSubobjectTypes)
+      : StoredKind(AmbiguousLookup), 
+        First(reinterpret_cast<uintptr_t>(Paths)),
+        Last(DifferentSubobjectTypes? 1 : 0),
         Context(&Context) { }
 
     LookupKind getKind() const;
@@ -688,11 +730,16 @@
     /// @brief Determine whether name look found something.
     operator bool() const { return getKind() != NotFound; }
 
+    /// @brief Determines whether the lookup resulted in an ambiguity.
+    bool isAmbiguous() const { return StoredKind == AmbiguousLookup; }
+
     /// @brief Allows conversion of a lookup result into a
     /// declaration, with the same behavior as getAsDecl.
     operator Decl*() const { return getAsDecl(); }
 
     Decl* getAsDecl() const;
+
+    BasePaths *getBasePaths() const;
   };
 
   LookupResult LookupName(Scope *S, DeclarationName Name, 
@@ -701,12 +748,15 @@
                                    LookupCriteria Criteria);
   LookupResult LookupParsedName(Scope *S, const CXXScopeSpec &SS, 
                                 DeclarationName Name, LookupCriteria Criteria);
-  
   LookupResult LookupDecl(DeclarationName Name, unsigned NSI, Scope *S,
                           const DeclContext *LookupCtx = 0,
                           bool enableLazyBuiltinCreation = true,
                           bool LookInParent = true,
                           bool NamespaceNameOnly = false);
+
+  bool DiagnoseAmbiguousLookup(LookupResult &Result, DeclarationName Name,
+                               SourceLocation NameLoc, 
+                               SourceRange LookupRange = SourceRange());
   //@}
   
   ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *Id);
@@ -1270,7 +1320,8 @@
 
   bool IsDerivedFrom(QualType Derived, QualType Base);
   bool IsDerivedFrom(QualType Derived, QualType Base, BasePaths &Paths);
-
+  bool LookupInBases(CXXRecordDecl *Class, const MemberLookupCriteria& Criteria,
+                     BasePaths &Paths);
   bool CheckDerivedToBaseConversion(QualType Derived, QualType Base,
                                     SourceLocation Loc, SourceRange Range);