[clang] 237c2a2 - DR458: Search template parameter scopes in the right order.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Tue Jun 16 19:41:29 PDT 2020


Author: Richard Smith
Date: 2020-06-16T19:41:14-07:00
New Revision: 237c2a23b6d4fa953f5ae910dccf492db61bb959

URL: https://github.com/llvm/llvm-project/commit/237c2a23b6d4fa953f5ae910dccf492db61bb959
DIFF: https://github.com/llvm/llvm-project/commit/237c2a23b6d4fa953f5ae910dccf492db61bb959.diff

LOG: DR458: Search template parameter scopes in the right order.

C++ unqualified name lookup searches template parameter scopes
immediately after finishing searching the entity the parameters belong
to. (Eg, for a class template, you search the template parameter scope
after looking in that class template and its base classes and before
looking in the scope containing the class template.) This is complicated
by the fact that scope lookup within a template parameter scope looks in
a different sequence of places prior to reaching the end of the
declarator-id in the template declaration.

We used to approximate the proper lookup rule with a hack in the scope /
decl context walk inside name lookup. Now we instead compute the lookup
parent for each template parameter scope. This gets the right answer and
as a bonus is substantially simpler and more uniform.

In order to get this right, we now make sure to enter a distinct Scope
for each template parameter scope. (The fact that we didn't before was
already a bug, but not really observable most of the time, since
template parameters can't shadow each other.)

Added: 
    

Modified: 
    clang/include/clang/Parse/Parser.h
    clang/include/clang/Sema/Scope.h
    clang/lib/AST/DeclBase.cpp
    clang/lib/Parse/ParseExprCXX.cpp
    clang/lib/Parse/ParseTemplate.cpp
    clang/lib/Sema/SemaDecl.cpp
    clang/lib/Sema/SemaLookup.cpp
    clang/lib/Sema/SemaTemplate.cpp
    clang/test/CXX/drs/dr4xx.cpp
    clang/test/CXX/temp/temp.res/temp.local/p8.cpp
    clang/test/SemaCXX/lambda-expressions.cpp
    clang/www/cxx_dr_status.html

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 1ae219781c69..31840694da27 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -1088,6 +1088,31 @@ class Parser : public CodeCompletionHandler {
     }
   };
 
+  /// Introduces zero or more scopes for parsing. The scopes will all be exited
+  /// when the object is destroyed.
+  class MultiParseScope {
+    Parser &Self;
+    unsigned NumScopes = 0;
+
+    MultiParseScope(const MultiParseScope&) = delete;
+
+  public:
+    MultiParseScope(Parser &Self) : Self(Self) {}
+    void Enter(unsigned ScopeFlags) {
+      Self.EnterScope(ScopeFlags);
+      ++NumScopes;
+    }
+    void Exit() {
+      while (NumScopes) {
+        Self.ExitScope();
+        --NumScopes;
+      }
+    }
+    ~MultiParseScope() {
+      Exit();
+    }
+  };
+
   /// EnterScope - Start a new scope.
   void EnterScope(unsigned ScopeFlags);
 
@@ -3240,7 +3265,7 @@ class Parser : public CodeCompletionHandler {
       DeclaratorContext Context, const ParsedTemplateInfo &TemplateInfo,
       ParsingDeclRAIIObject &DiagsFromParams, SourceLocation &DeclEnd,
       ParsedAttributes &AccessAttrs, AccessSpecifier AS = AS_none);
