[cfe-commits] r62247 - in /cfe/trunk: include/clang/Basic/DiagnosticKinds.def lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaInherit.cpp lib/Sema/SemaInherit.h lib/Sema/SemaLookup.cpp

Douglas Gregor dgregor at apple.com
Wed Jan 14 16:26:25 PST 2009


Author: dgregor
Date: Wed Jan 14 18:26:24 2009
New Revision: 62247

URL: http://llvm.org/viewvc/llvm-project?rev=62247&view=rev
Log:
Initial implementation of member name lookup

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticKinds.def
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaInherit.cpp
    cfe/trunk/lib/Sema/SemaInherit.h
    cfe/trunk/lib/Sema/SemaLookup.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=62247&r1=62246&r2=62247&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Wed Jan 14 18:26:24 2009
@@ -1519,7 +1519,7 @@
 DIAG(err_anonymous_record_nonpublic_member, ERROR,
      "anonymous %select{struct|union}0 cannot contain a %select{private|protected}1 data member")
 
-// Derived classes.
+// C++ derived classes
 DIAG(err_dup_virtual, ERROR,
      "duplicate 'virtual' in base specifier")
 DIAG(err_base_clause_on_union, ERROR,
@@ -1536,6 +1536,12 @@
 DIAG(err_ambiguous_derived_to_base_conv, ERROR,
      "ambiguous conversion from derived class %0 to base class %1:%2")
 
+// C++ member name lookup
+DIAG(err_ambiguous_member_multiple_subobjects, ERROR,
+     "non-static member %0 found in multiple base-class subobjects of type %1")
+DIAG(err_ambiguous_member_multiple_subobject_types, ERROR,
+     "member %0 found in multiple base classes of different types")
+
 // C++ operator overloading
 DIAG(err_operator_overload_needs_class_or_enum, ERROR,
      "overloaded %0 must have at least one parameter of class "

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Jan 14 18:26:24 2009
@@ -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);
 

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Jan 14 18:26:24 2009
@@ -39,12 +39,28 @@
       return 0;
     DC = static_cast<DeclContext*>(SS->getScopeRep());
   }
-  Decl *IIDecl = LookupDecl(&II, Decl::IDNS_Ordinary, S, DC, false);
+  LookupResult Result = LookupDecl(&II, Decl::IDNS_Ordinary, S, DC, false);
 
-  if (IIDecl && (isa<TypedefDecl>(IIDecl) || 
-                 isa<ObjCInterfaceDecl>(IIDecl) ||
-                 isa<TagDecl>(IIDecl) ||
-		 isa<TemplateTypeParmDecl>(IIDecl)))
+  Decl *IIDecl = 0;
+  switch (Result.getKind()) {
+  case LookupResult::NotFound:
+  case LookupResult::FoundOverloaded:
+  case LookupResult::AmbiguousBaseSubobjectTypes:
+  case LookupResult::AmbiguousBaseSubobjects:
+    // FIXME: In the event of an ambiguous lookup, we could visit all of
+    // the entities found to determine whether they are all types. This
+    // might provide better diagnostics.
+    return 0;
+
+  case LookupResult::Found:
+    IIDecl = Result.getAsDecl();
+    break;
+  }
+
+  if (isa<TypedefDecl>(IIDecl) || 
+      isa<ObjCInterfaceDecl>(IIDecl) ||
+      isa<TagDecl>(IIDecl) ||
+      isa<TemplateTypeParmDecl>(IIDecl))
     return IIDecl;
   return 0;
 }

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Jan 14 18:26:24 2009
@@ -546,14 +546,22 @@
   }
 
   // Could be enum-constant, value decl, instance variable, etc.
-  Decl *D;
+  Decl *D = 0;
+  LookupResult Lookup;
   if (SS && !SS->isEmpty()) {
     DeclContext *DC = static_cast<DeclContext*>(SS->getScopeRep());
     if (DC == 0)
       return true;
-    D = LookupDecl(Name, Decl::IDNS_Ordinary, S, DC);
+    Lookup = LookupDecl(Name, Decl::IDNS_Ordinary, S, DC);
   } else
