[cfe-commits] r98544 - in /cfe/trunk: lib/Sema/SemaLookup.cpp test/CXX/temp/temp.res/temp.local/p7.cpp test/CXX/temp/temp.res/temp.local/p8.cpp test/CXX/temp/temp.res/temp.local/p9.cpp

Douglas Gregor dgregor at apple.com
Mon Mar 15 07:33:29 PDT 2010


Author: dgregor
Date: Mon Mar 15 09:33:29 2010
New Revision: 98544

URL: http://llvm.org/viewvc/llvm-project?rev=98544&view=rev
Log:
Implement C++ [temp.local]p8, which specifies that a template
parameter hides a namespace-scope declararion with the same name in an
out-of-line definition of a template. The lookup requires a strange
interleaving of lexical and semantic scopes (go C++), which I have not
yet handled in the typo correction/code completion path.

Fixes PR6594.

Added:
    cfe/trunk/test/CXX/temp/temp.res/temp.local/p7.cpp   (with props)
    cfe/trunk/test/CXX/temp/temp.res/temp.local/p8.cpp   (with props)
    cfe/trunk/test/CXX/temp/temp.res/temp.local/p9.cpp   (with props)
Modified:
    cfe/trunk/lib/Sema/SemaLookup.cpp

Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=98544&r1=98543&r2=98544&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Mon Mar 15 09:33:29 2010
@@ -590,13 +590,74 @@
   return false;
 }
 