-  bool ParseTemplateParameters(unsigned Depth,
+  bool ParseTemplateParameters(MultiParseScope &TemplateScopes, unsigned Depth,
                                SmallVectorImpl<NamedDecl *> &TemplateParams,
                                SourceLocation &LAngleLoc,
                                SourceLocation &RAngleLoc);

diff  --git a/clang/include/clang/Sema/Scope.h b/clang/include/clang/Sema/Scope.h
index 9b8f1415a1e3..b7260f15fe1b 100644
--- a/clang/include/clang/Sema/Scope.h
+++ b/clang/include/clang/Sema/Scope.h
@@ -322,8 +322,21 @@ class Scope {
   /// declared in.
   bool isDeclScope(const Decl *D) const { return DeclsInScope.count(D) != 0; }
 
-  DeclContext *getEntity() const { return Entity; }
-  void setEntity(DeclContext *E) { Entity = E; }
+  /// Get the entity corresponding to this scope.
+  DeclContext *getEntity() const {
+    return isTemplateParamScope() ? nullptr : Entity;
+  }
+
+  /// Get the DeclContext in which to continue unqualified lookup after a
+  /// lookup in this scope.
+  DeclContext *getLookupEntity() const { return Entity; }
+
+  void setEntity(DeclContext *E) {
+    assert(!isTemplateParamScope() &&
+           "entity associated with template param scope");
+    Entity = E;
+  }
+  void setLookupEntity(DeclContext *E) { Entity = E; }
 
   /// Determine whether any unrecoverable errors have occurred within this
   /// scope. Note that this may return false even if the scope contains invalid

diff  --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index 2aab53f4fa90..50ad0255f838 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/lib/AST/DeclBase.cpp
@@ -241,7 +241,7 @@ TemplateDecl *Decl::getDescribedTemplate() const {
 }
 
 bool Decl::isTemplated() const {
-  // A declaration is dependent if it is a template or a template pattern, or
+  // A declaration is templated if it is a template or a template pattern, or
   // is within (lexcially for a friend, semantically otherwise) a dependent
   // context.
   // FIXME: Should local extern declarations be treated like friends?

diff  --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 48277dc85466..aa35200c33b6 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -1258,17 +1258,16 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
   };
 
   // FIXME: Consider allowing this as an extension for GCC compatibiblity.
-  const bool HasExplicitTemplateParams = Tok.is(tok::less);
-  ParseScope TemplateParamScope(this, Scope::TemplateParamScope,
-                                /*EnteredScope=*/HasExplicitTemplateParams);
-  if (HasExplicitTemplateParams) {
+  MultiParseScope TemplateParamScope(*this);
+  if (Tok.is(tok::less)) {
     Diag(Tok, getLangOpts().CPlusPlus20
                   ? diag::warn_cxx17_compat_lambda_template_parameter_list
                   : diag::ext_lambda_template_parameter_list);
 
     SmallVector<NamedDecl*, 4> TemplateParams;
     SourceLocation LAngleLoc, RAngleLoc;
-    if (ParseTemplateParameters(CurTemplateDepthTracker.getDepth(),
+    if (ParseTemplateParameters(TemplateParamScope,
+                                CurTemplateDepthTracker.getDepth(),
                                 TemplateParams, LAngleLoc, RAngleLoc)) {
       Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope());
       return ExprError();

diff  --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp
index 16aecffa494a..847c513b5baa 100644
--- a/clang/lib/Parse/ParseTemplate.cpp
+++ b/clang/lib/Parse/ParseTemplate.cpp
@@ -67,8 +67,7 @@ Decl *Parser::ParseTemplateDeclarationOrSpecialization(
   assert(Tok.isOneOf(tok::kw_export, tok::kw_template) &&
          "Token does not start a template declaration.");
 
-  // Enter template-parameter scope.
-  ParseScope TemplateParmScope(this, Scope::TemplateParamScope);
+  MultiParseScope TemplateParamScopes(*this);
 
   // Tell the action that names should be checked in the context of
   // the declaration to come.
@@ -116,7 +115,8 @@ Decl *Parser::ParseTemplateDeclarationOrSpecialization(
     // Parse the '<' template-parameter-list '>'
     SourceLocation LAngleLoc, RAngleLoc;
     SmallVector<NamedDecl*, 4> TemplateParams;
-    if (ParseTemplateParameters(CurTemplateDepthTracker.getDepth(),
+    if (ParseTemplateParameters(TemplateParamScopes,
+                                CurTemplateDepthTracker.getDepth(),
                                 TemplateParams, LAngleLoc, RAngleLoc)) {
       // Skip until the semi-colon or a '}'.
       SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
@@ -150,9 +150,6 @@ Decl *Parser::ParseTemplateDeclarationOrSpecialization(
         TemplateParams, RAngleLoc, OptionalRequiresClauseConstraintER.get()));
   } while (Tok.isOneOf(tok::kw_export, tok::kw_template));
 
-  unsigned NewFlags = getCurScope()->getFlags() & ~Scope::TemplateParamScope;
-  ParseScopeFlags TemplateScopeFlags(this, NewFlags, isSpecialization);
-
   // Parse the actual template declaration.
   if (Tok.is(tok::kw_concept))
     return ParseConceptDefinition(
@@ -430,8 +427,9 @@ Parser::ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo,
 ///
 /// \returns true if an error occurred, false otherwise.
 bool Parser::ParseTemplateParameters(
-    unsigned Depth, SmallVectorImpl<NamedDecl *> &TemplateParams,
-    SourceLocation &LAngleLoc, SourceLocation &RAngleLoc) {
+    MultiParseScope &TemplateScopes, unsigned Depth,
+    SmallVectorImpl<NamedDecl *> &TemplateParams, SourceLocation &LAngleLoc,
+    SourceLocation &RAngleLoc) {
   // Get the template parameter list.
   if (!TryConsumeToken(tok::less, LAngleLoc)) {
     Diag(Tok.getLocation(), diag::err_expected_less_after) << "template";
@@ -440,8 +438,11 @@ bool Parser::ParseTemplateParameters(
 
   // Try to parse the template parameter list.
   bool Failed = false;
-  if (!Tok.is(tok::greater) && !Tok.is(tok::greatergreater))
+  // FIXME: Missing greatergreatergreater support.
+  if (!Tok.is(tok::greater) && !Tok.is(tok::greatergreater)) {
+    TemplateScopes.Enter(Scope::TemplateParamScope);
     Failed = ParseTemplateParameterList(Depth, TemplateParams);
+  }
 
   if (Tok.is(tok::greatergreater)) {
     // No diagnostic required here: a template-parameter-list can only be
@@ -850,9 +851,9 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
   SmallVector<NamedDecl*,8> TemplateParams;
   SourceLocation LAngleLoc, RAngleLoc;
   {
-    ParseScope TemplateParmScope(this, Scope::TemplateParamScope);
-    if (ParseTemplateParameters(Depth + 1, TemplateParams, LAngleLoc,
-                               RAngleLoc)) {
+    MultiParseScope TemplateParmScope(*this);
+    if (ParseTemplateParameters(TemplateParmScope, Depth + 1, TemplateParams,
+                                LAngleLoc, RAngleLoc)) {
       return nullptr;
     }
   }
@@ -1630,7 +1631,7 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) {
   Sema::ContextRAII GlobalSavedContext(
       Actions, Actions.Context.getTranslationUnitDecl());
 
-  SmallVector<ParseScope*, 4> TemplateParamScopeStack;
+  MultiParseScope Scopes(*this);
 
   // Get the list of DeclContexts to reenter. For inline methods, we only want
   // to push the DeclContext of the outermost class. This matches the way the
@@ -1655,13 +1656,12 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) {
 
   // Reenter template scopes from outermost to innermost.
   for (ContainingDC CDC : reverse(DeclContextsToReenter)) {
-    TemplateParamScopeStack.push_back(
-        new ParseScope(this, Scope::TemplateParamScope));
+    Scopes.Enter(Scope::TemplateParamScope);
     unsigned NumParamLists = Actions.ActOnReenterTemplateScope(
         getCurScope(), cast<Decl>(CDC.getDC()));
     CurTemplateDepthTracker.addDepth(NumParamLists);
     if (CDC.shouldPushDC()) {
-      TemplateParamScopeStack.push_back(new ParseScope(this, Scope::DeclScope));
+      Scopes.Enter(Scope::DeclScope);
       Actions.PushDeclContext(Actions.getCurScope(), CDC.getDC());
     }
   }
@@ -1709,13 +1709,6 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) {
     } else
       Actions.ActOnFinishFunctionBody(LPT.D, nullptr);
   }
-
-  // Exit scopes.
-  FnScope.Exit();
-  SmallVectorImpl<ParseScope *>::reverse_iterator I =
-   TemplateParamScopeStack.rbegin();
-  for (; I != TemplateParamScopeStack.rend(); ++I)
-    delete *I;
 }
 
 /// Lex a delayed template function for late parsing.

diff  --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 2bf16d138d5a..1d046c776709 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -1358,6 +1358,50 @@ void Sema::EnterDeclaratorContext(Scope *S, DeclContext *DC) {
 
   CurContext = DC;
   S->setEntity(DC);
+
+  if (!S->getParent()->isTemplateParamScope())
+    return;
+
+  // Also set the corresponding entities for all immediately-enclosing template
+  // parameter scopes.
+  //
+  // C++20 [temp.local]p7:
+  //   In the definition of a member of a class template that appears outside
+  //   of the class template definition, the name of a member of the class
+  //   template hides the name of a template-parameter of any enclosing class
+  //   templates (but not a template-parameter of the member if the member is a
+  //   class or function template).
+  // C++20 [temp.local]p9:
+  //   In the definition of a class template or in the definition of a member
+  //   of such a template that appears outside of the template definition, for
+  //   each non-dependent base class (13.8.2.1), if the name of the base class
+  //   or the name of a member of the base class is the same as the name of a
+  //   template-parameter, the base class name or member name hides the
+  //   template-parameter name (6.4.10).
+  //
+  // This means that a template parameter scope should be searched immediately
+  // after searching the DeclContext for which it is a template parameter
+  // scope. For example, for
+  //   template<typename T> template<typename U> template<typename V>
+  //     void N::A<T>::B<U>::f(...)
+  // we search V then B<U> (and base classes) then U then A<T> (and base
+  // classes) then T then N then ::.
+  unsigned ScopeDepth = getTemplateDepth(S);
+  for (Scope *OuterS = S->getParent(); OuterS && OuterS->isTemplateParamScope();
+       OuterS = OuterS->getParent(), --ScopeDepth) {
+    auto *SearchDCAfterScope = DC;
+    for (; DC; DC = DC->getLookupParent()) {
+      if (auto *TD = cast<Decl>(DC)->getDescribedTemplate()) {
+        unsigned DCDepth = TD->getTemplateParameters()->getDepth() + 1;
+        if (DCDepth > ScopeDepth)
+          continue;
+        if (ScopeDepth == DCDepth)
+          SearchDCAfterScope = DC = DC->getLookupParent();
+        break;
+      }
+    }
+    OuterS->setLookupEntity(SearchDCAfterScope);
+  }
 }
 
 void Sema::ExitDeclaratorContext(Scope *S) {

diff  --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 06a4dfa0a636..5757eaf3fac0 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -1153,73 +1153,14 @@ static bool isNamespaceOrTranslationUnitScope(Scope *S) {
   return false;
 }
 
-// Find the next outer declaration context from this scope. This
-// routine actually returns the semantic outer context, which may
-// 
diff er 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 = S->getEntity();
-  DeclContext *Lexical = nullptr;
-  for (Scope *OuterS = S->getParent(); OuterS;
-       OuterS = OuterS->getParent()) {
-    if (OuterS->getEntity()) {
-      Lexical = OuterS->getEntity();
-      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();
-
-  // 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);
+/// Find the outer declaration context from this scope. This indicates the
+/// context that we should search up to (exclusive) before considering the
+/// parent of the specified scope.
+static DeclContext *findOuterContext(Scope *S) {
+  for (Scope *OuterS = S->getParent(); OuterS; OuterS = OuterS->getParent())
+    if (DeclContext *DC = OuterS->getLookupEntity())
+      return DC;
+  return nullptr;
 }
 
 namespace {
@@ -1286,13 +1227,11 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
   UnqualUsingDirectiveSet UDirs(*this);
   bool VisitedUsingDirectives = false;
   bool LeftStartingScope = false;
-  DeclContext *OutsideOfTemplateParamDC = nullptr;
 
   // When performing a scope lookup, we want to find local extern decls.
   FindLocalExternScope FindLocals(R);
 
   for (; S && !isNamespaceOrTranslationUnitScope(S); S = S->getParent()) {
-    DeclContext *Ctx = S->getEntity();
     bool SearchNamespaceScope = true;
     // Check whether the IdResolver has anything in this scope.
     for (; I != IEnd && S->isDeclScope(*I); ++I) {
@@ -1324,7 +1263,8 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
     if (!SearchNamespaceScope) {
       R.resolveKind();
       if (S->isClassScope())
-        if (CXXRecordDecl *Record = dyn_cast_or_null<CXXRecordDecl>(Ctx))
+        if (CXXRecordDecl *Record =
+                dyn_cast_or_null<CXXRecordDecl>(S->getEntity()))
           R.setNamingClass(Record);
       return true;
     }
@@ -1338,24 +1278,8 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
       return false;
     }
 
-    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 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 = nullptr;
-    }
-
-    if (Ctx) {
-      DeclContext *OuterCtx;
-      bool SearchAfterTemplateScope;
-      std::tie(OuterCtx, SearchAfterTemplateScope) = findOuterContext(S);
-      if (SearchAfterTemplateScope)
-        OutsideOfTemplateParamDC = OuterCtx;
-
+    if (DeclContext *Ctx = S->getLookupEntity()) {
+      DeclContext *OuterCtx = findOuterContext(S);
       for (; Ctx && !Ctx->Equals(OuterCtx); Ctx = Ctx->getLookupParent()) {
         // We do not directly look into transparent contexts, since
         // those entities will be found in the nearest enclosing
@@ -1480,25 +1404,9 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
       return true;
     }
 
-    DeclContext *Ctx = 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 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 = nullptr;
-    }
-
+    DeclContext *Ctx = S->getLookupEntity();
     if (Ctx) {
-      DeclContext *OuterCtx;
-      bool SearchAfterTemplateScope;
-      std::tie(OuterCtx, SearchAfterTemplateScope) = findOuterContext(S);
-      if (SearchAfterTemplateScope)
-        OutsideOfTemplateParamDC = OuterCtx;
-
+      DeclContext *OuterCtx = findOuterContext(S);
       for (; Ctx && !Ctx->Equals(OuterCtx); Ctx = Ctx->getLookupParent()) {
         // We do not directly look into transparent contexts, since
         // those entities will be found in the nearest enclosing
@@ -3995,14 +3903,12 @@ class LookupVisibleHelper {
       }
     }
 
-    // FIXME: C++ [temp.local]p8
-    DeclContext *Entity = nullptr;
-    if (S->getEntity()) {
+    DeclContext *Entity = S->getLookupEntity();
+    if (Entity) {
       // 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 = S->getEntity();
-      DeclContext *OuterCtx = findOuterContext(S).first; // FIXME
+      DeclContext *OuterCtx = findOuterContext(S);
 
       for (DeclContext *Ctx = Entity; Ctx && !Ctx->Equals(OuterCtx);
            Ctx = Ctx->getLookupParent()) {

diff  --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 073b4e818a24..6bf46f273a02 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -51,8 +51,7 @@ unsigned Sema::getTemplateDepth(Scope *S) const {
 
   // Each template parameter scope represents one level of template parameter
   // depth.
-  for (Scope *TempParamScope = S->getTemplateParamParent();
-       TempParamScope && !Depth;
+  for (Scope *TempParamScope = S->getTemplateParamParent(); TempParamScope;
        TempParamScope = TempParamScope->getParent()->getTemplateParamParent()) {
     ++Depth;
   }

diff  --git a/clang/test/CXX/drs/dr4xx.cpp b/clang/test/CXX/drs/dr4xx.cpp
index 2c762237037d..ff90ee82d4d4 100644
--- a/clang/test/CXX/drs/dr4xx.cpp
+++ b/clang/test/CXX/drs/dr4xx.cpp
@@ -690,7 +690,7 @@ namespace dr457 { // dr457: yes
   };
 }
 
-namespace dr458 { // dr458: no
+namespace dr458 { // dr458: 11
   struct A {
     int T;
     int f();
@@ -706,9 +706,9 @@ namespace dr458 { // dr458: no
   int A::f() {
     return T;
   }
-  template<typename T>
+  template<typename T> // expected-note {{declared here}}
   int A::g() {
-    return T; // FIXME: this is invalid, it finds the template parameter
+    return T; // expected-error {{'T' does not refer to a value}}
   }
 
   template<typename T>
@@ -719,9 +719,9 @@ namespace dr458 { // dr458: no
   int B<T>::g() {
     return T;
   }
-  template<typename U> template<typename T>
+  template<typename U> template<typename T> // expected-note {{declared here}}
   int B<U>::h() {
-    return T; // FIXME: this is invalid, it finds the template parameter
+    return T; // expected-error {{'T' does not refer to a value}}
   }
 }
 

diff  --git a/clang/test/CXX/temp/temp.res/temp.local/p8.cpp b/clang/test/CXX/temp/temp.res/temp.local/p8.cpp
index fecfed06f109..c2b4c1950ea5 100644
--- a/clang/test/CXX/temp/temp.res/temp.local/p8.cpp
+++ b/clang/test/CXX/temp/temp.res/temp.local/p8.cpp
@@ -1,5 +1,4 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
-// expected-no-diagnostics
 
 namespace N { 
   enum { C };
@@ -52,3 +51,63 @@ void N::Y::f(D) {
   D d;
 }
 
+// Ensure we properly interleave the searches within classes and template parameter lists.
+namespace SearchClassBetweenTemplateParameterLists {
+  int AA, BB; // none of the below lookups should ever consider these
+
+  template<typename T> struct A {
+    using AA = void;
+    template<typename U> struct B {
+      using BB = void;
+      void f(U);
+      void g(U);
+      void h(T);
+      void i(T);
+      template<typename V> void j(V);
+      template<typename V> void k(U);
+    };
+  };
+
+  // Search order for the below is:
+  // 1) template parameter scope of the function itself (if any)
+  // 2) class of which function is a member
+  // 3) template parameter scope of inner class
+  // 4) class of which class is a member
+  // 5) template parameter scope of outer class
+
+  // OK, 'AA' found in (3)
+  template<typename T> template<typename AA>
+  void A<T>::B<AA>::f(AA) {
+    AA aa;
+  }
+
+  // error, 'BB' found in (2)
+  template<typename T> template<typename BB>
+  void A<T>::B<BB>::g(BB) { // expected-error {{does not match}}
+    BB bb; // expected-error {{incomplete type}}
+  }
+
+  // error, 'AA' found in (4)
+  template<typename AA> template<typename U>
+  void A<AA>::B<U>::h(AA) { // expected-error {{does not match}}
+    AA aa; // expected-error {{incomplete type}}
+  }
+
+  // error, 'BB' found in (2)
+  template<typename BB> template<typename U>
+  void A<BB>::B<U>::i(BB) { // expected-error {{does not match}}
+    BB bb; // expected-error {{incomplete type}}
+  }
+
+  // OK, 'BB' found in (1)
+  template<typename T> template<typename U> template<typename BB>
+  void A<T>::B<U>::j(BB) {
+    BB bb;
+  }
+
+  // error, 'BB' found in (2)
+  template<typename T> template<typename BB> template<typename V>
+  void A<T>::B<BB>::k(V) { // expected-error {{does not match}}
+    BB bb; // expected-error {{incomplete type}}
+  }
+}

diff  --git a/clang/test/SemaCXX/lambda-expressions.cpp b/clang/test/SemaCXX/lambda-expressions.cpp
index 0f4edc4d1f34..3240d5351fc5 100644
--- a/clang/test/SemaCXX/lambda-expressions.cpp
+++ b/clang/test/SemaCXX/lambda-expressions.cpp
@@ -601,16 +601,24 @@ namespace ConversionOperatorDoesNotHaveDeducedReturnType {
 #if __cplusplus > 201402L
     friend constexpr auto T::operator()(int) const;
     friend constexpr T::operator ExpectedTypeT() const noexcept;
+
+    template<typename T>
+      friend constexpr void U::operator()(T&) const;
+    // FIXME: This should not match; the return type is specified as behaving
+    // "as if it were a decltype-specifier denoting the return type of
+    // [operator()]", which is not equivalent to this alias template.
+    template<typename T>
+      friend constexpr U::operator ExpectedTypeU<T>() const noexcept;
 #else
     friend auto T::operator()(int) const;
     friend T::operator ExpectedTypeT() const;
-#endif
 
-    // FIXME: The first of these should match. The second should not.
     template<typename T>
-      friend void U::operator()(T&) const; // expected-error {{does not match}}
+      friend void U::operator()(T&) const;
+    // FIXME: This should not match, as above.
     template<typename T>
-      friend U::operator ExpectedTypeU<T>() const; // expected-error {{does not match}}
+      friend U::operator ExpectedTypeU<T>() const;
+#endif
 
   private:
     int n;

diff  --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
index 4abdc0fa2639..22755e4b20ea 100755
--- a/clang/www/cxx_dr_status.html
+++ b/clang/www/cxx_dr_status.html
@@ -2789,7 +2789,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
     <td><a href="https://wg21.link/cwg458">458</a></td>
     <td>C++11</td>
     <td>Hiding of member template parameters by other members</td>
-    <td class="none" align="center">No</td>
+    <td class="unreleased" align="center">Clang 11</td>
   </tr>
   <tr class="open" id="459">
     <td><a href="https://wg21.link/cwg459">459</a></td>
@@ -12307,7 +12307,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
     <td><a href="https://wg21.link/cwg2082">2082</a></td>
     <td>CD4</td>
     <td>Referring to parameters in unevaluated operands of default arguments</td>
-    <td class="none" align="center">Unknown</td>
+    <td class="unreleased" align="center">Clang 11</td>
   </tr>
   <tr id="2083">
     <td><a href="https://wg21.link/cwg2083">2083</a></td>
@@ -13891,7 +13891,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
     <td><a href="https://wg21.link/cwg2346">2346</a></td>
     <td>DRWP</td>
     <td>Local variables in default arguments</td>
-    <td class="none" align="center">Unknown</td>
+    <td class="unreleased" align="center">Clang 11</td>
   </tr>
   <tr id="2347">
     <td><a href="https://wg21.link/cwg2347">2347</a></td>


        


More information about the cfe-commits mailing list