-    D = LookupDecl(Name, Decl::IDNS_Ordinary, S);
+    Lookup = LookupDecl(Name, Decl::IDNS_Ordinary, S);
+
+  if (Lookup.isAmbiguous())
+    return DiagnoseAmbiguousLookup(Lookup, Name, Loc, 
+                                   SS && SS->isSet()? SS->getRange() 
+                                                    : SourceRange());
+  else
+    D = Lookup.getAsDecl();
 
   // If this reference is in an Objective-C method, then ivar lookup happens as
   // well.
@@ -1444,11 +1452,21 @@
     // The record definition is complete, now make sure the member is valid.
     // FIXME: Qualified name lookup for C++ is a bit more complicated
     // than this.
-    Decl *MemberDecl = LookupDecl(DeclarationName(&Member), Decl::IDNS_Ordinary,
-                                  S, RDecl, false, false);
-    if (!MemberDecl)
+    LookupResult Result 
+      = LookupQualifiedName(RDecl, DeclarationName(&Member), 
+                            LookupCriteria(LookupCriteria::Member,
+                                           /*RedeclarationOnly=*/false, 
+                                           getLangOptions().CPlusPlus));
+
+    Decl *MemberDecl = 0;
+    if (!Result)
       return Diag(MemberLoc, diag::err_typecheck_no_member)
                << &Member << BaseExpr->getSourceRange();
+    else if (Result.isAmbiguous())
+      return DiagnoseAmbiguousLookup(Result, DeclarationName(&Member),
+                                     MemberLoc, BaseExpr->getSourceRange());
+    else 
+      MemberDecl = Result;
 
     if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl)) {
       // We may have found a field within an anonymous union or struct

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaInherit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInherit.cpp Wed Jan 14 18:26:24 2009
@@ -20,6 +20,7 @@
 #include "clang/AST/Type.h"
 #include "clang/AST/TypeOrdering.h"
 #include "clang/Basic/Diagnostic.h"
+#include <algorithm>
 #include <memory>
 #include <set>
 #include <string>
@@ -45,6 +46,17 @@
   DetectedVirtual = 0;
 }
 
+/// @brief Swaps the contents of this BasePaths structure with the
+/// contents of Other.
+void BasePaths::swap(BasePaths &Other) {
+  Paths.swap(Other.Paths);
+  ClassSubobjects.swap(Other.ClassSubobjects);
+  std::swap(FindAmbiguities, Other.FindAmbiguities);
+  std::swap(RecordPaths, Other.RecordPaths);
+  std::swap(DetectVirtual, Other.DetectVirtual);
+  std::swap(DetectedVirtual, Other.DetectedVirtual);
+}
+
 /// IsDerivedFrom - Determine whether the type Derived is derived from
 /// the type Base, ignoring qualifiers on Base and Derived. This
 /// routine does not assess whether an actual conversion from a