-// Find the next outer declaration context corresponding to this scope.
-static DeclContext *findOuterContext(Scope *S) {
-  for (S = S->getParent(); S; S = S->getParent())
-    if (S->getEntity())
-      return static_cast<DeclContext *>(S->getEntity())->getPrimaryContext();
+// Find the next outer declaration context from this scope. This
+// routine actually returns the semantic outer context, which may
+// differ from the lexical context (encoded directly in the Scope
+// stack) when we are parsing a member of a class template. In this
+// case, the second element of the pair will be true, to indicate that
+// name lookup should continue searching in this semantic context when
+// it leaves the current template parameter scope.
+static std::pair<DeclContext *, bool> findOuterContext(Scope *S) {
+  DeclContext *DC = static_cast<DeclContext *>(S->getEntity());
+  DeclContext *Lexical = 0;
+  for (Scope *OuterS = S->getParent(); OuterS; 
+       OuterS = OuterS->getParent()) {
+    if (OuterS->getEntity()) {
+      Lexical
+        = static_cast<DeclContext *>(OuterS->getEntity())->getPrimaryContext();
+      break;
+    }
+  }
+
+  // C++ [temp.local]p8:
+  //   In the definition of a member of a class template that appears
+  //   outside of the namespace containing the class template
+  //   definition, the name of a template-parameter hides the name of
+  //   a member of this namespace.
+  //
+  // Example:
+  //
+  //   namespace N { 
+  //     class C { }; 
+  //
+  //     template<class T> class B {
+  //       void f(T);
+  //     }; 
+  //   }
+  //
+  //   template<class C> void N::B<C>::f(C) {
+  //     C b;  // C is the template parameter, not N::C
+  //   }
+  //
+  // In this example, the lexical context we return is the
+  // TranslationUnit, while the semantic context is the namespace N.
+  if (!Lexical || !DC || !S->getParent() || 
+      !S->getParent()->isTemplateParamScope())
+    return std::make_pair(Lexical, false);
+
+  // Find the outermost template parameter scope. 
+  // For the example, this is the scope for the template parameters of
+  // template<class C>.
+  Scope *OutermostTemplateScope = S->getParent();
+  while (OutermostTemplateScope->getParent() &&
+         OutermostTemplateScope->getParent()->isTemplateParamScope())
+    OutermostTemplateScope = OutermostTemplateScope->getParent();
   
-  return 0;
+  // Find the namespace context in which the original scope occurs. In
+  // the example, this is namespace N.
+  DeclContext *Semantic = DC;
+  while (!Semantic->isFileContext())
+    Semantic = Semantic->getParent();
+  
+  // Find the declaration context just outside of the template
+  // parameter scope. This is the context in which the template is
+  // being lexically declaration (a namespace context). In the
+  // example, this is the global scope.
+  if (Lexical->isFileContext() && !Lexical->Equals(Semantic) &&
+      Lexical->Encloses(Semantic))
+    return std::make_pair(Semantic, true);
+
+  return std::make_pair(Lexical, false);
 }
 
 bool Sema::CppLookupName(LookupResult &R, Scope *S) {
@@ -627,6 +688,7 @@
   //   }
   // }
   //
+  DeclContext *OutsideOfTemplateParamDC = 0;
   for (; S && !isNamespaceOrTranslationUnitScope(S); S = S->getParent()) {
     // Check whether the IdResolver has anything in this scope.
     bool Found = false;
@@ -641,8 +703,25 @@
       return true;
     }
 
-    if (DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity())) {
-      DeclContext *OuterCtx = findOuterContext(S);
+    DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity());
+    if (!Ctx && S->isTemplateParamScope() && OutsideOfTemplateParamDC &&
+        S->getParent() && !S->getParent()->isTemplateParamScope()) {
+      // We've just searched the last template parameter scope and
+      // found nothing, so look into the the contexts between the
+      // lexical and semantic declaration contexts returned by
+      // findOuterContext(). This implements the name lookup behavior
+      // of C++ [temp.local]p8.
+      Ctx = OutsideOfTemplateParamDC;
+      OutsideOfTemplateParamDC = 0;
+    }
+
+    if (Ctx) {
+      DeclContext *OuterCtx;
+      bool SearchAfterTemplateScope;
+      llvm::tie(OuterCtx, SearchAfterTemplateScope) = findOuterContext(S);
+      if (SearchAfterTemplateScope)
+        OutsideOfTemplateParamDC = OuterCtx;
+
       for (; Ctx && Ctx->getPrimaryContext() != OuterCtx; 
            Ctx = Ctx->getLookupParent()) {
         // We do not directly look into transparent contexts, since
@@ -725,7 +804,10 @@
       }
     }
 
-    if (Ctx) {
+    // If we have a context, and it's not a context stashed in the
+    // template parameter scope for an out-of-line definition, also
+    // look into that context.
+    if (Ctx && !(Found && S && S->isTemplateParamScope())) {
       assert(Ctx->isFileContext() &&
              "We should have been looking only at file context here already.");
 
@@ -2216,13 +2298,14 @@
     }
   }
   
+  // FIXME: C++ [temp.local]p8
   DeclContext *Entity = 0;
   if (S->getEntity()) {
     // Look into this scope's declaration context, along with any of its
     // parent lookup contexts (e.g., enclosing classes), up to the point
     // where we hit the context stored in the next outer scope.
     Entity = (DeclContext *)S->getEntity();
-    DeclContext *OuterCtx = findOuterContext(S);
+    DeclContext *OuterCtx = findOuterContext(S).first; // FIXME
     
     for (DeclContext *Ctx = Entity; Ctx && Ctx->getPrimaryContext() != OuterCtx;
          Ctx = Ctx->getLookupParent()) {

Added: cfe/trunk/test/CXX/temp/temp.res/temp.local/p7.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.res/temp.local/p7.cpp?rev=98544&view=auto
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.res/temp.local/p7.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.res/temp.local/p7.cpp Mon Mar 15 09:33:29 2010
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+template<class T> struct A { 
+  int B;
+  int f();
+}; 
+
+template<class B> int A<B>::f() {
+  return B;
+}

Propchange: cfe/trunk/test/CXX/temp/temp.res/temp.local/p7.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/CXX/temp/temp.res/temp.local/p7.cpp
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/CXX/temp/temp.res/temp.local/p7.cpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cfe/trunk/test/CXX/temp/temp.res/temp.local/p8.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.res/temp.local/p8.cpp?rev=98544&view=auto
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.res/temp.local/p8.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.res/temp.local/p8.cpp Mon Mar 15 09:33:29 2010
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+namespace N { 
+  enum { C };
+  template<class T> class B {
+    void f(T);
+  }; 
+}
+
+template<class C> void N::B<C>::f(C) {
+  C b;
+}
+
+namespace N {
+  enum { D };
+  namespace M {
+    enum { C , D };
+    template<typename C> class X {
+      template<typename U> void f(C, U);
+
+      template<typename D> void g(C, D) {
+        C c;
+        D d;
+      }
+    };
+  }
+}
+
+template<typename C> 
+template<typename D>
+void N::M::X<C>::f(C, D) {
+  C c;
+  D d;
+}

Propchange: cfe/trunk/test/CXX/temp/temp.res/temp.local/p8.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/CXX/temp/temp.res/temp.local/p8.cpp
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/CXX/temp/temp.res/temp.local/p8.cpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cfe/trunk/test/CXX/temp/temp.res/temp.local/p9.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.res/temp.local/p9.cpp?rev=98544&view=auto
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.res/temp.local/p9.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.res/temp.local/p9.cpp Mon Mar 15 09:33:29 2010
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+struct A { 
+  struct B { void f(); }; 
+  int a; 
+  int Y;
+};
+
+template<class B, class a> struct X : A { 
+  B b;  // A's B 
+  a c;  // expected-error{{unknown type name 'a'}} 
+
+  void g() {
+    b.g(); // expected-error{{no member named 'g' in 'A::B'}}
+  }
+};

Propchange: cfe/trunk/test/CXX/temp/temp.res/temp.local/p9.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/CXX/temp/temp.res/temp.local/p9.cpp
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/CXX/temp/temp.res/temp.local/p9.cpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain





More information about the cfe-commits mailing list