Keep the parser's template depth up to date when parsing local templates and
late-parsed templates. Patch by Faisal Vali!


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@180708 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index a61b59c..44c213c 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -172,6 +172,25 @@
   /// The "depth" of the template parameters currently being parsed.
   unsigned TemplateParameterDepth;
 
+  /// \brief RAII class that manages the template parameter depth.
+  class TemplateParameterDepthRAII {
+    unsigned &Depth;
+    unsigned AddedLevels;
+  public:
+    explicit TemplateParameterDepthRAII(unsigned &Depth)
+      : Depth(Depth), AddedLevels(0) {}
+
+    ~TemplateParameterDepthRAII() {
+      Depth -= AddedLevels;
+    }
+
+    void operator++() {
+      ++Depth;
+      ++AddedLevels;
+    }
+    unsigned getDepth() const { return Depth; }
+  };
+
   /// Factory object for creating AttributeList objects.
   AttributeFactory AttrFactory;
 
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index 5d77f81..5fc4189 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -278,8 +278,11 @@
 void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) {
   bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope;
   ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, HasTemplateScope);
-  if (HasTemplateScope)
+  TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
+  if (HasTemplateScope) {
     Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate);
+    ++CurTemplateDepthTracker;
+  }
 
   // The current scope is still active if we're the top-level class.
   // Otherwise we'll need to push and enter a new scope.
@@ -300,9 +303,11 @@
 void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
   // If this is a member template, introduce the template parameter scope.
   ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope);
-  if (LM.TemplateScope)
+  TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
+  if (LM.TemplateScope) {
     Actions.ActOnReenterTemplateScope(getCurScope(), LM.Method);
-
+    ++CurTemplateDepthTracker;
+  }
   // Start the delayed C++ method declaration
   Actions.ActOnStartDelayedCXXMethodDeclaration(getCurScope(), LM.Method);
 
@@ -378,9 +383,11 @@
 void Parser::ParseLexedMethodDefs(ParsingClass &Class) {
   bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope;
   ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, HasTemplateScope);
-  if (HasTemplateScope)
+  TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
+  if (HasTemplateScope) {
     Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate);
-
+    ++CurTemplateDepthTracker;
+  }
   bool HasClassScope = !Class.TopLevelClass;
   ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope,
                         HasClassScope);
@@ -393,9 +400,11 @@
 void Parser::ParseLexedMethodDef(LexedMethod &LM) {
   // If this is a member template, introduce the template parameter scope.
   ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope);
-  if (LM.TemplateScope)
+  TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
+  if (LM.TemplateScope) {
     Actions.ActOnReenterTemplateScope(getCurScope(), LM.D);
-
+    ++CurTemplateDepthTracker;
+  }
   // Save the current token position.
   SourceLocation origLoc = Tok.getLocation();
 
@@ -440,6 +449,13 @@
   } else
     Actions.ActOnDefaultCtorInitializers(LM.D);
 
+  assert((Actions.getDiagnostics().hasErrorOccurred() ||
+          !isa<FunctionTemplateDecl>(LM.D) ||
+          cast<FunctionTemplateDecl>(LM.D)->getTemplateParameters()->getDepth()
+            < TemplateParameterDepth) &&
+         "TemplateParameterDepth should be greater than the depth of "
+         "current template being instantiated!");
+
   ParseFunctionStatementBody(LM.D, FnScope);
 
   // Clear the late-template-parsed bit if we set it before.
@@ -465,9 +481,11 @@
   bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope;
   ParseScope ClassTemplateScope(this, Scope::TemplateParamScope,
                                 HasTemplateScope);
-  if (HasTemplateScope)
+  TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
+  if (HasTemplateScope) {
     Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate);
-
+    ++CurTemplateDepthTracker;
+  }
   // Set or update the scope flags.
   bool AlreadyHasClassScope = Class.TopLevelClass;
   unsigned ScopeFlags = Scope::ClassScope|Scope::DeclScope;
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index f25beff..fd49e7a 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -39,28 +39,7 @@
                                                   AccessAttrs);
 }
 
-/// \brief RAII class that manages the template parameter depth.
-namespace {
-  class TemplateParameterDepthCounter {
-    unsigned &Depth;
-    unsigned AddedLevels;
 
-  public:
-    explicit TemplateParameterDepthCounter(unsigned &Depth)
-      : Depth(Depth), AddedLevels(0) { }
-
-    ~TemplateParameterDepthCounter() {
-      Depth -= AddedLevels;
-    }
-
-    void operator++() {
-      ++Depth;
-      ++AddedLevels;
-    }
-
-    operator unsigned() const { return Depth; }
-  };
-}
 
 /// \brief Parse a template declaration or an explicit specialization.
 ///
