]> granicus.if.org Git - clang/commitdiff
When performing qualified name lookup into the current instantiation,
authorDouglas Gregor <dgregor@apple.com>
Fri, 15 Jan 2010 01:44:47 +0000 (01:44 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 15 Jan 2010 01:44:47 +0000 (01:44 +0000)
do not look into base classes if there are any dependent base
classes. Instead, note in the lookup result that we couldn't look into
any dependent bases. Use that new result kind to detect when this case
occurs, so that we can fall back to treating the type/value/etc. as a
member of an unknown specialization.

Fixes an issue where we were resolving lookup at template definition
time and then missing an ambiguity at template instantiation time.

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

lib/Sema/Lookup.h
lib/Sema/Sema.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaLookup.cpp
lib/Sema/SemaTemplate.cpp
test/SemaTemplate/dependent-base-classes.cpp

index e761346c677cc04dd091edd62c08e8167fd50c0b..9064de6aa019e320fa814862c938050797efd7b3 100644 (file)
@@ -32,6 +32,11 @@ public:
     /// @brief No entity found met the criteria.
     NotFound = 0,
 
+    /// @brief No entity found met the criteria within the current 
+    /// instantiation,, but there were dependent base classes of the 
+    /// current instantiation that could not be searched.
+    NotFoundInCurrentInstantiation,
+    
     /// @brief Name lookup found a single declaration that met the
     /// criteria.  getFoundDecl() will return this declaration.
     Found,
@@ -268,6 +273,19 @@ public:
     Decls.set_size(N);
   }
 
+  /// \brief Determine whether no result was found because we could not
+  /// search into dependent base classes of the current instantiation.
+  bool wasNotFoundInCurrentInstantiation() const {
+    return ResultKind == NotFoundInCurrentInstantiation;
+  }
+  
+  /// \brief Note that while no result was found in the current instantiation,
+  /// there were dependent base classes that could not be searched.
+  void setNotFoundInCurrentInstantiation() {
+    assert(ResultKind == NotFound && Decls.empty());
+    ResultKind = NotFoundInCurrentInstantiation;
+  }
+  
   /// \brief Resolves the result kind of the lookup, possibly hiding
   /// decls.
   ///
@@ -278,9 +296,10 @@ public:
   /// \brief Re-resolves the result kind of the lookup after a set of
   /// removals has been performed.
   void resolveKindAfterFilter() {
-    if (Decls.empty())
-      ResultKind = NotFound;
-    else {
+    if (Decls.empty()) {
+      if (ResultKind != NotFoundInCurrentInstantiation)
+        ResultKind = NotFound;
+    } else {
       ResultKind = Found;
       resolveKind();
     }
index 44bf48915ea7d7e66780583e3d101e6b46e460bd..953a00fa42298627c06c71a55ec04e4dae62b704 100644 (file)
@@ -1212,7 +1212,8 @@ public:
                                 = NotForRedeclaration);
   bool LookupName(LookupResult &R, Scope *S,
                   bool AllowBuiltinCreation = false);
-  bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx);
+  bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
+                           bool InUnqualifiedLookup = false);
   bool LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS,
                         bool AllowBuiltinCreation = false,
                         bool EnteringContext = false);
index 79bb1cb54a061e0c1e73809db06219e846c47b80..8176710e35a13efabb680b06588805f3a47f0d9e 100644 (file)
@@ -138,6 +138,7 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
   NamedDecl *IIDecl = 0;
   switch (Result.getResultKind()) {
   case LookupResult::NotFound:
+  case LookupResult::NotFoundInCurrentInstantiation:
   case LookupResult::FoundOverloaded:
   case LookupResult::FoundUnresolvedValue:
     return 0;
@@ -4791,7 +4792,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
       // and that current instantiation has any dependent base
       // classes, we might find something at instantiation time: treat
       // this as a dependent elaborated-type-specifier.
-      if (isCurrentInstantiationWithDependentBases(SS)) {
+      if (Previous.wasNotFoundInCurrentInstantiation()) {
         IsDependent = true;
         return DeclPtrTy();
       }
index c6ab6a6b19805da2d014a6ea5fb33ac7335c59f5..cda245deba13697f5bdbae91fc0f414ca75ba57f 100644 (file)
@@ -623,7 +623,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
         // example, inside a class without any base classes, we never need to
         // perform qualified lookup because all of the members are on top of the
         // identifier chain.
-        if (LookupQualifiedName(R, Ctx))
+        if (LookupQualifiedName(R, Ctx, /*InUnqualifiedLookup=*/true))
           return true;
       }
     }
@@ -927,11 +927,11 @@ static bool LookupQualifiedNameInUsingDirectives(LookupResult &R,
   return Found;
 }
 
