[cfe-commits] r93433 - in /cfe/trunk: include/clang/AST/DeclCXX.h lib/AST/DeclCXX.cpp lib/Sema/Sema.h lib/Sema/SemaCXXScopeSpec.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaTemplate.cpp test/SemaTemplate/dependent-base-classes.cpp

Douglas Gregor dgregor at apple.com
Thu Jan 14 09:47:40 PST 2010


Author: dgregor
Date: Thu Jan 14 11:47:39 2010
New Revision: 93433

URL: http://llvm.org/viewvc/llvm-project?rev=93433&view=rev
Log:
When qualified lookup into the current instantiation fails (because it
finds nothing), and the current instantiation has dependent base
classes, treat the qualified lookup as if it referred to an unknown
specialization. Fixes PR6031.

Modified:
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/test/SemaTemplate/dependent-base-classes.cpp

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=93433&r1=93432&r2=93433&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Thu Jan 14 11:47:39 2010
@@ -393,6 +393,9 @@
     return reverse_base_class_const_iterator(vbases_begin());
  }
 
+  /// \brief Determine whether this class has any dependent base classes.
+  bool hasAnyDependentBases() const;
+
   /// Iterator access to method members.  The method iterator visits
   /// all method members of the class, including non-instance methods,
   /// special methods, etc.

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=93433&r1=93432&r2=93433&view=diff

==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Thu Jan 14 11:47:39 2010
@@ -144,6 +144,19 @@
   }
 }
 
+/// Callback function for CXXRecordDecl::forallBases that acknowledges
+/// that it saw a base class.
+static bool SawBase(const CXXRecordDecl *, void *) {
+  return true;
+}
+
+bool CXXRecordDecl::hasAnyDependentBases() const {
+  if (!isDependentContext())
+    return false;
+
+  return !forallBases(SawBase, 0);
+}
+
 bool CXXRecordDecl::hasConstCopyConstructor(ASTContext &Context) const {
   return getCopyConstructor(Context, Qualifiers::Const) != 0;
 }

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Thu Jan 14 11:47:39 2010
@@ -2032,6 +2032,7 @@
   bool isDependentScopeSpecifier(const CXXScopeSpec &SS);
   CXXRecordDecl *getCurrentInstantiationOf(NestedNameSpecifier *NNS);
   bool isUnknownSpecialization(const CXXScopeSpec &SS);
+  bool isCurrentInstantiationWithDependentBases(const CXXScopeSpec &SS);
 
   /// ActOnCXXGlobalScopeSpecifier - Return the object that represents the
   /// global scope ('::').

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp Thu Jan 14 11:47:39 2010
@@ -210,6 +210,28 @@
   return getCurrentInstantiationOf(NNS) == 0;
 }
 
+/// \brief Determine whether the given scope specifier refers to a
+/// current instantiation that has any dependent base clases.
+///
+/// This check is typically used when we've performed lookup into the
+/// current instantiation of a template, but that lookup failed. When
+/// there are dependent bases present, however, the lookup needs to be
+/// delayed until template instantiation time.
+bool Sema::isCurrentInstantiationWithDependentBases(const CXXScopeSpec &SS) {
+  if (!SS.isSet())
+    return false;
+
+  NestedNameSpecifier *NNS = (NestedNameSpecifier*)SS.getScopeRep();
+  if (!NNS->isDependent())
+    return false;
+
+  CXXRecordDecl *CurrentInstantiation = getCurrentInstantiationOf(NNS);
+  if (!CurrentInstantiation)
+    return false;
+
+  return CurrentInstantiation->hasAnyDependentBases();
+}
+
 /// \brief If the given nested name specifier refers to the current
 /// instantiation, return the declaration that corresponds to that
 /// current instantiation (C++0x [temp.dep.type]p1).

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Jan 14 11:47:39 2010
@@ -4785,8 +4785,18 @@
     if (Previous.isAmbiguous())
       return DeclPtrTy();
 
-    // A tag 'foo::bar' must already exist.
     if (Previous.empty()) {
+      // Name lookup did not find anything. However, if the
+      // nested-name-specifier refers to the current instantiation,
+      // 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)) {
+        IsDependent = true;
+        return DeclPtrTy();
+      }
+
+      // A tag 'foo::bar' must already exist.
       Diag(NameLoc, diag::err_not_tag_in_scope) << Name << SS.getRange();
       Name = 0;
       Invalid = true;

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Jan 14 11:47:39 2010
@@ -1608,15 +1608,19 @@
     TemplateTy Template;
     TemplateNameKind TNK = isTemplateName(0, SS, Name, ObjectType,
                                           EnteringContext, Template);
-    if (TNK == TNK_Non_template) {
+    if (TNK == TNK_Non_template && 
+        isCurrentInstantiationWithDependentBases(SS)) {
+      // This is a dependent template.
+    } else if (TNK == TNK_Non_template) {
       Diag(Name.getSourceRange().getBegin(), 
            diag::err_template_kw_refers_to_non_template)
         << GetNameFromUnqualifiedId(Name)
         << Name.getSourceRange();
       return TemplateTy();
+    } else {
+      // We found something; return it.
+      return Template;
     }
-
-    return Template;
   }
 
   NestedNameSpecifier *Qualifier
@@ -4765,6 +4769,14 @@
   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;
 

Modified: cfe/trunk/test/SemaTemplate/dependent-base-classes.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/dependent-base-classes.cpp?rev=93433&r1=93432&r2=93433&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/dependent-base-classes.cpp (original)
+++ cfe/trunk/test/SemaTemplate/dependent-base-classes.cpp Thu Jan 14 11:47:39 2010
@@ -10,3 +10,56 @@
 
 template<typename T>
 struct X2 : vector<T> { }; // expected-error{{unknown template name 'vector'}}
+
+namespace PR6031 {
+  template<typename T>
+  struct A;
+
+  template <class X>
+  struct C { };
+
+  template <class TT>
+  struct II {
+    typedef typename A<TT>::type type;
+  };
+
+  template <class TT>
+  struct FI : II<TT>
+  {
+    C<typename FI::type> a;
+  };
+
+  template <class TT>
+  struct FI2
+  {
+    C<typename FI2::type> a; // expected-error{{no type named 'type' in 'struct PR6031::FI2'}} \
+        // expected-error{{C++ requires a type specifier for all declarations}}
+  };
+
+  template<typename T>
+  struct Base {
+    class Nested { };
+    template<typename U> struct MemberTemplate { };
+    int a;
+  };
+
+  template<typename T>
+  struct HasDepBase : Base<T> {
+    int foo() {
+      class HasDepBase::Nested nested;
+      typedef typename HasDepBase::template MemberTemplate<T>::type type;
+      return HasDepBase::a;
+    }
+  };
+
+  template<typename T>
+  struct NoDepBase {
+    int foo() {
+      class NoDepBase::Nested nested; // expected-error{{'Nested' does not name a tag member in the specified scope}}
+      typedef typename NoDepBase::template MemberTemplate<T>::type type; // expected-error{{'MemberTemplate' following the 'template' keyword does not refer to a template}} \
+      // FIXME: expected-error{{expected an identifier or template-id after '::'}} \
+      // FIXME: expected-error{{unqualified-id}}
+      return NoDepBase::a; // expected-error{{no member named 'a' in 'struct PR6031::NoDepBase'}}
+    }
+  };
+}





More information about the cfe-commits mailing list