@@ -65,8 +77,6 @@
 /// ambiguous paths (if @c Paths.isFindingAmbiguities()) and record
 /// information about all of the paths (if @c Paths.isRecordingPaths()).
 bool Sema::IsDerivedFrom(QualType Derived, QualType Base, BasePaths &Paths) {
-  bool FoundPath = false;
-
   Derived = Context.getCanonicalType(Derived).getUnqualifiedType();
   Base = Context.getCanonicalType(Base).getUnqualifiedType();
 
@@ -76,71 +86,112 @@
   if (Derived == Base)
     return false;
 
-  if (const RecordType *DerivedType = Derived->getAsRecordType()) {
-    const CXXRecordDecl *Decl 
-      = static_cast<const CXXRecordDecl *>(DerivedType->getDecl());
-    for (CXXRecordDecl::base_class_const_iterator BaseSpec = Decl->bases_begin();
-         BaseSpec != Decl->bases_end(); ++BaseSpec) {
-      // Find the record of the base class subobjects for this type.
-      QualType BaseType = Context.getCanonicalType(BaseSpec->getType());
-      BaseType = BaseType.getUnqualifiedType();
-      
-      // Determine whether we need to visit this base class at all,
-      // updating the count of subobjects appropriately.
-      std::pair<bool, unsigned>& Subobjects = Paths.ClassSubobjects[BaseType];
-      bool VisitBase = true;
-      bool SetVirtual = false;
-      if (BaseSpec->isVirtual()) {
-        VisitBase = !Subobjects.first;
-        Subobjects.first = true;
-        if (Paths.isDetectingVirtual() && Paths.DetectedVirtual == 0) {
-          // If this is the first virtual we find, remember it. If it turns out
-          // there is no base path here, we'll reset it later.
-          Paths.DetectedVirtual = static_cast<const CXXRecordType*>(
-            BaseType->getAsRecordType());
-          SetVirtual = true;
-        }
-      } else
-        ++Subobjects.second;
+  return LookupInBases(cast<CXXRecordType>(Derived->getAsRecordType())->getDecl(),
+                       MemberLookupCriteria(Base), Paths);
+}
 
-      if (Paths.isRecordingPaths()) {
-        // Add this base specifier to the current path.
-        BasePathElement Element;
-        Element.Base = &*BaseSpec;
-        if (BaseSpec->isVirtual())
-          Element.SubobjectNumber = 0;
-        else
-          Element.SubobjectNumber = Subobjects.second;
-        Paths.ScratchPath.push_back(Element);
+/// LookupInBases - Look for something that meets the specified
+/// Criteria within the base classes of Class (or any of its base
+/// classes, transitively). This routine populates BasePaths with the
+/// list of paths that one can take to find the entity that meets the
+/// search criteria, and returns true if any such entity is found. The
+/// various options passed to the BasePath constructor will affect the
+/// behavior of this lookup, e.g., whether it finds ambiguities,
+/// records paths, or attempts to detect the use of virtual base
+/// classes.
+bool Sema::LookupInBases(CXXRecordDecl *Class, 
+                         const MemberLookupCriteria& Criteria,
+                         BasePaths &Paths) {
+  bool FoundPath = false;
+
+  for (CXXRecordDecl::base_class_const_iterator BaseSpec = Class->bases_begin(),
+                                             BaseSpecEnd = Class->bases_end(); 
+       BaseSpec != BaseSpecEnd; ++BaseSpec) {
+    // Find the record of the base class subobjects for this type.
+    QualType BaseType = Context.getCanonicalType(BaseSpec->getType());
+    BaseType = BaseType.getUnqualifiedType();
+    
+    // Determine whether we need to visit this base class at all,
+    // updating the count of subobjects appropriately.
+    std::pair<bool, unsigned>& Subobjects = Paths.ClassSubobjects[BaseType];
+    bool VisitBase = true;
+    bool SetVirtual = false;
+    if (BaseSpec->isVirtual()) {
+      VisitBase = !Subobjects.first;
+      Subobjects.first = true;
+      if (Paths.isDetectingVirtual() && Paths.DetectedVirtual == 0) {
+        // If this is the first virtual we find, remember it. If it turns out
+        // there is no base path here, we'll reset it later.
+        Paths.DetectedVirtual = cast<CXXRecordType>(BaseType->getAsRecordType());
+        SetVirtual = true;
       }
+    } else
+      ++Subobjects.second;
 
-      if (Context.getCanonicalType(BaseSpec->getType()) == Base) {
-        // We've found the base we're looking for.
-        FoundPath = true;
-        if (Paths.isRecordingPaths()) {
-          // We have a path. Make a copy of it before moving on.
-          Paths.Paths.push_back(Paths.ScratchPath);
-        } else if (!Paths.isFindingAmbiguities()) {
-          // We found a path and we don't care about ambiguities;
-          // return immediately.
-          return FoundPath;
+    if (Paths.isRecordingPaths()) {
+      // Add this base specifier to the current path.
+      BasePathElement Element;
+      Element.Base = &*BaseSpec;
+      if (BaseSpec->isVirtual())
+        Element.SubobjectNumber = 0;
+      else
+        Element.SubobjectNumber = Subobjects.second;
+      Paths.ScratchPath.push_back(Element);
+    }
+
+    CXXRecordDecl *BaseRecord 
+      = cast<CXXRecordDecl>(BaseSpec->getType()->getAsRecordType()->getDecl());
+
+    // Either look at the base class type or look into the base class
+    // type to see if we've found a member that meets the search
+    // criteria.
+    bool FoundPathToThisBase = false;
+    if (Criteria.LookupBase) {
+      FoundPathToThisBase 
+        = (Context.getCanonicalType(BaseSpec->getType()) == Criteria.Base);
+    } else {
+      Paths.ScratchPath.Decls = BaseRecord->lookup(Criteria.Name);
+      while (Paths.ScratchPath.Decls.first != Paths.ScratchPath.Decls.second) {
+        if (Criteria.Criteria.isLookupResult(*Paths.ScratchPath.Decls.first)) {
+          FoundPathToThisBase = true;
+          break;
         }
-      } else if (VisitBase && IsDerivedFrom(BaseSpec->getType(), Base, Paths)) {
-        // There is a path to the base we want. If we're not
-        // collecting paths or finding ambiguities, we're done.
-        FoundPath = true;
-        if (!Paths.isFindingAmbiguities())
-          return FoundPath;
+        ++Paths.ScratchPath.Decls.first;
       }
+    }
 
-      // Pop this base specifier off the current path (if we're
-      // collecting paths).
-      if (Paths.isRecordingPaths())
-        Paths.ScratchPath.pop_back();
-      // If we set a virtual earlier, and this isn't a path, forget it again.
-      if (SetVirtual && !FoundPath) {
-        Paths.DetectedVirtual = 0;
+    if (FoundPathToThisBase) {
+      // We've found a path that terminates that this base.
+      FoundPath = true;
+      if (Paths.isRecordingPaths()) {
+        // We have a path. Make a copy of it before moving on.
+        Paths.Paths.push_back(Paths.ScratchPath);
+      } else if (!Paths.isFindingAmbiguities()) {
+        // We found a path and we don't care about ambiguities;
+        // return immediately.
+        return FoundPath;
       }
+    } 
+    // C++ [class.member.lookup]p2:
+    //   A member name f in one sub-object B hides a member name f in
+    //   a sub-object A if A is a base class sub-object of B. Any
+    //   declarations that are so hidden are eliminated from
+    //   consideration.
+    else if (VisitBase && LookupInBases(BaseRecord, Criteria, Paths)) {
+      // There is a path to a base class that meets the criteria. If we're not
+      // collecting paths or finding ambiguities, we're done.
+      FoundPath = true;
+      if (!Paths.isFindingAmbiguities())
+        return FoundPath;
+    }
+
+    // Pop this base specifier off the current path (if we're
+    // collecting paths).
+    if (Paths.isRecordingPaths())
+      Paths.ScratchPath.pop_back();
+    // If we set a virtual earlier, and this isn't a path, forget it again.
+    if (SetVirtual && !FoundPath) {
+      Paths.DetectedVirtual = 0;
     }
   }
 
@@ -208,4 +259,3 @@
     << Derived << Base << PathDisplayStr << Range;
   return true;
 }
-

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaInherit.h (original)
+++ cfe/trunk/lib/Sema/SemaInherit.h Wed Jan 14 18:26:24 2009
@@ -16,6 +16,8 @@
 #ifndef LLVM_CLANG_SEMA_INHERIT_H
 #define LLVM_CLANG_SEMA_INHERIT_H
 
+#include "clang/AST/DeclarationName.h"
+#include "clang/AST/DeclBase.h"
 #include "clang/AST/Type.h"
 #include "clang/AST/TypeOrdering.h"
 #include "llvm/ADT/SmallVector.h"
@@ -48,12 +50,17 @@
 
   /// BasePath - Represents a path from a specific derived class
   /// (which is not represented as part of the path) to a particular
-  /// (direct or indirect) base class subobject. Individual elements
+  /// (direct or indirect) base class subobject that contains some
+  /// number of declarations with the same name. Individual elements
   /// in the path are described by the BasePathElement structure,
   /// which captures both the link from a derived class to one of its
   /// direct bases and identification describing which base class
-  /// subobject is being used. 
-  typedef llvm::SmallVector<BasePathElement, 4> BasePath;
+  /// subobject is being used.
+  struct BasePath : public llvm::SmallVector<BasePathElement, 4> {
+    /// Decls - The set of declarations found inside this base class
+    /// subobject.
+    DeclContext::lookup_result Decls;
+  };
 
   /// BasePaths - Represents the set of paths from a derived class to
   /// one of its (direct or indirect) bases. For example, given the
@@ -137,6 +144,9 @@
     paths_iterator begin() const { return Paths.begin(); }
     paths_iterator end()   const { return Paths.end(); }
 
+    BasePath&       front()       { return Paths.front(); }
+    const BasePath& front() const { return Paths.front(); }
+
     bool isAmbiguous(QualType BaseType);
 
     /// isFindingAmbiguities - Whether we are finding multiple paths
@@ -159,6 +169,41 @@
     }
 
     void clear();
+
+    void swap(BasePaths &Other);
+  };
+
+  /// MemberLookupCriteria - Criteria for performing lookup of a
+  /// member of a C++ class. Objects of this type are used to direct
+  /// Sema::LookupCXXClassMember.
+  struct MemberLookupCriteria {
+    /// MemberLookupCriteria - Constructs member lookup criteria to
+    /// search for a base class of type Base.
+    explicit MemberLookupCriteria(QualType Base) 
+      : LookupBase(true), Base(Base) { }
+
+    /// MemberLookupCriteria - Constructs member lookup criteria to
+    /// search for a class member with the given Name.
+    explicit MemberLookupCriteria(DeclarationName Name, 
+                                  Sema::LookupCriteria Criteria) 
+      : LookupBase(false), Name(Name), Criteria(Criteria) { }
+
+    /// LookupBase - True if we are looking for a base class (whose
+    /// type is Base). If false, we are looking for a named member of
+    /// the class (with the name Name).
+    bool LookupBase;
+
+    /// Base - The type of the base class we're searching for, if
+    /// LookupBase is true.
+    QualType Base;
+
+    /// Name - The name of the member we're searching for, if
+    /// LookupBase is false.
+    DeclarationName Name;
+
+    /// Criteria - The criteria by which we evaluate a named member,
+    /// if LookupBase is false.
+    Sema::LookupCriteria Criteria;
   };
 }
 

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Wed Jan 14 18:26:24 2009
@@ -12,6 +12,8 @@
 //
 //===----------------------------------------------------------------------===//
 #include "Sema.h"
+#include "SemaInherit.h"
+#include "clang/AST/ASTContext.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclObjC.h"
@@ -125,6 +127,46 @@
   return false;
 }
 
+Sema::LookupResult::LookupResult(ASTContext &Context, 
+                                 IdentifierResolver::iterator F, 
+                                 IdentifierResolver::iterator L)
+  : Context(&Context) {
+  if (F != L && isa<FunctionDecl>(*F)) {
+    IdentifierResolver::iterator Next = F;
+    ++Next;
+    if (Next != L && isa<FunctionDecl>(*Next)) {
+      StoredKind = OverloadedDeclFromIdResolver;
+      First = F.getAsOpaqueValue();
+      Last = L.getAsOpaqueValue();
+      return;
+    }
+  } 
+    
+  StoredKind = SingleDecl;
+  First = reinterpret_cast<uintptr_t>(*F);
+  Last = 0;
+}
+
+Sema::LookupResult::LookupResult(ASTContext &Context, 
+                                 DeclContext::lookup_iterator F, 
+                                 DeclContext::lookup_iterator L)
+  : Context(&Context) {
+  if (F != L && isa<FunctionDecl>(*F)) {
+    DeclContext::lookup_iterator Next = F;
+    ++Next;
+    if (Next != L && isa<FunctionDecl>(*Next)) {
+      StoredKind = OverloadedDeclFromDeclContext;
+      First = reinterpret_cast<uintptr_t>(F);
+      Last = reinterpret_cast<uintptr_t>(L);
+      return;
+    }
+  }
+  
+  StoredKind = SingleDecl;
+  First = reinterpret_cast<uintptr_t>(*F);
+  Last = 0;
+}
+
 /// @brief Determine the result of name lookup.
 Sema::LookupResult::LookupKind Sema::LookupResult::getKind() const {
   switch (StoredKind) {
@@ -136,11 +178,11 @@
     return FoundOverloaded;
 
   case AmbiguousLookup:
-    return Ambiguous;
+    return Last? AmbiguousBaseSubobjectTypes : AmbiguousBaseSubobjects;
   }
 
-  // We can't get here, but GCC complains nonetheless.
-  return Ambiguous;
+  // We can't ever get here.
+  return NotFound;
 }
 
 /// @brief Converts the result of name lookup into a single (possible
@@ -180,6 +222,14 @@
   return 0;
 }
 
+/// @brief Retrieves the BasePaths structure describing an ambiguous
+/// name lookup.
+BasePaths *Sema::LookupResult::getBasePaths() const {
+  assert((StoredKind == AmbiguousLookup) && 
+         "getBasePaths can only be used on an ambiguous lookup");
+  return reinterpret_cast<BasePaths *>(First);
+}
+
 /// @brief Perform unqualified name lookup starting from a given
 /// scope.
 ///
@@ -379,13 +429,99 @@
     Criteria.IDNS |= Decl::IDNS_Member;
 
   // Perform qualified name lookup into the LookupCtx.
-  // FIXME: Will need to look into base classes and such.
   DeclContext::lookup_iterator I, E;
   for (llvm::tie(I, E) = LookupCtx->lookup(Name); I != E; ++I)
     if (Criteria.isLookupResult(*I))
       return LookupResult(Context, I, E);
 
-  return LookupResult(Context, 0);
+  // If this isn't a C++ class or we aren't allowed to look into base
+  // classes, we're done.
+  if (Criteria.RedeclarationOnly || !isa<CXXRecordDecl>(LookupCtx))
+    return LookupResult(Context, 0);
+
+  // Perform lookup into our base classes.
+  BasePaths Paths;
+
+  // Look for this member in our base classes
+  if (!LookupInBases(cast<CXXRecordDecl>(LookupCtx), 
+                     MemberLookupCriteria(Name, Criteria), Paths))
+    return LookupResult(Context, 0);
+
+  // C++ [class.member.lookup]p2:
+  //   [...] If the resulting set of declarations are not all from
+  //   sub-objects of the same type, or the set has a nonstatic member
+  //   and includes members from distinct sub-objects, there is an
+  //   ambiguity and the program is ill-formed. Otherwise that set is
+  //   the result of the lookup.
+  // FIXME: support using declarations!
+  QualType SubobjectType;
+  int SubobjectNumber;
+  for (BasePaths::paths_iterator Path = Paths.begin(), PathEnd = Paths.end();
+       Path != PathEnd; ++Path) {
+    const BasePathElement &PathElement = Path->back();
+
+    // Determine whether we're looking at a distinct sub-object or not.
+    if (SubobjectType.isNull()) {
+      // This is the first subobject we've looked at. Record it's type.
+      SubobjectType = Context.getCanonicalType(PathElement.Base->getType());
+      SubobjectNumber = PathElement.SubobjectNumber;
+    } else if (SubobjectType 
+                 != Context.getCanonicalType(PathElement.Base->getType())) {
+      // We found members of the given name in two subobjects of
+      // different types. This lookup is ambiguous.
+      BasePaths *PathsOnHeap = new BasePaths;
+      PathsOnHeap->swap(Paths);
+      return LookupResult(Context, PathsOnHeap, true);
+    } else if (SubobjectNumber != PathElement.SubobjectNumber) {
+      // We have a different subobject of the same type.
+
+      // C++ [class.member.lookup]p5:
+      //   A static member, a nested type or an enumerator defined in
+      //   a base class T can unambiguously be found even if an object
+      //   has more than one base class subobject of type T. 
+      ScopedDecl *FirstDecl = *Path->Decls.first;
+      if (isa<VarDecl>(FirstDecl) ||
+          isa<TypeDecl>(FirstDecl) ||
+          isa<EnumConstantDecl>(FirstDecl))
+        continue;
+
+      if (isa<CXXMethodDecl>(FirstDecl)) {
+        // Determine whether all of the methods are static.
+        bool AllMethodsAreStatic = true;
+        for (DeclContext::lookup_iterator Func = Path->Decls.first;
+             Func != Path->Decls.second; ++Func) {
+          if (!isa<CXXMethodDecl>(*Func)) {
+            assert(isa<TagDecl>(*Func) && "Non-function must be a tag decl");
+            break;
+          }
+
+          if (!cast<CXXMethodDecl>(*Func)->isStatic()) {
+            AllMethodsAreStatic = false;
+            break;
+          }
+        }
+
+        if (AllMethodsAreStatic)
+          continue;
+      }
+
+      // We have found a nonstatic member name in multiple, distinct
+      // subobjects. Name lookup is ambiguous.
+      BasePaths *PathsOnHeap = new BasePaths;
+      PathsOnHeap->swap(Paths);
+      return LookupResult(Context, PathsOnHeap, false);
+    }
+  }
+
+  // Lookup in a base class succeeded; return these results.
+
+  // If we found a function declaration, return an overload set.
+  if (isa<FunctionDecl>(*Paths.front().Decls.first))
+    return LookupResult(Context, 
+                        Paths.front().Decls.first, Paths.front().Decls.second);
+
+  // We found a non-function declaration; return a single declaration.
+  return LookupResult(Context, *Paths.front().Decls.first);
 }
 
 /// @brief Performs name lookup for a name that was parsed in the