-/// @brief Perform qualified name lookup into a given context.
+/// \brief Perform qualified name lookup into a given context.
 ///
 /// Qualified name lookup (C++ [basic.lookup.qual]) is used to find
 /// names when the context of those names is explicit specified, e.g.,
-/// "std::vector" or "x->member".
+/// "std::vector" or "x->member", or as part of unqualified name lookup.
 ///
 /// Different lookup criteria can find different names. For example, a
 /// particular scope can have both a struct and a function of the same
@@ -939,25 +939,18 @@ static bool LookupQualifiedNameInUsingDirectives(LookupResult &R,
 /// information about lookup criteria, see the documentation for the
 /// class LookupCriteria.
 ///
-/// @param LookupCtx The context in which qualified name lookup will
+/// \param R captures both the lookup criteria and any lookup results found.
+///
+/// \param LookupCtx The context in which qualified name lookup will
 /// search. If the lookup criteria permits, name lookup may also search
 /// in the parent contexts or (for C++ classes) base classes.
 ///
-/// @param Name     The name of the entity that we are searching for.
-///
-/// @param Criteria The criteria that this routine will use to
-/// determine which names are visible and which names will be
-/// found. Note that name lookup will find a name that is visible by
-/// the given criteria, but the entity itself may not be semantically
-/// correct or even the kind of entity expected based on the
-/// lookup. For example, searching for a nested-name-specifier name
-/// might result in an EnumDecl, which is visible but is not permitted
-/// as a nested-name-specifier in C++03.
+/// \param InUnqualifiedLookup true if this is qualified name lookup that 
+/// occurs as part of unqualified name lookup.
 ///
-/// @returns The result of name lookup, which includes zero or more
-/// declarations and possibly additional information used to diagnose
-/// ambiguities.
-bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx) {
+/// \returns true if lookup succeeded, false if it failed.
+bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
+                               bool InUnqualifiedLookup) {
   assert(LookupCtx && "Sema::LookupQualifiedName requires a lookup context");
 
   if (!R.getLookupName())
@@ -995,11 +988,22 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx) {
 
   // If this isn't a C++ class, we aren't allowed to look into base
   // classes, we're done.
-  if (!isa<CXXRecordDecl>(LookupCtx))
+  CXXRecordDecl *LookupRec = dyn_cast<CXXRecordDecl>(LookupCtx);
+  if (!LookupRec)
     return false;
 
+  // If we're performing qualified name lookup into a dependent class,
+  // then we are actually looking into a current instantiation. If we have any
+  // dependent base classes, then we either have to delay lookup until 
+  // template instantiation time (at which point all bases will be available)
+  // or we have to fail.
+  if (!InUnqualifiedLookup && LookupRec->isDependentContext() &&
+      LookupRec->hasAnyDependentBases()) {
+    R.setNotFoundInCurrentInstantiation();
+    return false;
+  }
+    
   // Perform lookup into our base classes.
-  CXXRecordDecl *LookupRec = cast<CXXRecordDecl>(LookupCtx);
   CXXBasePaths Paths;
   Paths.setOrigin(LookupRec);
 
index d2e70cf9ad6f0efd64ff1ab0c271318ecff58738..2fad8325d4dda930c6fe53c6c19f1766cbe72faa 100644 (file)
@@ -4769,16 +4769,12 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
   Decl *Referenced = 0;
   switch (Result.getResultKind()) {
   case LookupResult::NotFound:
-    if (CurrentInstantiation && CurrentInstantiation->hasAnyDependentBases()) {
-      // We performed a lookup in the current instantiation and didn't
-      // find anything. However, this current instantiation has
-      // dependent bases, so we might be able to find something at
-      // instantiation time: just build a TypenameType and move on.
-      return Context.getTypenameType(NNS, &II);
-    }
-
     DiagID = diag::err_typename_nested_not_found;
     break;
+      
+  case LookupResult::NotFoundInCurrentInstantiation:
+    // Okay, it's a member of an unknown instantiation.
+    return Context.getTypenameType(NNS, &II);
 
   case LookupResult::Found:
     if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getFoundDecl())) {
index b9666dba61c661251299c7a47834ef4415badd95..79b28c2239fe1025396a6f364cc0b9740a18002a 100644 (file)
@@ -63,3 +63,22 @@ namespace PR6031 {
     }
   };
 }
+
+namespace Ambig {
+  template<typename T>
+  struct Base1 {
+    typedef int type; // expected-note{{member found by ambiguous name lookup}}
+  };
+
+  struct Base2 {
+    typedef float type; // expected-note{{member found by ambiguous name lookup}}
+  };
+
+  template<typename T>
+  struct Derived : Base1<T>, Base2 {
+    typedef typename Derived::type type; // expected-error{{member 'type' found in multiple base classes of different types}}
+    type *foo(float *fp) { return fp; }
+  };
+
+  Derived<int> di; // expected-note{{instantiation of}}
+}