@@ -117,7 +96,8 @@
   bool isSpecialization = true;
   bool LastParamListWasEmpty = false;
   TemplateParameterLists ParamLists;
-  TemplateParameterDepthCounter Depth(TemplateParameterDepth);
+  TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
+
   do {
     // Consume the 'export', if any.
     SourceLocation ExportLoc;
@@ -137,8 +117,8 @@
     // Parse the '<' template-parameter-list '>'
     SourceLocation LAngleLoc, RAngleLoc;
     SmallVector<Decl*, 4> TemplateParams;
-    if (ParseTemplateParameters(Depth, TemplateParams, LAngleLoc,
-                                RAngleLoc)) {
+    if (ParseTemplateParameters(CurTemplateDepthTracker.getDepth(),
+                                TemplateParams, LAngleLoc, RAngleLoc)) {
       // Skip until the semi-colon or a }.
       SkipUntil(tok::r_brace, true, true);
       if (Tok.is(tok::semi))
@@ -147,14 +127,15 @@
     }
 
     ParamLists.push_back(
-      Actions.ActOnTemplateParameterList(Depth, ExportLoc,
+      Actions.ActOnTemplateParameterList(CurTemplateDepthTracker.getDepth(), 
+                                         ExportLoc,
                                          TemplateLoc, LAngleLoc,
                                          TemplateParams.data(),
                                          TemplateParams.size(), RAngleLoc));
 
     if (!TemplateParams.empty()) {
       isSpecialization = false;
-      ++Depth;
+      ++CurTemplateDepthTracker;
     } else {
       LastParamListWasEmpty = true;
     }
@@ -1249,11 +1230,11 @@
      return;
 
   // Get the FunctionDecl.
-  FunctionDecl *FD = 0;
-  if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(LMT.D))
-    FD = FunTmpl->getTemplatedDecl();
-  else
-    FD = cast<FunctionDecl>(LMT.D);
+  FunctionTemplateDecl *FunTmplD = dyn_cast<FunctionTemplateDecl>(LMT.D);
+  FunctionDecl *FunD =
+      FunTmplD ? FunTmplD->getTemplatedDecl() : cast<FunctionDecl>(LMT.D);
+  // Track template parameter depth.
+  TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
 
   // To restore the context after late parsing.
   Sema::ContextRAII GlobalSavedContext(Actions, Actions.CurContext);
@@ -1262,7 +1243,7 @@
 
   // Get the list of DeclContexts to reenter.
   SmallVector<DeclContext*, 4> DeclContextsToReenter;
-  DeclContext *DD = FD->getLexicalParent();
+  DeclContext *DD = FunD->getLexicalParent();
   while (DD && !DD->isTranslationUnit()) {
     DeclContextsToReenter.push_back(DD);
     DD = DD->getLexicalParent();
@@ -1277,12 +1258,14 @@
       TemplateParamScopeStack.push_back(
           new ParseScope(this, Scope::TemplateParamScope));
       Actions.ActOnReenterTemplateScope(getCurScope(), MD);
+      ++CurTemplateDepthTracker;
     } else if (CXXRecordDecl *MD = dyn_cast_or_null<CXXRecordDecl>(*II)) {
       bool ManageScope = MD->getDescribedClassTemplate() != 0;
       TemplateParamScopeStack.push_back(
           new ParseScope(this, Scope::TemplateParamScope, ManageScope));
       Actions.ActOnReenterTemplateScope(getCurScope(),
                                         MD->getDescribedClassTemplate());
+      ++CurTemplateDepthTracker;
     }
     TemplateParamScopeStack.push_back(new ParseScope(this, Scope::DeclScope));
     Actions.PushDeclContext(Actions.getCurScope(), *II);
@@ -1290,10 +1273,13 @@
   TemplateParamScopeStack.push_back(
       new ParseScope(this, Scope::TemplateParamScope));
 
-  DeclaratorDecl *Declarator = dyn_cast<DeclaratorDecl>(FD);
-  if (Declarator && Declarator->getNumTemplateParameterLists() != 0)
+  DeclaratorDecl *Declarator = dyn_cast<DeclaratorDecl>(FunD);
+  if (Declarator && Declarator->getNumTemplateParameterLists() != 0) {
     Actions.ActOnReenterDeclaratorTemplateScope(getCurScope(), Declarator);
+    ++CurTemplateDepthTracker;
+  }
   Actions.ActOnReenterTemplateScope(getCurScope(), LMT.D);
+  ++CurTemplateDepthTracker;
 
   assert(!LMT.Toks.empty() && "Empty body!");
 
@@ -1312,15 +1298,9 @@
   ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope);
 
   // Recreate the containing function DeclContext.
-  Sema::ContextRAII FunctionSavedContext(Actions, Actions.getContainingDC(FD));
+  Sema::ContextRAII FunctionSavedContext(Actions, Actions.getContainingDC(FunD));
 
-  if (FunctionTemplateDecl *FunctionTemplate
-        = dyn_cast_or_null<FunctionTemplateDecl>(LMT.D))
-    Actions.ActOnStartOfFunctionDef(getCurScope(),
-                                   FunctionTemplate->getTemplatedDecl());
-  if (FunctionDecl *Function = dyn_cast_or_null<FunctionDecl>(LMT.D))
-    Actions.ActOnStartOfFunctionDef(getCurScope(), Function);
-
+  Actions.ActOnStartOfFunctionDef(getCurScope(), FunD);
 
   if (Tok.is(tok::kw_try)) {
     ParseFunctionTryBlock(LMT.D, FnScope);
@@ -1331,8 +1311,12 @@
       Actions.ActOnDefaultCtorInitializers(LMT.D);
 
     if (Tok.is(tok::l_brace)) {
+      assert((!FunTmplD || FunTmplD->getTemplateParameters()->getDepth() <
+                               TemplateParameterDepth) &&
+             "TemplateParameterDepth should be greater than the depth of "
+             "current template being instantiated!");
       ParseFunctionStatementBody(LMT.D, FnScope);
-      Actions.MarkAsLateParsedTemplate(FD, false);
+      Actions.MarkAsLateParsedTemplate(FunD, false);
     } else
       Actions.ActOnFinishFunctionBody(LMT.D, 0);
   }
diff --git a/test/SemaTemplate/local-member-templates.cpp b/test/SemaTemplate/local-member-templates.cpp
new file mode 100644
index 0000000..3cdf5df
--- /dev/null
+++ b/test/SemaTemplate/local-member-templates.cpp
@@ -0,0 +1,76 @@
+// RUN: %clang_cc1 -std=c++1y -verify %s
+// RUN: %clang_cc1 -std=c++1y -verify %s -fdelayed-template-parsing
+
+namespace nested_local_templates_1 {
+
+template <class T> struct Outer {
+  template <class U> int outer_mem(T t, U u) {
+    struct Inner {
+      template <class V> int inner_mem(T t, U u, V v) {
+        struct InnerInner {
+          template <class W> int inner_inner_mem(W w, T t, U u, V v) {
+            return 0;
+          }
+        };
+        InnerInner().inner_inner_mem("abc", t, u, v);
+        return 0;
+      }
+    };
+    Inner i;
+    i.inner_mem(t, u, 3.14);
+    return 0;
+  }
+
+  template <class U> int outer_mem(T t, U *u);
+};
+
+template int Outer<int>::outer_mem(int, char);
+
+template <class T> template <class U> int Outer<T>::outer_mem(T t, U *u) {
+  struct Inner {
+    template <class V>
+    int inner_mem(T t, U u, V v) { //expected-note{{candidate function}}
+      struct InnerInner {
+        template <class W> int inner_inner_mem(W w, T t, U u, V v) { return 0; }
+      };
+      InnerInner().inner_inner_mem("abc", t, u, v);
+      return 0;
+    }
+  };
+  Inner i;
+  i.inner_mem(t, U{}, i);
+  i.inner_mem(t, u, 3.14); //expected-error{{no matching member function for call to 'inner}}
+  return 0;
+}
+
+template int Outer<int>::outer_mem(int, char *); //expected-note{{in instantiation of function}}
+
+} // end ns
+
+namespace nested_local_templates_2 {
+
+template <class T> struct Outer {
+  template <class U> void outer_mem(T t, U u) {
+    struct Inner {
+      template <class V> struct InnerTemplateClass {
+        template <class W>
+        void itc_mem(T t, U u, V v, W w) { //expected-note{{candidate function}}
+          struct InnerInnerInner {
+            template <class X> void iii_mem(X x) {}
+          };
+          InnerInnerInner i;
+          i.iii_mem("abc");
+        }
+      };
+    };
+    Inner i;
+    typename Inner::template InnerTemplateClass<Inner> ii;
+    ii.itc_mem(t, u, i, "jim");
+    ii.itc_mem(t, u, 0, "abd"); //expected-error{{no matching member function}}
+  }
+};
+
+template void
+Outer<int>::outer_mem(int, char); //expected-note{{in instantiation of}}
+
+}