@@ -419,4 +555,41 @@
   return LookupName(S, Name, Criteria);
 }
 
+/// @brief Produce a diagnostic describing the ambiguity that resulted
+/// from name lookup.
+///
+/// @param Result       The ambiguous name lookup result.
+/// 
+/// @param Name         The name of the entity that name lookup was
+/// searching for.
+///
+/// @param NameLoc      The location of the name within the source code.
+///
+/// @param LookupRange  A source range that provides more
+/// source-location information concerning the lookup itself. For
+/// example, this range might highlight a nested-name-specifier that
+/// precedes the name.
+///
+/// @returns true
+bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result, DeclarationName Name,
+                                   SourceLocation NameLoc, 
+                                   SourceRange LookupRange) {
+  assert(Result.isAmbiguous() && "Lookup result must be ambiguous");
+
+  if (Result.getKind() == LookupResult::AmbiguousBaseSubobjects) {
+    BasePaths *Paths = Result.getBasePaths();
+    QualType SubobjectType = Paths->front().back().Base->getType();
+    return Diag(NameLoc, diag::err_ambiguous_member_multiple_subobjects)
+      << Name << SubobjectType << LookupRange;
+  } 
+
+  assert(Result.getKind() == LookupResult::AmbiguousBaseSubobjectTypes &&
+         "Unhandled form of name lookup ambiguity");
+
+  Diag(NameLoc, diag::err_ambiguous_member_multiple_subobject_types)
+    << Name << LookupRange;
+
+  // FIXME: point out the members we found using notes.
+  return true;
+}
 





More information about the cfe-commits mailing list