[clang] [Clang] Implement resolution for CWG1835 (PR #92957)

Krystian Stasiowski via cfe-commits cfe-commits at lists.llvm.org
Mon Jun 3 06:35:19 PDT 2024


https://github.com/sdkrystian updated https://github.com/llvm/llvm-project/pull/92957

>From 2e4fe34128390910ef440512950dd98d8cafe034 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Tue, 21 May 2024 13:15:24 -0400
Subject: [PATCH 01/11] [WIP][Clang] Implement resolution for CWG1835

---
 clang/include/clang/Sema/DeclSpec.h           |  8 +++
 clang/include/clang/Sema/Sema.h               |  2 +-
 clang/lib/Parse/ParseDeclCXX.cpp              |  2 +-
 clang/lib/Parse/ParseExpr.cpp                 |  9 +--
 clang/lib/Sema/SemaCXXScopeSpec.cpp           | 60 +++++++++++++------
 clang/lib/Sema/SemaExprMember.cpp             | 10 +---
 clang/lib/Sema/SemaPseudoObject.cpp           | 16 ++---
 clang/lib/Sema/SemaTemplate.cpp               | 22 ++++---
 clang/lib/Sema/TreeTransform.h                | 15 +++++
 .../basic.lookup.classref/p1-cxx11.cpp        | 16 +++--
 .../basic.lookup/basic.lookup.classref/p1.cpp | 16 +++--
 .../class.derived/class.member.lookup/p8.cpp  |  4 +-
 clang/test/CXX/drs/cwg1xx.cpp                 |  7 ++-
 clang/test/SemaCXX/static-assert-cxx17.cpp    |  2 +-
 .../SemaTemplate/temp_arg_nontype_cxx20.cpp   |  2 +-
 15 files changed, 127 insertions(+), 64 deletions(-)

diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h
index 23bc780e04979..c6d87ca1683a8 100644
--- a/clang/include/clang/Sema/DeclSpec.h
+++ b/clang/include/clang/Sema/DeclSpec.h
@@ -75,6 +75,7 @@ class CXXScopeSpec {
   SourceRange Range;
   NestedNameSpecifierLocBuilder Builder;
   ArrayRef<TemplateParameterList *> TemplateParamLists;
+  NamedDecl *FoundFirstQualifierInScope;
 
 public:
   SourceRange getRange() const { return Range; }
@@ -91,6 +92,13 @@ class CXXScopeSpec {
     return TemplateParamLists;
   }
 
+  void setFoundFirstQualifierInScope(NamedDecl *Found) {
+    FoundFirstQualifierInScope = Found;
+  }
+  NamedDecl *getFirstQualifierFoundInScope() const {
+    return FoundFirstQualifierInScope;
+  }
+
   /// Retrieve the representation of the nested-name-specifier.
   NestedNameSpecifier *getScopeRep() const {
     return Builder.getRepresentation();
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 7dea2b6826cfd..6c3d1e65e0dfb 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -6942,7 +6942,7 @@ class Sema final : public SemaBase {
       const TemplateArgumentListInfo *TemplateArgs);
 
   ExprResult ActOnMemberAccessExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
-                                   tok::TokenKind OpKind, CXXScopeSpec &SS,
+                                   bool IsArrow, CXXScopeSpec &SS,
                                    SourceLocation TemplateKWLoc,
                                    UnqualifiedId &Member, Decl *ObjCImpDecl);
 
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 9a4a777f575b2..884e7ea8ee2de 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -720,7 +720,7 @@ Parser::DeclGroupPtrTy Parser::ParseUsingDeclaration(
       return nullptr;
     }
     CXXScopeSpec SS;
-    if (ParseOptionalCXXScopeSpecifier(SS, /*ParsedType=*/nullptr,
+    if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
                                        /*ObectHasErrors=*/false,
                                        /*EnteringConttext=*/false,
                                        /*MayBePseudoDestructor=*/nullptr,
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index eb7447fa038e4..b3c25f88b403d 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -2254,6 +2254,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
           }
           break;
         }
+
         ParseOptionalCXXScopeSpecifier(
             SS, ObjectType, LHS.get() && LHS.get()->containsErrors(),
             /*EnteringContext=*/false, &MayBePseudoDestructor);
@@ -2328,10 +2329,10 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
       }
 
       if (!LHS.isInvalid())
-        LHS = Actions.ActOnMemberAccessExpr(getCurScope(), LHS.get(), OpLoc,
-                                            OpKind, SS, TemplateKWLoc, Name,
-                                 CurParsedObjCImpl ? CurParsedObjCImpl->Dcl
-                                                   : nullptr);
+        LHS = Actions.ActOnMemberAccessExpr(
+            getCurScope(), LHS.get(), OpLoc, OpKind == tok::arrow, SS,
+            TemplateKWLoc, Name,
+            CurParsedObjCImpl ? CurParsedObjCImpl->Dcl : nullptr);
       if (!LHS.isInvalid()) {
         if (Tok.is(tok::less))
           checkPotentialAngleBracket(LHS);
diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp
index c405fbc0aa421..6efa8925d1446 100644
--- a/clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -397,11 +397,19 @@ NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) {
   while (NNS->getPrefix())
     NNS = NNS->getPrefix();
 
-  if (NNS->getKind() != NestedNameSpecifier::Identifier)
-    return nullptr;
-
-  LookupResult Found(*this, NNS->getAsIdentifier(), SourceLocation(),
-                     LookupNestedNameSpecifierName);
+  const IdentifierInfo *II = NNS->getAsIdentifier();
+  if (!II) {
+    if (const auto *DTST =
+            dyn_cast_if_present<DependentTemplateSpecializationType>(
+                NNS->getAsType()))
+      II = DTST->getIdentifier();
+    else
+      return nullptr;
+  }
+  assert(II && "Missing first qualifier in scope");
+  LookupResult Found(*this, II, SourceLocation(),
+                     NNS->getAsIdentifier() ? LookupNestedNameSpecifierName
+                                            : LookupOrdinaryName);
   LookupName(Found, S);
   assert(!Found.isAmbiguous() && "Cannot handle ambiguities here yet");
 
@@ -409,10 +417,10 @@ NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) {
     return nullptr;
 
   NamedDecl *Result = Found.getFoundDecl();
-  if (isAcceptableNestedNameSpecifier(Result))
-    return Result;
+  // if (isAcceptableNestedNameSpecifier(Result))
+  return Result;
 
-  return nullptr;
+  // return nullptr;
 }
 
 namespace {
@@ -493,12 +501,15 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
     // x->B::f, and we are looking into the type of the object.
     assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist");
     LookupCtx = computeDeclContext(ObjectType);
-    isDependent = ObjectType->isDependentType();
-  } else if (SS.isSet()) {
+    isDependent = !LookupCtx && ObjectType->isDependentType();
+  } else if (SS.isNotEmpty()) {
     // This nested-name-specifier occurs after another nested-name-specifier,
     // so look into the context associated with the prior nested-name-specifier.
     LookupCtx = computeDeclContext(SS, EnteringContext);
-    isDependent = isDependentScopeSpecifier(SS);
+    isDependent = !LookupCtx && isDependentScopeSpecifier(SS);
+    // The declaration context must be complete.
+    if (LookupCtx && RequireCompleteDeclContext(SS, LookupCtx))
+      return true;
     Found.setContextRange(SS.getRange());
   }
 
@@ -509,14 +520,28 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
     // expression or the declaration context associated with a prior
     // nested-name-specifier.
 
-    // The declaration context must be complete.
-    if (!LookupCtx->isDependentContext() &&
-        RequireCompleteDeclContext(SS, LookupCtx))
-      return true;
-
     LookupQualifiedName(Found, LookupCtx);
 
-    if (!ObjectType.isNull() && Found.empty()) {
+    isDependent |= Found.wasNotFoundInCurrentInstantiation();
+  }
+
+  bool LookupFirstQualifierInScope =
+      Found.empty() && !ObjectType.isNull() && !isDependent;
+
+  // FIXME: We should still do the lookup if the object expression is dependent,
+  // but instead of using them we should store them via
+  // setFirstQualifierFoundInScope and pretend we found nothing.
+  if (SS.isEmpty() && (ObjectType.isNull() || LookupFirstQualifierInScope)) {
+    if (S)
+      LookupName(Found, S);
+    else if (LookupFirstQualifierInScope && SS.getFirstQualifierFoundInScope())
+      Found.addDecl(SS.getFirstQualifierFoundInScope());
+
+    if (!ObjectType.isNull())
+      ObjectTypeSearchedInScope = true;
+  }
+#if 0
+    if (!ObjectType.isNull() && Found.empty() && !isDependent) {
       // C++ [basic.lookup.classref]p4:
       //   If the id-expression in a class member access is a qualified-id of
       //   the form
@@ -548,6 +573,7 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
     // Perform unqualified name lookup in the current scope.
     LookupName(Found, S);
   }
+#endif
 
   if (Found.isAmbiguous())
     return true;
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 3ae1af26d0096..6dbb0b4c398c4 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -1054,7 +1054,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
       if (RetryExpr.isUsable() && !Trap.hasErrorOccurred()) {
         CXXScopeSpec TempSS(SS);
         RetryExpr = ActOnMemberAccessExpr(
-            ExtraArgs->S, RetryExpr.get(), OpLoc, tok::arrow, TempSS,
+            ExtraArgs->S, RetryExpr.get(), OpLoc, /*IsArrow=*/true, TempSS,
             TemplateKWLoc, ExtraArgs->Id, ExtraArgs->ObjCImpDecl);
       }
       if (Trap.hasErrorOccurred())
@@ -1768,12 +1768,10 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
 ///   decl; this is an ugly hack around the fact that Objective-C
 ///   \@implementations aren't properly put in the context chain
 ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
-                                       SourceLocation OpLoc,
-                                       tok::TokenKind OpKind,
+                                       SourceLocation OpLoc, bool IsArrow,
                                        CXXScopeSpec &SS,
                                        SourceLocation TemplateKWLoc,
-                                       UnqualifiedId &Id,
-                                       Decl *ObjCImpDecl) {
+                                       UnqualifiedId &Id, Decl *ObjCImpDecl) {
   if (SS.isSet() && SS.isInvalid())
     return ExprError();
 
@@ -1791,8 +1789,6 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
   DecomposeUnqualifiedId(Id, TemplateArgsBuffer,
                          NameInfo, TemplateArgs);
 
-  bool IsArrow = (OpKind == tok::arrow);
-
   if (getLangOpts().HLSL && IsArrow)
     return ExprError(Diag(OpLoc, diag::err_hlsl_operator_unsupported) << 2);
 
diff --git a/clang/lib/Sema/SemaPseudoObject.cpp b/clang/lib/Sema/SemaPseudoObject.cpp
index fdb584ceb8105..86c303e67bc1d 100644
--- a/clang/lib/Sema/SemaPseudoObject.cpp
+++ b/clang/lib/Sema/SemaPseudoObject.cpp
@@ -1395,10 +1395,10 @@ ExprResult MSPropertyOpBuilder::buildGet() {
   GetterName.setIdentifier(II, RefExpr->getMemberLoc());
   CXXScopeSpec SS;
   SS.Adopt(RefExpr->getQualifierLoc());
-  ExprResult GetterExpr =
-      S.ActOnMemberAccessExpr(S.getCurScope(), InstanceBase, SourceLocation(),
-                              RefExpr->isArrow() ? tok::arrow : tok::period, SS,
-                              SourceLocation(), GetterName, nullptr);
+  ExprResult GetterExpr = S.ActOnMemberAccessExpr(
+      S.getCurScope(), InstanceBase, /*OpLoc=*/SourceLocation(),
+      RefExpr->isArrow(), SS, /*TemplateKWLoc=*/SourceLocation(), GetterName,
+      /*ObjCImpDecl=*/nullptr);
   if (GetterExpr.isInvalid()) {
     S.Diag(RefExpr->getMemberLoc(),
            diag::err_cannot_find_suitable_accessor) << 0 /* getter */
@@ -1424,10 +1424,10 @@ ExprResult MSPropertyOpBuilder::buildSet(Expr *op, SourceLocation sl,
   SetterName.setIdentifier(II, RefExpr->getMemberLoc());
   CXXScopeSpec SS;
   SS.Adopt(RefExpr->getQualifierLoc());
-  ExprResult SetterExpr =
-      S.ActOnMemberAccessExpr(S.getCurScope(), InstanceBase, SourceLocation(),
-                              RefExpr->isArrow() ? tok::arrow : tok::period, SS,
-                              SourceLocation(), SetterName, nullptr);
+  ExprResult SetterExpr = S.ActOnMemberAccessExpr(
+      S.getCurScope(), InstanceBase, /*OpLoc=*/SourceLocation(),
+      RefExpr->isArrow(), SS, /*TemplateKWLoc=*/SourceLocation(), SetterName,
+      /*ObjCImpDecl=*/nullptr);
   if (SetterExpr.isInvalid()) {
     S.Diag(RefExpr->getMemberLoc(),
            diag::err_cannot_find_suitable_accessor) << 1 /* setter */
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 40a759ea330de..6fc290e382b0f 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -214,6 +214,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
                          &AssumedTemplate,
                          /*AllowTypoCorrection=*/!Disambiguation))
     return TNK_Non_template;
+
   MemberOfUnknownSpecialization = R.wasNotFoundInCurrentInstantiation();
 
   if (AssumedTemplate != AssumedTemplateKind::None) {
@@ -433,7 +434,6 @@ bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS,
   }
 
   bool ObjectTypeSearchedInScope = false;
-  bool AllowFunctionTemplatesInLookup = true;
   if (LookupCtx) {
     // Perform "qualified" name lookup into the declaration context we
     // computed, which is either the type of the base of a member access
@@ -452,7 +452,14 @@ bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS,
     IsDependent |= Found.wasNotFoundInCurrentInstantiation();
   }
 
-  if (SS.isEmpty() && (ObjectType.isNull() || Found.empty())) {
+  bool LookupFirstQualifierInScope =
+      Found.getLookupKind() != LookupMemberName && Found.empty() &&
+      !ObjectType.isNull() && !IsDependent;
+
+  // FIXME: We should still do the lookup if the object expression is dependent,
+  // but instead of using them we should store them via
+  // setFirstQualifierFoundInScope and pretend we found nothing.
+  if (SS.isEmpty() && (ObjectType.isNull() || LookupFirstQualifierInScope)) {
     // C++ [basic.lookup.classref]p1:
     //   In a class member access expression (5.2.5), if the . or -> token is
     //   immediately followed by an identifier followed by a <, the
@@ -464,14 +471,11 @@ bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS,
     //   template.
     if (S)
       LookupName(Found, S);
+    else if (LookupFirstQualifierInScope && SS.getFirstQualifierFoundInScope())
+      Found.addDecl(SS.getFirstQualifierFoundInScope());
 
-    if (!ObjectType.isNull()) {
-      //  FIXME: We should filter out all non-type templates here, particularly
-      //  variable templates and concepts. But the exclusion of alias templates
-      //  and template template parameters is a wording defect.
-      AllowFunctionTemplatesInLookup = false;
+    if (!ObjectType.isNull())
       ObjectTypeSearchedInScope = true;
-    }
 
     IsDependent |= Found.wasNotFoundInCurrentInstantiation();
   }
@@ -542,7 +546,7 @@ bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS,
 
   NamedDecl *ExampleLookupResult =
       Found.empty() ? nullptr : Found.getRepresentativeDecl();
-  FilterAcceptableTemplateNames(Found, AllowFunctionTemplatesInLookup);
+  FilterAcceptableTemplateNames(Found);
   if (Found.empty()) {
     if (IsDependent) {
       Found.setNotFoundInCurrentInstantiation();
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index efba99b85b0fb..c037f93bbbc3f 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -2894,6 +2894,8 @@ class TreeTransform {
 
     CXXScopeSpec SS;
     SS.Adopt(QualifierLoc);
+    if (FirstQualifierInScope)
+      SS.setFoundFirstQualifierInScope(FirstQualifierInScope);
 
     Base = BaseResult.get();
     QualType BaseType = Base->getType();
@@ -3582,6 +3584,9 @@ class TreeTransform {
     CXXScopeSpec SS;
     SS.Adopt(QualifierLoc);
 
+    if (FirstQualifierInScope)
+      SS.setFoundFirstQualifierInScope(FirstQualifierInScope);
+
     return SemaRef.BuildMemberReferenceExpr(BaseE, BaseType,
                                             OperatorLoc, IsArrow,
                                             SS, TemplateKWLoc,
@@ -3605,6 +3610,9 @@ class TreeTransform {
     CXXScopeSpec SS;
     SS.Adopt(QualifierLoc);
 
+    if (FirstQualifierInScope)
+      SS.setFoundFirstQualifierInScope(FirstQualifierInScope);
+
     return SemaRef.BuildMemberReferenceExpr(BaseE, BaseType,
                                             OperatorLoc, IsArrow,
                                             SS, TemplateKWLoc,
@@ -4383,6 +4391,8 @@ NestedNameSpecifierLoc TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
   insertNNS(NNS);
 
   CXXScopeSpec SS;
+  if (FirstQualifierInScope)
+    SS.setFoundFirstQualifierInScope(FirstQualifierInScope);
   while (!Qualifiers.empty()) {
     NestedNameSpecifierLoc Q = Qualifiers.pop_back_val();
     NestedNameSpecifier *QNNS = Q.getNestedNameSpecifier();
@@ -5180,6 +5190,9 @@ TypeSourceInfo *TreeTransform<Derived>::TransformTSIInObjectScope(
   TypeLocBuilder TLB;
   QualType Result;
 
+  if (UnqualLookup)
+    SS.setFoundFirstQualifierInScope(UnqualLookup);
+
   if (isa<TemplateSpecializationType>(T)) {
     TemplateSpecializationTypeLoc SpecTL =
         TL.castAs<TemplateSpecializationTypeLoc>();
@@ -16173,6 +16186,8 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
   UnqualifiedId TemplateName;
   TemplateName.setIdentifier(&Name, NameLoc);
   Sema::TemplateTy Template;
+  if (FirstQualifierInScope)
+    SS.setFoundFirstQualifierInScope(FirstQualifierInScope);
   getSema().ActOnTemplateName(/*Scope=*/nullptr, SS, TemplateKWLoc,
                               TemplateName, ParsedType::make(ObjectType),
                               /*EnteringContext=*/false, Template,
diff --git a/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1-cxx11.cpp b/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1-cxx11.cpp
index 1afea99e8895c..476745537f691 100644
--- a/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1-cxx11.cpp
+++ b/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1-cxx11.cpp
@@ -55,15 +55,21 @@ namespace PR11856 {
 
   template<typename T> T *end(T*);
 
-  class X { };
+  struct X { };
+  struct Y {
+    int end;
+  };
   template <typename T>
   void Foo2() {
     T it1;
-    if (it1->end < it1->end) {
-    }
+    if (it1->end < it1->end) { }
 
     X *x;
-    if (x->end < 7) {  // expected-error{{no member named 'end' in 'PR11856::X'}}
-    }
+    if (x->end < 7) { } // expected-error{{expected '>'}}
+                        // expected-note at -1{{to match this '<'}}
+                        // expected-error at -2{{expected unqualified-id}}
+
+    Y *y;
+    if (y->end < 7) { }
   }
 }
diff --git a/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp b/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp
index e3599db18350b..cabf3f73830bc 100644
--- a/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp
+++ b/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp
@@ -86,15 +86,21 @@ namespace PR11856 {
 
   template<typename T> T *end(T*);
 
-  class X { };
+  struct X { };
+  struct Y {
+    int end;
+  };
   template <typename T>
   void Foo2() {
     T it1;
-    if (it1->end < it1->end) {
-    }
+    if (it1->end < it1->end) { }
 
     X *x;
-    if (x->end < 7) {  // expected-error{{no member named 'end' in 'PR11856::X'}}
-    }
+    if (x->end < 7) { } // expected-error{{expected '>'}}
+                        // expected-note at -1{{to match this '<'}}
+                        // expected-error at -2{{expected unqualified-id}}
+
+    Y *y;
+    if (y->end < 7) { }
   }
 }
diff --git a/clang/test/CXX/class.derived/class.member.lookup/p8.cpp b/clang/test/CXX/class.derived/class.member.lookup/p8.cpp
index 78e83c0ab4566..e9a57f739cc35 100644
--- a/clang/test/CXX/class.derived/class.member.lookup/p8.cpp
+++ b/clang/test/CXX/class.derived/class.member.lookup/p8.cpp
@@ -47,8 +47,8 @@ template<typename T>
 void DerivedT<T>::Inner() {
   Derived1T<T>::Foo();
   Derived2T<T>::Member = 42;
-  this->Derived1T<T>::Foo();
-  this->Derived2T<T>::Member = 42;
+  this->Derived1T<T>::Foo(); // expected-error{{use 'template' keyword to treat 'Derived1T' as a dependent template name}}
+  this->Derived2T<T>::Member = 42; // expected-error{{use 'template' keyword to treat 'Derived2T' as a dependent template name}}
   this->Foo(); // expected-error{{non-static member 'Foo' found in multiple base-class subobjects of type 'BaseT<int>'}}
 }
 
diff --git a/clang/test/CXX/drs/cwg1xx.cpp b/clang/test/CXX/drs/cwg1xx.cpp
index b39cc21fa4917..ea38bff0d8d34 100644
--- a/clang/test/CXX/drs/cwg1xx.cpp
+++ b/clang/test/CXX/drs/cwg1xx.cpp
@@ -618,7 +618,6 @@ namespace cwg141 { // cwg141: 3.1
     // FIXME: we issue a useful diagnostic first, then some bogus ones.
     b.f<int>();
     // expected-error at -1 {{no member named 'f' in 'cwg141::B'}}
-    // expected-error at -2 +{{}}
     (void)b.S<int>::n;
   }
   template<typename T> struct C {
@@ -628,10 +627,12 @@ namespace cwg141 { // cwg141: 3.1
       // expected-error at -1 {{use 'template' keyword to treat 'f' as a dependent template name}}
     }
     void h() {
-      (void)t.S<int>::n; // ok
+      (void)t.S<int>::n;
+      // expected-error at -1 {{use 'template' keyword to treat 'S' as a dependent template name}}
     }
     void i() {
-      (void)t.S<int>(); // ok!
+      (void)t.S<int>();
+      // expected-error at -1 {{use 'template' keyword to treat 'S' as a dependent template name}}
     }
   };
   void h() { C<B>().h(); } // ok
diff --git a/clang/test/SemaCXX/static-assert-cxx17.cpp b/clang/test/SemaCXX/static-assert-cxx17.cpp
index 41a7b025d0eb7..754f4ae5f1d38 100644
--- a/clang/test/SemaCXX/static-assert-cxx17.cpp
+++ b/clang/test/SemaCXX/static-assert-cxx17.cpp
@@ -96,7 +96,7 @@ void foo6() {
   // expected-error at -1{{static assertion failed due to requirement 'static_cast<const X<int> *>(nullptr)'}}
   static_assert((const X<typename T::T>[]){} == nullptr);
   // expected-error at -1{{static assertion failed due to requirement '(const X<int>[0]){} == nullptr'}}
-  static_assert(sizeof(X<decltype(X<typename T::T>().X<typename T::T>::~X())>) == 0);
+  static_assert(sizeof(X<decltype(X<typename T::T>().template X<typename T::T>::~X())>) == 0);
   // expected-error at -1{{static assertion failed due to requirement 'sizeof(X<void>) == 0'}} \
   // expected-note at -1 {{evaluates to '8 == 0'}}
   static_assert(constexpr_return_false<typename T::T, typename T::U>());
diff --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp b/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
index ad73daa8e214c..7768d2f03ac5b 100644
--- a/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
+++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
@@ -115,7 +115,7 @@ namespace CopyCounting {
   static_assert(f(X<A{}>()) == 0);
 
   template<A a> struct Y { void f(); };
-  template<A a> void g(Y<a> y) { y.Y<a>::f(); }
+  template<A a> void g(Y<a> y) { y.template Y<a>::f(); }
   void h() { constexpr A a; g<a>(Y<a>{}); }
 
   template<A a> struct Z {

>From 9e0b8dc456d5132183028d02d5fe05481a8f5e20 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Tue, 21 May 2024 15:57:06 -0400
Subject: [PATCH 02/11] [FOLD] add comment

---
 clang/lib/Sema/SemaCXXScopeSpec.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp
index 6efa8925d1446..f70ba1ecfa17c 100644
--- a/clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -397,6 +397,8 @@ NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) {
   while (NNS->getPrefix())
     NNS = NNS->getPrefix();
 
+  // FIXME: This is a rather nasty hack! Ideally we should get the results
+  // from LookupTemplateName/BuildCXXNestedNameSpecifier.
   const IdentifierInfo *II = NNS->getAsIdentifier();
   if (!II) {
     if (const auto *DTST =

>From f2dbd87e48c9aafb1935df2ea439ebe518a66090 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Fri, 31 May 2024 12:59:34 -0400
Subject: [PATCH 03/11] [FOLD] store all results found by unqualified lookup
 for the first component name of a member-qualified nested-name-specifier

---
 clang/include/clang/AST/ExprCXX.h          |  83 +++++++++----
 clang/include/clang/AST/Stmt.h             |  13 +-
 clang/include/clang/AST/UnresolvedSet.h    |   4 +
 clang/include/clang/Sema/DeclSpec.h        |  10 +-
 clang/include/clang/Sema/Lookup.h          |   8 +-
 clang/include/clang/Sema/Sema.h            |  10 +-
 clang/lib/AST/ASTImporter.cpp              |  13 +-
 clang/lib/AST/ExprCXX.cpp                  |  65 ++++++----
 clang/lib/AST/ItaniumMangle.cpp            |  10 +-
 clang/lib/Sema/SemaCXXScopeSpec.cpp        |  41 ++++---
 clang/lib/Sema/SemaCoroutine.cpp           |   2 +-
 clang/lib/Sema/SemaDeclCXX.cpp             |  22 ++--
 clang/lib/Sema/SemaExpr.cpp                |   2 +-
 clang/lib/Sema/SemaExprMember.cpp          |  37 +++---
 clang/lib/Sema/SemaOverload.cpp            |   3 +-
 clang/lib/Sema/SemaStmtAsm.cpp             |   7 +-
 clang/lib/Sema/SemaTemplate.cpp            |  11 +-
 clang/lib/Sema/SemaTemplateInstantiate.cpp |   5 +-
 clang/lib/Sema/TreeTransform.h             | 132 +++++++++------------
 clang/lib/Serialization/ASTReaderStmt.cpp  |  51 +++++++-
 clang/lib/Serialization/ASTWriterStmt.cpp  |  38 ++++++
 clang/test/SemaCXX/pseudo-destructors.cpp  |  18 +--
 22 files changed, 359 insertions(+), 226 deletions(-)

diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index dbf693611a7fa..3e4d673590b71 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -3672,8 +3672,10 @@ class CXXUnresolvedConstructExpr final
 class CXXDependentScopeMemberExpr final
     : public Expr,
       private llvm::TrailingObjects<CXXDependentScopeMemberExpr,
+                                    NestedNameSpecifierLoc,
+                                    DeclAccessPair,
                                     ASTTemplateKWAndArgsInfo,
-                                    TemplateArgumentLoc, NamedDecl *> {
+                                    TemplateArgumentLoc> {
   friend class ASTStmtReader;
   friend class ASTStmtWriter;
   friend TrailingObjects;
@@ -3686,17 +3688,15 @@ class CXXDependentScopeMemberExpr final
   /// implicit accesses.
   QualType BaseType;
 
-  /// The nested-name-specifier that precedes the member name, if any.
-  /// FIXME: This could be in principle store as a trailing object.
-  /// However the performance impact of doing so should be investigated first.
-  NestedNameSpecifierLoc QualifierLoc;
-
   /// The member to which this member expression refers, which
   /// can be name, overloaded operator, or destructor.
   ///
   /// FIXME: could also be a template-id
   DeclarationNameInfo MemberNameInfo;
 
+  /// The location of the '->' or '.' operator.
+  SourceLocation OperatorLoc;
+
   // CXXDependentScopeMemberExpr is followed by several trailing objects,
   // some of which optional. They are in order:
   //
@@ -3716,8 +3716,16 @@ class CXXDependentScopeMemberExpr final
     return CXXDependentScopeMemberExprBits.HasTemplateKWAndArgsInfo;
   }
 
-  bool hasFirstQualifierFoundInScope() const {
-    return CXXDependentScopeMemberExprBits.HasFirstQualifierFoundInScope;
+  unsigned getNumUnqualifiedLookups() const {
+    return CXXDependentScopeMemberExprBits.NumUnqualifiedLookups;
+  }
+
+  unsigned numTrailingObjects(OverloadToken<NestedNameSpecifierLoc>) const {
+    return hasQualifier();
+  }
+
+  unsigned numTrailingObjects(OverloadToken<DeclAccessPair>) const {
+    return getNumUnqualifiedLookups();
   }
 
   unsigned numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const {
@@ -3728,33 +3736,35 @@ class CXXDependentScopeMemberExpr final
     return getNumTemplateArgs();
   }
 
-  unsigned numTrailingObjects(OverloadToken<NamedDecl *>) const {
-    return hasFirstQualifierFoundInScope();
-  }
-
   CXXDependentScopeMemberExpr(const ASTContext &Ctx, Expr *Base,
                               QualType BaseType, bool IsArrow,
                               SourceLocation OperatorLoc,
                               NestedNameSpecifierLoc QualifierLoc,
                               SourceLocation TemplateKWLoc,
-                              NamedDecl *FirstQualifierFoundInScope,
+                              ArrayRef<DeclAccessPair> UnqualifiedLookups,
                               DeclarationNameInfo MemberNameInfo,
                               const TemplateArgumentListInfo *TemplateArgs);
 
-  CXXDependentScopeMemberExpr(EmptyShell Empty, bool HasTemplateKWAndArgsInfo,
-                              bool HasFirstQualifierFoundInScope);
+  CXXDependentScopeMemberExpr(EmptyShell Empty, bool HasQualifier,
+                              unsigned NumUnqualifiedLookups,
+                              bool HasTemplateKWAndArgsInfo);
 
 public:
   static CXXDependentScopeMemberExpr *
-  Create(const ASTContext &Ctx, Expr *Base, QualType BaseType, bool IsArrow,
-         SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc,
-         SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierFoundInScope,
+  Create(const ASTContext &Ctx, Expr *Base,
+         QualType BaseType, bool IsArrow,
+         SourceLocation OperatorLoc,
+         NestedNameSpecifierLoc QualifierLoc,
+         SourceLocation TemplateKWLoc,
+         ArrayRef<DeclAccessPair> UnqualifiedLookups,
          DeclarationNameInfo MemberNameInfo,
          const TemplateArgumentListInfo *TemplateArgs);
 
   static CXXDependentScopeMemberExpr *
-  CreateEmpty(const ASTContext &Ctx, bool HasTemplateKWAndArgsInfo,
-              unsigned NumTemplateArgs, bool HasFirstQualifierFoundInScope);
+  CreateEmpty(const ASTContext &Ctx, bool HasQualifier,
+              unsigned NumUnqualifiedLookups,
+              bool HasTemplateKWAndArgsInfo,
+              unsigned NumTemplateArgs);
 
   /// True if this is an implicit access, i.e. one in which the
   /// member being accessed was not written in the source.  The source
@@ -3780,18 +3790,32 @@ class CXXDependentScopeMemberExpr final
 
   /// Retrieve the location of the '->' or '.' operator.
   SourceLocation getOperatorLoc() const {
-    return CXXDependentScopeMemberExprBits.OperatorLoc;
+    return OperatorLoc;
+  }
+
+  /// Determines whether this member expression had a nested-name-specifier
+  /// prior to the name of the member, e.g., x->Base::foo.
+  bool hasQualifier() const {
+    return CXXDependentScopeMemberExprBits.HasQualifier;
   }
 
-  /// Retrieve the nested-name-specifier that qualifies the member name.
+  /// If the member name was qualified, retrieves the nested-name-specifier
+  /// that precedes the member name, with source-location information.
+  NestedNameSpecifierLoc getQualifierLoc() const {
+    if (!hasQualifier())
+      return NestedNameSpecifierLoc();
+    return *getTrailingObjects<NestedNameSpecifierLoc>();
+  }
+
+  /// If the member name was qualified, retrieves the
+  /// nested-name-specifier that precedes the member name. Otherwise, returns
+  /// NULL.
   NestedNameSpecifier *getQualifier() const {
-    return QualifierLoc.getNestedNameSpecifier();
+    return getQualifierLoc().getNestedNameSpecifier();
   }
 
-  /// Retrieve the nested-name-specifier that qualifies the member
-  /// name, with source location information.
-  NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
 
+  #if 0
   /// Retrieve the first part of the nested-name-specifier that was
   /// found in the scope of the member access expression when the member access
   /// was initially parsed.
@@ -3808,6 +3832,13 @@ class CXXDependentScopeMemberExpr final
       return nullptr;
     return *getTrailingObjects<NamedDecl *>();
   }
+  #endif
+
+  ArrayRef<DeclAccessPair> unqualified_lookups() const {
+    if (!getNumUnqualifiedLookups())
+      return std::nullopt;
+    return {getTrailingObjects<DeclAccessPair>(), getNumUnqualifiedLookups()};
+  }
 
   /// Retrieve the name of the member that this expression refers to.
   const DeclarationNameInfo &getMemberNameInfo() const {
diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index 9cd7a364cd3f1..e0e5c8fb99dc3 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -1020,18 +1020,25 @@ class alignas(void *) Stmt {
     LLVM_PREFERRED_TYPE(bool)
     unsigned IsArrow : 1;
 
+    /// True if this member expression used a nested-name-specifier to
+    /// refer to the member, e.g., "x->Base::f".
+    LLVM_PREFERRED_TYPE(bool)
+    unsigned HasQualifier : 1;
+
     /// Whether this member expression has info for explicit template
     /// keyword and arguments.
     LLVM_PREFERRED_TYPE(bool)
     unsigned HasTemplateKWAndArgsInfo : 1;
 
+    #if 0
     /// See getFirstQualifierFoundInScope() and the comment listing
     /// the trailing objects.
     LLVM_PREFERRED_TYPE(bool)
     unsigned HasFirstQualifierFoundInScope : 1;
-
-    /// The location of the '->' or '.' operator.
-    SourceLocation OperatorLoc;
+    #endif
+    /// Number of declarations found by unqualified lookup for the
+    /// first component name of the nested-name-specifier.
+    unsigned NumUnqualifiedLookups;
   };
 
   class OverloadExprBitfields {
diff --git a/clang/include/clang/AST/UnresolvedSet.h b/clang/include/clang/AST/UnresolvedSet.h
index ee31be969b6e3..e2083e2a0bd24 100644
--- a/clang/include/clang/AST/UnresolvedSet.h
+++ b/clang/include/clang/AST/UnresolvedSet.h
@@ -96,6 +96,10 @@ class UnresolvedSetImpl {
     decls().push_back(DeclAccessPair::make(D, AS));
   }
 
+  void addAllDecls(ArrayRef<DeclAccessPair> Other) {
+    append(iterator(Other.begin()), iterator(Other.end()));
+  }
+
   /// Replaces the given declaration with the new one, once.
   ///
   /// \return true if the set changed
diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h
index c6d87ca1683a8..231f3fc6fec83 100644
--- a/clang/include/clang/Sema/DeclSpec.h
+++ b/clang/include/clang/Sema/DeclSpec.h
@@ -75,7 +75,7 @@ class CXXScopeSpec {
   SourceRange Range;
   NestedNameSpecifierLocBuilder Builder;
   ArrayRef<TemplateParameterList *> TemplateParamLists;
-  NamedDecl *FoundFirstQualifierInScope;
+  ArrayRef<DeclAccessPair> UnqualifiedLookups;
 
 public:
   SourceRange getRange() const { return Range; }
@@ -92,11 +92,11 @@ class CXXScopeSpec {
     return TemplateParamLists;
   }
 
-  void setFoundFirstQualifierInScope(NamedDecl *Found) {
-    FoundFirstQualifierInScope = Found;
+  void setUnqualifiedLookups(ArrayRef<DeclAccessPair> Found) {
+    UnqualifiedLookups = Found;
   }
-  NamedDecl *getFirstQualifierFoundInScope() const {
-    return FoundFirstQualifierInScope;
+  ArrayRef<DeclAccessPair> getUnqualifiedLookups() const {
+    return UnqualifiedLookups;
   }
 
   /// Retrieve the representation of the nested-name-specifier.
diff --git a/clang/include/clang/Sema/Lookup.h b/clang/include/clang/Sema/Lookup.h
index b0a08a05ac6a0..6b765ef3c980f 100644
--- a/clang/include/clang/Sema/Lookup.h
+++ b/clang/include/clang/Sema/Lookup.h
@@ -483,11 +483,15 @@ class LookupResult {
     ResultKind = Found;
   }
 
+  void addAllDecls(ArrayRef<DeclAccessPair> Other) {
+    Decls.addAllDecls(Other);
+    ResultKind = Found;
+  }
+
   /// Add all the declarations from another set of lookup
   /// results.
   void addAllDecls(const LookupResult &Other) {
-    Decls.append(Other.Decls.begin(), Other.Decls.end());
-    ResultKind = Found;
+    addAllDecls(Other.Decls.pairs());
   }
 
   /// Determine whether no result was found because we could not
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 6c3d1e65e0dfb..9fab8d13a1c35 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -2390,7 +2390,7 @@ class Sema final : public SemaBase {
 
   bool isAcceptableNestedNameSpecifier(const NamedDecl *SD,
                                        bool *CanCorrect = nullptr);
-  NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS);
+  bool LookupFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS, UnresolvedSetImpl &R);
 
   /// Keeps information about an identifier in a nested-name-spec.
   ///
@@ -2423,7 +2423,6 @@ class Sema final : public SemaBase {
 
   bool BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
                                    bool EnteringContext, CXXScopeSpec &SS,
-                                   NamedDecl *ScopeLookupResult,
                                    bool ErrorRecoveryLookup,
                                    bool *IsCorrectedToColon = nullptr,
                                    bool OnlyNamespace = false);
@@ -6938,7 +6937,7 @@ class Sema final : public SemaBase {
   ExprResult ActOnDependentMemberExpr(
       Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OpLoc,
       const CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
-      NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo,
+      const DeclarationNameInfo &NameInfo,
       const TemplateArgumentListInfo *TemplateArgs);
 
   ExprResult ActOnMemberAccessExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
@@ -6973,15 +6972,14 @@ class Sema final : public SemaBase {
   ExprResult BuildMemberReferenceExpr(
       Expr *Base, QualType BaseType, SourceLocation OpLoc, bool IsArrow,
       CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
-      NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo,
+      const DeclarationNameInfo &NameInfo,
       const TemplateArgumentListInfo *TemplateArgs, const Scope *S,
       ActOnMemberAccessExtraArgs *ExtraArgs = nullptr);
 
   ExprResult
   BuildMemberReferenceExpr(Expr *Base, QualType BaseType, SourceLocation OpLoc,
                            bool IsArrow, const CXXScopeSpec &SS,
-                           SourceLocation TemplateKWLoc,
-                           NamedDecl *FirstQualifierInScope, LookupResult &R,
+                           SourceLocation TemplateKWLoc, LookupResult &R,
                            const TemplateArgumentListInfo *TemplateArgs,
                            const Scope *S, bool SuppressQualifierCheck = false,
                            ActOnMemberAccessExtraArgs *ExtraArgs = nullptr);
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index cab5ee6047956..6c306418fe071 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -8432,8 +8432,15 @@ ExpectedStmt ASTNodeImporter::VisitCXXDependentScopeMemberExpr(
   auto ToOperatorLoc = importChecked(Err, E->getOperatorLoc());
   auto ToQualifierLoc = importChecked(Err, E->getQualifierLoc());
   auto ToTemplateKeywordLoc = importChecked(Err, E->getTemplateKeywordLoc());
-  auto ToFirstQualifierFoundInScope =
-      importChecked(Err, E->getFirstQualifierFoundInScope());
+
+
+  UnresolvedSet<8> ToUnqualifiedLookups;
+  for (auto D : E->unqualified_lookups())
+    if (auto ToDOrErr = import(D.getDecl()))
+      ToUnqualifiedLookups.addDecl(*ToDOrErr);
+    else
+      return ToDOrErr.takeError();
+
   if (Err)
     return std::move(Err);
 
@@ -8467,7 +8474,7 @@ ExpectedStmt ASTNodeImporter::VisitCXXDependentScopeMemberExpr(
 
   return CXXDependentScopeMemberExpr::Create(
       Importer.getToContext(), ToBase, ToType, E->isArrow(), ToOperatorLoc,
-      ToQualifierLoc, ToTemplateKeywordLoc, ToFirstQualifierFoundInScope,
+      ToQualifierLoc, ToTemplateKeywordLoc, ToUnqualifiedLookups.pairs(),
       ToMemberNameInfo, ResInfo);
 }
 
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index 2abc0acbfde3b..87e33564ca02e 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -1442,19 +1442,27 @@ SourceLocation CXXUnresolvedConstructExpr::getBeginLoc() const {
 CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(
     const ASTContext &Ctx, Expr *Base, QualType BaseType, bool IsArrow,
     SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc,
-    SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierFoundInScope,
+    SourceLocation TemplateKWLoc, ArrayRef<DeclAccessPair> UnqualifiedLookups,
     DeclarationNameInfo MemberNameInfo,
     const TemplateArgumentListInfo *TemplateArgs)
     : Expr(CXXDependentScopeMemberExprClass, Ctx.DependentTy, VK_LValue,
            OK_Ordinary),
-      Base(Base), BaseType(BaseType), QualifierLoc(QualifierLoc),
+      Base(Base), BaseType(BaseType), OperatorLoc(OperatorLoc),
       MemberNameInfo(MemberNameInfo) {
   CXXDependentScopeMemberExprBits.IsArrow = IsArrow;
+  CXXDependentScopeMemberExprBits.HasQualifier =
+      QualifierLoc.hasQualifier();
+  CXXDependentScopeMemberExprBits.NumUnqualifiedLookups =
+      UnqualifiedLookups.size();
   CXXDependentScopeMemberExprBits.HasTemplateKWAndArgsInfo =
       (TemplateArgs != nullptr) || TemplateKWLoc.isValid();
-  CXXDependentScopeMemberExprBits.HasFirstQualifierFoundInScope =
-      FirstQualifierFoundInScope != nullptr;
-  CXXDependentScopeMemberExprBits.OperatorLoc = OperatorLoc;
+
+  if (hasQualifier())
+    new (getTrailingObjects<NestedNameSpecifierLoc>())
+        NestedNameSpecifierLoc(QualifierLoc);
+
+  std::uninitialized_copy_n(UnqualifiedLookups.data(),
+      UnqualifiedLookups.size(), getTrailingObjects<DeclAccessPair>());
 
   if (TemplateArgs) {
     auto Deps = TemplateArgumentDependence::None;
@@ -1466,54 +1474,61 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(
         TemplateKWLoc);
   }
 
-  if (hasFirstQualifierFoundInScope())
-    *getTrailingObjects<NamedDecl *>() = FirstQualifierFoundInScope;
   setDependence(computeDependence(this));
 }
 
 CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(
-    EmptyShell Empty, bool HasTemplateKWAndArgsInfo,
-    bool HasFirstQualifierFoundInScope)
+    EmptyShell Empty, bool HasQualifier, unsigned NumUnqualifiedLookups,
+    bool HasTemplateKWAndArgsInfo)
     : Expr(CXXDependentScopeMemberExprClass, Empty) {
+  CXXDependentScopeMemberExprBits.HasQualifier = HasQualifier;
+  CXXDependentScopeMemberExprBits.NumUnqualifiedLookups =
+      NumUnqualifiedLookups;
   CXXDependentScopeMemberExprBits.HasTemplateKWAndArgsInfo =
       HasTemplateKWAndArgsInfo;
-  CXXDependentScopeMemberExprBits.HasFirstQualifierFoundInScope =
-      HasFirstQualifierFoundInScope;
 }
 
 CXXDependentScopeMemberExpr *CXXDependentScopeMemberExpr::Create(
     const ASTContext &Ctx, Expr *Base, QualType BaseType, bool IsArrow,
     SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc,
-    SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierFoundInScope,
+    SourceLocation TemplateKWLoc, ArrayRef<DeclAccessPair> UnqualifiedLookups,
     DeclarationNameInfo MemberNameInfo,
     const TemplateArgumentListInfo *TemplateArgs) {
+  bool HasQualifier = QualifierLoc.hasQualifier();
+  unsigned NumUnqualifiedLookups = UnqualifiedLookups.size();
+  assert(!NumUnqualifiedLookups || HasQualifier);
   bool HasTemplateKWAndArgsInfo =
       (TemplateArgs != nullptr) || TemplateKWLoc.isValid();
   unsigned NumTemplateArgs = TemplateArgs ? TemplateArgs->size() : 0;
-  bool HasFirstQualifierFoundInScope = FirstQualifierFoundInScope != nullptr;
-
-  unsigned Size = totalSizeToAlloc<ASTTemplateKWAndArgsInfo,
-                                   TemplateArgumentLoc, NamedDecl *>(
-      HasTemplateKWAndArgsInfo, NumTemplateArgs, HasFirstQualifierFoundInScope);
+  unsigned Size = totalSizeToAlloc<NestedNameSpecifierLoc,
+                                   DeclAccessPair,
+                                   ASTTemplateKWAndArgsInfo,
+                                   TemplateArgumentLoc>(
+      HasQualifier, NumUnqualifiedLookups,
+      HasTemplateKWAndArgsInfo, NumTemplateArgs);
 
   void *Mem = Ctx.Allocate(Size, alignof(CXXDependentScopeMemberExpr));
   return new (Mem) CXXDependentScopeMemberExpr(
       Ctx, Base, BaseType, IsArrow, OperatorLoc, QualifierLoc, TemplateKWLoc,
-      FirstQualifierFoundInScope, MemberNameInfo, TemplateArgs);
+      UnqualifiedLookups, MemberNameInfo, TemplateArgs);
 }
 
 CXXDependentScopeMemberExpr *CXXDependentScopeMemberExpr::CreateEmpty(
-    const ASTContext &Ctx, bool HasTemplateKWAndArgsInfo,
-    unsigned NumTemplateArgs, bool HasFirstQualifierFoundInScope) {
-  assert(NumTemplateArgs == 0 || HasTemplateKWAndArgsInfo);
+    const ASTContext &Ctx, bool HasQualifier, unsigned NumUnqualifiedLookups,
+    bool HasTemplateKWAndArgsInfo, unsigned NumTemplateArgs) {
+  assert(!NumTemplateArgs || HasTemplateKWAndArgsInfo);
+  assert(!NumUnqualifiedLookups || HasQualifier);
 
-  unsigned Size = totalSizeToAlloc<ASTTemplateKWAndArgsInfo,
-                                   TemplateArgumentLoc, NamedDecl *>(
-      HasTemplateKWAndArgsInfo, NumTemplateArgs, HasFirstQualifierFoundInScope);
+  unsigned Size = totalSizeToAlloc<NestedNameSpecifierLoc,
+                                   DeclAccessPair,
+                                   ASTTemplateKWAndArgsInfo,
+                                   TemplateArgumentLoc>(
+      HasQualifier, NumUnqualifiedLookups,
+      HasTemplateKWAndArgsInfo, NumTemplateArgs);
 
   void *Mem = Ctx.Allocate(Size, alignof(CXXDependentScopeMemberExpr));
   return new (Mem) CXXDependentScopeMemberExpr(
-      EmptyShell(), HasTemplateKWAndArgsInfo, HasFirstQualifierFoundInScope);
+      EmptyShell(), HasQualifier, NumUnqualifiedLookups, HasTemplateKWAndArgsInfo);
 }
 
 CXXThisExpr *CXXThisExpr::Create(const ASTContext &Ctx, SourceLocation L,
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index ed9e6eeb36c75..43c046a46ade3 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -595,7 +595,7 @@ class CXXNameMangler {
   void mangleMemberExprBase(const Expr *base, bool isArrow);
   void mangleMemberExpr(const Expr *base, bool isArrow,
                         NestedNameSpecifier *qualifier,
-                        NamedDecl *firstQualifierLookup,
+                        ArrayRef<DeclAccessPair> UnqualifiedLookups,
                         DeclarationName name,
                         const TemplateArgumentLoc *TemplateArgs,
                         unsigned NumTemplateArgs,
@@ -4494,7 +4494,7 @@ void CXXNameMangler::mangleMemberExprBase(const Expr *Base, bool IsArrow) {
 void CXXNameMangler::mangleMemberExpr(const Expr *base,
                                       bool isArrow,
                                       NestedNameSpecifier *qualifier,
-                                      NamedDecl *firstQualifierLookup,
+                                      ArrayRef<DeclAccessPair> UnqualifiedLookups,
                                       DeclarationName member,
                                       const TemplateArgumentLoc *TemplateArgs,
                                       unsigned NumTemplateArgs,
@@ -4980,7 +4980,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
     NotPrimaryExpr();
     const MemberExpr *ME = cast<MemberExpr>(E);
     mangleMemberExpr(ME->getBase(), ME->isArrow(),
-                     ME->getQualifier(), nullptr,
+                     ME->getQualifier(), std::nullopt,
                      ME->getMemberDecl()->getDeclName(),
                      ME->getTemplateArgs(), ME->getNumTemplateArgs(),
                      Arity);
@@ -4991,7 +4991,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
     NotPrimaryExpr();
     const UnresolvedMemberExpr *ME = cast<UnresolvedMemberExpr>(E);
     mangleMemberExpr(ME->isImplicitAccess() ? nullptr : ME->getBase(),
-                     ME->isArrow(), ME->getQualifier(), nullptr,
+                     ME->isArrow(), ME->getQualifier(), std::nullopt,
                      ME->getMemberName(),
                      ME->getTemplateArgs(), ME->getNumTemplateArgs(),
                      Arity);
@@ -5004,7 +5004,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
       = cast<CXXDependentScopeMemberExpr>(E);
     mangleMemberExpr(ME->isImplicitAccess() ? nullptr : ME->getBase(),
                      ME->isArrow(), ME->getQualifier(),
-                     ME->getFirstQualifierFoundInScope(),
+                     ME->unqualified_lookups(),
                      ME->getMember(),
                      ME->getTemplateArgs(), ME->getNumTemplateArgs(),
                      Arity);
diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp
index f70ba1ecfa17c..99c5476392fc9 100644
--- a/clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -390,9 +390,9 @@ bool Sema::isAcceptableNestedNameSpecifier(const NamedDecl *SD,
 /// (e.g., Base::), perform name lookup for that identifier as a
 /// nested-name-specifier within the given scope, and return the result of that
 /// name lookup.
-NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) {
-  if (!S || !NNS)
-    return nullptr;
+bool Sema::LookupFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS, UnresolvedSetImpl &R) {
+  if (!S)
+    return false;
 
   while (NNS->getPrefix())
     NNS = NNS->getPrefix();
@@ -406,23 +406,20 @@ NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) {
                 NNS->getAsType()))
       II = DTST->getIdentifier();
     else
-      return nullptr;
+      return false;
   }
   assert(II && "Missing first qualifier in scope");
   LookupResult Found(*this, II, SourceLocation(),
                      NNS->getAsIdentifier() ? LookupNestedNameSpecifierName
                                             : LookupOrdinaryName);
   LookupName(Found, S);
-  assert(!Found.isAmbiguous() && "Cannot handle ambiguities here yet");
-
-  if (!Found.isSingleResult())
-    return nullptr;
 
-  NamedDecl *Result = Found.getFoundDecl();
-  // if (isAcceptableNestedNameSpecifier(Result))
-  return Result;
+  if (Found.empty())
+    return false;
 
-  // return nullptr;
+  R.addAllDecls(Found.asUnresolvedSet().pairs());
+  Found.suppressDiagnostics();
+  return true;
 }
 
 namespace {
@@ -482,7 +479,6 @@ class NestedNameSpecifierValidatorCCC final
 /// specifier.
 bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
                                        bool EnteringContext, CXXScopeSpec &SS,
-                                       NamedDecl *ScopeLookupResult,
                                        bool ErrorRecoveryLookup,
                                        bool *IsCorrectedToColon,
                                        bool OnlyNamespace) {
@@ -534,10 +530,13 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
   // but instead of using them we should store them via
   // setFirstQualifierFoundInScope and pretend we found nothing.
   if (SS.isEmpty() && (ObjectType.isNull() || LookupFirstQualifierInScope)) {
-    if (S)
+    if (S) {
       LookupName(Found, S);
-    else if (LookupFirstQualifierInScope && SS.getFirstQualifierFoundInScope())
-      Found.addDecl(SS.getFirstQualifierFoundInScope());
+    } else if (LookupFirstQualifierInScope &&
+        !SS.getUnqualifiedLookups().empty()) {
+      Found.addAllDecls(SS.getUnqualifiedLookups());
+      Found.resolveKind();
+    }
 
     if (!ObjectType.isNull())
       ObjectTypeSearchedInScope = true;
@@ -687,14 +686,14 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
       // scope, reconstruct the result from the template instantiation itself.
       //
       // Note that C++11 does *not* perform this redundant lookup.
-      NamedDecl *OuterDecl;
+      NamedDecl *OuterDecl = nullptr;
       if (S) {
         LookupResult FoundOuter(*this, IdInfo.Identifier, IdInfo.IdentifierLoc,
                                 LookupNestedNameSpecifierName);
         LookupName(FoundOuter, S);
         OuterDecl = FoundOuter.getAsSingle<NamedDecl>();
-      } else
-        OuterDecl = ScopeLookupResult;
+      } else if (!SS.getUnqualifiedLookups().empty())
+        OuterDecl = SS.getUnqualifiedLookups().front().getDecl();
 
       if (isAcceptableNestedNameSpecifier(OuterDecl) &&
           OuterDecl->getCanonicalDecl() != SD->getCanonicalDecl() &&
@@ -872,7 +871,7 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
     return true;
 
   return BuildCXXNestedNameSpecifier(S, IdInfo, EnteringContext, SS,
-                                     /*ScopeLookupResult=*/nullptr, false,
+                                     /*ErrorRecoveryLookup=*/false,
                                      IsCorrectedToColon, OnlyNamespace);
 }
 
@@ -939,7 +938,7 @@ bool Sema::IsInvalidUnlessNestedName(Scope *S, CXXScopeSpec &SS,
     return false;
 
   return !BuildCXXNestedNameSpecifier(S, IdInfo, EnteringContext, SS,
-                                      /*ScopeLookupResult=*/nullptr, true);
+                                      /*ErrorRecoveryLookup=*/true);
 }
 
 bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp
index 81334c817b2af..dbe0f0cf11b90 100644
--- a/clang/lib/Sema/SemaCoroutine.cpp
+++ b/clang/lib/Sema/SemaCoroutine.cpp
@@ -307,7 +307,7 @@ static ExprResult buildMemberCall(Sema &S, Expr *Base, SourceLocation Loc,
   CXXScopeSpec SS;
   ExprResult Result = S.BuildMemberReferenceExpr(
       Base, Base->getType(), Loc, /*IsPtr=*/false, SS,
-      SourceLocation(), nullptr, NameInfo, /*TemplateArgs=*/nullptr,
+      SourceLocation(), NameInfo, /*TemplateArgs=*/nullptr,
       /*Scope=*/nullptr);
   if (Result.isInvalid())
     return ExprError();
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 631fd4e354927..29ff6e2501b5b 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -1293,9 +1293,11 @@ static bool checkTupleLikeDecomposition(Sema &S,
     if (UseMemberGet) {
       //   if [lookup of member get] finds at least one declaration, the
       //   initializer is e.get<i-1>().
-      E = S.BuildMemberReferenceExpr(E.get(), DecompType, Loc, false,
-                                     CXXScopeSpec(), SourceLocation(), nullptr,
-                                     MemberGet, &Args, nullptr);
+      E = S.BuildMemberReferenceExpr(E.get(), DecompType, Loc,
+                                     /*IsArrow=*/false,
+                                     /*SS=*/CXXScopeSpec(),
+                                     /*TemplateKWLoc=*/SourceLocation(),
+                                     MemberGet, &Args, /*S=*/nullptr);
       if (E.isInvalid())
         return true;
 
@@ -5016,10 +5018,9 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
                                          /*IsArrow=*/false,
                                          SS,
                                          /*TemplateKWLoc=*/SourceLocation(),
-                                         /*FirstQualifierInScope=*/nullptr,
                                          MemberLookup,
                                          /*TemplateArgs=*/nullptr,
-                                         /*S*/nullptr);
+                                         /*S=*/nullptr);
     if (CtorArg.isInvalid())
       return true;
 
@@ -14543,8 +14544,9 @@ class MemberBuilder: public ExprBuilder {
 public:
   Expr *build(Sema &S, SourceLocation Loc) const override {
     return assertNotNull(S.BuildMemberReferenceExpr(
-        Builder.build(S, Loc), Type, Loc, IsArrow, SS, SourceLocation(),
-        nullptr, MemberLookup, nullptr, nullptr).get());
+        Builder.build(S, Loc), Type, Loc, IsArrow, SS,
+        /*TemplateKwLoc=*/SourceLocation(), MemberLookup,
+        /*TemplateArgs=*/nullptr, /*S=*/nullptr).get());
   }
 
   MemberBuilder(const ExprBuilder &Builder, QualType Type, bool IsArrow,
@@ -14753,7 +14755,6 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T,
     ExprResult OpEqualRef
       = S.BuildMemberReferenceExpr(To.build(S, Loc), T, Loc, /*IsArrow=*/false,
                                    SS, /*TemplateKWLoc=*/SourceLocation(),
-                                   /*FirstQualifierInScope=*/nullptr,
                                    OpLookup,
                                    /*TemplateArgs=*/nullptr, /*S*/nullptr,
                                    /*SuppressQualifierCheck=*/true);
@@ -17390,8 +17391,9 @@ bool Sema::EvaluateStaticAssertMessageAsString(Expr *Message,
 
   auto BuildExpr = [&](LookupResult &LR) {
     ExprResult Res = BuildMemberReferenceExpr(
-        Message, Message->getType(), Message->getBeginLoc(), false,
-        CXXScopeSpec(), SourceLocation(), nullptr, LR, nullptr, nullptr);
+        Message, Message->getType(), Message->getBeginLoc(), /*IsArrow=*/false,
+        /*SS=*/CXXScopeSpec(), /*TemplateKWLoc=*/SourceLocation(), LR,
+        /*TemplateArgs=*/nullptr, /*S=*/nullptr);
     if (Res.isInvalid())
       return ExprError();
     Res = BuildCallExpr(nullptr, Res.get(), Loc, std::nullopt, Loc, nullptr,
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index fb4154757775b..fc8a05ef71b45 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2677,7 +2677,7 @@ recoverFromMSUnqualifiedLookup(Sema &S, ASTContext &Context,
     return CXXDependentScopeMemberExpr::Create(
         Context, /*This=*/nullptr, ThisType, /*IsArrow=*/true,
         /*Op=*/SourceLocation(), NestedNameSpecifierLoc(), TemplateKWLoc,
-        /*FirstQualifierFoundInScope=*/nullptr, NameInfo, TemplateArgs);
+        /*UnqualifiedLookups=*/std::nullopt, NameInfo, TemplateArgs);
   }
 
   // Synthesize a fake NNS that points to the derived class.  This will
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 6dbb0b4c398c4..5efa5d0d1421e 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -557,7 +557,6 @@ Sema::ActOnDependentMemberExpr(Expr *BaseExpr, QualType BaseType,
                                bool IsArrow, SourceLocation OpLoc,
                                const CXXScopeSpec &SS,
                                SourceLocation TemplateKWLoc,
-                               NamedDecl *FirstQualifierInScope,
                                const DeclarationNameInfo &NameInfo,
                                const TemplateArgumentListInfo *TemplateArgs) {
   // Even in dependent contexts, try to diagnose base expressions with
@@ -591,8 +590,8 @@ Sema::ActOnDependentMemberExpr(Expr *BaseExpr, QualType BaseType,
   // must have pointer type, and the accessed type is the pointee.
   return CXXDependentScopeMemberExpr::Create(
       Context, BaseExpr, BaseType, IsArrow, OpLoc,
-      SS.getWithLocInContext(Context), TemplateKWLoc, FirstQualifierInScope,
-      NameInfo, TemplateArgs);
+      SS.getWithLocInContext(Context), TemplateKWLoc,
+      SS.getUnqualifiedLookups(), NameInfo, TemplateArgs);
 }
 
 /// We know that the given qualified member reference points only to
@@ -780,8 +779,9 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
           R.addDecl(ND);
         R.resolveKind();
         return SemaRef.BuildMemberReferenceExpr(
-            BaseExpr, BaseExpr->getType(), OpLoc, IsArrow, SS, SourceLocation(),
-            nullptr, R, nullptr, nullptr);
+            BaseExpr, BaseExpr->getType(), OpLoc, IsArrow, SS,
+            /*TemplateKWLoc=*/SourceLocation(), R, /*TemplateArgs=*/nullptr,
+            /*S=*/nullptr);
       },
       Sema::CTK_ErrorRecovery, DC);
 
@@ -797,7 +797,7 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
 ExprResult Sema::BuildMemberReferenceExpr(
     Expr *Base, QualType BaseType, SourceLocation OpLoc, bool IsArrow,
     CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
-    NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo,
+    const DeclarationNameInfo &NameInfo,
     const TemplateArgumentListInfo *TemplateArgs, const Scope *S,
     ActOnMemberAccessExtraArgs *ExtraArgs) {
   LookupResult R(*this, NameInfo, LookupMemberName);
@@ -841,8 +841,9 @@ ExprResult Sema::BuildMemberReferenceExpr(
 
   return BuildMemberReferenceExpr(Base, BaseType,
                                   OpLoc, IsArrow, SS, TemplateKWLoc,
-                                  FirstQualifierInScope, R, TemplateArgs, S,
-                                  false, ExtraArgs);
+                                  R, TemplateArgs, S,
+                                  /*SuppressQualifierCheck=*/false,
+                                  ExtraArgs);
 }
 
 ExprResult
@@ -985,7 +986,6 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
                                SourceLocation OpLoc, bool IsArrow,
                                const CXXScopeSpec &SS,
                                SourceLocation TemplateKWLoc,
-                               NamedDecl *FirstQualifierInScope,
                                LookupResult &R,
                                const TemplateArgumentListInfo *TemplateArgs,
                                const Scope *S,
@@ -1000,8 +1000,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
        (SS.isSet() ? SS.getScopeRep()->isDependent()
                    : BaseExprType->isDependentType())))
     return ActOnDependentMemberExpr(BaseExpr, BaseExprType, IsArrow, OpLoc, SS,
-                                    TemplateKWLoc, FirstQualifierInScope,
-                                    R.getLookupNameInfo(), TemplateArgs);
+                                    TemplateKWLoc, R.getLookupNameInfo(),
+                                    TemplateArgs);
 
   QualType BaseType = BaseExprType;
   if (IsArrow) {
@@ -1208,7 +1208,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
     if (!VDecl.get())
       return ActOnDependentMemberExpr(
           BaseExpr, BaseExpr->getType(), IsArrow, OpLoc, SS, TemplateKWLoc,
-          FirstQualifierInScope, MemberNameInfo, TemplateArgs);
+          MemberNameInfo, TemplateArgs);
 
     VarDecl *Var = cast<VarDecl>(VDecl.get());
     if (!Var->getTemplateSpecializationKind())
@@ -1792,9 +1792,10 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
   if (getLangOpts().HLSL && IsArrow)
     return ExprError(Diag(OpLoc, diag::err_hlsl_operator_unsupported) << 2);
 
-  NamedDecl *FirstQualifierInScope
-    = (!SS.isSet() ? nullptr : FindFirstQualifierInScope(S, SS.getScopeRep()));
-
+  UnresolvedSet<4> UnqualifiedLookups;
+  if (SS.isValid() && LookupFirstQualifierInScope(S, SS.getScopeRep(), UnqualifiedLookups)) {
+    SS.setUnqualifiedLookups(UnqualifiedLookups.pairs());
+  }
   // This is a postfix expression, so get rid of ParenListExprs.
   ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Base);
   if (Result.isInvalid()) return ExprError();
@@ -1803,7 +1804,7 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
   ActOnMemberAccessExtraArgs ExtraArgs = {S, Id, ObjCImpDecl};
   ExprResult Res = BuildMemberReferenceExpr(
       Base, Base->getType(), OpLoc, IsArrow, SS, TemplateKWLoc,
-      FirstQualifierInScope, NameInfo, TemplateArgs, S, &ExtraArgs);
+      NameInfo, TemplateArgs, S, &ExtraArgs);
 
   if (!Res.isInvalid() && isa<MemberExpr>(Res.get()))
     CheckMemberAccessOfNoDeref(cast<MemberExpr>(Res.get()));
@@ -1954,6 +1955,6 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
   return BuildMemberReferenceExpr(
       baseExpr, ThisTy,
       /*OpLoc=*/SourceLocation(),
-      /*IsArrow=*/!getLangOpts().HLSL, SS, TemplateKWLoc,
-      /*FirstQualifierInScope=*/nullptr, R, TemplateArgs, S);
+      /*IsArrow=*/!getLangOpts().HLSL, SS,
+      TemplateKWLoc, R, TemplateArgs, S);
 }
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 6c4ce1022ae27..6f066235461b0 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -16219,9 +16219,8 @@ Sema::BuildForRangeBeginEndCall(SourceLocation Loc,
   if (!MemberLookup.empty()) {
     ExprResult MemberRef =
         BuildMemberReferenceExpr(Range, Range->getType(), Loc,
-                                 /*IsPtr=*/false, CXXScopeSpec(),
+                                 /*IsPtr=*/false, /*SS=*/CXXScopeSpec(),
                                  /*TemplateKWLoc=*/SourceLocation(),
-                                 /*FirstQualifierInScope=*/nullptr,
                                  MemberLookup,
                                  /*TemplateArgs=*/nullptr, S);
     if (MemberRef.isInvalid()) {
diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp
index 32d42f3c3f3bb..9b1e49620173d 100644
--- a/clang/lib/Sema/SemaStmtAsm.cpp
+++ b/clang/lib/Sema/SemaStmtAsm.cpp
@@ -900,7 +900,7 @@ Sema::LookupInlineAsmVarDeclField(Expr *E, StringRef Member,
     return CXXDependentScopeMemberExpr::Create(
         Context, E, T, /*IsArrow=*/false, AsmLoc, NestedNameSpecifierLoc(),
         SourceLocation(),
-        /*FirstQualifierFoundInScope=*/nullptr, NameInfo, /*TemplateArgs=*/nullptr);
+        /*UnqualifiedLookups=*/std::nullopt, NameInfo, /*TemplateArgs=*/nullptr);
   }
 
   const RecordType *RT = T->getAs<RecordType>();
@@ -923,8 +923,9 @@ Sema::LookupInlineAsmVarDeclField(Expr *E, StringRef Member,
 
   // Make an Expr to thread through OpDecl.
   ExprResult Result = BuildMemberReferenceExpr(
-      E, E->getType(), AsmLoc, /*IsArrow=*/false, CXXScopeSpec(),
-      SourceLocation(), nullptr, FieldResult, nullptr, nullptr);
+      E, E->getType(), AsmLoc, /*IsArrow=*/false, /*SS=*/CXXScopeSpec(),
+      /*TemplateKWLoc*/SourceLocation(), FieldResult,
+      /*TemplateArgs=*/nullptr, /*S=*/nullptr);
 
   return Result;
 }
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 6fc290e382b0f..57fe755ae8fc0 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -469,10 +469,13 @@ bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS,
     //   expression. If the identifier is not found, it is then looked up in
     //   the context of the entire postfix-expression and shall name a class
     //   template.
-    if (S)
+    if (S) {
       LookupName(Found, S);
-    else if (LookupFirstQualifierInScope && SS.getFirstQualifierFoundInScope())
-      Found.addDecl(SS.getFirstQualifierFoundInScope());
+    } else if (LookupFirstQualifierInScope &&
+        !SS.getUnqualifiedLookups().empty()) {
+      Found.addAllDecls(SS.getUnqualifiedLookups());
+      Found.resolveKind();
+    }
 
     if (!ObjectType.isNull())
       ObjectTypeSearchedInScope = true;
@@ -747,7 +750,7 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS,
         /*IsArrow=*/!Context.getLangOpts().HLSL,
         /*OperatorLoc=*/SourceLocation(),
         /*QualifierLoc=*/NestedNameSpecifierLoc(), TemplateKWLoc,
-        /*FirstQualifierFoundInScope=*/nullptr, NameInfo, TemplateArgs);
+        /*UnqualifiedLookups=*/std::nullopt, NameInfo, TemplateArgs);
   }
   return BuildDependentDeclRefExpr(SS, TemplateKWLoc, NameInfo, TemplateArgs);
 }
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index abb8a260faab9..73ca3a0fde478 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1549,7 +1549,6 @@ namespace {
     TransformTemplateName(CXXScopeSpec &SS, TemplateName Name,
                           SourceLocation NameLoc,
                           QualType ObjectType = QualType(),
-                          NamedDecl *FirstQualifierInScope = nullptr,
                           bool AllowInjectedClassName = false);
 
     const CXXAssumeAttr *TransformCXXAssumeAttr(const CXXAssumeAttr *AA);
@@ -1982,8 +1981,7 @@ TemplateInstantiator::RebuildElaboratedType(SourceLocation KeywordLoc,
 
 TemplateName TemplateInstantiator::TransformTemplateName(
     CXXScopeSpec &SS, TemplateName Name, SourceLocation NameLoc,
-    QualType ObjectType, NamedDecl *FirstQualifierInScope,
-    bool AllowInjectedClassName) {
+    QualType ObjectType, bool AllowInjectedClassName) {
   if (TemplateTemplateParmDecl *TTP
        = dyn_cast_or_null<TemplateTemplateParmDecl>(Name.getAsTemplateDecl())) {
     if (TTP->getDepth() < TemplateArgs.getNumLevels()) {
@@ -2057,7 +2055,6 @@ TemplateName TemplateInstantiator::TransformTemplateName(
   }
 
   return inherited::TransformTemplateName(SS, Name, NameLoc, ObjectType,
-                                          FirstQualifierInScope,
                                           AllowInjectedClassName);
 }
 
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index c037f93bbbc3f..e421510105c69 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -544,7 +544,7 @@ class TreeTransform {
   NestedNameSpecifierLoc
   TransformNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
                                   QualType ObjectType = QualType(),
-                                  NamedDecl *FirstQualifierInScope = nullptr);
+                                  ArrayRef<DeclAccessPair> UnqualifiedLookups = std::nullopt);
 
   /// Transform the given declaration name.
   ///
@@ -589,7 +589,6 @@ class TreeTransform {
   TransformTemplateName(CXXScopeSpec &SS, TemplateName Name,
                         SourceLocation NameLoc,
                         QualType ObjectType = QualType(),
-                        NamedDecl *FirstQualifierInScope = nullptr,
                         bool AllowInjectedClassName = false);
 
   /// Transform the given template argument.
@@ -1140,7 +1139,7 @@ class TreeTransform {
     CXXScopeSpec SS;
     SS.Adopt(QualifierLoc);
     TemplateName InstName = getDerived().RebuildTemplateName(
-        SS, TemplateKWLoc, *Name, NameLoc, QualType(), nullptr,
+        SS, TemplateKWLoc, *Name, NameLoc, QualType(),
         AllowInjectedClassName);
 
     if (InstName.isNull())
@@ -1312,7 +1311,6 @@ class TreeTransform {
                                    SourceLocation TemplateKWLoc,
                                    const IdentifierInfo &Name,
                                    SourceLocation NameLoc, QualType ObjectType,
-                                   NamedDecl *FirstQualifierInScope,
                                    bool AllowInjectedClassName);
 
   /// Build a new template name given a nested name specifier and the
@@ -2857,7 +2855,7 @@ class TreeTransform {
                                ValueDecl *Member,
                                NamedDecl *FoundDecl,
                         const TemplateArgumentListInfo *ExplicitTemplateArgs,
-                               NamedDecl *FirstQualifierInScope) {
+                               ArrayRef<DeclAccessPair> UnqualifiedLookups) {
     ExprResult BaseResult = getSema().PerformMemberExprBaseConversion(Base,
                                                                       isArrow);
     if (!Member->getDeclName()) {
@@ -2894,8 +2892,7 @@ class TreeTransform {
 
     CXXScopeSpec SS;
     SS.Adopt(QualifierLoc);
-    if (FirstQualifierInScope)
-      SS.setFoundFirstQualifierInScope(FirstQualifierInScope);
+    SS.setUnqualifiedLookups(UnqualifiedLookups);
 
     Base = BaseResult.get();
     QualType BaseType = Base->getType();
@@ -2926,7 +2923,6 @@ class TreeTransform {
 
     return getSema().BuildMemberReferenceExpr(Base, BaseType, OpLoc, isArrow,
                                               SS, TemplateKWLoc,
-                                              FirstQualifierInScope,
                                               R, ExplicitTemplateArgs,
                                               /*S*/nullptr);
   }
@@ -3001,10 +2997,9 @@ class TreeTransform {
     CXXScopeSpec SS;
     DeclarationNameInfo NameInfo(&Accessor, AccessorLoc);
     return getSema().BuildMemberReferenceExpr(
-        Base, Base->getType(), OpLoc, IsArrow, SS, SourceLocation(),
-        /*FirstQualifierInScope*/ nullptr, NameInfo,
-        /* TemplateArgs */ nullptr,
-        /*S*/ nullptr);
+        Base, Base->getType(), OpLoc, IsArrow, SS,
+        /*TemplateKWLoc=*/SourceLocation(), NameInfo,
+        /*TemplateArgs=*/ nullptr, /*S=*/nullptr);
   }
 
   /// Build a new initializer list expression.
@@ -3578,21 +3573,18 @@ class TreeTransform {
                                                 SourceLocation OperatorLoc,
                                           NestedNameSpecifierLoc QualifierLoc,
                                                 SourceLocation TemplateKWLoc,
-                                            NamedDecl *FirstQualifierInScope,
+                                  ArrayRef<DeclAccessPair> UnqualifiedLookups,
                                    const DeclarationNameInfo &MemberNameInfo,
                               const TemplateArgumentListInfo *TemplateArgs) {
     CXXScopeSpec SS;
     SS.Adopt(QualifierLoc);
-
-    if (FirstQualifierInScope)
-      SS.setFoundFirstQualifierInScope(FirstQualifierInScope);
+    SS.setUnqualifiedLookups(UnqualifiedLookups);
 
     return SemaRef.BuildMemberReferenceExpr(BaseE, BaseType,
                                             OperatorLoc, IsArrow,
                                             SS, TemplateKWLoc,
-                                            FirstQualifierInScope,
                                             MemberNameInfo,
-                                            TemplateArgs, /*S*/nullptr);
+                                            TemplateArgs, /*S=*/nullptr);
   }
 
   /// Build a new member reference expression.
@@ -3604,20 +3596,17 @@ class TreeTransform {
                                          bool IsArrow,
                                          NestedNameSpecifierLoc QualifierLoc,
                                          SourceLocation TemplateKWLoc,
-                                         NamedDecl *FirstQualifierInScope,
+                                         ArrayRef<DeclAccessPair> UnqualifiedLookups,
                                          LookupResult &R,
                                 const TemplateArgumentListInfo *TemplateArgs) {
     CXXScopeSpec SS;
     SS.Adopt(QualifierLoc);
-
-    if (FirstQualifierInScope)
-      SS.setFoundFirstQualifierInScope(FirstQualifierInScope);
+    SS.setUnqualifiedLookups(UnqualifiedLookups);
 
     return SemaRef.BuildMemberReferenceExpr(BaseE, BaseType,
                                             OperatorLoc, IsArrow,
                                             SS, TemplateKWLoc,
-                                            FirstQualifierInScope,
-                                            R, TemplateArgs, /*S*/nullptr);
+                                            R, TemplateArgs, /*S=*/nullptr);
   }
 
   /// Build a new noexcept expression.
@@ -3836,10 +3825,8 @@ class TreeTransform {
     DeclarationNameInfo NameInfo(Ivar->getDeclName(), IvarLoc);
     ExprResult Result = getSema().BuildMemberReferenceExpr(
         BaseArg, BaseArg->getType(),
-        /*FIXME:*/ IvarLoc, IsArrow, SS, SourceLocation(),
-        /*FirstQualifierInScope=*/nullptr, NameInfo,
-        /*TemplateArgs=*/nullptr,
-        /*S=*/nullptr);
+        /*FIXME:*/ IvarLoc, IsArrow, SS, /*TemplateKWLoc=*/SourceLocation(),
+        NameInfo, /*TemplateArgs=*/nullptr, /*S=*/nullptr);
     if (IsFreeIvar && Result.isUsable())
       cast<ObjCIvarRefExpr>(Result.get())->setIsFreeIvar(IsFreeIvar);
     return Result;
@@ -3857,8 +3844,7 @@ class TreeTransform {
     return getSema().BuildMemberReferenceExpr(BaseArg, BaseArg->getType(),
                                               /*FIXME:*/PropertyLoc,
                                               /*IsArrow=*/false,
-                                              SS, SourceLocation(),
-                                              /*FirstQualifierInScope=*/nullptr,
+                                              SS, /*TemplateKWLoc=*/SourceLocation(),
                                               NameInfo,
                                               /*TemplateArgs=*/nullptr,
                                               /*S=*/nullptr);
@@ -3890,8 +3876,7 @@ class TreeTransform {
     DeclarationNameInfo NameInfo(&getSema().Context.Idents.get("isa"), IsaLoc);
     return getSema().BuildMemberReferenceExpr(BaseArg, BaseArg->getType(),
                                               OpLoc, IsArrow,
-                                              SS, SourceLocation(),
-                                              /*FirstQualifierInScope=*/nullptr,
+                                              SS, /*TemplateKWLoc=*/SourceLocation(),
                                               NameInfo,
                                               /*TemplateArgs=*/nullptr,
                                               /*S=*/nullptr);
@@ -4052,16 +4037,14 @@ class TreeTransform {
 private:
   TypeLoc TransformTypeInObjectScope(TypeLoc TL,
                                      QualType ObjectType,
-                                     NamedDecl *FirstQualifierInScope,
                                      CXXScopeSpec &SS);
 
   TypeSourceInfo *TransformTypeInObjectScope(TypeSourceInfo *TSInfo,
                                              QualType ObjectType,
-                                             NamedDecl *FirstQualifierInScope,
                                              CXXScopeSpec &SS);
 
-  TypeSourceInfo *TransformTSIInObjectScope(TypeLoc TL, QualType ObjectType,
-                                            NamedDecl *FirstQualifierInScope,
+  TypeSourceInfo *TransformTSIInObjectScope(TypeLoc TL,
+                                            QualType ObjectType,
                                             CXXScopeSpec &SS);
 
   QualType TransformDependentNameType(TypeLocBuilder &TLB,
@@ -4380,7 +4363,7 @@ Sema::ConditionResult TreeTransform<Derived>::TransformCondition(
 template <typename Derived>
 NestedNameSpecifierLoc TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
     NestedNameSpecifierLoc NNS, QualType ObjectType,
-    NamedDecl *FirstQualifierInScope) {
+    ArrayRef<DeclAccessPair> UnqualifiedLookups) {
   SmallVector<NestedNameSpecifierLoc, 4> Qualifiers;
 
   auto insertNNS = [&Qualifiers](NestedNameSpecifierLoc NNS) {
@@ -4391,8 +4374,8 @@ NestedNameSpecifierLoc TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
   insertNNS(NNS);
 
   CXXScopeSpec SS;
-  if (FirstQualifierInScope)
-    SS.setFoundFirstQualifierInScope(FirstQualifierInScope);
+  SS.setUnqualifiedLookups(UnqualifiedLookups);
+
   while (!Qualifiers.empty()) {
     NestedNameSpecifierLoc Q = Qualifiers.pop_back_val();
     NestedNameSpecifier *QNNS = Q.getNestedNameSpecifier();
@@ -4402,8 +4385,9 @@ NestedNameSpecifierLoc TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
       Sema::NestedNameSpecInfo IdInfo(QNNS->getAsIdentifier(),
                                       Q.getLocalBeginLoc(), Q.getLocalEndLoc(),
                                       ObjectType);
-      if (SemaRef.BuildCXXNestedNameSpecifier(/*Scope=*/nullptr, IdInfo, false,
-                                              SS, FirstQualifierInScope, false))
+      if (SemaRef.BuildCXXNestedNameSpecifier(/*Scope=*/nullptr, IdInfo,
+                                              /*EnteringContext=*/false,
+                                              SS, /*ErrorRecoveryLookup=*/false))
         return NestedNameSpecifierLoc();
       break;
     }
@@ -4441,8 +4425,7 @@ NestedNameSpecifierLoc TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
 
     case NestedNameSpecifier::TypeSpecWithTemplate:
     case NestedNameSpecifier::TypeSpec: {
-      TypeLoc TL = TransformTypeInObjectScope(Q.getTypeLoc(), ObjectType,
-                                              FirstQualifierInScope, SS);
+      TypeLoc TL = TransformTypeInObjectScope(Q.getTypeLoc(), ObjectType, SS);
 
       if (!TL)
         return NestedNameSpecifierLoc();
@@ -4475,7 +4458,7 @@ NestedNameSpecifierLoc TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
     }
 
     // The qualifier-in-scope and object type only apply to the leftmost entity.
-    FirstQualifierInScope = nullptr;
+    SS.setUnqualifiedLookups(std::nullopt);
     ObjectType = QualType();
   }
 
@@ -4564,7 +4547,6 @@ TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS,
                                               TemplateName Name,
                                               SourceLocation NameLoc,
                                               QualType ObjectType,
-                                              NamedDecl *FirstQualifierInScope,
                                               bool AllowInjectedClassName) {
   if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) {
     TemplateDecl *Template = QTN->getUnderlyingTemplate().getAsTemplateDecl();
@@ -4589,7 +4571,7 @@ TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS,
     if (SS.getScopeRep()) {
       // These apply to the scope specifier, not the template.
       ObjectType = QualType();
-      FirstQualifierInScope = nullptr;
+      SS.setUnqualifiedLookups(std::nullopt);
     }
 
     if (!getDerived().AlwaysRebuild() &&
@@ -4606,7 +4588,6 @@ TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS,
                                               *DTN->getIdentifier(),
                                               NameLoc,
                                               ObjectType,
-                                              FirstQualifierInScope,
                                               AllowInjectedClassName);
     }
 
@@ -5155,13 +5136,12 @@ template<typename Derived>
 TypeLoc
 TreeTransform<Derived>::TransformTypeInObjectScope(TypeLoc TL,
                                                    QualType ObjectType,
-                                                   NamedDecl *UnqualLookup,
                                                    CXXScopeSpec &SS) {
   if (getDerived().AlreadyTransformed(TL.getType()))
     return TL;
 
   TypeSourceInfo *TSI =
-      TransformTSIInObjectScope(TL, ObjectType, UnqualLookup, SS);
+      TransformTSIInObjectScope(TL, ObjectType, SS);
   if (TSI)
     return TSI->getTypeLoc();
   return TypeLoc();
@@ -5171,35 +5151,29 @@ template<typename Derived>
 TypeSourceInfo *
 TreeTransform<Derived>::TransformTypeInObjectScope(TypeSourceInfo *TSInfo,
                                                    QualType ObjectType,
-                                                   NamedDecl *UnqualLookup,
                                                    CXXScopeSpec &SS) {
   if (getDerived().AlreadyTransformed(TSInfo->getType()))
     return TSInfo;
 
-  return TransformTSIInObjectScope(TSInfo->getTypeLoc(), ObjectType,
-                                   UnqualLookup, SS);
+  return TransformTSIInObjectScope(TSInfo->getTypeLoc(), ObjectType, SS);
 }
 
 template <typename Derived>
 TypeSourceInfo *TreeTransform<Derived>::TransformTSIInObjectScope(
-    TypeLoc TL, QualType ObjectType, NamedDecl *UnqualLookup,
-    CXXScopeSpec &SS) {
+    TypeLoc TL, QualType ObjectType, CXXScopeSpec &SS) {
   QualType T = TL.getType();
   assert(!getDerived().AlreadyTransformed(T));
 
   TypeLocBuilder TLB;
   QualType Result;
 
-  if (UnqualLookup)
-    SS.setFoundFirstQualifierInScope(UnqualLookup);
-
   if (isa<TemplateSpecializationType>(T)) {
     TemplateSpecializationTypeLoc SpecTL =
         TL.castAs<TemplateSpecializationTypeLoc>();
 
     TemplateName Template = getDerived().TransformTemplateName(
         SS, SpecTL.getTypePtr()->getTemplateName(), SpecTL.getTemplateNameLoc(),
-        ObjectType, UnqualLookup, /*AllowInjectedClassName*/true);
+        ObjectType, /*AllowInjectedClassName=*/true);
     if (Template.isNull())
       return nullptr;
 
@@ -5214,8 +5188,8 @@ TypeSourceInfo *TreeTransform<Derived>::TransformTSIInObjectScope(
                                          SpecTL.getTemplateKeywordLoc(),
                                          *SpecTL.getTypePtr()->getIdentifier(),
                                          SpecTL.getTemplateNameLoc(),
-                                         ObjectType, UnqualLookup,
-                                         /*AllowInjectedClassName*/true);
+                                         ObjectType,
+                                         /*AllowInjectedClassName=*/true);
     if (Template.isNull())
       return nullptr;
 
@@ -12259,7 +12233,8 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
   // first-qualifier-in-scope here, just in case we had a dependent
   // base (and therefore couldn't do the check) and a
   // nested-name-qualifier (and therefore could do the lookup).
-  NamedDecl *FirstQualifierInScope = nullptr;
+  ArrayRef<DeclAccessPair> UnqualifiedLookups;
+
   DeclarationNameInfo MemberNameInfo = E->getMemberNameInfo();
   if (MemberNameInfo.getName()) {
     MemberNameInfo = getDerived().TransformDeclarationNameInfo(MemberNameInfo);
@@ -12276,7 +12251,7 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
                                         FoundDecl,
                                         (E->hasExplicitTemplateArgs()
                                            ? &TransArgs : nullptr),
-                                        FirstQualifierInScope);
+                                        UnqualifiedLookups);
 }
 
 template<typename Derived>
@@ -13400,7 +13375,7 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
   if (E->getDestroyedTypeInfo()) {
     TypeSourceInfo *DestroyedTypeInfo
       = getDerived().TransformTypeInObjectScope(E->getDestroyedTypeInfo(),
-                                                ObjectType, nullptr, SS);
+                                                ObjectType, SS);
     if (!DestroyedTypeInfo)
       return ExprError();
     Destroyed = DestroyedTypeInfo;
@@ -13426,7 +13401,7 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
   if (E->getScopeTypeInfo()) {
     CXXScopeSpec EmptySS;
     ScopeTypeInfo = getDerived().TransformTypeInObjectScope(
-                      E->getScopeTypeInfo(), ObjectType, nullptr, EmptySS);
+                      E->getScopeTypeInfo(), ObjectType, EmptySS);
     if (!ScopeTypeInfo)
       return ExprError();
   }
@@ -14688,19 +14663,28 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
     ObjectType = BaseType->castAs<PointerType>()->getPointeeType();
   }
 
+  #if 0
   // Transform the first part of the nested-name-specifier that qualifies
   // the member name.
   NamedDecl *FirstQualifierInScope
     = getDerived().TransformFirstQualifierInScope(
                                             E->getFirstQualifierFoundInScope(),
                                             E->getQualifierLoc().getBeginLoc());
+  #endif
+
+  UnresolvedSet<4> UnqualifiedLookups;
+  for (auto D : E->unqualified_lookups()) {
+    if (NamedDecl *InstD = getDerived().TransformFirstQualifierInScope(
+        D.getDecl(), E->getQualifierLoc().getBeginLoc()))
+      UnqualifiedLookups.addDecl(InstD);
+  }
 
   NestedNameSpecifierLoc QualifierLoc;
   if (E->getQualifier()) {
     QualifierLoc
       = getDerived().TransformNestedNameSpecifierLoc(E->getQualifierLoc(),
                                                      ObjectType,
-                                                     FirstQualifierInScope);
+                                                     UnqualifiedLookups.pairs());
     if (!QualifierLoc)
       return ExprError();
   }
@@ -14724,7 +14708,7 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
         BaseType == E->getBaseType() &&
         QualifierLoc == E->getQualifierLoc() &&
         NameInfo.getName() == E->getMember() &&
-        FirstQualifierInScope == E->getFirstQualifierFoundInScope())
+        UnqualifiedLookups.pairs() == E->unqualified_lookups())
       return E;
 
     return getDerived().RebuildCXXDependentScopeMemberExpr(Base.get(),
@@ -14733,7 +14717,7 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
                                                        E->getOperatorLoc(),
                                                        QualifierLoc,
                                                        TemplateKWLoc,
-                                                       FirstQualifierInScope,
+                                                       UnqualifiedLookups.pairs(),
                                                        NameInfo,
                                                        /*TemplateArgs*/nullptr);
   }
@@ -14750,7 +14734,7 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
                                                      E->getOperatorLoc(),
                                                      QualifierLoc,
                                                      TemplateKWLoc,
-                                                     FirstQualifierInScope,
+                                                     UnqualifiedLookups.pairs(),
                                                      NameInfo,
                                                      &TransArgs);
 }
@@ -14813,11 +14797,11 @@ ExprResult TreeTransform<Derived>::TransformUnresolvedMemberExpr(
   // first-qualifier-in-scope here, just in case we had a dependent
   // base (and therefore couldn't do the check) and a
   // nested-name-qualifier (and therefore could do the lookup).
-  NamedDecl *FirstQualifierInScope = nullptr;
+  ArrayRef<DeclAccessPair> UnqualifiedLookups;
 
   return getDerived().RebuildUnresolvedMemberExpr(
       Base.get(), BaseType, Old->getOperatorLoc(), Old->isArrow(), QualifierLoc,
-      TemplateKWLoc, FirstQualifierInScope, R,
+      TemplateKWLoc, UnqualifiedLookups, R,
       (Old->hasExplicitTemplateArgs() ? &TransArgs : nullptr));
 }
 
@@ -16181,13 +16165,10 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
                                             const IdentifierInfo &Name,
                                             SourceLocation NameLoc,
                                             QualType ObjectType,
-                                            NamedDecl *FirstQualifierInScope,
                                             bool AllowInjectedClassName) {
   UnqualifiedId TemplateName;
   TemplateName.setIdentifier(&Name, NameLoc);
   Sema::TemplateTy Template;
-  if (FirstQualifierInScope)
-    SS.setFoundFirstQualifierInScope(FirstQualifierInScope);
   getSema().ActOnTemplateName(/*Scope=*/nullptr, SS, TemplateKWLoc,
                               TemplateName, ParsedType::make(ObjectType),
                               /*EnteringContext=*/false, Template,
@@ -16342,10 +16323,9 @@ TreeTransform<Derived>::RebuildCXXPseudoDestructorExpr(Expr *Base,
   return getSema().BuildMemberReferenceExpr(Base, BaseType,
                                             OperatorLoc, isArrow,
                                             SS, TemplateKWLoc,
-                                            /*FIXME: FirstQualifier*/ nullptr,
                                             NameInfo,
-                                            /*TemplateArgs*/ nullptr,
-                                            /*S*/nullptr);
+                                            /*TemplateArgs=*/nullptr,
+                                            /*S=*/nullptr);
 }
 
 template<typename Derived>
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index bea2b94989107..1054abf3170a1 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -1983,6 +1983,43 @@ void ASTStmtReader::VisitCXXDependentScopeMemberExpr(
     CXXDependentScopeMemberExpr *E) {
   VisitExpr(E);
 
+  CurrentUnpackingBits.emplace(Record.readInt());
+  bool HasQualifier = CurrentUnpackingBits->getNextBit();
+  bool HasTemplateInfo = CurrentUnpackingBits->getNextBit();
+  unsigned NumUnqualifiedLookups = Record.readInt();
+  unsigned NumTemplateArgs = Record.readInt();
+  E->CXXDependentScopeMemberExprBits.HasQualifier = HasQualifier;
+  E->CXXDependentScopeMemberExprBits.NumUnqualifiedLookups = NumUnqualifiedLookups;
+  E->CXXDependentScopeMemberExprBits.HasTemplateKWAndArgsInfo = HasTemplateInfo;
+
+  E->BaseType = Record.readType();
+  E->CXXDependentScopeMemberExprBits.IsArrow = CurrentUnpackingBits->getNextBit();
+
+  if (CurrentUnpackingBits->getNextBit())
+    E->Base = Record.readSubExpr();
+  else
+    E->Base = nullptr;
+
+  E->OperatorLoc = Record.readSourceLocation();
+  E->MemberNameInfo = Record.readDeclarationNameInfo();
+
+  if (HasQualifier)
+    new (E->getTrailingObjects<NestedNameSpecifierLoc>())
+        NestedNameSpecifierLoc(Record.readNestedNameSpecifierLoc());
+
+  for (unsigned I = 0; I != NumUnqualifiedLookups; ++I) {
+    auto *FoundD = Record.readDeclAs<NamedDecl>();
+    auto AS = (AccessSpecifier)Record.readInt();
+    E->getTrailingObjects<DeclAccessPair>()[I] = DeclAccessPair::make(FoundD, AS);;
+  }
+
+  if (HasTemplateInfo)
+    ReadTemplateKWAndArgsInfo(
+        *E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(),
+        E->getTrailingObjects<TemplateArgumentLoc>(), NumTemplateArgs);
+
+
+  #if 0
   unsigned NumTemplateArgs = Record.readInt();
   CurrentUnpackingBits.emplace(Record.readInt());
   bool HasTemplateKWAndArgsInfo = CurrentUnpackingBits->getNextBit();
@@ -2019,6 +2056,7 @@ void ASTStmtReader::VisitCXXDependentScopeMemberExpr(
     *E->getTrailingObjects<NamedDecl *>() = readDeclAs<NamedDecl>();
 
   E->MemberNameInfo = Record.readDeclarationNameInfo();
+  #endif
 }
 
 void
@@ -4055,6 +4093,8 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
       break;
 
     case EXPR_CXX_DEPENDENT_SCOPE_MEMBER: {
+
+      #if 0
       unsigned NumTemplateArgs = Record[ASTStmtReader::NumExprFields];
       BitsUnpacker DependentScopeMemberBits(
           Record[ASTStmtReader::NumExprFields + 1]);
@@ -4062,9 +4102,16 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
 
       bool HasFirstQualifierFoundInScope =
           DependentScopeMemberBits.getNextBit();
+      #endif
+      BitsUnpacker DependentScopeMemberBits(Record[ASTStmtReader::NumExprFields]);
+      bool HasQualifier = DependentScopeMemberBits.getNextBit();
+      bool HasTemplateInfo = DependentScopeMemberBits.getNextBit();
+      unsigned NumUnqualifiedLookups = Record[ASTStmtReader::NumExprFields + 1];
+      unsigned NumTemplateArgs = Record[ASTStmtReader::NumExprFields + 2];
+
       S = CXXDependentScopeMemberExpr::CreateEmpty(
-          Context, HasTemplateKWAndArgsInfo, NumTemplateArgs,
-          HasFirstQualifierFoundInScope);
+          Context, HasQualifier, NumUnqualifiedLookups,
+          HasTemplateInfo, NumTemplateArgs);
       break;
     }
 
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 3c586b270fbf4..bb117d1d2a7d2 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -1977,6 +1977,42 @@ void ASTStmtWriter::VisitCXXDependentScopeMemberExpr(
     CXXDependentScopeMemberExpr *E) {
   VisitExpr(E);
 
+  bool HasQualifier = E->hasQualifier();
+  unsigned NumUnqualifiedLookups = E->getNumUnqualifiedLookups();
+  bool HasTemplateInfo = E->hasTemplateKWAndArgsInfo();
+  unsigned NumTemplateArgs = E->getNumTemplateArgs();
+
+  // Write these first for easy access when deserializing, as they affect the
+  // size of the CXXDependentScopeMemberExpr.
+  CurrentPackingBits.updateBits();
+  CurrentPackingBits.addBit(HasQualifier);
+  CurrentPackingBits.addBit(HasTemplateInfo);
+  Record.push_back(NumUnqualifiedLookups);
+  Record.push_back(NumTemplateArgs);
+
+  Record.AddTypeRef(E->getBaseType());
+  CurrentPackingBits.addBit(E->isArrow());
+  CurrentPackingBits.addBit(!E->isImplicitAccess());
+  if (!E->isImplicitAccess())
+    Record.AddStmt(E->getBase());
+
+  Record.AddSourceLocation(E->getOperatorLoc());
+
+  Record.AddDeclarationNameInfo(E->MemberNameInfo);
+
+  if (HasQualifier)
+    Record.AddNestedNameSpecifierLoc(E->getQualifierLoc());
+
+  for (DeclAccessPair D : E->unqualified_lookups()) {
+    Record.AddDeclRef(D.getDecl());
+    Record.push_back(D.getAccess());
+  }
+
+  if (HasTemplateInfo)
+    AddTemplateKWAndArgsInfo(*E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(),
+                             E->getTrailingObjects<TemplateArgumentLoc>());
+
+  #if 0
   // Don't emit anything here (or if you do you will have to update
   // the corresponding deserialization function).
   Record.push_back(E->getNumTemplateArgs());
@@ -2005,6 +2041,8 @@ void ASTStmtWriter::VisitCXXDependentScopeMemberExpr(
     Record.AddDeclRef(E->getFirstQualifierFoundInScope());
 
   Record.AddDeclarationNameInfo(E->MemberNameInfo);
+  #endif
+
   Code = serialization::EXPR_CXX_DEPENDENT_SCOPE_MEMBER;
 }
 
diff --git a/clang/test/SemaCXX/pseudo-destructors.cpp b/clang/test/SemaCXX/pseudo-destructors.cpp
index 55a96002be2ab..44dc9ce8b1520 100644
--- a/clang/test/SemaCXX/pseudo-destructors.cpp
+++ b/clang/test/SemaCXX/pseudo-destructors.cpp
@@ -22,21 +22,21 @@ void cv_test(const volatile T* cvt) {
 void f(A* a, Foo *f, int *i, double *d, int ii) {
   a->~A();
   a->A::~A();
-  
+
   a->~foo(); // expected-error{{undeclared identifier 'foo' in destructor name}}
-  
+
   a->~Bar(); // expected-error{{destructor type 'Bar' (aka 'Foo') in object destruction expression does not match the type 'A' of the object being destroyed}}
-  
+
   f->~Bar();
   f->~Foo();
   i->~Bar(); // expected-error{{does not match}}
-  
+
   g().~Bar(); // expected-error{{non-scalar}}
-  
+
   f->::~Bar(); // expected-error {{not a structure or union}}
   f->::Bar::~Bar();
   f->N::~Wibble(); // expected-error{{'N' does not refer to a type}} expected-error{{'Wibble' does not refer to a type}}
-  
+
   f->Bar::~Bar(17, 42); // expected-error{{cannot have any arguments}}
 
   i->~Integer();
@@ -148,12 +148,12 @@ namespace TwoPhaseLookup {
   namespace Template {
     template<typename T> struct Y {};
     template<class U> using G = Y<U>;
-    template<typename T> void f(T *p) { p->~G<int>(); } // expected-error {{no member named '~Y'}}
+    template<typename T> void f(T *p) { p->~G<int>(); } // expected-error {{no member named 'G'}}
     void h1(Y<int> *p) { p->~G<int>(); }
-    void h2(Y<int> *p) { f(p); }
+    void h2(Y<int> *p) { f(p); } // expected-note {{instantiation of}}
     namespace N { template<typename T> struct G {}; }
     void h3(N::G<int> *p) { p->~G<int>(); }
-    void h4(N::G<int> *p) { f(p); } // expected-note {{instantiation of}}
+    void h4(N::G<int> *p) { f(p); }
   }
 
   namespace TemplateUndeclared {

>From cd778c571a8dfa6f789332a071c769c8ed69d9a1 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Fri, 31 May 2024 13:13:40 -0400
Subject: [PATCH 04/11] [FOLD] format

---
 clang/include/clang/AST/ExprCXX.h          |  26 +--
 clang/include/clang/AST/Stmt.h             |   4 +-
 clang/include/clang/Sema/Sema.h            |  14 +-
 clang/lib/AST/ASTImporter.cpp              |   1 -
 clang/lib/AST/ExprCXX.cpp                  |  36 ++-
 clang/lib/AST/ItaniumMangle.cpp            |  35 ++-
 clang/lib/Sema/SemaCXXScopeSpec.cpp        |   5 +-
 clang/lib/Sema/SemaCoroutine.cpp           |   4 +-
 clang/lib/Sema/SemaDeclCXX.cpp             |  33 ++-
 clang/lib/Sema/SemaExprMember.cpp          |  50 ++--
 clang/lib/Sema/SemaOverload.cpp            |  11 +-
 clang/lib/Sema/SemaStmtAsm.cpp             |   5 +-
 clang/lib/Sema/SemaTemplate.cpp            |   2 +-
 clang/lib/Sema/SemaTemplateInstantiate.cpp |   9 +-
 clang/lib/Sema/TreeTransform.h             | 260 ++++++++-------------
 clang/lib/Serialization/ASTReaderStmt.cpp  |  26 ++-
 clang/lib/Serialization/ASTWriterStmt.cpp  |   4 +-
 17 files changed, 222 insertions(+), 303 deletions(-)

diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index 3e4d673590b71..d8f87ad4a94f3 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -3671,11 +3671,9 @@ class CXXUnresolvedConstructExpr final
 /// an implicit access if a qualifier is provided.
 class CXXDependentScopeMemberExpr final
     : public Expr,
-      private llvm::TrailingObjects<CXXDependentScopeMemberExpr,
-                                    NestedNameSpecifierLoc,
-                                    DeclAccessPair,
-                                    ASTTemplateKWAndArgsInfo,
-                                    TemplateArgumentLoc> {
+      private llvm::TrailingObjects<
+          CXXDependentScopeMemberExpr, NestedNameSpecifierLoc, DeclAccessPair,
+          ASTTemplateKWAndArgsInfo, TemplateArgumentLoc> {
   friend class ASTStmtReader;
   friend class ASTStmtWriter;
   friend TrailingObjects;
@@ -3751,10 +3749,8 @@ class CXXDependentScopeMemberExpr final
 
 public:
   static CXXDependentScopeMemberExpr *
-  Create(const ASTContext &Ctx, Expr *Base,
-         QualType BaseType, bool IsArrow,
-         SourceLocation OperatorLoc,
-         NestedNameSpecifierLoc QualifierLoc,
+  Create(const ASTContext &Ctx, Expr *Base, QualType BaseType, bool IsArrow,
+         SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc,
          SourceLocation TemplateKWLoc,
          ArrayRef<DeclAccessPair> UnqualifiedLookups,
          DeclarationNameInfo MemberNameInfo,
@@ -3762,8 +3758,7 @@ class CXXDependentScopeMemberExpr final
 
   static CXXDependentScopeMemberExpr *
   CreateEmpty(const ASTContext &Ctx, bool HasQualifier,
-              unsigned NumUnqualifiedLookups,
-              bool HasTemplateKWAndArgsInfo,
+              unsigned NumUnqualifiedLookups, bool HasTemplateKWAndArgsInfo,
               unsigned NumTemplateArgs);
 
   /// True if this is an implicit access, i.e. one in which the
@@ -3789,9 +3784,7 @@ class CXXDependentScopeMemberExpr final
   bool isArrow() const { return CXXDependentScopeMemberExprBits.IsArrow; }
 
   /// Retrieve the location of the '->' or '.' operator.
-  SourceLocation getOperatorLoc() const {
-    return OperatorLoc;
-  }
+  SourceLocation getOperatorLoc() const { return OperatorLoc; }
 
   /// Determines whether this member expression had a nested-name-specifier
   /// prior to the name of the member, e.g., x->Base::foo.
@@ -3814,8 +3807,7 @@ class CXXDependentScopeMemberExpr final
     return getQualifierLoc().getNestedNameSpecifier();
   }
 
-
-  #if 0
+#if 0
   /// Retrieve the first part of the nested-name-specifier that was
   /// found in the scope of the member access expression when the member access
   /// was initially parsed.
@@ -3832,7 +3824,7 @@ class CXXDependentScopeMemberExpr final
       return nullptr;
     return *getTrailingObjects<NamedDecl *>();
   }
-  #endif
+#endif
 
   ArrayRef<DeclAccessPair> unqualified_lookups() const {
     if (!getNumUnqualifiedLookups())
diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index e0e5c8fb99dc3..6e6221ec15fdb 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -1030,12 +1030,12 @@ class alignas(void *) Stmt {
     LLVM_PREFERRED_TYPE(bool)
     unsigned HasTemplateKWAndArgsInfo : 1;
 
-    #if 0
+#if 0
     /// See getFirstQualifierFoundInScope() and the comment listing
     /// the trailing objects.
     LLVM_PREFERRED_TYPE(bool)
     unsigned HasFirstQualifierFoundInScope : 1;
-    #endif
+#endif
     /// Number of declarations found by unqualified lookup for the
     /// first component name of the nested-name-specifier.
     unsigned NumUnqualifiedLookups;
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 9fab8d13a1c35..4208da06db3dc 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -2390,7 +2390,8 @@ class Sema final : public SemaBase {
 
   bool isAcceptableNestedNameSpecifier(const NamedDecl *SD,
                                        bool *CanCorrect = nullptr);
-  bool LookupFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS, UnresolvedSetImpl &R);
+  bool LookupFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS,
+                                   UnresolvedSetImpl &R);
 
   /// Keeps information about an identifier in a nested-name-spec.
   ///
@@ -6934,11 +6935,12 @@ class Sema final : public SemaBase {
                           const TemplateArgumentListInfo *TemplateArgs,
                           bool IsDefiniteInstance, const Scope *S);
 
-  ExprResult ActOnDependentMemberExpr(
-      Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OpLoc,
-      const CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
-      const DeclarationNameInfo &NameInfo,
-      const TemplateArgumentListInfo *TemplateArgs);
+  ExprResult
+  ActOnDependentMemberExpr(Expr *Base, QualType BaseType, bool IsArrow,
+                           SourceLocation OpLoc, const CXXScopeSpec &SS,
+                           SourceLocation TemplateKWLoc,
+                           const DeclarationNameInfo &NameInfo,
+                           const TemplateArgumentListInfo *TemplateArgs);
 
   ExprResult ActOnMemberAccessExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
                                    bool IsArrow, CXXScopeSpec &SS,
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 6c306418fe071..b47d7e86013dd 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -8433,7 +8433,6 @@ ExpectedStmt ASTNodeImporter::VisitCXXDependentScopeMemberExpr(
   auto ToQualifierLoc = importChecked(Err, E->getQualifierLoc());
   auto ToTemplateKeywordLoc = importChecked(Err, E->getTemplateKeywordLoc());
 
-
   UnresolvedSet<8> ToUnqualifiedLookups;
   for (auto D : E->unqualified_lookups())
     if (auto ToDOrErr = import(D.getDecl()))
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index 87e33564ca02e..826f66fe1624c 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -1450,8 +1450,7 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(
       Base(Base), BaseType(BaseType), OperatorLoc(OperatorLoc),
       MemberNameInfo(MemberNameInfo) {
   CXXDependentScopeMemberExprBits.IsArrow = IsArrow;
-  CXXDependentScopeMemberExprBits.HasQualifier =
-      QualifierLoc.hasQualifier();
+  CXXDependentScopeMemberExprBits.HasQualifier = QualifierLoc.hasQualifier();
   CXXDependentScopeMemberExprBits.NumUnqualifiedLookups =
       UnqualifiedLookups.size();
   CXXDependentScopeMemberExprBits.HasTemplateKWAndArgsInfo =
@@ -1462,7 +1461,8 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(
         NestedNameSpecifierLoc(QualifierLoc);
 
   std::uninitialized_copy_n(UnqualifiedLookups.data(),
-      UnqualifiedLookups.size(), getTrailingObjects<DeclAccessPair>());
+                            UnqualifiedLookups.size(),
+                            getTrailingObjects<DeclAccessPair>());
 
   if (TemplateArgs) {
     auto Deps = TemplateArgumentDependence::None;
@@ -1482,8 +1482,7 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(
     bool HasTemplateKWAndArgsInfo)
     : Expr(CXXDependentScopeMemberExprClass, Empty) {
   CXXDependentScopeMemberExprBits.HasQualifier = HasQualifier;
-  CXXDependentScopeMemberExprBits.NumUnqualifiedLookups =
-      NumUnqualifiedLookups;
+  CXXDependentScopeMemberExprBits.NumUnqualifiedLookups = NumUnqualifiedLookups;
   CXXDependentScopeMemberExprBits.HasTemplateKWAndArgsInfo =
       HasTemplateKWAndArgsInfo;
 }
@@ -1500,12 +1499,11 @@ CXXDependentScopeMemberExpr *CXXDependentScopeMemberExpr::Create(
   bool HasTemplateKWAndArgsInfo =
       (TemplateArgs != nullptr) || TemplateKWLoc.isValid();
   unsigned NumTemplateArgs = TemplateArgs ? TemplateArgs->size() : 0;
-  unsigned Size = totalSizeToAlloc<NestedNameSpecifierLoc,
-                                   DeclAccessPair,
-                                   ASTTemplateKWAndArgsInfo,
-                                   TemplateArgumentLoc>(
-      HasQualifier, NumUnqualifiedLookups,
-      HasTemplateKWAndArgsInfo, NumTemplateArgs);
+  unsigned Size =
+      totalSizeToAlloc<NestedNameSpecifierLoc, DeclAccessPair,
+                       ASTTemplateKWAndArgsInfo, TemplateArgumentLoc>(
+          HasQualifier, NumUnqualifiedLookups, HasTemplateKWAndArgsInfo,
+          NumTemplateArgs);
 
   void *Mem = Ctx.Allocate(Size, alignof(CXXDependentScopeMemberExpr));
   return new (Mem) CXXDependentScopeMemberExpr(
@@ -1519,16 +1517,16 @@ CXXDependentScopeMemberExpr *CXXDependentScopeMemberExpr::CreateEmpty(
   assert(!NumTemplateArgs || HasTemplateKWAndArgsInfo);
   assert(!NumUnqualifiedLookups || HasQualifier);
 
-  unsigned Size = totalSizeToAlloc<NestedNameSpecifierLoc,
-                                   DeclAccessPair,
-                                   ASTTemplateKWAndArgsInfo,
-                                   TemplateArgumentLoc>(
-      HasQualifier, NumUnqualifiedLookups,
-      HasTemplateKWAndArgsInfo, NumTemplateArgs);
+  unsigned Size =
+      totalSizeToAlloc<NestedNameSpecifierLoc, DeclAccessPair,
+                       ASTTemplateKWAndArgsInfo, TemplateArgumentLoc>(
+          HasQualifier, NumUnqualifiedLookups, HasTemplateKWAndArgsInfo,
+          NumTemplateArgs);
 
   void *Mem = Ctx.Allocate(Size, alignof(CXXDependentScopeMemberExpr));
-  return new (Mem) CXXDependentScopeMemberExpr(
-      EmptyShell(), HasQualifier, NumUnqualifiedLookups, HasTemplateKWAndArgsInfo);
+  return new (Mem) CXXDependentScopeMemberExpr(EmptyShell(), HasQualifier,
+                                               NumUnqualifiedLookups,
+                                               HasTemplateKWAndArgsInfo);
 }
 
 CXXThisExpr *CXXThisExpr::Create(const ASTContext &Ctx, SourceLocation L,
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 43c046a46ade3..631d32427a1d7 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -598,8 +598,7 @@ class CXXNameMangler {
                         ArrayRef<DeclAccessPair> UnqualifiedLookups,
                         DeclarationName name,
                         const TemplateArgumentLoc *TemplateArgs,
-                        unsigned NumTemplateArgs,
-                        unsigned knownArity);
+                        unsigned NumTemplateArgs, unsigned knownArity);
   void mangleCastExpression(const Expr *E, StringRef CastEncoding);
   void mangleInitListElements(const InitListExpr *InitList);
   void mangleRequirement(SourceLocation RequiresExprLoc,
@@ -4491,14 +4490,11 @@ void CXXNameMangler::mangleMemberExprBase(const Expr *Base, bool IsArrow) {
 }
 
 /// Mangles a member expression.
-void CXXNameMangler::mangleMemberExpr(const Expr *base,
-                                      bool isArrow,
-                                      NestedNameSpecifier *qualifier,
-                                      ArrayRef<DeclAccessPair> UnqualifiedLookups,
-                                      DeclarationName member,
-                                      const TemplateArgumentLoc *TemplateArgs,
-                                      unsigned NumTemplateArgs,
-                                      unsigned arity) {
+void CXXNameMangler::mangleMemberExpr(
+    const Expr *base, bool isArrow, NestedNameSpecifier *qualifier,
+    ArrayRef<DeclAccessPair> UnqualifiedLookups, DeclarationName member,
+    const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs,
+    unsigned arity) {
   // <expression> ::= dt <expression> <unresolved-name>
   //              ::= pt <expression> <unresolved-name>
   if (base)
@@ -4979,11 +4975,9 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
   case Expr::MemberExprClass: {
     NotPrimaryExpr();
     const MemberExpr *ME = cast<MemberExpr>(E);
-    mangleMemberExpr(ME->getBase(), ME->isArrow(),
-                     ME->getQualifier(), std::nullopt,
-                     ME->getMemberDecl()->getDeclName(),
-                     ME->getTemplateArgs(), ME->getNumTemplateArgs(),
-                     Arity);
+    mangleMemberExpr(ME->getBase(), ME->isArrow(), ME->getQualifier(),
+                     std::nullopt, ME->getMemberDecl()->getDeclName(),
+                     ME->getTemplateArgs(), ME->getNumTemplateArgs(), Arity);
     break;
   }
 
@@ -4992,9 +4986,8 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
     const UnresolvedMemberExpr *ME = cast<UnresolvedMemberExpr>(E);
     mangleMemberExpr(ME->isImplicitAccess() ? nullptr : ME->getBase(),
                      ME->isArrow(), ME->getQualifier(), std::nullopt,
-                     ME->getMemberName(),
-                     ME->getTemplateArgs(), ME->getNumTemplateArgs(),
-                     Arity);
+                     ME->getMemberName(), ME->getTemplateArgs(),
+                     ME->getNumTemplateArgs(), Arity);
     break;
   }
 
@@ -5004,10 +4997,8 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
       = cast<CXXDependentScopeMemberExpr>(E);
     mangleMemberExpr(ME->isImplicitAccess() ? nullptr : ME->getBase(),
                      ME->isArrow(), ME->getQualifier(),
-                     ME->unqualified_lookups(),
-                     ME->getMember(),
-                     ME->getTemplateArgs(), ME->getNumTemplateArgs(),
-                     Arity);
+                     ME->unqualified_lookups(), ME->getMember(),
+                     ME->getTemplateArgs(), ME->getNumTemplateArgs(), Arity);
     break;
   }
 
diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp
index 99c5476392fc9..fd3f68bfbd0a5 100644
--- a/clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -390,7 +390,8 @@ bool Sema::isAcceptableNestedNameSpecifier(const NamedDecl *SD,
 /// (e.g., Base::), perform name lookup for that identifier as a
 /// nested-name-specifier within the given scope, and return the result of that
 /// name lookup.
-bool Sema::LookupFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS, UnresolvedSetImpl &R) {
+bool Sema::LookupFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS,
+                                       UnresolvedSetImpl &R) {
   if (!S)
     return false;
 
@@ -533,7 +534,7 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
     if (S) {
       LookupName(Found, S);
     } else if (LookupFirstQualifierInScope &&
-        !SS.getUnqualifiedLookups().empty()) {
+               !SS.getUnqualifiedLookups().empty()) {
       Found.addAllDecls(SS.getUnqualifiedLookups());
       Found.resolveKind();
     }
diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp
index dbe0f0cf11b90..fa0eb1d2afbee 100644
--- a/clang/lib/Sema/SemaCoroutine.cpp
+++ b/clang/lib/Sema/SemaCoroutine.cpp
@@ -306,8 +306,8 @@ static ExprResult buildMemberCall(Sema &S, Expr *Base, SourceLocation Loc,
   // FIXME: Fix BuildMemberReferenceExpr to take a const CXXScopeSpec&.
   CXXScopeSpec SS;
   ExprResult Result = S.BuildMemberReferenceExpr(
-      Base, Base->getType(), Loc, /*IsPtr=*/false, SS,
-      SourceLocation(), NameInfo, /*TemplateArgs=*/nullptr,
+      Base, Base->getType(), Loc, /*IsPtr=*/false, SS, SourceLocation(),
+      NameInfo, /*TemplateArgs=*/nullptr,
       /*Scope=*/nullptr);
   if (Result.isInvalid())
     return ExprError();
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 29ff6e2501b5b..4a77b40a3acd3 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -5012,15 +5012,12 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
     MemberLookup.addDecl(Indirect ? cast<ValueDecl>(Indirect)
                                   : cast<ValueDecl>(Field), AS_public);
     MemberLookup.resolveKind();
-    ExprResult CtorArg
-      = SemaRef.BuildMemberReferenceExpr(MemberExprBase,
-                                         ParamType, Loc,
-                                         /*IsArrow=*/false,
-                                         SS,
-                                         /*TemplateKWLoc=*/SourceLocation(),
-                                         MemberLookup,
-                                         /*TemplateArgs=*/nullptr,
-                                         /*S=*/nullptr);
+    ExprResult CtorArg = SemaRef.BuildMemberReferenceExpr(
+        MemberExprBase, ParamType, Loc,
+        /*IsArrow=*/false, SS,
+        /*TemplateKWLoc=*/SourceLocation(), MemberLookup,
+        /*TemplateArgs=*/nullptr,
+        /*S=*/nullptr);
     if (CtorArg.isInvalid())
       return true;
 
@@ -14544,9 +14541,10 @@ class MemberBuilder: public ExprBuilder {
 public:
   Expr *build(Sema &S, SourceLocation Loc) const override {
     return assertNotNull(S.BuildMemberReferenceExpr(
-        Builder.build(S, Loc), Type, Loc, IsArrow, SS,
-        /*TemplateKwLoc=*/SourceLocation(), MemberLookup,
-        /*TemplateArgs=*/nullptr, /*S=*/nullptr).get());
+                              Builder.build(S, Loc), Type, Loc, IsArrow, SS,
+                              /*TemplateKwLoc=*/SourceLocation(), MemberLookup,
+                              /*TemplateArgs=*/nullptr, /*S=*/nullptr)
+                             .get());
   }
 
   MemberBuilder(const ExprBuilder &Builder, QualType Type, bool IsArrow,
@@ -14752,12 +14750,11 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T,
                    Loc);
 
     // Create the reference to operator=.
-    ExprResult OpEqualRef
-      = S.BuildMemberReferenceExpr(To.build(S, Loc), T, Loc, /*IsArrow=*/false,
-                                   SS, /*TemplateKWLoc=*/SourceLocation(),
-                                   OpLookup,
-                                   /*TemplateArgs=*/nullptr, /*S*/nullptr,
-                                   /*SuppressQualifierCheck=*/true);
+    ExprResult OpEqualRef = S.BuildMemberReferenceExpr(
+        To.build(S, Loc), T, Loc, /*IsArrow=*/false, SS,
+        /*TemplateKWLoc=*/SourceLocation(), OpLookup,
+        /*TemplateArgs=*/nullptr, /*S*/ nullptr,
+        /*SuppressQualifierCheck=*/true);
     if (OpEqualRef.isInvalid())
       return StmtError();
 
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 5efa5d0d1421e..038b3e9ceadb3 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -553,9 +553,8 @@ static Decl *FindGetterSetterNameDecl(const ObjCObjectPointerType *QIdTy,
 }
 
 ExprResult
-Sema::ActOnDependentMemberExpr(Expr *BaseExpr, QualType BaseType,
-                               bool IsArrow, SourceLocation OpLoc,
-                               const CXXScopeSpec &SS,
+Sema::ActOnDependentMemberExpr(Expr *BaseExpr, QualType BaseType, bool IsArrow,
+                               SourceLocation OpLoc, const CXXScopeSpec &SS,
                                SourceLocation TemplateKWLoc,
                                const DeclarationNameInfo &NameInfo,
                                const TemplateArgumentListInfo *TemplateArgs) {
@@ -839,11 +838,9 @@ ExprResult Sema::BuildMemberReferenceExpr(
     BaseType = Base->getType();
   }
 
-  return BuildMemberReferenceExpr(Base, BaseType,
-                                  OpLoc, IsArrow, SS, TemplateKWLoc,
-                                  R, TemplateArgs, S,
-                                  /*SuppressQualifierCheck=*/false,
-                                  ExtraArgs);
+  return BuildMemberReferenceExpr(Base, BaseType, OpLoc, IsArrow, SS,
+                                  TemplateKWLoc, R, TemplateArgs, S,
+                                  /*SuppressQualifierCheck=*/false, ExtraArgs);
 }
 
 ExprResult
@@ -981,16 +978,11 @@ static bool IsInFnTryBlockHandler(const Scope *S) {
   return false;
 }
 
-ExprResult
-Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
-                               SourceLocation OpLoc, bool IsArrow,
-                               const CXXScopeSpec &SS,
-                               SourceLocation TemplateKWLoc,
-                               LookupResult &R,
-                               const TemplateArgumentListInfo *TemplateArgs,
-                               const Scope *S,
-                               bool SuppressQualifierCheck,
-                               ActOnMemberAccessExtraArgs *ExtraArgs) {
+ExprResult Sema::BuildMemberReferenceExpr(
+    Expr *BaseExpr, QualType BaseExprType, SourceLocation OpLoc, bool IsArrow,
+    const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R,
+    const TemplateArgumentListInfo *TemplateArgs, const Scope *S,
+    bool SuppressQualifierCheck, ActOnMemberAccessExtraArgs *ExtraArgs) {
   assert(!SS.isInvalid() && "nested-name-specifier cannot be invalid");
   // If the member wasn't found in the current instantiation, or if the
   // arrow operator was used with a dependent non-pointer object expression,
@@ -1206,9 +1198,9 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
 
     // Non-dependent member, but dependent template arguments.
     if (!VDecl.get())
-      return ActOnDependentMemberExpr(
-          BaseExpr, BaseExpr->getType(), IsArrow, OpLoc, SS, TemplateKWLoc,
-          MemberNameInfo, TemplateArgs);
+      return ActOnDependentMemberExpr(BaseExpr, BaseExpr->getType(), IsArrow,
+                                      OpLoc, SS, TemplateKWLoc, MemberNameInfo,
+                                      TemplateArgs);
 
     VarDecl *Var = cast<VarDecl>(VDecl.get());
     if (!Var->getTemplateSpecializationKind())
@@ -1793,7 +1785,8 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
     return ExprError(Diag(OpLoc, diag::err_hlsl_operator_unsupported) << 2);
 
   UnresolvedSet<4> UnqualifiedLookups;
-  if (SS.isValid() && LookupFirstQualifierInScope(S, SS.getScopeRep(), UnqualifiedLookups)) {
+  if (SS.isValid() &&
+      LookupFirstQualifierInScope(S, SS.getScopeRep(), UnqualifiedLookups)) {
     SS.setUnqualifiedLookups(UnqualifiedLookups.pairs());
   }
   // This is a postfix expression, so get rid of ParenListExprs.
@@ -1803,8 +1796,8 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
 
   ActOnMemberAccessExtraArgs ExtraArgs = {S, Id, ObjCImpDecl};
   ExprResult Res = BuildMemberReferenceExpr(
-      Base, Base->getType(), OpLoc, IsArrow, SS, TemplateKWLoc,
-      NameInfo, TemplateArgs, S, &ExtraArgs);
+      Base, Base->getType(), OpLoc, IsArrow, SS, TemplateKWLoc, NameInfo,
+      TemplateArgs, S, &ExtraArgs);
 
   if (!Res.isInvalid() && isa<MemberExpr>(Res.get()))
     CheckMemberAccessOfNoDeref(cast<MemberExpr>(Res.get()));
@@ -1952,9 +1945,8 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
     baseExpr = BuildCXXThisExpr(loc, ThisTy, /*IsImplicit=*/true);
   }
 
-  return BuildMemberReferenceExpr(
-      baseExpr, ThisTy,
-      /*OpLoc=*/SourceLocation(),
-      /*IsArrow=*/!getLangOpts().HLSL, SS,
-      TemplateKWLoc, R, TemplateArgs, S);
+  return BuildMemberReferenceExpr(baseExpr, ThisTy,
+                                  /*OpLoc=*/SourceLocation(),
+                                  /*IsArrow=*/!getLangOpts().HLSL, SS,
+                                  TemplateKWLoc, R, TemplateArgs, S);
 }
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 6f066235461b0..a7f4f8454fe09 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -16217,12 +16217,11 @@ Sema::BuildForRangeBeginEndCall(SourceLocation Loc,
 
   CandidateSet->clear(OverloadCandidateSet::CSK_Normal);
   if (!MemberLookup.empty()) {
-    ExprResult MemberRef =
-        BuildMemberReferenceExpr(Range, Range->getType(), Loc,
-                                 /*IsPtr=*/false, /*SS=*/CXXScopeSpec(),
-                                 /*TemplateKWLoc=*/SourceLocation(),
-                                 MemberLookup,
-                                 /*TemplateArgs=*/nullptr, S);
+    ExprResult MemberRef = BuildMemberReferenceExpr(
+        Range, Range->getType(), Loc,
+        /*IsPtr=*/false, /*SS=*/CXXScopeSpec(),
+        /*TemplateKWLoc=*/SourceLocation(), MemberLookup,
+        /*TemplateArgs=*/nullptr, S);
     if (MemberRef.isInvalid()) {
       *CallExpr = ExprError();
       return FRS_DiagnosticIssued;
diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp
index 9b1e49620173d..da2e99b6bc00c 100644
--- a/clang/lib/Sema/SemaStmtAsm.cpp
+++ b/clang/lib/Sema/SemaStmtAsm.cpp
@@ -900,7 +900,8 @@ Sema::LookupInlineAsmVarDeclField(Expr *E, StringRef Member,
     return CXXDependentScopeMemberExpr::Create(
         Context, E, T, /*IsArrow=*/false, AsmLoc, NestedNameSpecifierLoc(),
         SourceLocation(),
-        /*UnqualifiedLookups=*/std::nullopt, NameInfo, /*TemplateArgs=*/nullptr);
+        /*UnqualifiedLookups=*/std::nullopt, NameInfo,
+        /*TemplateArgs=*/nullptr);
   }
 
   const RecordType *RT = T->getAs<RecordType>();
@@ -924,7 +925,7 @@ Sema::LookupInlineAsmVarDeclField(Expr *E, StringRef Member,
   // Make an Expr to thread through OpDecl.
   ExprResult Result = BuildMemberReferenceExpr(
       E, E->getType(), AsmLoc, /*IsArrow=*/false, /*SS=*/CXXScopeSpec(),
-      /*TemplateKWLoc*/SourceLocation(), FieldResult,
+      /*TemplateKWLoc*/ SourceLocation(), FieldResult,
       /*TemplateArgs=*/nullptr, /*S=*/nullptr);
 
   return Result;
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 57fe755ae8fc0..4f38af1187896 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -472,7 +472,7 @@ bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS,
     if (S) {
       LookupName(Found, S);
     } else if (LookupFirstQualifierInScope &&
-        !SS.getUnqualifiedLookups().empty()) {
+               !SS.getUnqualifiedLookups().empty()) {
       Found.addAllDecls(SS.getUnqualifiedLookups());
       Found.resolveKind();
     }
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 73ca3a0fde478..dcbe8aff6127d 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1545,11 +1545,10 @@ namespace {
                                    NestedNameSpecifierLoc QualifierLoc,
                                    QualType T);
 
-    TemplateName
-    TransformTemplateName(CXXScopeSpec &SS, TemplateName Name,
-                          SourceLocation NameLoc,
-                          QualType ObjectType = QualType(),
-                          bool AllowInjectedClassName = false);
+    TemplateName TransformTemplateName(CXXScopeSpec &SS, TemplateName Name,
+                                       SourceLocation NameLoc,
+                                       QualType ObjectType = QualType(),
+                                       bool AllowInjectedClassName = false);
 
     const CXXAssumeAttr *TransformCXXAssumeAttr(const CXXAssumeAttr *AA);
     const LoopHintAttr *TransformLoopHintAttr(const LoopHintAttr *LH);
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index e421510105c69..f4e7ccdf309af 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -541,10 +541,9 @@ class TreeTransform {
   /// By default, transforms all of the types and declarations within the
   /// nested-name-specifier. Subclasses may override this function to provide
   /// alternate behavior.
-  NestedNameSpecifierLoc
-  TransformNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
-                                  QualType ObjectType = QualType(),
-                                  ArrayRef<DeclAccessPair> UnqualifiedLookups = std::nullopt);
+  NestedNameSpecifierLoc TransformNestedNameSpecifierLoc(
+      NestedNameSpecifierLoc NNS, QualType ObjectType = QualType(),
+      ArrayRef<DeclAccessPair> UnqualifiedLookups = std::nullopt);
 
   /// Transform the given declaration name.
   ///
@@ -585,11 +584,10 @@ class TreeTransform {
   /// By default, transforms the template name by transforming the declarations
   /// and nested-name-specifiers that occur within the template name.
   /// Subclasses may override this function to provide alternate behavior.
-  TemplateName
-  TransformTemplateName(CXXScopeSpec &SS, TemplateName Name,
-                        SourceLocation NameLoc,
-                        QualType ObjectType = QualType(),
-                        bool AllowInjectedClassName = false);
+  TemplateName TransformTemplateName(CXXScopeSpec &SS, TemplateName Name,
+                                     SourceLocation NameLoc,
+                                     QualType ObjectType = QualType(),
+                                     bool AllowInjectedClassName = false);
 
   /// Transform the given template argument.
   ///
@@ -1139,8 +1137,7 @@ class TreeTransform {
     CXXScopeSpec SS;
     SS.Adopt(QualifierLoc);
     TemplateName InstName = getDerived().RebuildTemplateName(
-        SS, TemplateKWLoc, *Name, NameLoc, QualType(),
-        AllowInjectedClassName);
+        SS, TemplateKWLoc, *Name, NameLoc, QualType(), AllowInjectedClassName);
 
     if (InstName.isNull())
       return QualType();
@@ -2847,15 +2844,14 @@ class TreeTransform {
   ///
   /// By default, performs semantic analysis to build the new expression.
   /// Subclasses may override this routine to provide different behavior.
-  ExprResult RebuildMemberExpr(Expr *Base, SourceLocation OpLoc,
-                               bool isArrow,
-                               NestedNameSpecifierLoc QualifierLoc,
-                               SourceLocation TemplateKWLoc,
-                               const DeclarationNameInfo &MemberNameInfo,
-                               ValueDecl *Member,
-                               NamedDecl *FoundDecl,
-                        const TemplateArgumentListInfo *ExplicitTemplateArgs,
-                               ArrayRef<DeclAccessPair> UnqualifiedLookups) {
+  ExprResult
+  RebuildMemberExpr(Expr *Base, SourceLocation OpLoc, bool isArrow,
+                    NestedNameSpecifierLoc QualifierLoc,
+                    SourceLocation TemplateKWLoc,
+                    const DeclarationNameInfo &MemberNameInfo,
+                    ValueDecl *Member, NamedDecl *FoundDecl,
+                    const TemplateArgumentListInfo *ExplicitTemplateArgs,
+                    ArrayRef<DeclAccessPair> UnqualifiedLookups) {
     ExprResult BaseResult = getSema().PerformMemberExprBaseConversion(Base,
                                                                       isArrow);
     if (!Member->getDeclName()) {
@@ -2922,9 +2918,9 @@ class TreeTransform {
     }
 
     return getSema().BuildMemberReferenceExpr(Base, BaseType, OpLoc, isArrow,
-                                              SS, TemplateKWLoc,
-                                              R, ExplicitTemplateArgs,
-                                              /*S*/nullptr);
+                                              SS, TemplateKWLoc, R,
+                                              ExplicitTemplateArgs,
+                                              /*S*/ nullptr);
   }
 
   /// Build a new binary operator expression.
@@ -2999,7 +2995,7 @@ class TreeTransform {
     return getSema().BuildMemberReferenceExpr(
         Base, Base->getType(), OpLoc, IsArrow, SS,
         /*TemplateKWLoc=*/SourceLocation(), NameInfo,
-        /*TemplateArgs=*/ nullptr, /*S=*/nullptr);
+        /*TemplateArgs=*/nullptr, /*S=*/nullptr);
   }
 
   /// Build a new initializer list expression.
@@ -3567,46 +3563,37 @@ class TreeTransform {
   ///
   /// By default, performs semantic analysis to build the new expression.
   /// Subclasses may override this routine to provide different behavior.
-  ExprResult RebuildCXXDependentScopeMemberExpr(Expr *BaseE,
-                                                QualType BaseType,
-                                                bool IsArrow,
-                                                SourceLocation OperatorLoc,
-                                          NestedNameSpecifierLoc QualifierLoc,
-                                                SourceLocation TemplateKWLoc,
-                                  ArrayRef<DeclAccessPair> UnqualifiedLookups,
-                                   const DeclarationNameInfo &MemberNameInfo,
-                              const TemplateArgumentListInfo *TemplateArgs) {
+  ExprResult RebuildCXXDependentScopeMemberExpr(
+      Expr *BaseE, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc,
+      NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc,
+      ArrayRef<DeclAccessPair> UnqualifiedLookups,
+      const DeclarationNameInfo &MemberNameInfo,
+      const TemplateArgumentListInfo *TemplateArgs) {
     CXXScopeSpec SS;
     SS.Adopt(QualifierLoc);
     SS.setUnqualifiedLookups(UnqualifiedLookups);
 
-    return SemaRef.BuildMemberReferenceExpr(BaseE, BaseType,
-                                            OperatorLoc, IsArrow,
-                                            SS, TemplateKWLoc,
-                                            MemberNameInfo,
-                                            TemplateArgs, /*S=*/nullptr);
+    return SemaRef.BuildMemberReferenceExpr(
+        BaseE, BaseType, OperatorLoc, IsArrow, SS, TemplateKWLoc,
+        MemberNameInfo, TemplateArgs, /*S=*/nullptr);
   }
 
   /// Build a new member reference expression.
   ///
   /// By default, performs semantic analysis to build the new expression.
   /// Subclasses may override this routine to provide different behavior.
-  ExprResult RebuildUnresolvedMemberExpr(Expr *BaseE, QualType BaseType,
-                                         SourceLocation OperatorLoc,
-                                         bool IsArrow,
-                                         NestedNameSpecifierLoc QualifierLoc,
-                                         SourceLocation TemplateKWLoc,
-                                         ArrayRef<DeclAccessPair> UnqualifiedLookups,
-                                         LookupResult &R,
-                                const TemplateArgumentListInfo *TemplateArgs) {
+  ExprResult RebuildUnresolvedMemberExpr(
+      Expr *BaseE, QualType BaseType, SourceLocation OperatorLoc, bool IsArrow,
+      NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc,
+      ArrayRef<DeclAccessPair> UnqualifiedLookups, LookupResult &R,
+      const TemplateArgumentListInfo *TemplateArgs) {
     CXXScopeSpec SS;
     SS.Adopt(QualifierLoc);
     SS.setUnqualifiedLookups(UnqualifiedLookups);
 
-    return SemaRef.BuildMemberReferenceExpr(BaseE, BaseType,
-                                            OperatorLoc, IsArrow,
-                                            SS, TemplateKWLoc,
-                                            R, TemplateArgs, /*S=*/nullptr);
+    return SemaRef.BuildMemberReferenceExpr(BaseE, BaseType, OperatorLoc,
+                                            IsArrow, SS, TemplateKWLoc, R,
+                                            TemplateArgs, /*S=*/nullptr);
   }
 
   /// Build a new noexcept expression.
@@ -3841,13 +3828,12 @@ class TreeTransform {
                                         SourceLocation PropertyLoc) {
     CXXScopeSpec SS;
     DeclarationNameInfo NameInfo(Property->getDeclName(), PropertyLoc);
-    return getSema().BuildMemberReferenceExpr(BaseArg, BaseArg->getType(),
-                                              /*FIXME:*/PropertyLoc,
-                                              /*IsArrow=*/false,
-                                              SS, /*TemplateKWLoc=*/SourceLocation(),
-                                              NameInfo,
-                                              /*TemplateArgs=*/nullptr,
-                                              /*S=*/nullptr);
+    return getSema().BuildMemberReferenceExpr(
+        BaseArg, BaseArg->getType(),
+        /*FIXME:*/ PropertyLoc,
+        /*IsArrow=*/false, SS, /*TemplateKWLoc=*/SourceLocation(), NameInfo,
+        /*TemplateArgs=*/nullptr,
+        /*S=*/nullptr);
   }
 
   /// Build a new Objective-C property reference expression.
@@ -3874,12 +3860,11 @@ class TreeTransform {
                                 SourceLocation OpLoc, bool IsArrow) {
     CXXScopeSpec SS;
     DeclarationNameInfo NameInfo(&getSema().Context.Idents.get("isa"), IsaLoc);
-    return getSema().BuildMemberReferenceExpr(BaseArg, BaseArg->getType(),
-                                              OpLoc, IsArrow,
-                                              SS, /*TemplateKWLoc=*/SourceLocation(),
-                                              NameInfo,
-                                              /*TemplateArgs=*/nullptr,
-                                              /*S=*/nullptr);
+    return getSema().BuildMemberReferenceExpr(
+        BaseArg, BaseArg->getType(), OpLoc, IsArrow, SS,
+        /*TemplateKWLoc=*/SourceLocation(), NameInfo,
+        /*TemplateArgs=*/nullptr,
+        /*S=*/nullptr);
   }
 
   /// Build a new shuffle vector expression.
@@ -4035,16 +4020,14 @@ class TreeTransform {
   }
 
 private:
-  TypeLoc TransformTypeInObjectScope(TypeLoc TL,
-                                     QualType ObjectType,
+  TypeLoc TransformTypeInObjectScope(TypeLoc TL, QualType ObjectType,
                                      CXXScopeSpec &SS);
 
   TypeSourceInfo *TransformTypeInObjectScope(TypeSourceInfo *TSInfo,
                                              QualType ObjectType,
                                              CXXScopeSpec &SS);
 
-  TypeSourceInfo *TransformTSIInObjectScope(TypeLoc TL,
-                                            QualType ObjectType,
+  TypeSourceInfo *TransformTSIInObjectScope(TypeLoc TL, QualType ObjectType,
                                             CXXScopeSpec &SS);
 
   QualType TransformDependentNameType(TypeLocBuilder &TLB,
@@ -4386,8 +4369,8 @@ NestedNameSpecifierLoc TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
                                       Q.getLocalBeginLoc(), Q.getLocalEndLoc(),
                                       ObjectType);
       if (SemaRef.BuildCXXNestedNameSpecifier(/*Scope=*/nullptr, IdInfo,
-                                              /*EnteringContext=*/false,
-                                              SS, /*ErrorRecoveryLookup=*/false))
+                                              /*EnteringContext=*/false, SS,
+                                              /*ErrorRecoveryLookup=*/false))
         return NestedNameSpecifierLoc();
       break;
     }
@@ -4541,13 +4524,10 @@ ::TransformDeclarationNameInfo(const DeclarationNameInfo &NameInfo) {
   llvm_unreachable("Unknown name kind.");
 }
 
-template<typename Derived>
-TemplateName
-TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS,
-                                              TemplateName Name,
-                                              SourceLocation NameLoc,
-                                              QualType ObjectType,
-                                              bool AllowInjectedClassName) {
+template <typename Derived>
+TemplateName TreeTransform<Derived>::TransformTemplateName(
+    CXXScopeSpec &SS, TemplateName Name, SourceLocation NameLoc,
+    QualType ObjectType, bool AllowInjectedClassName) {
   if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) {
     TemplateDecl *Template = QTN->getUnderlyingTemplate().getAsTemplateDecl();
     assert(Template && "qualified template name must refer to a template");
@@ -4583,12 +4563,9 @@ TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS,
     SourceLocation TemplateKWLoc = NameLoc;
 
     if (DTN->isIdentifier()) {
-      return getDerived().RebuildTemplateName(SS,
-                                              TemplateKWLoc,
-                                              *DTN->getIdentifier(),
-                                              NameLoc,
-                                              ObjectType,
-                                              AllowInjectedClassName);
+      return getDerived().RebuildTemplateName(
+          SS, TemplateKWLoc, *DTN->getIdentifier(), NameLoc, ObjectType,
+          AllowInjectedClassName);
     }
 
     return getDerived().RebuildTemplateName(SS, TemplateKWLoc,
@@ -5132,26 +5109,22 @@ QualType TreeTransform<Derived>::RebuildQualifiedType(QualType T,
   return SemaRef.BuildQualifiedType(T, Loc, Quals);
 }
 
-template<typename Derived>
-TypeLoc
-TreeTransform<Derived>::TransformTypeInObjectScope(TypeLoc TL,
-                                                   QualType ObjectType,
-                                                   CXXScopeSpec &SS) {
+template <typename Derived>
+TypeLoc TreeTransform<Derived>::TransformTypeInObjectScope(TypeLoc TL,
+                                                           QualType ObjectType,
+                                                           CXXScopeSpec &SS) {
   if (getDerived().AlreadyTransformed(TL.getType()))
     return TL;
 
-  TypeSourceInfo *TSI =
-      TransformTSIInObjectScope(TL, ObjectType, SS);
+  TypeSourceInfo *TSI = TransformTSIInObjectScope(TL, ObjectType, SS);
   if (TSI)
     return TSI->getTypeLoc();
   return TypeLoc();
 }
 
-template<typename Derived>
-TypeSourceInfo *
-TreeTransform<Derived>::TransformTypeInObjectScope(TypeSourceInfo *TSInfo,
-                                                   QualType ObjectType,
-                                                   CXXScopeSpec &SS) {
+template <typename Derived>
+TypeSourceInfo *TreeTransform<Derived>::TransformTypeInObjectScope(
+    TypeSourceInfo *TSInfo, QualType ObjectType, CXXScopeSpec &SS) {
   if (getDerived().AlreadyTransformed(TSInfo->getType()))
     return TSInfo;
 
@@ -5183,13 +5156,11 @@ TypeSourceInfo *TreeTransform<Derived>::TransformTSIInObjectScope(
     DependentTemplateSpecializationTypeLoc SpecTL =
         TL.castAs<DependentTemplateSpecializationTypeLoc>();
 
-    TemplateName Template
-      = getDerived().RebuildTemplateName(SS,
-                                         SpecTL.getTemplateKeywordLoc(),
-                                         *SpecTL.getTypePtr()->getIdentifier(),
-                                         SpecTL.getTemplateNameLoc(),
-                                         ObjectType,
-                                         /*AllowInjectedClassName=*/true);
+    TemplateName Template = getDerived().RebuildTemplateName(
+        SS, SpecTL.getTemplateKeywordLoc(),
+        *SpecTL.getTypePtr()->getIdentifier(), SpecTL.getTemplateNameLoc(),
+        ObjectType,
+        /*AllowInjectedClassName=*/true);
     if (Template.isNull())
       return nullptr;
 
@@ -12242,16 +12213,11 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
       return ExprError();
   }
 
-  return getDerived().RebuildMemberExpr(Base.get(), FakeOperatorLoc,
-                                        E->isArrow(),
-                                        QualifierLoc,
-                                        TemplateKWLoc,
-                                        MemberNameInfo,
-                                        Member,
-                                        FoundDecl,
-                                        (E->hasExplicitTemplateArgs()
-                                           ? &TransArgs : nullptr),
-                                        UnqualifiedLookups);
+  return getDerived().RebuildMemberExpr(
+      Base.get(), FakeOperatorLoc, E->isArrow(), QualifierLoc, TemplateKWLoc,
+      MemberNameInfo, Member, FoundDecl,
+      (E->hasExplicitTemplateArgs() ? &TransArgs : nullptr),
+      UnqualifiedLookups);
 }
 
 template<typename Derived>
@@ -13373,9 +13339,8 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
 
   PseudoDestructorTypeStorage Destroyed;
   if (E->getDestroyedTypeInfo()) {
-    TypeSourceInfo *DestroyedTypeInfo
-      = getDerived().TransformTypeInObjectScope(E->getDestroyedTypeInfo(),
-                                                ObjectType, SS);
+    TypeSourceInfo *DestroyedTypeInfo = getDerived().TransformTypeInObjectScope(
+        E->getDestroyedTypeInfo(), ObjectType, SS);
     if (!DestroyedTypeInfo)
       return ExprError();
     Destroyed = DestroyedTypeInfo;
@@ -13401,7 +13366,7 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
   if (E->getScopeTypeInfo()) {
     CXXScopeSpec EmptySS;
     ScopeTypeInfo = getDerived().TransformTypeInObjectScope(
-                      E->getScopeTypeInfo(), ObjectType, EmptySS);
+        E->getScopeTypeInfo(), ObjectType, EmptySS);
     if (!ScopeTypeInfo)
       return ExprError();
   }
@@ -14663,28 +14628,26 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
     ObjectType = BaseType->castAs<PointerType>()->getPointeeType();
   }
 
-  #if 0
+#if 0
   // Transform the first part of the nested-name-specifier that qualifies
   // the member name.
   NamedDecl *FirstQualifierInScope
     = getDerived().TransformFirstQualifierInScope(
                                             E->getFirstQualifierFoundInScope(),
                                             E->getQualifierLoc().getBeginLoc());
-  #endif
+#endif
 
   UnresolvedSet<4> UnqualifiedLookups;
   for (auto D : E->unqualified_lookups()) {
     if (NamedDecl *InstD = getDerived().TransformFirstQualifierInScope(
-        D.getDecl(), E->getQualifierLoc().getBeginLoc()))
+            D.getDecl(), E->getQualifierLoc().getBeginLoc()))
       UnqualifiedLookups.addDecl(InstD);
   }
 
   NestedNameSpecifierLoc QualifierLoc;
   if (E->getQualifier()) {
-    QualifierLoc
-      = getDerived().TransformNestedNameSpecifierLoc(E->getQualifierLoc(),
-                                                     ObjectType,
-                                                     UnqualifiedLookups.pairs());
+    QualifierLoc = getDerived().TransformNestedNameSpecifierLoc(
+        E->getQualifierLoc(), ObjectType, UnqualifiedLookups.pairs());
     if (!QualifierLoc)
       return ExprError();
   }
@@ -14703,23 +14666,16 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
   if (!E->hasExplicitTemplateArgs()) {
     // This is a reference to a member without an explicitly-specified
     // template argument list. Optimize for this common case.
-    if (!getDerived().AlwaysRebuild() &&
-        Base.get() == OldBase &&
-        BaseType == E->getBaseType() &&
-        QualifierLoc == E->getQualifierLoc() &&
+    if (!getDerived().AlwaysRebuild() && Base.get() == OldBase &&
+        BaseType == E->getBaseType() && QualifierLoc == E->getQualifierLoc() &&
         NameInfo.getName() == E->getMember() &&
         UnqualifiedLookups.pairs() == E->unqualified_lookups())
       return E;
 
-    return getDerived().RebuildCXXDependentScopeMemberExpr(Base.get(),
-                                                       BaseType,
-                                                       E->isArrow(),
-                                                       E->getOperatorLoc(),
-                                                       QualifierLoc,
-                                                       TemplateKWLoc,
-                                                       UnqualifiedLookups.pairs(),
-                                                       NameInfo,
-                                                       /*TemplateArgs*/nullptr);
+    return getDerived().RebuildCXXDependentScopeMemberExpr(
+        Base.get(), BaseType, E->isArrow(), E->getOperatorLoc(), QualifierLoc,
+        TemplateKWLoc, UnqualifiedLookups.pairs(), NameInfo,
+        /*TemplateArgs*/ nullptr);
   }
 
   TemplateArgumentListInfo TransArgs(E->getLAngleLoc(), E->getRAngleLoc());
@@ -14728,15 +14684,9 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
                                               TransArgs))
     return ExprError();
 
-  return getDerived().RebuildCXXDependentScopeMemberExpr(Base.get(),
-                                                     BaseType,
-                                                     E->isArrow(),
-                                                     E->getOperatorLoc(),
-                                                     QualifierLoc,
-                                                     TemplateKWLoc,
-                                                     UnqualifiedLookups.pairs(),
-                                                     NameInfo,
-                                                     &TransArgs);
+  return getDerived().RebuildCXXDependentScopeMemberExpr(
+      Base.get(), BaseType, E->isArrow(), E->getOperatorLoc(), QualifierLoc,
+      TemplateKWLoc, UnqualifiedLookups.pairs(), NameInfo, &TransArgs);
 }
 
 template <typename Derived>
@@ -16158,14 +16108,10 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
                                                   TemplateName(Template));
 }
 
-template<typename Derived>
-TemplateName
-TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
-                                            SourceLocation TemplateKWLoc,
-                                            const IdentifierInfo &Name,
-                                            SourceLocation NameLoc,
-                                            QualType ObjectType,
-                                            bool AllowInjectedClassName) {
+template <typename Derived>
+TemplateName TreeTransform<Derived>::RebuildTemplateName(
+    CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const IdentifierInfo &Name,
+    SourceLocation NameLoc, QualType ObjectType, bool AllowInjectedClassName) {
   UnqualifiedId TemplateName;
   TemplateName.setIdentifier(&Name, NameLoc);
   Sema::TemplateTy Template;
@@ -16320,12 +16266,10 @@ TreeTransform<Derived>::RebuildCXXPseudoDestructorExpr(Expr *Base,
   }
 
   SourceLocation TemplateKWLoc; // FIXME: retrieve it from caller.
-  return getSema().BuildMemberReferenceExpr(Base, BaseType,
-                                            OperatorLoc, isArrow,
-                                            SS, TemplateKWLoc,
-                                            NameInfo,
-                                            /*TemplateArgs=*/nullptr,
-                                            /*S=*/nullptr);
+  return getSema().BuildMemberReferenceExpr(
+      Base, BaseType, OperatorLoc, isArrow, SS, TemplateKWLoc, NameInfo,
+      /*TemplateArgs=*/nullptr,
+      /*S=*/nullptr);
 }
 
 template<typename Derived>
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index 1054abf3170a1..90645b5b5eaec 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -1989,11 +1989,13 @@ void ASTStmtReader::VisitCXXDependentScopeMemberExpr(
   unsigned NumUnqualifiedLookups = Record.readInt();
   unsigned NumTemplateArgs = Record.readInt();
   E->CXXDependentScopeMemberExprBits.HasQualifier = HasQualifier;
-  E->CXXDependentScopeMemberExprBits.NumUnqualifiedLookups = NumUnqualifiedLookups;
+  E->CXXDependentScopeMemberExprBits.NumUnqualifiedLookups =
+      NumUnqualifiedLookups;
   E->CXXDependentScopeMemberExprBits.HasTemplateKWAndArgsInfo = HasTemplateInfo;
 
   E->BaseType = Record.readType();
-  E->CXXDependentScopeMemberExprBits.IsArrow = CurrentUnpackingBits->getNextBit();
+  E->CXXDependentScopeMemberExprBits.IsArrow =
+      CurrentUnpackingBits->getNextBit();
 
   if (CurrentUnpackingBits->getNextBit())
     E->Base = Record.readSubExpr();
@@ -2010,7 +2012,9 @@ void ASTStmtReader::VisitCXXDependentScopeMemberExpr(
   for (unsigned I = 0; I != NumUnqualifiedLookups; ++I) {
     auto *FoundD = Record.readDeclAs<NamedDecl>();
     auto AS = (AccessSpecifier)Record.readInt();
-    E->getTrailingObjects<DeclAccessPair>()[I] = DeclAccessPair::make(FoundD, AS);;
+    E->getTrailingObjects<DeclAccessPair>()[I] =
+        DeclAccessPair::make(FoundD, AS);
+    ;
   }
 
   if (HasTemplateInfo)
@@ -2018,8 +2022,7 @@ void ASTStmtReader::VisitCXXDependentScopeMemberExpr(
         *E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(),
         E->getTrailingObjects<TemplateArgumentLoc>(), NumTemplateArgs);
 
-
-  #if 0
+#if 0
   unsigned NumTemplateArgs = Record.readInt();
   CurrentUnpackingBits.emplace(Record.readInt());
   bool HasTemplateKWAndArgsInfo = CurrentUnpackingBits->getNextBit();
@@ -2056,7 +2059,7 @@ void ASTStmtReader::VisitCXXDependentScopeMemberExpr(
     *E->getTrailingObjects<NamedDecl *>() = readDeclAs<NamedDecl>();
 
   E->MemberNameInfo = Record.readDeclarationNameInfo();
-  #endif
+#endif
 }
 
 void
@@ -4094,7 +4097,7 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
 
     case EXPR_CXX_DEPENDENT_SCOPE_MEMBER: {
 
-      #if 0
+#if 0
       unsigned NumTemplateArgs = Record[ASTStmtReader::NumExprFields];
       BitsUnpacker DependentScopeMemberBits(
           Record[ASTStmtReader::NumExprFields + 1]);
@@ -4102,16 +4105,17 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
 
       bool HasFirstQualifierFoundInScope =
           DependentScopeMemberBits.getNextBit();
-      #endif
-      BitsUnpacker DependentScopeMemberBits(Record[ASTStmtReader::NumExprFields]);
+#endif
+      BitsUnpacker DependentScopeMemberBits(
+          Record[ASTStmtReader::NumExprFields]);
       bool HasQualifier = DependentScopeMemberBits.getNextBit();
       bool HasTemplateInfo = DependentScopeMemberBits.getNextBit();
       unsigned NumUnqualifiedLookups = Record[ASTStmtReader::NumExprFields + 1];
       unsigned NumTemplateArgs = Record[ASTStmtReader::NumExprFields + 2];
 
       S = CXXDependentScopeMemberExpr::CreateEmpty(
-          Context, HasQualifier, NumUnqualifiedLookups,
-          HasTemplateInfo, NumTemplateArgs);
+          Context, HasQualifier, NumUnqualifiedLookups, HasTemplateInfo,
+          NumTemplateArgs);
       break;
     }
 
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index bb117d1d2a7d2..42d83cd2d8397 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -2012,7 +2012,7 @@ void ASTStmtWriter::VisitCXXDependentScopeMemberExpr(
     AddTemplateKWAndArgsInfo(*E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(),
                              E->getTrailingObjects<TemplateArgumentLoc>());
 
-  #if 0
+#if 0
   // Don't emit anything here (or if you do you will have to update
   // the corresponding deserialization function).
   Record.push_back(E->getNumTemplateArgs());
@@ -2041,7 +2041,7 @@ void ASTStmtWriter::VisitCXXDependentScopeMemberExpr(
     Record.AddDeclRef(E->getFirstQualifierFoundInScope());
 
   Record.AddDeclarationNameInfo(E->MemberNameInfo);
-  #endif
+#endif
 
   Code = serialization::EXPR_CXX_DEPENDENT_SCOPE_MEMBER;
 }

>From dd60ceb57dc1ad13729c2e8c7a781e139929b965 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Fri, 31 May 2024 14:35:35 -0400
Subject: [PATCH 05/11] [FOLD] add tests

---
 .../basic.lookup.qual.general/p3-example3.cpp |  27 ++
 .../basic.lookup.qual.general/p3.cpp          |  71 +++++
 clang/test/CXX/temp/temp.names/p3-23.cpp      | 250 ++++++++++++++++++
 3 files changed, 348 insertions(+)
 create mode 100644 clang/test/CXX/basic/basic.lookup/basic.lookup.qual/basic.lookup.qual.general/p3-example3.cpp
 create mode 100644 clang/test/CXX/basic/basic.lookup/basic.lookup.qual/basic.lookup.qual.general/p3.cpp
 create mode 100644 clang/test/CXX/temp/temp.names/p3-23.cpp

diff --git a/clang/test/CXX/basic/basic.lookup/basic.lookup.qual/basic.lookup.qual.general/p3-example3.cpp b/clang/test/CXX/basic/basic.lookup/basic.lookup.qual/basic.lookup.qual.general/p3-example3.cpp
new file mode 100644
index 0000000000000..423eacd21d441
--- /dev/null
+++ b/clang/test/CXX/basic/basic.lookup/basic.lookup.qual/basic.lookup.qual.general/p3-example3.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -std=c++23 %s -verify
+
+int f();
+
+struct A {
+  int B, C; // expected-note {{declared as a non-template here}}
+  template<int> using D = void;
+  using T = void;
+  void f();
+};
+
+using B = A;
+template<int> using C = A;
+template<int> using D = A;
+template<int> using X = A;
+
+template<class T>
+void g(T *p) {
+  p->X<0>::f(); // expected-error {{no member named 'X' in 'A'}}
+  p->template X<0>::f();
+  p->B::f();
+  p->template C<0>::f(); // expected-error {{'C' following the 'template' keyword does not refer to a template}}
+  p->template D<0>::f(); // expected-error {{type 'template D<0>' (aka 'void') cannot be used prior to '::' because it has no members}}
+  p->T::f(); // expected-error {{'A::T' (aka 'void') is not a class, namespace, or enumeration}}
+}
+
+template void g(A*); // expected-note {{in instantiation of}}
diff --git a/clang/test/CXX/basic/basic.lookup/basic.lookup.qual/basic.lookup.qual.general/p3.cpp b/clang/test/CXX/basic/basic.lookup/basic.lookup.qual/basic.lookup.qual.general/p3.cpp
new file mode 100644
index 0000000000000..e3c4aae984aeb
--- /dev/null
+++ b/clang/test/CXX/basic/basic.lookup/basic.lookup.qual/basic.lookup.qual.general/p3.cpp
@@ -0,0 +1,71 @@
+// RUN: %clang_cc1 -std=c++23 -Wno-unused %s -verify
+
+struct A {
+  int x;
+
+  template<typename T>
+  using C = A;
+};
+
+using B = A;
+
+template<typename T>
+using D = A;
+
+using E = void;
+
+struct F : A {
+  void non_template() {
+    this->x;
+    this->A::x;
+    this->B::x;
+    this->C<int>::x;
+    this->D<int>::x;
+    this->E::x; // expected-error {{'E' (aka 'void') is not a class, namespace, or enumeration}}
+  }
+};
+
+template<typename T>
+void not_instantiated(T t) {
+  t.x;
+  t.A::x;
+  t.B::x;
+  t.C<int>::x; // expected-error {{use 'template' keyword to treat 'C' as a dependent template name}}
+  t.template C<int>::x;
+  t.D<int>::x; // expected-error {{use 'template' keyword to treat 'D' as a dependent template name}}
+  t.template D<int>::x;
+  t.E::x;
+}
+
+template<typename T>
+void instantiated_valid(T t) {
+  t.x;
+  t.A::x;
+  t.B::x;
+  t.template C<int>::x;
+  t.template D<int>::x;
+  t.E::x;
+}
+
+template<typename T>
+void instantiated_invalid(T t) {
+  t.x;
+  t.A::x;
+  t.B::x; // expected-error {{'Invalid::B' (aka 'void') is not a class, namespace, or enumeration}}
+  t.template C<int>::x;
+  t.template D<int>::x; // expected-error {{'D' following the 'template' keyword does not refer to a template}}
+  t.E::x; // expected-error {{'E' (aka 'void') is not a class, namespace, or enumeration}}
+}
+
+struct Valid : A {
+  using E = A;
+};
+
+template void instantiated_valid(Valid);
+
+struct Invalid : A {
+  using B = void;
+  using D = A; // expected-note {{declared as a non-template here}}
+};
+
+template void instantiated_invalid(Invalid); // expected-note {{in instantiation of}}
diff --git a/clang/test/CXX/temp/temp.names/p3-23.cpp b/clang/test/CXX/temp/temp.names/p3-23.cpp
new file mode 100644
index 0000000000000..5119cd4ecac9f
--- /dev/null
+++ b/clang/test/CXX/temp/temp.names/p3-23.cpp
@@ -0,0 +1,250 @@
+// RUN: %clang_cc1 -std=c++23 %s -verify
+
+namespace FoundNothing {
+  template<typename T>
+  void f0(T &t) {
+    t.x<0;
+    t.x<0>; // expected-error {{expected expression}}
+    t.x<0>1;
+  }
+
+  template<typename T>
+  struct A {
+    void f1() {
+      this->x<0; // expected-error {{no member named 'x' in 'A<T>'}}
+      this->x<0>; // expected-error {{expected expression}}
+                  // expected-error at -1 {{no member named 'x' in 'A<T>'}}
+      this->x<0>1; // expected-error {{no member named 'x' in 'A<T>'}}
+    }
+  };
+} // namespace FoundNothing
+
+namespace FoundSingleNonTemplate {
+  void f0();
+
+  struct A0;
+
+  template<typename T>
+  void g0(T &t) {
+    t.f0<0;
+    t.f0<0>; // expected-error {{expected expression}}
+    t.f0<0> 1;
+
+    t.A0<0;
+    t.A0<0>; // expected-error {{expected expression}}
+    t.A0<0>1;
+  }
+
+  template<typename T>
+  struct B {
+    void f1();
+
+    struct A1; // expected-note 3{{member 'A1' declared here}}
+
+    void g1() {
+      this->f0<0; // expected-error {{no member named 'f0' in 'B<T>'}}
+      this->f0<0>; // expected-error {{expected expression}}
+                   // expected-error at -1 {{no member named 'f0' in 'B<T>'}}
+      this->f0<0>1; // expected-error {{no member named 'f0' in 'B<T>'}}
+
+      this->A0<0; // expected-error {{no member named 'A0' in 'B<T>'}}
+      this->A0<0>; // expected-error {{expected expression}}
+                   // expected-error at -1 {{no member named 'A0' in 'B<T>'}}
+      this->A0<0>1; // expected-error {{no member named 'A0' in 'B<T>'}}
+
+      this->f1<0; // expected-error {{reference to non-static member function must be called}}
+      this->f1<0>; // expected-error {{expected expression}}
+                   // expected-error at -1 {{reference to non-static member function must be called}}
+      this->f1<0>1; // expected-error {{reference to non-static member function must be called}}
+
+      this->A1<0; // expected-error {{cannot refer to type member 'A1' in 'B<T>' with '->'}}
+      this->A1<0>; // expected-error {{expected expression}}
+                   // expected-error at -1 {{cannot refer to type member 'A1' in 'B<T>' with '->'}}
+      this->A1<0>1; // expected-error {{cannot refer to type member 'A1' in 'B<T>' with '->'}}
+    }
+  };
+} // namespace FoundSingleNonTemplate
+
+namespace FoundSingleTemplate {
+  template<int I>
+  void f0();
+
+  template<int I>
+  struct A0;
+
+  template<typename T>
+  void g0(T &t) {
+    t.f0<0;
+    t.f0<0>; // expected-error {{expected expression}}
+    t.f0<0>1;
+
+    t.A0<0;
+    t.A0<0>; // expected-error {{expected expression}}
+    t.A0<0>1;
+  }
+
+  template<typename T>
+  struct B {
+    template<int I>
+    void f1(); // expected-note 2{{possible target for call}}
+
+    template<int I>
+    struct A1; // expected-note 2{{member 'A1' declared here}}
+
+    void g1() {
+      this->f0<0; // expected-error {{expected '>'}}
+                  // expected-note at -1 {{to match this '<'}}
+                  // expected-error at -2 {{expected unqualified-id}}
+      this->f0<0>; // expected-error {{no member named 'f0' in 'B<T>'}}
+      this->f0<0>1; // expected-error {{no member named 'f0' in 'B<T>'}}
+                    // expected-error at -1 {{expected ';' after expression}}
+
+      this->A0<0; // expected-error {{expected '>'}}
+                  // expected-note at -1 {{to match this '<'}}
+                  // expected-error at -2 {{expected unqualified-id}}
+      this->A0<0>; // expected-error {{no member named 'A0' in 'B<T>'}}
+      this->A0<0>1; // expected-error {{no member named 'A0' in 'B<T>'}}
+                    // expected-error at -1 {{expected ';' after expression}}
+
+
+      this->f1<0; // expected-error {{expected '>'}}
+                  // expected-note at -1 {{to match this '<'}}
+                  // expected-error at -2 {{expected unqualified-id}}
+      this->f1<0>; // expected-error {{reference to non-static member function must be called}}
+      this->f1<0>1; // expected-error {{reference to non-static member function must be called}}
+                    // expected-error at -1 {{expected ';' after expression}}
+
+      this->A1<0; // expected-error {{expected '>'}}
+                  // expected-note at -1 {{to match this '<'}}
+                  // expected-error at -2 {{expected unqualified-id}}
+      this->A1<0>; // expected-error {{cannot refer to member 'A1' in 'B<T>' with '->'}}
+      this->A1<0>1; // expected-error {{cannot refer to member 'A1' in 'B<T>' with '->'}}
+                    // expected-error at -1 {{expected ';' after expression}}
+    }
+  };
+} // namespace FoundSingleTemplate
+
+namespace FoundAmbiguousNonTemplate {
+  inline namespace N {
+    int f0;
+
+    struct A0;
+  } // namespace N
+
+  void f0();
+
+  struct A0;
+
+  template<typename T>
+  void g0(T &t) {
+    t.f0<0;
+    t.f0<0>; // expected-error {{expected expression}}
+    t.f0<0>1;
+
+    t.A0<0;
+    t.A0<0>; // expected-error {{expected expression}}
+    t.A0<0>1;
+  }
+
+  template<typename T>
+  struct B {
+    void f1();
+
+    struct A1; // expected-note 3{{member 'A1' declared here}}
+
+    void g1() {
+      this->f0<0; // expected-error {{no member named 'f0' in 'B<T>'}}
+      this->f0<0>; // expected-error {{expected expression}}
+                   // expected-error at -1 {{no member named 'f0' in 'B<T>'}}
+      this->f0<0>1; // expected-error {{no member named 'f0' in 'B<T>'}}
+
+      this->A0<0; // expected-error {{no member named 'A0' in 'B<T>'}}
+      this->A0<0>; // expected-error {{expected expression}}
+                   // expected-error at -1 {{no member named 'A0' in 'B<T>'}}
+      this->A0<0>1; // expected-error {{no member named 'A0' in 'B<T>'}}
+
+      this->f1<0; // expected-error {{reference to non-static member function must be called}}
+      this->f1<0>; // expected-error {{expected expression}}
+                   // expected-error at -1 {{reference to non-static member function must be called}}
+      this->f1<0>1; // expected-error {{reference to non-static member function must be called}}
+
+      this->A1<0; // expected-error {{cannot refer to type member 'A1' in 'B<T>' with '->'}}
+      this->A1<0>; // expected-error {{expected expression}}
+                   // expected-error at -1 {{cannot refer to type member 'A1' in 'B<T>' with '->'}}
+      this->A1<0>1; // expected-error {{cannot refer to type member 'A1' in 'B<T>' with '->'}}
+    }
+  };
+} // namespace FoundAmbiguousNonTemplates
+
+namespace FoundAmbiguousTemplate {
+  inline namespace N {
+    template<int I>
+    int f0; // expected-note 3{{candidate found by name lookup is 'FoundAmbiguousTemplate::N::f0'}}
+
+    template<int I>
+    struct A0; // expected-note 3{{candidate found by name lookup is 'FoundAmbiguousTemplate::N::A0'}}
+  } // namespace N
+
+  template<int I>
+  void f0(); // expected-note 3{{candidate found by name lookup is 'FoundAmbiguousTemplate::f0'}}
+
+  template<int I>
+  struct A0; // expected-note 3{{candidate found by name lookup is 'FoundAmbiguousTemplate::A0'}}
+
+  template<typename T>
+  void g0(T &t) {
+    t.f0<0;
+    t.f0<0>; // expected-error {{expected expression}}
+    t.f0<0>1;
+
+    t.A0<0;
+    t.A0<0>; // expected-error {{expected expression}}
+    t.A0<0>1;
+  }
+
+  template<typename T>
+  struct B {
+    template<int I>
+    void f1(); // expected-note 2{{possible target for call}}
+
+    template<int I>
+    struct A1; // expected-note 2{{member 'A1' declared here}}
+
+    void g1() {
+      this->f0<0; // expected-error {{expected '>'}}
+                  // expected-note at -1 {{to match this '<'}}
+                  // expected-error at -2 {{expected unqualified-id}}
+                  // expected-error at -3 {{reference to 'f0' is ambiguous}}
+      this->f0<0>; // expected-error {{no member named 'f0' in 'B<T>'}}
+                   // expected-error at -1 {{reference to 'f0' is ambiguous}}
+      this->f0<0>1; // expected-error {{no member named 'f0' in 'B<T>'}}
+                    // expected-error at -1 {{expected ';' after expression}}
+                    // expected-error at -2 {{reference to 'f0' is ambiguous}}
+
+      this->A0<0; // expected-error {{expected '>'}}
+                  // expected-note at -1 {{to match this '<'}}
+                  // expected-error at -2 {{expected unqualified-id}}
+                  // expected-error at -3 {{reference to 'A0' is ambiguous}}
+      this->A0<0>; // expected-error {{no member named 'A0' in 'B<T>'}}
+                   // expected-error at -1 {{reference to 'A0' is ambiguous}}
+      this->A0<0>1; // expected-error {{no member named 'A0' in 'B<T>'}}
+                    // expected-error at -1 {{expected ';' after expression}}
+                    // expected-error at -2 {{reference to 'A0' is ambiguous}}
+
+
+      this->f1<0; // expected-error {{expected '>'}}
+                  // expected-note at -1 {{to match this '<'}}
+                  // expected-error at -2 {{expected unqualified-id}}
+      this->f1<0>; // expected-error {{reference to non-static member function must be called}}
+      this->f1<0>1; // expected-error {{reference to non-static member function must be called}}
+                    // expected-error at -1 {{expected ';' after expression}}
+
+      this->A1<0; // expected-error {{expected '>'}}
+                  // expected-note at -1 {{to match this '<'}}
+                  // expected-error at -2 {{expected unqualified-id}}
+      this->A1<0>; // expected-error {{cannot refer to member 'A1' in 'B<T>' with '->'}}
+      this->A1<0>1; // expected-error {{cannot refer to member 'A1' in 'B<T>' with '->'}}
+                    // expected-error at -1 {{expected ';' after expression}}
+    }
+  };
+} // namespace FoundAmbiguousTemplate

>From 3ea596f56d5955405fcde8b1f0085d7a3eea89e6 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Fri, 31 May 2024 14:44:10 -0400
Subject: [PATCH 06/11] [FOLD] cleanups

---
 clang/include/clang/AST/ExprCXX.h         | 21 +---------
 clang/include/clang/AST/Stmt.h            |  6 ---
 clang/lib/Sema/TreeTransform.h            |  9 ----
 clang/lib/Serialization/ASTReaderStmt.cpp | 50 -----------------------
 clang/lib/Serialization/ASTWriterStmt.cpp | 31 --------------
 5 files changed, 2 insertions(+), 115 deletions(-)

diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index d8f87ad4a94f3..6cd6e049ad1e9 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -3807,25 +3807,8 @@ class CXXDependentScopeMemberExpr final
     return getQualifierLoc().getNestedNameSpecifier();
   }
 
-#if 0
-  /// Retrieve the first part of the nested-name-specifier that was
-  /// found in the scope of the member access expression when the member access
-  /// was initially parsed.
-  ///
-  /// This function only returns a useful result when member access expression
-  /// uses a qualified member name, e.g., "x.Base::f". Here, the declaration
-  /// returned by this function describes what was found by unqualified name
-  /// lookup for the identifier "Base" within the scope of the member access
-  /// expression itself. At template instantiation time, this information is
-  /// combined with the results of name lookup into the type of the object
-  /// expression itself (the class type of x).
-  NamedDecl *getFirstQualifierFoundInScope() const {
-    if (!hasFirstQualifierFoundInScope())
-      return nullptr;
-    return *getTrailingObjects<NamedDecl *>();
-  }
-#endif
-
+  /// Retrieve the declarations found by unqualified lookup for the first
+  /// component name of the nested-name-specifier, if any.
   ArrayRef<DeclAccessPair> unqualified_lookups() const {
     if (!getNumUnqualifiedLookups())
       return std::nullopt;
diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index 6e6221ec15fdb..257a61c97c9c6 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -1030,12 +1030,6 @@ class alignas(void *) Stmt {
     LLVM_PREFERRED_TYPE(bool)
     unsigned HasTemplateKWAndArgsInfo : 1;
 
-#if 0
-    /// See getFirstQualifierFoundInScope() and the comment listing
-    /// the trailing objects.
-    LLVM_PREFERRED_TYPE(bool)
-    unsigned HasFirstQualifierFoundInScope : 1;
-#endif
     /// Number of declarations found by unqualified lookup for the
     /// first component name of the nested-name-specifier.
     unsigned NumUnqualifiedLookups;
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index f4e7ccdf309af..da4d8469e55cf 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -14628,15 +14628,6 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
     ObjectType = BaseType->castAs<PointerType>()->getPointeeType();
   }
 
-#if 0
-  // Transform the first part of the nested-name-specifier that qualifies
-  // the member name.
-  NamedDecl *FirstQualifierInScope
-    = getDerived().TransformFirstQualifierInScope(
-                                            E->getFirstQualifierFoundInScope(),
-                                            E->getQualifierLoc().getBeginLoc());
-#endif
-
   UnresolvedSet<4> UnqualifiedLookups;
   for (auto D : E->unqualified_lookups()) {
     if (NamedDecl *InstD = getDerived().TransformFirstQualifierInScope(
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index 90645b5b5eaec..51fd6fdd44f5b 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -2014,52 +2014,12 @@ void ASTStmtReader::VisitCXXDependentScopeMemberExpr(
     auto AS = (AccessSpecifier)Record.readInt();
     E->getTrailingObjects<DeclAccessPair>()[I] =
         DeclAccessPair::make(FoundD, AS);
-    ;
   }
 
   if (HasTemplateInfo)
     ReadTemplateKWAndArgsInfo(
         *E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(),
         E->getTrailingObjects<TemplateArgumentLoc>(), NumTemplateArgs);
-
-#if 0
-  unsigned NumTemplateArgs = Record.readInt();
-  CurrentUnpackingBits.emplace(Record.readInt());
-  bool HasTemplateKWAndArgsInfo = CurrentUnpackingBits->getNextBit();
-  bool HasFirstQualifierFoundInScope = CurrentUnpackingBits->getNextBit();
-
-  assert((HasTemplateKWAndArgsInfo == E->hasTemplateKWAndArgsInfo()) &&
-         "Wrong HasTemplateKWAndArgsInfo!");
-  assert(
-      (HasFirstQualifierFoundInScope == E->hasFirstQualifierFoundInScope()) &&
-      "Wrong HasFirstQualifierFoundInScope!");
-
-  if (HasTemplateKWAndArgsInfo)
-    ReadTemplateKWAndArgsInfo(
-        *E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(),
-        E->getTrailingObjects<TemplateArgumentLoc>(), NumTemplateArgs);
-
-  assert((NumTemplateArgs == E->getNumTemplateArgs()) &&
-         "Wrong NumTemplateArgs!");
-
-  E->CXXDependentScopeMemberExprBits.IsArrow =
-      CurrentUnpackingBits->getNextBit();
-
-  E->BaseType = Record.readType();
-  E->QualifierLoc = Record.readNestedNameSpecifierLoc();
-  // not ImplicitAccess
-  if (CurrentUnpackingBits->getNextBit())
-    E->Base = Record.readSubExpr();
-  else
-    E->Base = nullptr;
-
-  E->CXXDependentScopeMemberExprBits.OperatorLoc = readSourceLocation();
-
-  if (HasFirstQualifierFoundInScope)
-    *E->getTrailingObjects<NamedDecl *>() = readDeclAs<NamedDecl>();
-
-  E->MemberNameInfo = Record.readDeclarationNameInfo();
-#endif
 }
 
 void
@@ -4096,16 +4056,6 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
       break;
 
     case EXPR_CXX_DEPENDENT_SCOPE_MEMBER: {
-
-#if 0
-      unsigned NumTemplateArgs = Record[ASTStmtReader::NumExprFields];
-      BitsUnpacker DependentScopeMemberBits(
-          Record[ASTStmtReader::NumExprFields + 1]);
-      bool HasTemplateKWAndArgsInfo = DependentScopeMemberBits.getNextBit();
-
-      bool HasFirstQualifierFoundInScope =
-          DependentScopeMemberBits.getNextBit();
-#endif
       BitsUnpacker DependentScopeMemberBits(
           Record[ASTStmtReader::NumExprFields]);
       bool HasQualifier = DependentScopeMemberBits.getNextBit();
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 42d83cd2d8397..d37afd0c226a0 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -2012,37 +2012,6 @@ void ASTStmtWriter::VisitCXXDependentScopeMemberExpr(
     AddTemplateKWAndArgsInfo(*E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(),
                              E->getTrailingObjects<TemplateArgumentLoc>());
 
-#if 0
-  // Don't emit anything here (or if you do you will have to update
-  // the corresponding deserialization function).
-  Record.push_back(E->getNumTemplateArgs());
-  CurrentPackingBits.updateBits();
-  CurrentPackingBits.addBit(E->hasTemplateKWAndArgsInfo());
-  CurrentPackingBits.addBit(E->hasFirstQualifierFoundInScope());
-
-  if (E->hasTemplateKWAndArgsInfo()) {
-    const ASTTemplateKWAndArgsInfo &ArgInfo =
-        *E->getTrailingObjects<ASTTemplateKWAndArgsInfo>();
-    AddTemplateKWAndArgsInfo(ArgInfo,
-                             E->getTrailingObjects<TemplateArgumentLoc>());
-  }
-
-  CurrentPackingBits.addBit(E->isArrow());
-
-  Record.AddTypeRef(E->getBaseType());
-  Record.AddNestedNameSpecifierLoc(E->getQualifierLoc());
-  CurrentPackingBits.addBit(!E->isImplicitAccess());
-  if (!E->isImplicitAccess())
-    Record.AddStmt(E->getBase());
-
-  Record.AddSourceLocation(E->getOperatorLoc());
-
-  if (E->hasFirstQualifierFoundInScope())
-    Record.AddDeclRef(E->getFirstQualifierFoundInScope());
-
-  Record.AddDeclarationNameInfo(E->MemberNameInfo);
-#endif
-
   Code = serialization::EXPR_CXX_DEPENDENT_SCOPE_MEMBER;
 }
 

>From 64123aa73f59bb1e47f07df3fc3104f50565dbaa Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Fri, 31 May 2024 15:29:21 -0400
Subject: [PATCH 07/11] [FOLD] use -Wno-unused for test

---
 clang/test/CXX/temp/temp.names/p3-23.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/test/CXX/temp/temp.names/p3-23.cpp b/clang/test/CXX/temp/temp.names/p3-23.cpp
index 5119cd4ecac9f..a7015c2d250fb 100644
--- a/clang/test/CXX/temp/temp.names/p3-23.cpp
+++ b/clang/test/CXX/temp/temp.names/p3-23.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++23 %s -verify
+// RUN: %clang_cc1 -std=c++23 -Wno-unused %s -verify
 
 namespace FoundNothing {
   template<typename T>

>From be3a1f3bd909d7f738981ffee45c3def5b78515e Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Fri, 31 May 2024 16:39:54 -0400
Subject: [PATCH 08/11] [FOLD] add additional tests

---
 .../basic.lookup.qual.general/p3.cpp          | 151 +++++++++++-------
 1 file changed, 89 insertions(+), 62 deletions(-)

diff --git a/clang/test/CXX/basic/basic.lookup/basic.lookup.qual/basic.lookup.qual.general/p3.cpp b/clang/test/CXX/basic/basic.lookup/basic.lookup.qual/basic.lookup.qual.general/p3.cpp
index e3c4aae984aeb..6798e961123c3 100644
--- a/clang/test/CXX/basic/basic.lookup/basic.lookup.qual/basic.lookup.qual.general/p3.cpp
+++ b/clang/test/CXX/basic/basic.lookup/basic.lookup.qual/basic.lookup.qual.general/p3.cpp
@@ -1,71 +1,98 @@
 // RUN: %clang_cc1 -std=c++23 -Wno-unused %s -verify
 
-struct A {
-  int x;
+namespace Unambiguous {
+  struct A {
+    int x;
+
+    template<typename T>
+    using C = A;
+  };
+
+  using B = A;
 
   template<typename T>
-  using C = A;
-};
+  using D = A;
+
+  using E = void;
 
-using B = A;
+  struct F : A {
+    void non_template() {
+      this->x;
+      this->A::x;
+      this->B::x;
+      this->C<int>::x;
+      this->D<int>::x;
+      this->E::x; // expected-error {{'Unambiguous::E' (aka 'void') is not a class, namespace, or enumeration}}
+    }
+  };
 
-template<typename T>
-using D = A;
+  template<typename T>
+  void not_instantiated(T t) {
+    t.x;
+    t.A::x;
+    t.B::x;
+    t.C<int>::x; // expected-error {{use 'template' keyword to treat 'C' as a dependent template name}}
+    t.template C<int>::x;
+    t.D<int>::x; // expected-error {{use 'template' keyword to treat 'D' as a dependent template name}}
+    t.template D<int>::x;
+    t.E::x;
+  }
 
-using E = void;
+  template<typename T>
+  void instantiated_valid(T t) {
+    t.x;
+    t.A::x;
+    t.B::x;
+    t.template C<int>::x;
+    t.template D<int>::x;
+    t.E::x;
+  }
 
-struct F : A {
-  void non_template() {
-    this->x;
-    this->A::x;
-    this->B::x;
-    this->C<int>::x;
-    this->D<int>::x;
-    this->E::x; // expected-error {{'E' (aka 'void') is not a class, namespace, or enumeration}}
+  template<typename T>
+  void instantiated_invalid(T t) {
+    t.x;
+    t.A::x;
+    t.B::x; // expected-error {{'Unambiguous::Invalid::B' (aka 'void') is not a class, namespace, or enumeration}}
+    t.template C<int>::x;
+    t.template D<int>::x; // expected-error {{'D' following the 'template' keyword does not refer to a template}}
+    t.E::x; // expected-error {{'Unambiguous::E' (aka 'void') is not a class, namespace, or enumeration}}
   }
-};
-
-template<typename T>
-void not_instantiated(T t) {
-  t.x;
-  t.A::x;
-  t.B::x;
-  t.C<int>::x; // expected-error {{use 'template' keyword to treat 'C' as a dependent template name}}
-  t.template C<int>::x;
-  t.D<int>::x; // expected-error {{use 'template' keyword to treat 'D' as a dependent template name}}
-  t.template D<int>::x;
-  t.E::x;
-}
-
-template<typename T>
-void instantiated_valid(T t) {
-  t.x;
-  t.A::x;
-  t.B::x;
-  t.template C<int>::x;
-  t.template D<int>::x;
-  t.E::x;
-}
-
-template<typename T>
-void instantiated_invalid(T t) {
-  t.x;
-  t.A::x;
-  t.B::x; // expected-error {{'Invalid::B' (aka 'void') is not a class, namespace, or enumeration}}
-  t.template C<int>::x;
-  t.template D<int>::x; // expected-error {{'D' following the 'template' keyword does not refer to a template}}
-  t.E::x; // expected-error {{'E' (aka 'void') is not a class, namespace, or enumeration}}
-}
-
-struct Valid : A {
-  using E = A;
-};
-
-template void instantiated_valid(Valid);
-
-struct Invalid : A {
-  using B = void;
-  using D = A; // expected-note {{declared as a non-template here}}
-};
-
-template void instantiated_invalid(Invalid); // expected-note {{in instantiation of}}
+
+  struct Valid : A {
+    using E = A;
+  };
+
+  template void instantiated_valid(Valid);
+
+  struct Invalid : A {
+    using B = void;
+    using D = A; // expected-note {{declared as a non-template here}}
+  };
+
+  template void instantiated_invalid(Invalid); // expected-note {{in instantiation of}}
+} // namespace Unambiguous
+
+namespace Ambiguous {
+  inline namespace N {
+    struct A { }; // expected-note {{candidate found by name lookup is 'Ambiguous::N::A'}}
+  }
+
+  struct A { }; // expected-note {{candidate found by name lookup is 'Ambiguous::A'}}
+
+  template<typename T>
+  void f(T t) {
+    t.A::x; // expected-error {{reference to 'A' is ambiguous}}
+  }
+
+  struct B {
+    using A = B;
+
+    int x;
+  };
+
+  struct C { };
+
+  template void f(B);
+  template void f(C); // expected-note {{in instantiation of}}
+
+} // namespace Ambiguous

>From 5e510b862c0fad0504e29863382cb0d281b72eb6 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Mon, 3 Jun 2024 06:40:11 -0400
Subject: [PATCH 09/11] [FOLD] factor out some NFC changes

---
 clang/include/clang/Sema/Sema.h     |  2 +-
 clang/lib/Parse/ParseDeclCXX.cpp    |  2 +-
 clang/lib/Parse/ParseExpr.cpp       |  9 ++++-----
 clang/lib/Sema/SemaExprMember.cpp   |  9 ++++++---
 clang/lib/Sema/SemaPseudoObject.cpp | 16 ++++++++--------
 5 files changed, 20 insertions(+), 18 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 4208da06db3dc..e83602af36676 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -6943,7 +6943,7 @@ class Sema final : public SemaBase {
                            const TemplateArgumentListInfo *TemplateArgs);
 
   ExprResult ActOnMemberAccessExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
-                                   bool IsArrow, CXXScopeSpec &SS,
+                                   tok::TokenKind OpKind, CXXScopeSpec &SS,
                                    SourceLocation TemplateKWLoc,
                                    UnqualifiedId &Member, Decl *ObjCImpDecl);
 
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 884e7ea8ee2de..9a4a777f575b2 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -720,7 +720,7 @@ Parser::DeclGroupPtrTy Parser::ParseUsingDeclaration(
       return nullptr;
     }
     CXXScopeSpec SS;
-    if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
+    if (ParseOptionalCXXScopeSpecifier(SS, /*ParsedType=*/nullptr,
                                        /*ObectHasErrors=*/false,
                                        /*EnteringConttext=*/false,
                                        /*MayBePseudoDestructor=*/nullptr,
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index b3c25f88b403d..eb7447fa038e4 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -2254,7 +2254,6 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
           }
           break;
         }
-
         ParseOptionalCXXScopeSpecifier(
             SS, ObjectType, LHS.get() && LHS.get()->containsErrors(),
             /*EnteringContext=*/false, &MayBePseudoDestructor);
@@ -2329,10 +2328,10 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
       }
 
       if (!LHS.isInvalid())
-        LHS = Actions.ActOnMemberAccessExpr(
-            getCurScope(), LHS.get(), OpLoc, OpKind == tok::arrow, SS,
-            TemplateKWLoc, Name,
-            CurParsedObjCImpl ? CurParsedObjCImpl->Dcl : nullptr);
+        LHS = Actions.ActOnMemberAccessExpr(getCurScope(), LHS.get(), OpLoc,
+                                            OpKind, SS, TemplateKWLoc, Name,
+                                 CurParsedObjCImpl ? CurParsedObjCImpl->Dcl
+                                                   : nullptr);
       if (!LHS.isInvalid()) {
         if (Tok.is(tok::less))
           checkPotentialAngleBracket(LHS);
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 038b3e9ceadb3..c45cbfe017de9 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -1046,7 +1046,7 @@ ExprResult Sema::BuildMemberReferenceExpr(
       if (RetryExpr.isUsable() && !Trap.hasErrorOccurred()) {
         CXXScopeSpec TempSS(SS);
         RetryExpr = ActOnMemberAccessExpr(
-            ExtraArgs->S, RetryExpr.get(), OpLoc, /*IsArrow=*/true, TempSS,
+            ExtraArgs->S, RetryExpr.get(), OpLoc, tok::arrow, TempSS,
             TemplateKWLoc, ExtraArgs->Id, ExtraArgs->ObjCImpDecl);
       }
       if (Trap.hasErrorOccurred())
@@ -1760,10 +1760,12 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
 ///   decl; this is an ugly hack around the fact that Objective-C
 ///   \@implementations aren't properly put in the context chain
 ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
-                                       SourceLocation OpLoc, bool IsArrow,
+                                       SourceLocation OpLoc,
+                                       tok::TokenKind OpKind,
                                        CXXScopeSpec &SS,
                                        SourceLocation TemplateKWLoc,
-                                       UnqualifiedId &Id, Decl *ObjCImpDecl) {
+                                       UnqualifiedId &Id,
+                                       Decl *ObjCImpDecl) {
   if (SS.isSet() && SS.isInvalid())
     return ExprError();
 
@@ -1780,6 +1782,7 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
   const TemplateArgumentListInfo *TemplateArgs;
   DecomposeUnqualifiedId(Id, TemplateArgsBuffer,
                          NameInfo, TemplateArgs);
+  bool IsArrow = OpKind == tok::arrow;
 
   if (getLangOpts().HLSL && IsArrow)
     return ExprError(Diag(OpLoc, diag::err_hlsl_operator_unsupported) << 2);
diff --git a/clang/lib/Sema/SemaPseudoObject.cpp b/clang/lib/Sema/SemaPseudoObject.cpp
index 86c303e67bc1d..fdb584ceb8105 100644
--- a/clang/lib/Sema/SemaPseudoObject.cpp
+++ b/clang/lib/Sema/SemaPseudoObject.cpp
@@ -1395,10 +1395,10 @@ ExprResult MSPropertyOpBuilder::buildGet() {
   GetterName.setIdentifier(II, RefExpr->getMemberLoc());
   CXXScopeSpec SS;
   SS.Adopt(RefExpr->getQualifierLoc());
-  ExprResult GetterExpr = S.ActOnMemberAccessExpr(
-      S.getCurScope(), InstanceBase, /*OpLoc=*/SourceLocation(),
-      RefExpr->isArrow(), SS, /*TemplateKWLoc=*/SourceLocation(), GetterName,
-      /*ObjCImpDecl=*/nullptr);
+  ExprResult GetterExpr =
+      S.ActOnMemberAccessExpr(S.getCurScope(), InstanceBase, SourceLocation(),
+                              RefExpr->isArrow() ? tok::arrow : tok::period, SS,
+                              SourceLocation(), GetterName, nullptr);
   if (GetterExpr.isInvalid()) {
     S.Diag(RefExpr->getMemberLoc(),
            diag::err_cannot_find_suitable_accessor) << 0 /* getter */
@@ -1424,10 +1424,10 @@ ExprResult MSPropertyOpBuilder::buildSet(Expr *op, SourceLocation sl,
   SetterName.setIdentifier(II, RefExpr->getMemberLoc());
   CXXScopeSpec SS;
   SS.Adopt(RefExpr->getQualifierLoc());
-  ExprResult SetterExpr = S.ActOnMemberAccessExpr(
-      S.getCurScope(), InstanceBase, /*OpLoc=*/SourceLocation(),
-      RefExpr->isArrow(), SS, /*TemplateKWLoc=*/SourceLocation(), SetterName,
-      /*ObjCImpDecl=*/nullptr);
+  ExprResult SetterExpr =
+      S.ActOnMemberAccessExpr(S.getCurScope(), InstanceBase, SourceLocation(),
+                              RefExpr->isArrow() ? tok::arrow : tok::period, SS,
+                              SourceLocation(), SetterName, nullptr);
   if (SetterExpr.isInvalid()) {
     S.Diag(RefExpr->getMemberLoc(),
            diag::err_cannot_find_suitable_accessor) << 1 /* setter */

>From 95ca24bbb9cd6f856f15ba262ee6b2c6f1ae6d0f Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Mon, 3 Jun 2024 06:44:35 -0400
Subject: [PATCH 10/11] [FOLD] remove fixme from test

---
 clang/test/CXX/drs/cwg1xx.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/clang/test/CXX/drs/cwg1xx.cpp b/clang/test/CXX/drs/cwg1xx.cpp
index ea38bff0d8d34..b59e70260e1e0 100644
--- a/clang/test/CXX/drs/cwg1xx.cpp
+++ b/clang/test/CXX/drs/cwg1xx.cpp
@@ -615,7 +615,6 @@ namespace cwg141 { // cwg141: 3.1
     //   cxx98-note@#cwg141-S {{lookup from the current scope refers here}}
     // expected-error@#cwg141-a {{no member named 'n' in 'cwg141::A::S<int>'; did you mean '::cwg141::S<int>::n'?}}
     //   expected-note@#cwg141-S {{'::cwg141::S<int>::n' declared here}}
-    // FIXME: we issue a useful diagnostic first, then some bogus ones.
     b.f<int>();
     // expected-error at -1 {{no member named 'f' in 'cwg141::B'}}
     (void)b.S<int>::n;

>From 13ff86541342c92d8a13cb8c732ed32dc2f39d82 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Mon, 3 Jun 2024 08:36:13 -0400
Subject: [PATCH 11/11] [FOLD] make missing 'template' keyword an extension

---
 .../clang/Basic/DiagnosticParseKinds.td       |  4 +---
 clang/lib/Parse/ParseExprCXX.cpp              |  8 ++------
 .../basic.lookup.qual.general/p3.cpp          |  4 ++--
 .../class.derived/class.member.lookup/p8.cpp  |  4 ++--
 clang/test/CXX/temp/temp.res/p3.cpp           |  2 +-
 clang/test/FixIt/fixit.cpp                    |  4 ++--
 clang/test/Misc/warning-flags.c               |  2 +-
 .../Parser/cxx2a-concepts-requires-expr.cpp   |  2 +-
 .../SemaTemplate/dependent-base-classes.cpp   | 20 +++++++++----------
 .../dependent-template-recover.cpp            | 12 +++++------
 clang/test/SemaTemplate/template-id-expr.cpp  | 14 ++++++-------
 .../SemaTemplate/typename-specifier-3.cpp     |  2 +-
 12 files changed, 36 insertions(+), 42 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index d8c3fee7841f4..f52ed78fd4eac 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -892,9 +892,7 @@ def missing_template_arg_list_after_template_kw : Extension<
   "keyword">, InGroup<DiagGroup<"missing-template-arg-list-after-template-kw">>,
   DefaultError;
 
-def err_missing_dependent_template_keyword : Error<
-  "use 'template' keyword to treat '%0' as a dependent template name">;
-def warn_missing_dependent_template_keyword : ExtWarn<
+def ext_missing_dependent_template_keyword : ExtWarn<
   "use 'template' keyword to treat '%0' as a dependent template name">;
 
 def ext_extern_template : Extension<
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 1558e3dcb8974..804c1b2d4c1ff 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -566,11 +566,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
           // member of an unknown specialization. However, this will only
           // parse correctly as a template, so suggest the keyword 'template'
           // before 'getAs' and treat this as a dependent template name.
-          unsigned DiagID = diag::err_missing_dependent_template_keyword;
-          if (getLangOpts().MicrosoftExt)
-            DiagID = diag::warn_missing_dependent_template_keyword;
-
-          Diag(Tok.getLocation(), DiagID)
+          Diag(Tok.getLocation(), diag::ext_missing_dependent_template_keyword)
               << II.getName()
               << FixItHint::CreateInsertion(Tok.getLocation(), "template ");
         }
@@ -2577,7 +2573,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(
             else
               Name += Id.Identifier->getName();
           }
-          Diag(Id.StartLocation, diag::err_missing_dependent_template_keyword)
+          Diag(Id.StartLocation, diag::ext_missing_dependent_template_keyword)
               << Name
               << FixItHint::CreateInsertion(Id.StartLocation, "template ");
         }
diff --git a/clang/test/CXX/basic/basic.lookup/basic.lookup.qual/basic.lookup.qual.general/p3.cpp b/clang/test/CXX/basic/basic.lookup/basic.lookup.qual/basic.lookup.qual.general/p3.cpp
index 6798e961123c3..7d843649c3f30 100644
--- a/clang/test/CXX/basic/basic.lookup/basic.lookup.qual/basic.lookup.qual.general/p3.cpp
+++ b/clang/test/CXX/basic/basic.lookup/basic.lookup.qual/basic.lookup.qual.general/p3.cpp
@@ -31,9 +31,9 @@ namespace Unambiguous {
     t.x;
     t.A::x;
     t.B::x;
-    t.C<int>::x; // expected-error {{use 'template' keyword to treat 'C' as a dependent template name}}
+    t.C<int>::x; // expected-warning {{use 'template' keyword to treat 'C' as a dependent template name}}
     t.template C<int>::x;
-    t.D<int>::x; // expected-error {{use 'template' keyword to treat 'D' as a dependent template name}}
+    t.D<int>::x; // expected-warning {{use 'template' keyword to treat 'D' as a dependent template name}}
     t.template D<int>::x;
     t.E::x;
   }
diff --git a/clang/test/CXX/class.derived/class.member.lookup/p8.cpp b/clang/test/CXX/class.derived/class.member.lookup/p8.cpp
index e9a57f739cc35..97d3587881bbc 100644
--- a/clang/test/CXX/class.derived/class.member.lookup/p8.cpp
+++ b/clang/test/CXX/class.derived/class.member.lookup/p8.cpp
@@ -47,8 +47,8 @@ template<typename T>
 void DerivedT<T>::Inner() {
   Derived1T<T>::Foo();
   Derived2T<T>::Member = 42;
-  this->Derived1T<T>::Foo(); // expected-error{{use 'template' keyword to treat 'Derived1T' as a dependent template name}}
-  this->Derived2T<T>::Member = 42; // expected-error{{use 'template' keyword to treat 'Derived2T' as a dependent template name}}
+  this->Derived1T<T>::Foo(); // expected-warning{{use 'template' keyword to treat 'Derived1T' as a dependent template name}}
+  this->Derived2T<T>::Member = 42; // expected-warning{{use 'template' keyword to treat 'Derived2T' as a dependent template name}}
   this->Foo(); // expected-error{{non-static member 'Foo' found in multiple base-class subobjects of type 'BaseT<int>'}}
 }
 
diff --git a/clang/test/CXX/temp/temp.res/p3.cpp b/clang/test/CXX/temp/temp.res/p3.cpp
index 37ab93559e369..a4d735e05e9b8 100644
--- a/clang/test/CXX/temp/temp.res/p3.cpp
+++ b/clang/test/CXX/temp/temp.res/p3.cpp
@@ -30,6 +30,6 @@ template<typename T> int A<T>::template C<int>::*f5() {} // expected-error {{has
 template<typename T> template<typename U> struct A<T>::B {
   friend A<T>::C<T> f6(); // ok, same as 'friend T f6();'
 
-  friend A<U>::C<T> f7(); // expected-error {{use 'template' keyword to treat 'C' as a dependent template name}} expected-warning {{missing 'typename'}}
+  friend A<U>::C<T> f7(); // expected-warning {{use 'template' keyword to treat 'C' as a dependent template name}} expected-warning {{missing 'typename'}}
   friend A<U>::template C<T> f8(); // expected-warning {{missing 'typename'}}
 };
diff --git a/clang/test/FixIt/fixit.cpp b/clang/test/FixIt/fixit.cpp
index 605c2d0bd0235..144eefb3ae4bd 100644
--- a/clang/test/FixIt/fixit.cpp
+++ b/clang/test/FixIt/fixit.cpp
@@ -158,12 +158,12 @@ class F1 {
  
 template<class T>
 class F2  {
-  typename F1<T>:: /*template*/  Iterator<0> Mypos; // expected-error {{use 'template' keyword to treat 'Iterator' as a dependent template name}}
+  typename F1<T>:: /*template*/  Iterator<0> Mypos; // expected-warning {{use 'template' keyword to treat 'Iterator' as a dependent template name}}
 };
 
 template <class T>
 void f(){
-  typename F1<T>:: /*template*/ Iterator<0> Mypos; // expected-error {{use 'template' keyword to treat 'Iterator' as a dependent template name}}
+  typename F1<T>:: /*template*/ Iterator<0> Mypos; // expected-warning {{use 'template' keyword to treat 'Iterator' as a dependent template name}}
 }
 
 // Tests for &/* fixits
diff --git a/clang/test/Misc/warning-flags.c b/clang/test/Misc/warning-flags.c
index dd73331913c6f..147fc088b6681 100644
--- a/clang/test/Misc/warning-flags.c
+++ b/clang/test/Misc/warning-flags.c
@@ -22,6 +22,7 @@ CHECK: Warnings without flags (66):
 
 CHECK-NEXT:   ext_expected_semi_decl_list
 CHECK-NEXT:   ext_explicit_specialization_storage_class
+CHECK-NEXT:   ext_missing_dependent_template_keyword
 CHECK-NEXT:   ext_missing_whitespace_after_macro_name
 CHECK-NEXT:   ext_new_paren_array_nonconst
 CHECK-NEXT:   ext_plain_complex
@@ -62,7 +63,6 @@ CHECK-NEXT:   warn_invalid_cpu_supports
 CHECK-NEXT:   warn_maynot_respond
 CHECK-NEXT:   warn_method_param_redefinition
 CHECK-NEXT:   warn_missing_case_for_condition
-CHECK-NEXT:   warn_missing_dependent_template_keyword
 CHECK-NEXT:   warn_missing_whitespace_after_macro_name
 CHECK-NEXT:   warn_mt_message
 CHECK-NEXT:   warn_no_constructor_for_refconst
diff --git a/clang/test/Parser/cxx2a-concepts-requires-expr.cpp b/clang/test/Parser/cxx2a-concepts-requires-expr.cpp
index 971591afb08db..980493b777b12 100644
--- a/clang/test/Parser/cxx2a-concepts-requires-expr.cpp
+++ b/clang/test/Parser/cxx2a-concepts-requires-expr.cpp
@@ -78,7 +78,7 @@ bool r22 = requires { typename s::~s; };
 
 template<typename T>
 bool r23 = requires { typename identity<T>::temp<T>; };
-// expected-error at -1 {{use 'template' keyword to treat 'temp' as a dependent template name}}
+// expected-warning at -1 {{use 'template' keyword to treat 'temp' as a dependent template name}}
 
 template<typename T>
 bool r24 = requires {
diff --git a/clang/test/SemaTemplate/dependent-base-classes.cpp b/clang/test/SemaTemplate/dependent-base-classes.cpp
index 92a37efaa7e73..4cb88a5b4070a 100644
--- a/clang/test/SemaTemplate/dependent-base-classes.cpp
+++ b/clang/test/SemaTemplate/dependent-base-classes.cpp
@@ -1,12 +1,12 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 
 template<typename T, typename U>
-struct X0 : T::template apply<U> { 
+struct X0 : T::template apply<U> {
   X0(U u) : T::template apply<U>(u) { }
 };
 
 template<typename T, typename U>
-struct X1 : T::apply<U> { }; // expected-error{{use 'template' keyword to treat 'apply' as a dependent template name}}
+struct X1 : T::apply<U> { }; // expected-warning{{use 'template' keyword to treat 'apply' as a dependent template name}}
 
 template<typename T>
 struct X2 : vector<T> { }; // expected-error{{no template named 'vector'}}
@@ -85,7 +85,7 @@ namespace PR6081 {
   struct A { };
 
   template<typename T>
-  class B : public A<T> 
+  class B : public A<T>
   {
   public:
     template< class X >
@@ -109,9 +109,9 @@ namespace PR6081 {
 
 namespace PR6413 {
   template <typename T> class Base_A { };
-  
+
   class Base_B { };
-  
+
   template <typename T>
   class Derived
     : public virtual Base_A<T>
@@ -120,12 +120,12 @@ namespace PR6413 {
 }
 
 namespace PR5812 {
-  template <class T> struct Base { 
-    Base* p; 
-  }; 
+  template <class T> struct Base {
+    Base* p;
+  };
 
-  template <class T> struct Derived: public Base<T> { 
-    typename Derived::Base* p; // meaning Derived::Base<T> 
+  template <class T> struct Derived: public Base<T> {
+    typename Derived::Base* p; // meaning Derived::Base<T>
   };
 
   Derived<int> di;
diff --git a/clang/test/SemaTemplate/dependent-template-recover.cpp b/clang/test/SemaTemplate/dependent-template-recover.cpp
index c7e27e8da25f1..c763989e6dadb 100644
--- a/clang/test/SemaTemplate/dependent-template-recover.cpp
+++ b/clang/test/SemaTemplate/dependent-template-recover.cpp
@@ -2,15 +2,15 @@
 template<typename T, typename U, int N>
 struct X {
   void f(T* t) {
-    t->f0<U>(); // expected-error{{use 'template' keyword to treat 'f0' as a dependent template name}}
-    t->f0<int>(); // expected-error{{use 'template' keyword to treat 'f0' as a dependent template name}}
+    t->f0<U>(); // expected-warning{{use 'template' keyword to treat 'f0' as a dependent template name}}
+    t->f0<int>(); // expected-warning{{use 'template' keyword to treat 'f0' as a dependent template name}}
 
-    t->operator+<U const, 1>(1); // expected-error{{use 'template' keyword to treat 'operator +' as a dependent template name}}
-    t->f1<int const, 2>(1); // expected-error{{use 'template' keyword to treat 'f1' as a dependent template name}}
+    t->operator+<U const, 1>(1); // expected-warning{{use 'template' keyword to treat 'operator +' as a dependent template name}}
+    t->f1<int const, 2>(1); // expected-warning{{use 'template' keyword to treat 'f1' as a dependent template name}}
     t->f1<3, int const>(1); // expected-error{{missing 'template' keyword prior to dependent template name 'f1'}}
 
-    T::getAs<U>(); // expected-error{{use 'template' keyword to treat 'getAs' as a dependent template name}}
-    t->T::getAs<U>(); // expected-error{{use 'template' keyword to treat 'getAs' as a dependent template name}}
+    T::getAs<U>(); // expected-warning{{use 'template' keyword to treat 'getAs' as a dependent template name}}
+    t->T::getAs<U>(); // expected-warning{{use 'template' keyword to treat 'getAs' as a dependent template name}}
 
     (*t).f2<N>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f2'}}
     (*t).f2<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f2'}}
diff --git a/clang/test/SemaTemplate/template-id-expr.cpp b/clang/test/SemaTemplate/template-id-expr.cpp
index 6c98e29cdaa95..fe2d22848f342 100644
--- a/clang/test/SemaTemplate/template-id-expr.cpp
+++ b/clang/test/SemaTemplate/template-id-expr.cpp
@@ -19,7 +19,7 @@ template<typename T>
 struct X0 {
   template<typename U>
   void f1();
-  
+
   template<typename U>
   void f2(U) {
     f1<U>();
@@ -39,9 +39,9 @@ struct Y {
 template<int I>
 struct X {
   X(int, int);
-  void f() { 
-    Y<X<I> >(X<I>(0, 0)); 
-    Y<X<I> >(::X<I>(0, 0)); 
+  void f() {
+    Y<X<I> >(X<I>(0, 0));
+    Y<X<I> >(::X<I>(0, 0));
   }
 };
 
@@ -149,11 +149,11 @@ struct Y2 : Y1<T> {
 
     int x;
     x = Y1::f4(0);
-    x = Y1::f4<int>(0); // expected-error {{use 'template'}} expected-error {{assigning to 'int' from incompatible type 'void'}}
+    x = Y1::f4<int>(0); // expected-warning {{use 'template'}} expected-error {{assigning to 'int' from incompatible type 'void'}}
     x = Y1::template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} expected-error {{a template argument list is expected after a name prefixed by the template keyword}}
 
     x = p->f4(0);
-    x = p->f4<int>(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} expected-error {{use 'template'}}
+    x = p->f4<int>(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} expected-warning {{use 'template'}}
     x = p->template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} expected-error {{a template argument list is expected after a name prefixed by the template keyword}}
   }
 };
@@ -184,7 +184,7 @@ class E {
 #if __cplusplus <= 199711L
 // expected-warning at +2 {{extension}}
 #endif
-template<typename T> using D = int; // expected-note {{declared here}} 
+template<typename T> using D = int; // expected-note {{declared here}}
 E<D> ed; // expected-note {{instantiation of}}
 
 namespace non_functions {
diff --git a/clang/test/SemaTemplate/typename-specifier-3.cpp b/clang/test/SemaTemplate/typename-specifier-3.cpp
index 714830f0032d2..a9010969322e5 100644
--- a/clang/test/SemaTemplate/typename-specifier-3.cpp
+++ b/clang/test/SemaTemplate/typename-specifier-3.cpp
@@ -46,7 +46,7 @@ namespace PR12884_half_fixed {
       typedef int arg;
     };
     struct C {
-      typedef typename B::X<typename B::arg> x; // expected-error {{use 'template'}} expected-error {{refers to non-type}}
+      typedef typename B::X<typename B::arg> x; // expected-warning {{use 'template'}} expected-error {{refers to non-type}}
     };
   };
 



More information about the cfe-commits mailing list