[clang] [clang-tools-extra] [Clang][Sema] Diagnose class member access expressions naming non-existent members of the current instantiation prior to instantiation in the absence of dependent base classes (PR #84050)

Krystian Stasiowski via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 25 06:18:35 PDT 2024


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

>From dc39390759a3925902c70b673bcd261bc46b2420 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Fri, 1 Mar 2024 08:08:52 -0500
Subject: [PATCH 01/25] [Clang][Sema] Earlier resolution of class member access
 expressions naming member of the current instantiation

---
 clang/lib/AST/Expr.cpp                      |   2 +-
 clang/lib/Sema/SemaExpr.cpp                 |   4 +-
 clang/lib/Sema/SemaExprMember.cpp           | 121 ++++++++++++++------
 clang/lib/Sema/SemaOverload.cpp             |   3 +
 clang/test/SemaTemplate/dependent-names.cpp |   4 +-
 5 files changed, 93 insertions(+), 41 deletions(-)

diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 9eec7edc9d1a3e..ef0a149a7e6937 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -103,7 +103,7 @@ const Expr *Expr::skipRValueSubobjectAdjustments(
       }
     } else if (const auto *ME = dyn_cast<MemberExpr>(E)) {
       if (!ME->isArrow()) {
-        assert(ME->getBase()->getType()->isRecordType());
+        assert(ME->getBase()->getType()->getAsRecordDecl());
         if (const auto *Field = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
           if (!Field->isBitField() && !Field->getType()->isReferenceType()) {
             E = ME->getBase();
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 5c861467bc1023..020130b885cd0a 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -673,7 +673,9 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
   // expressions of certain types in C++.
   if (getLangOpts().CPlusPlus &&
       (E->getType() == Context.OverloadTy ||
-       T->isDependentType() ||
+      // FIXME: This is a hack! We want the lvalue-to-rvalue conversion applied
+      // to pointer types even if the pointee type is dependent.
+      (T->isDependentType() && !T->isPointerType()) ||
        T->isRecordType()))
     return E;
 
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 6e30716b9ae436..850f182facf2db 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -667,8 +667,8 @@ namespace {
 // classes, one of its base classes.
 class RecordMemberExprValidatorCCC final : public CorrectionCandidateCallback {
 public:
-  explicit RecordMemberExprValidatorCCC(const RecordType *RTy)
-      : Record(RTy->getDecl()) {
+  explicit RecordMemberExprValidatorCCC(QualType RTy)
+      : Record(RTy->getAsRecordDecl()) {
     // Don't add bare keywords to the consumer since they will always fail
     // validation by virtue of not being associated with any decls.
     WantTypeSpecifiers = false;
@@ -714,33 +714,55 @@ class RecordMemberExprValidatorCCC final : public CorrectionCandidateCallback {
 
 static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
                                      Expr *BaseExpr,
-                                     const RecordType *RTy,
+                                     QualType RTy,
                                      SourceLocation OpLoc, bool IsArrow,
                                      CXXScopeSpec &SS, bool HasTemplateArgs,
                                      SourceLocation TemplateKWLoc,
                                      TypoExpr *&TE) {
+  RecordDecl *RDecl = RTy->getAsRecordDecl();
+  DeclContext *DC = SemaRef.computeDeclContext(RTy);
+  // If the object expression is dependent and isn't the current instantiation,
+  // lookup will not find anything and we must defer until instantiation.
+  if (!DC) {
+    R.setNotFoundInCurrentInstantiation();
+    return false;
+  }
+
+  // FIXME: Should this use Name.isDependentName()?
+  if (DeclarationName Name = R.getLookupName();
+      Name.getNameKind() == DeclarationName::CXXConversionFunctionName &&
+      Name.getCXXNameType()->isDependentType()) {
+    R.setNotFoundInCurrentInstantiation();
+    return false;
+  }
+
   SourceRange BaseRange = BaseExpr ? BaseExpr->getSourceRange() : SourceRange();
-  RecordDecl *RDecl = RTy->getDecl();
-  if (!SemaRef.isThisOutsideMemberFunctionBody(QualType(RTy, 0)) &&
-      SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0),
+  if (!RTy->isDependentType() &&
+      !SemaRef.isThisOutsideMemberFunctionBody(RTy) &&
+      SemaRef.RequireCompleteType(OpLoc, RTy,
                                   diag::err_typecheck_incomplete_tag,
                                   BaseRange))
     return true;
 
   if (HasTemplateArgs || TemplateKWLoc.isValid()) {
     // LookupTemplateName doesn't expect these both to exist simultaneously.
-    QualType ObjectType = SS.isSet() ? QualType() : QualType(RTy, 0);
+    QualType ObjectType = SS.isSet() ? QualType() : RTy;
 
     bool MOUS;
     return SemaRef.LookupTemplateName(R, nullptr, SS, ObjectType, false, MOUS,
                                       TemplateKWLoc);
   }
 
-  DeclContext *DC = RDecl;
   if (SS.isSet()) {
     // If the member name was a qualified-id, look into the
     // nested-name-specifier.
     DC = SemaRef.computeDeclContext(SS, false);
+    // We tried to look into a dependent context that is not the current
+    // instantiation. Defer lookup until instantiation.
+    if (!DC) {
+      R.setNotFoundInCurrentInstantiation();
+      return false;
+    }
 
     if (SemaRef.RequireCompleteDeclContext(SS, DC)) {
       SemaRef.Diag(SS.getRange().getEnd(), diag::err_typecheck_incomplete_tag)
@@ -760,7 +782,7 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
   // The record definition is complete, now look up the member.
   SemaRef.LookupQualifiedName(R, DC, SS);
 
-  if (!R.empty())
+  if (!R.empty() || R.wasNotFoundInCurrentInstantiation())
     return false;
 
   DeclarationName Typo = R.getLookupName();
@@ -824,6 +846,7 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
                                const TemplateArgumentListInfo *TemplateArgs,
                                const Scope *S,
                                ActOnMemberAccessExtraArgs *ExtraArgs) {
+  #if 0
   if (BaseType->isDependentType() ||
       (SS.isSet() && isDependentScopeSpecifier(SS)) ||
       NameInfo.getName().isDependentName())
@@ -831,6 +854,7 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
                                     IsArrow, OpLoc,
                                     SS, TemplateKWLoc, FirstQualifierInScope,
                                     NameInfo, TemplateArgs);
+  #endif
 
   LookupResult R(*this, NameInfo, LookupMemberName);
 
@@ -840,7 +864,7 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
     QualType RecordTy = BaseType;
     if (IsArrow) RecordTy = RecordTy->castAs<PointerType>()->getPointeeType();
     if (LookupMemberExprInRecord(
-            *this, R, nullptr, RecordTy->castAs<RecordType>(), OpLoc, IsArrow,
+            *this, R, nullptr, RecordTy, OpLoc, IsArrow,
             SS, TemplateArgs != nullptr, TemplateKWLoc, TE))
       return ExprError();
     if (TE)
@@ -1033,6 +1057,14 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
                                const Scope *S,
                                bool SuppressQualifierCheck,
                                ActOnMemberAccessExtraArgs *ExtraArgs) {
+
+  if (R.wasNotFoundInCurrentInstantiation() || (SS.isValid() && !computeDeclContext(SS, false))) {
+    return ActOnDependentMemberExpr(BaseExpr, BaseExprType,
+                                    IsArrow, OpLoc,
+                                    SS, TemplateKWLoc, FirstQualifierInScope,
+                                    R.getLookupNameInfo(), TemplateArgs);
+  }
+
   QualType BaseType = BaseExprType;
   if (IsArrow) {
     assert(BaseType->isPointerType());
@@ -1071,11 +1103,11 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
     // Rederive where we looked up.
     DeclContext *DC = (SS.isSet()
                        ? computeDeclContext(SS, false)
-                       : BaseType->castAs<RecordType>()->getDecl());
+                       : BaseType->getAsRecordDecl());
 
     if (ExtraArgs) {
       ExprResult RetryExpr;
-      if (!IsArrow && BaseExpr) {
+      if (!IsArrow && BaseExpr && !BaseExpr->isTypeDependent()) {
         SFINAETrap Trap(*this, true);
         ParsedType ObjectType;
         bool MayBePseudoDestructor = false;
@@ -1098,9 +1130,16 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
       }
     }
 
-    Diag(R.getNameLoc(), diag::err_no_member)
-      << MemberName << DC
-      << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
+    if(DC) {
+      Diag(R.getNameLoc(), diag::err_no_member)
+          << MemberName << DC
+          << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
+    } else {
+      // FIXME: Is this needed?
+      Diag(R.getNameLoc(), diag::err_no_member)
+          << MemberName << BaseExprType
+          << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
+    }
     return ExprError();
   }
 
@@ -1330,7 +1369,10 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
     return ExprError();
 
   QualType BaseType = BaseExpr.get()->getType();
+
+  #if 0
   assert(!BaseType->isDependentType());
+  #endif
 
   DeclarationName MemberName = R.getLookupName();
   SourceLocation MemberLoc = R.getNameLoc();
@@ -1342,29 +1384,32 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
   if (IsArrow) {
     if (const PointerType *Ptr = BaseType->getAs<PointerType>())
       BaseType = Ptr->getPointeeType();
-    else if (const ObjCObjectPointerType *Ptr
+    else if (!BaseType->isDependentType()) {
+      if (const ObjCObjectPointerType *Ptr
                = BaseType->getAs<ObjCObjectPointerType>())
       BaseType = Ptr->getPointeeType();
-    else if (BaseType->isRecordType()) {
-      // Recover from arrow accesses to records, e.g.:
-      //   struct MyRecord foo;
-      //   foo->bar
-      // This is actually well-formed in C++ if MyRecord has an
-      // overloaded operator->, but that should have been dealt with
-      // by now--or a diagnostic message already issued if a problem
-      // was encountered while looking for the overloaded operator->.
-      if (!S.getLangOpts().CPlusPlus) {
-        S.Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
-          << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
-          << FixItHint::CreateReplacement(OpLoc, ".");
+      else if (BaseType->isRecordType()) {
+        // Recover from arrow accesses to records, e.g.:
+         //   struct MyRecord foo;
+        //   foo->bar
+        // This is actually well-formed in C++ if MyRecord has an
+        // overloaded operator->, but that should have been dealt with
+        // by now--or a diagnostic message already issued if a problem
+        // was encountered while looking for the overloaded operator->.
+        if (!S.getLangOpts().CPlusPlus) {
+          S.Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
+              << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
+              << FixItHint::CreateReplacement(OpLoc, ".");
+        }
+        IsArrow = false;
+      } else if (BaseType->isFunctionType()) {
+        goto fail;
+      } else {
+        S.Diag(MemberLoc, diag::err_typecheck_member_reference_arrow)
+            << BaseType << BaseExpr.get()->getSourceRange();
+        return ExprError();
       }
-      IsArrow = false;
-    } else if (BaseType->isFunctionType()) {
-      goto fail;
-    } else {
-      S.Diag(MemberLoc, diag::err_typecheck_member_reference_arrow)
-        << BaseType << BaseExpr.get()->getSourceRange();
-      return ExprError();
+
     }
   }
 
@@ -1384,9 +1429,9 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
   }
 
   // Handle field access to simple records.
-  if (const RecordType *RTy = BaseType->getAs<RecordType>()) {
+  if (BaseType->getAsRecordDecl() || BaseType->isDependentType()) {
     TypoExpr *TE = nullptr;
-    if (LookupMemberExprInRecord(S, R, BaseExpr.get(), RTy, OpLoc, IsArrow, SS,
+    if (LookupMemberExprInRecord(S, R, BaseExpr.get(), BaseType, OpLoc, IsArrow, SS,
                                  HasTemplateArgs, TemplateKWLoc, TE))
       return ExprError();
 
@@ -1824,12 +1869,14 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
   if (Result.isInvalid()) return ExprError();
   Base = Result.get();
 
+  #if 0
   if (Base->getType()->isDependentType() || Name.isDependentName() ||
       isDependentScopeSpecifier(SS)) {
     return ActOnDependentMemberExpr(Base, Base->getType(), IsArrow, OpLoc, SS,
                                     TemplateKWLoc, FirstQualifierInScope,
                                     NameInfo, TemplateArgs);
   }
+  #endif
 
   ActOnMemberAccessExtraArgs ExtraArgs = {S, Id, ObjCImpDecl};
   ExprResult Res = BuildMemberReferenceExpr(
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 04cd9e78739d20..27c3fd51422b6c 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -5805,7 +5805,10 @@ static ImplicitConversionSequence TryObjectArgumentInitialization(
     return ICS;
   }
 
+  // FIXME: Should this check getAsRecordDecl instead?
+  #if 0
   assert(FromType->isRecordType());
+  #endif
 
   QualType ClassType = S.Context.getTypeDeclType(ActingContext);
   // C++98 [class.dtor]p2:
diff --git a/clang/test/SemaTemplate/dependent-names.cpp b/clang/test/SemaTemplate/dependent-names.cpp
index 641ec950054f57..a661f14af80d34 100644
--- a/clang/test/SemaTemplate/dependent-names.cpp
+++ b/clang/test/SemaTemplate/dependent-names.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s 
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
 
 typedef double A;
 template<typename T> class B {
@@ -334,7 +334,7 @@ int arr[sizeof(Sub)];
 namespace PR11421 {
 template < unsigned > struct X {
   static const unsigned dimension = 3;
-  template<unsigned dim=dimension> 
+  template<unsigned dim=dimension>
   struct Y: Y<dim> { }; // expected-error{{circular inheritance between 'Y<dim>' and 'Y<dim>'}}
 };
 typedef X<3> X3;

>From 0438e872148470c2f63b905fdf8066c5bc1f3bbb Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Fri, 1 Mar 2024 11:54:23 -0500
Subject: [PATCH 02/25] [FOLD] update tests

---
 .../temp.res/temp.dep/temp.dep.type/p4.cpp    | 110 ++++++++++++++++++
 .../SemaTemplate/instantiate-function-1.cpp   |  14 +--
 2 files changed, 117 insertions(+), 7 deletions(-)
 create mode 100644 clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp

diff --git a/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp b/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp
new file mode 100644
index 00000000000000..7b36e3ad3b0131
--- /dev/null
+++ b/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp
@@ -0,0 +1,110 @@
+// RUN: %clang_cc1 -Wno-unused-value -verify %s
+
+namespace N0 {
+  template<typename T>
+  struct A {
+    int x;
+    void f();
+    using X = int;
+
+    void not_instantiated(A *a, A &b) {
+      x;
+      f();
+      new X;
+
+      this->x;
+      this->f();
+      this->A::x;
+      this->A::f();
+
+      a->x;
+      a->f();
+      a->A::x;
+      a->A::f();
+
+      (*this).x;
+      (*this).f();
+      (*this).A::x;
+      (*this).A::f();
+
+      b.x;
+      b.f();
+      b.A::x;
+      b.A::f();
+
+      A::x;
+      A::f();
+      new A::X;
+
+      y; // expected-error{{use of undeclared identifier 'y'}}
+      g(); // expected-error{{use of undeclared identifier 'g'}}
+      new Y; // expected-error{{unknown type name 'Y'}}
+
+      this->y; // expected-error{{no member named 'y' in 'A<T>'}}
+      this->g(); // expected-error{{no member named 'g' in 'A<T>'}}
+      this->A::y; // expected-error{{no member named 'y' in 'A<T>'}}
+      this->A::g(); // expected-error{{no member named 'g' in 'A<T>'}}
+
+      a->y; // expected-error{{no member named 'y' in 'A<T>'}}
+      a->g(); // expected-error{{no member named 'g' in 'A<T>'}}
+      a->A::y; // expected-error{{no member named 'y' in 'A<T>'}}
+      a->A::g(); // expected-error{{no member named 'g' in 'A<T>'}}
+
+      // FIXME: An overloaded unary 'operator*' is built for these
+      // even though the operand is a pointer (to a dependent type).
+      // Type::isOverloadableType should return false for such cases.
+      (*this).y;
+      (*this).g();
+      (*this).A::y;
+      (*this).A::g();
+
+      b.y; // expected-error{{no member named 'y' in 'A<T>'}}
+      b.g(); // expected-error{{no member named 'g' in 'A<T>'}}
+      b.A::y; // expected-error{{no member named 'y' in 'A<T>'}}
+      b.A::g(); // expected-error{{no member named 'g' in 'A<T>'}}
+
+      A::y; // expected-error{{no member named 'y' in 'A<T>'}}
+      A::g(); // expected-error{{no member named 'g' in 'A<T>'}}
+      new A::Y; // expected-error{{no type named 'Y' in 'A<T>'}}
+    }
+  };
+} // namespace N0
+
+namespace N1 {
+  struct A {
+    template<int I>
+    void f();
+  };
+
+  template<typename T>
+  struct B {
+    template<int I>
+    void f();
+
+    A x;
+    A g();
+
+    void not_instantiated(B *a, B &b) {
+      f<0>();
+      this->f<0>();
+      a->f<0>();
+      // FIXME: This should not require 'template'!
+      (*this).f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}}
+      b.f<0>();
+
+      x.f<0>();
+      this->x.f<0>();
+      a->x.f<0>();
+      // FIXME: This should not require 'template'!
+      (*this).x.f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}}
+      b.x.f<0>();
+
+      // FIXME: None of these should require 'template'!
+      g().f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}}
+      this->g().f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}}
+      a->g().f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}}
+      (*this).g().f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}}
+      b.g().f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}}
+    }
+  };
+} // namespace N1
diff --git a/clang/test/SemaTemplate/instantiate-function-1.cpp b/clang/test/SemaTemplate/instantiate-function-1.cpp
index ceef2743774805..a4967264c654b7 100644
--- a/clang/test/SemaTemplate/instantiate-function-1.cpp
+++ b/clang/test/SemaTemplate/instantiate-function-1.cpp
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify %s
 template<typename T, typename U>
 struct X0 {
-  void f(T x, U y) { 
+  void f(T x, U y) {
     (void)(x + y); // expected-error{{invalid operands}}
   }
 };
@@ -41,7 +41,7 @@ template <typename T> struct X4 {
   T f() const {
     return; // expected-error{{non-void function 'f' should return a value}}
   }
-  
+
   T g() const {
     return 1; // expected-error{{void function 'g' should not return a value}}
   }
@@ -64,7 +64,7 @@ template<typename T, typename U, typename V> struct X6 {
     // IfStmt
     if (t > 0)
       return u;
-    else { 
+    else {
       if (t < 0)
         return v; // expected-error{{cannot initialize return object of type}}
     }
@@ -131,12 +131,12 @@ template<typename T> struct Member0 {
     t;
     t.f;
     t->f;
-    
+
     T* tp;
     tp.f; // expected-error{{member reference base type 'T *' is not a structure or union}}
     tp->f;
 
-    this->f;
+    this->f; // expected-error{{reference to non-static member function must be called}}
     this.f; // expected-error{{member reference base type 'Member0<T> *' is not a structure or union}}
   }
 };
@@ -239,11 +239,11 @@ namespace PR9880 {
     static yes_tag check(char[sizeof(&U::luaIndex)]);
     enum { value = sizeof(check<T>(0)) == sizeof(yes_tag) };
   };
-  
+
   class SomeClass {
   public:
     int luaIndex(lua_State* L);
   };
-  
+
   int i = HasIndexMetamethod<SomeClass>::value;
 }

>From 91f09205c520498e4969a79fec1bb147df025a86 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Mon, 4 Mar 2024 06:59:58 -0500
Subject: [PATCH 03/25] [FOLD] build DependentMemberExpr for
 LookupResult::FoundUnresolved

---
 clang/lib/Sema/SemaExprMember.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 850f182facf2db..1e5e05b0e60c32 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -719,7 +719,6 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
                                      CXXScopeSpec &SS, bool HasTemplateArgs,
                                      SourceLocation TemplateKWLoc,
                                      TypoExpr *&TE) {
-  RecordDecl *RDecl = RTy->getAsRecordDecl();
   DeclContext *DC = SemaRef.computeDeclContext(RTy);
   // If the object expression is dependent and isn't the current instantiation,
   // lookup will not find anything and we must defer until instantiation.
@@ -1058,7 +1057,9 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
                                bool SuppressQualifierCheck,
                                ActOnMemberAccessExtraArgs *ExtraArgs) {
 
-  if (R.wasNotFoundInCurrentInstantiation() || (SS.isValid() && !computeDeclContext(SS, false))) {
+  if (R.wasNotFoundInCurrentInstantiation() ||
+      (SS.isValid() && !computeDeclContext(SS, false)) ||
+      (R.isUnresolvableResult() && R.isClassLookup() && R.getNamingClass()->isDependentContext())) {
     return ActOnDependentMemberExpr(BaseExpr, BaseExprType,
                                     IsArrow, OpLoc,
                                     SS, TemplateKWLoc, FirstQualifierInScope,

>From 8f01497f29ffb6a88bb9925224d20158fdba133d Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Tue, 5 Mar 2024 10:03:05 -0500
Subject: [PATCH 04/25] [FOLD] TransformOverloadExprDecls filters template
 names

---
 clang/lib/Sema/SemaExprMember.cpp |  3 +--
 clang/lib/Sema/TreeTransform.h    | 20 ++++++++++++++++++++
 2 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 1e5e05b0e60c32..28939e0166bff6 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -1058,8 +1058,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
                                ActOnMemberAccessExtraArgs *ExtraArgs) {
 
   if (R.wasNotFoundInCurrentInstantiation() ||
-      (SS.isValid() && !computeDeclContext(SS, false)) ||
-      (R.isUnresolvableResult() && R.isClassLookup() && R.getNamingClass()->isDependentContext())) {
+      (SS.isValid() && !computeDeclContext(SS, false))) {
     return ActOnDependentMemberExpr(BaseExpr, BaseExprType,
                                     IsArrow, OpLoc,
                                     SS, TemplateKWLoc, FirstQualifierInScope,
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 1d30ba31e17940..e3f48a6573e3a9 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -13204,6 +13204,26 @@ bool TreeTransform<Derived>::TransformOverloadExprDecls(OverloadExpr *Old,
   // Resolve a kind, but don't do any further analysis.  If it's
   // ambiguous, the callee needs to deal with it.
   R.resolveKind();
+
+  if (Old->hasTemplateKeyword() && !R.empty()) {
+    NamedDecl *FoundDecl = R.getRepresentativeDecl()->getUnderlyingDecl();
+    getSema().FilterAcceptableTemplateNames(R,
+                                            /*AllowFunctionTemplates=*/true,
+                                            /*AllowDependent=*/true);
+    if (R.empty()) {
+      // If a 'template' keyword was used, a lookup that finds only non-template
+      // names is an error.
+      getSema().Diag(R.getNameLoc(), diag::err_template_kw_refers_to_non_template)
+          << R.getLookupName()
+          << Old->getQualifierLoc().getSourceRange()
+          << Old->hasTemplateKeyword()
+          << Old->getTemplateKeywordLoc();
+      getSema().Diag(FoundDecl->getLocation(), diag::note_template_kw_refers_to_non_template)
+          << R.getLookupName();
+        return true;
+    }
+  }
+
   return false;
 }
 

>From 04fdae1ce5daeee065ce5bc55e37fdfe1b631407 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Tue, 5 Mar 2024 10:50:53 -0500
Subject: [PATCH 05/25] [FOLD] update tests

---
 clang/test/AST/HLSL/this-reference-template.hlsl         | 2 +-
 clang/test/CodeGenCXX/mangle.cpp                         | 8 --------
 clang/test/Index/annotate-nested-name-specifier.cpp      | 4 ++--
 clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp | 4 ++--
 4 files changed, 5 insertions(+), 13 deletions(-)

diff --git a/clang/test/AST/HLSL/this-reference-template.hlsl b/clang/test/AST/HLSL/this-reference-template.hlsl
index 60e057986ebf80..d427e73044b788 100644
--- a/clang/test/AST/HLSL/this-reference-template.hlsl
+++ b/clang/test/AST/HLSL/this-reference-template.hlsl
@@ -24,7 +24,7 @@ void main() {
 // CHECK:     -CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <line:8:3, line:10:3> line:8:5 getFirst 'K ()' implicit-inline
 // CHECK-NEXT:-CompoundStmt 0x{{[0-9A-Fa-f]+}} <col:16, line:10:3>
 // CHECK-NEXT:-ReturnStmt 0x{{[0-9A-Fa-f]+}} <line:9:4, col:16>
-// CHECK-NEXT:-CXXDependentScopeMemberExpr 0x{{[0-9A-Fa-f]+}} <col:11, col:16> '<dependent type>' lvalue .First
+// CHECK-NEXT:-MemberExpr 0x{{[0-9A-Fa-f]+}} <col:11, col:16> 'K' lvalue .First 0x{{[0-9A-Fa-f]+}}
 // CHECK-NEXT:-CXXThisExpr 0x{{[0-9A-Fa-f]+}} <col:11> 'Pair<K, V>' lvalue this
 // CHECK-NEXT:-CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <line:12:3, line:14:3> line:12:5 getSecond 'V ()' implicit-inline
 // CHECK-NEXT:-CompoundStmt 0x{{[0-9A-Fa-f]+}} <col:17, line:14:3>
diff --git a/clang/test/CodeGenCXX/mangle.cpp b/clang/test/CodeGenCXX/mangle.cpp
index 31467d943840e0..d0800af55c87e8 100644
--- a/clang/test/CodeGenCXX/mangle.cpp
+++ b/clang/test/CodeGenCXX/mangle.cpp
@@ -1032,10 +1032,6 @@ namespace test51 {
   template <typename T>
   decltype(S1<T>().~S1<T>(), S1<T>().~S1<T>()) fun4() {};
   template <typename T>
-  decltype(S1<int>().~S1<T>()) fun5(){};
-  template <template <typename T> class U>
-  decltype(S1<int>().~U<int>()) fun6(){};
-  template <typename T>
   decltype(E().E::~T()) fun7() {}
   template <template <typename> class U>
   decltype(X<int>::Y().U<int>::Y::~Y()) fun8() {}
@@ -1047,10 +1043,6 @@ namespace test51 {
   // CHECK-LABEL: @_ZN6test514fun3I2S1IiEiEEDTcldtcvS1_IT0_E_EdnT_EEv
   template void fun4<int>();
   // CHECK-LABEL: @_ZN6test514fun4IiEEDTcmcldtcv2S1IT_E_Edn2S1IS2_EEcldtcvS3__Edn2S1IS2_EEEv
-  template void fun5<int>();
-  // CHECK-LABEL: @_ZN6test514fun5IiEEDTcldtcv2S1IiE_Edn2S1IT_EEEv
-  template void fun6<S1>();
-  // CHECK-LABEL: @_ZN6test514fun6I2S1EEDTcldtcvS1_IiE_EdnT_IiEEEv
   template void fun7<E>();
   // CHECK-LABEL: @_ZN6test514fun7INS_1EEEEDTcldtcvS1__Esr1EEdnT_EEv
   template void fun8<X>();
diff --git a/clang/test/Index/annotate-nested-name-specifier.cpp b/clang/test/Index/annotate-nested-name-specifier.cpp
index a7338db6b05b77..3181497258407f 100644
--- a/clang/test/Index/annotate-nested-name-specifier.cpp
+++ b/clang/test/Index/annotate-nested-name-specifier.cpp
@@ -132,7 +132,7 @@ struct X8 {
 
 struct X9 : X8 {
   typedef X8 inherited;
-  void f() { 
+  void f() {
     inherited::f();
   }
 };
@@ -299,7 +299,7 @@ struct X9 : X8 {
 // CHECK: Identifier: "type" [77:16 - 77:20] TypeRef=X4::type:70:13
 // CHECK: Punctuation: ">" [77:20 - 77:21] MemberRefExpr=
 // CHECK: Punctuation: "::" [77:21 - 77:23] MemberRefExpr=
-// CHECK: Identifier: "g" [77:23 - 77:24] MemberRefExpr=
+// CHECK: Identifier: "g" [77:23 - 77:24] OverloadedDeclRef=
 // CHECK: Punctuation: "(" [77:24 - 77:25] CallExpr=
 // CHECK: Identifier: "t" [77:25 - 77:26] DeclRefExpr=t:74:12
 // CHECK: Punctuation: ")" [77:26 - 77:27] CallExpr=
diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
index 87774b00956a5a..739f495510dee5 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -1569,8 +1569,8 @@ TEST_P(ASTMatchersTest, IsArrow_MatchesMemberVariablesViaArrow) {
       matches("class Y { void x() { y; } int y; };", memberExpr(isArrow())));
   EXPECT_TRUE(notMatches("class Y { void x() { (*this).y; } int y; };",
                          memberExpr(isArrow())));
-  EXPECT_TRUE(matches("template <class T> class Y { void x() { this->m; } };",
-                      cxxDependentScopeMemberExpr(isArrow())));
+  EXPECT_TRUE(matches("template <class T> class Y { void x() { this->m; } int m; };",
+                         memberExpr(isArrow())));
   EXPECT_TRUE(
       notMatches("template <class T> class Y { void x() { (*this).m; } };",
                  cxxDependentScopeMemberExpr(isArrow())));

>From 93043236adce89a81eb36d97de476dc468f5717b Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Tue, 5 Mar 2024 12:33:40 -0500
Subject: [PATCH 06/25] [FOLD] cleanup

---
 clang/lib/Sema/SemaExprMember.cpp           | 19 -------------------
 clang/test/SemaTemplate/dependent-names.cpp |  4 ++--
 2 files changed, 2 insertions(+), 21 deletions(-)

diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 28939e0166bff6..926459567cd8d1 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -845,16 +845,6 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
                                const TemplateArgumentListInfo *TemplateArgs,
                                const Scope *S,
                                ActOnMemberAccessExtraArgs *ExtraArgs) {
-  #if 0
-  if (BaseType->isDependentType() ||
-      (SS.isSet() && isDependentScopeSpecifier(SS)) ||
-      NameInfo.getName().isDependentName())
-    return ActOnDependentMemberExpr(Base, BaseType,
-                                    IsArrow, OpLoc,
-                                    SS, TemplateKWLoc, FirstQualifierInScope,
-                                    NameInfo, TemplateArgs);
-  #endif
-
   LookupResult R(*this, NameInfo, LookupMemberName);
 
   // Implicit member accesses.
@@ -1869,15 +1859,6 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
   if (Result.isInvalid()) return ExprError();
   Base = Result.get();
 
-  #if 0
-  if (Base->getType()->isDependentType() || Name.isDependentName() ||
-      isDependentScopeSpecifier(SS)) {
-    return ActOnDependentMemberExpr(Base, Base->getType(), IsArrow, OpLoc, SS,
-                                    TemplateKWLoc, FirstQualifierInScope,
-                                    NameInfo, TemplateArgs);
-  }
-  #endif
-
   ActOnMemberAccessExtraArgs ExtraArgs = {S, Id, ObjCImpDecl};
   ExprResult Res = BuildMemberReferenceExpr(
       Base, Base->getType(), OpLoc, IsArrow, SS, TemplateKWLoc,
diff --git a/clang/test/SemaTemplate/dependent-names.cpp b/clang/test/SemaTemplate/dependent-names.cpp
index a661f14af80d34..641ec950054f57 100644
--- a/clang/test/SemaTemplate/dependent-names.cpp
+++ b/clang/test/SemaTemplate/dependent-names.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s 
 
 typedef double A;
 template<typename T> class B {
@@ -334,7 +334,7 @@ int arr[sizeof(Sub)];
 namespace PR11421 {
 template < unsigned > struct X {
   static const unsigned dimension = 3;
-  template<unsigned dim=dimension>
+  template<unsigned dim=dimension> 
   struct Y: Y<dim> { }; // expected-error{{circular inheritance between 'Y<dim>' and 'Y<dim>'}}
 };
 typedef X<3> X3;

>From 9b11b735c3fba24fa287ba401e36a17349f551d4 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Tue, 5 Mar 2024 13:03:00 -0500
Subject: [PATCH 07/25] [FOLD] format

---
 clang/lib/Sema/SemaExpr.cpp                   |  7 +--
 clang/lib/Sema/SemaExprMember.cpp             | 59 ++++++++-----------
 clang/lib/Sema/SemaOverload.cpp               |  6 +-
 clang/lib/Sema/TreeTransform.h                | 14 ++---
 .../ASTMatchers/ASTMatchersNarrowingTest.cpp  |  5 +-
 5 files changed, 41 insertions(+), 50 deletions(-)

diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 020130b885cd0a..125dce65117f11 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -673,10 +673,9 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
   // expressions of certain types in C++.
   if (getLangOpts().CPlusPlus &&
       (E->getType() == Context.OverloadTy ||
-      // FIXME: This is a hack! We want the lvalue-to-rvalue conversion applied
-      // to pointer types even if the pointee type is dependent.
-      (T->isDependentType() && !T->isPointerType()) ||
-       T->isRecordType()))
+       // FIXME: This is a hack! We want the lvalue-to-rvalue conversion applied
+       // to pointer types even if the pointee type is dependent.
+       (T->isDependentType() && !T->isPointerType()) || T->isRecordType()))
     return E;
 
   // The C standard is actually really unclear on this point, and
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 926459567cd8d1..b0b9f2e395b023 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -713,8 +713,7 @@ class RecordMemberExprValidatorCCC final : public CorrectionCandidateCallback {
 }
 
 static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
-                                     Expr *BaseExpr,
-                                     QualType RTy,
+                                     Expr *BaseExpr, QualType RTy,
                                      SourceLocation OpLoc, bool IsArrow,
                                      CXXScopeSpec &SS, bool HasTemplateArgs,
                                      SourceLocation TemplateKWLoc,
@@ -738,9 +737,8 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
   SourceRange BaseRange = BaseExpr ? BaseExpr->getSourceRange() : SourceRange();
   if (!RTy->isDependentType() &&
       !SemaRef.isThisOutsideMemberFunctionBody(RTy) &&
-      SemaRef.RequireCompleteType(OpLoc, RTy,
-                                  diag::err_typecheck_incomplete_tag,
-                                  BaseRange))
+      SemaRef.RequireCompleteType(
+          OpLoc, RTy, diag::err_typecheck_incomplete_tag, BaseRange))
     return true;
 
   if (HasTemplateArgs || TemplateKWLoc.isValid()) {
@@ -835,16 +833,12 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
                                    Decl *ObjCImpDecl, bool HasTemplateArgs,
                                    SourceLocation TemplateKWLoc);
 
-ExprResult
-Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
-                               SourceLocation OpLoc, bool IsArrow,
-                               CXXScopeSpec &SS,
-                               SourceLocation TemplateKWLoc,
-                               NamedDecl *FirstQualifierInScope,
-                               const DeclarationNameInfo &NameInfo,
-                               const TemplateArgumentListInfo *TemplateArgs,
-                               const Scope *S,
-                               ActOnMemberAccessExtraArgs *ExtraArgs) {
+ExprResult Sema::BuildMemberReferenceExpr(
+    Expr *Base, QualType BaseType, SourceLocation OpLoc, bool IsArrow,
+    CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
+    NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo,
+    const TemplateArgumentListInfo *TemplateArgs, const Scope *S,
+    ActOnMemberAccessExtraArgs *ExtraArgs) {
   LookupResult R(*this, NameInfo, LookupMemberName);
 
   // Implicit member accesses.
@@ -852,9 +846,9 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
     TypoExpr *TE = nullptr;
     QualType RecordTy = BaseType;
     if (IsArrow) RecordTy = RecordTy->castAs<PointerType>()->getPointeeType();
-    if (LookupMemberExprInRecord(
-            *this, R, nullptr, RecordTy, OpLoc, IsArrow,
-            SS, TemplateArgs != nullptr, TemplateKWLoc, TE))
+    if (LookupMemberExprInRecord(*this, R, nullptr, RecordTy, OpLoc, IsArrow,
+                                 SS, TemplateArgs != nullptr, TemplateKWLoc,
+                                 TE))
       return ExprError();
     if (TE)
       return TE;
@@ -1049,9 +1043,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
 
   if (R.wasNotFoundInCurrentInstantiation() ||
       (SS.isValid() && !computeDeclContext(SS, false))) {
-    return ActOnDependentMemberExpr(BaseExpr, BaseExprType,
-                                    IsArrow, OpLoc,
-                                    SS, TemplateKWLoc, FirstQualifierInScope,
+    return ActOnDependentMemberExpr(BaseExpr, BaseExprType, IsArrow, OpLoc, SS,
+                                    TemplateKWLoc, FirstQualifierInScope,
                                     R.getLookupNameInfo(), TemplateArgs);
   }
 
@@ -1091,9 +1084,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
 
   if (R.empty()) {
     // Rederive where we looked up.
-    DeclContext *DC = (SS.isSet()
-                       ? computeDeclContext(SS, false)
-                       : BaseType->getAsRecordDecl());
+    DeclContext *DC = (SS.isSet() ? computeDeclContext(SS, false)
+                                  : BaseType->getAsRecordDecl());
 
     if (ExtraArgs) {
       ExprResult RetryExpr;
@@ -1120,7 +1112,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
       }
     }
 
-    if(DC) {
+    if (DC) {
       Diag(R.getNameLoc(), diag::err_no_member)
           << MemberName << DC
           << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
@@ -1360,9 +1352,9 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
 
   QualType BaseType = BaseExpr.get()->getType();
 
-  #if 0
+#if 0
   assert(!BaseType->isDependentType());
-  #endif
+#endif
 
   DeclarationName MemberName = R.getLookupName();
   SourceLocation MemberLoc = R.getNameLoc();
@@ -1375,12 +1367,12 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
     if (const PointerType *Ptr = BaseType->getAs<PointerType>())
       BaseType = Ptr->getPointeeType();
     else if (!BaseType->isDependentType()) {
-      if (const ObjCObjectPointerType *Ptr
-               = BaseType->getAs<ObjCObjectPointerType>())
-      BaseType = Ptr->getPointeeType();
+      if (const ObjCObjectPointerType *Ptr =
+              BaseType->getAs<ObjCObjectPointerType>())
+        BaseType = Ptr->getPointeeType();
       else if (BaseType->isRecordType()) {
         // Recover from arrow accesses to records, e.g.:
-         //   struct MyRecord foo;
+        //   struct MyRecord foo;
         //   foo->bar
         // This is actually well-formed in C++ if MyRecord has an
         // overloaded operator->, but that should have been dealt with
@@ -1399,7 +1391,6 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
             << BaseType << BaseExpr.get()->getSourceRange();
         return ExprError();
       }
-
     }
   }
 
@@ -1421,8 +1412,8 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
   // Handle field access to simple records.
   if (BaseType->getAsRecordDecl() || BaseType->isDependentType()) {
     TypoExpr *TE = nullptr;
-    if (LookupMemberExprInRecord(S, R, BaseExpr.get(), BaseType, OpLoc, IsArrow, SS,
-                                 HasTemplateArgs, TemplateKWLoc, TE))
+    if (LookupMemberExprInRecord(S, R, BaseExpr.get(), BaseType, OpLoc, IsArrow,
+                                 SS, HasTemplateArgs, TemplateKWLoc, TE))
       return ExprError();
 
     // Returning valid-but-null is how we indicate to the caller that
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 27c3fd51422b6c..965194e9df175b 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -5805,10 +5805,10 @@ static ImplicitConversionSequence TryObjectArgumentInitialization(
     return ICS;
   }
 
-  // FIXME: Should this check getAsRecordDecl instead?
-  #if 0
+// FIXME: Should this check getAsRecordDecl instead?
+#if 0
   assert(FromType->isRecordType());
-  #endif
+#endif
 
   QualType ClassType = S.Context.getTypeDeclType(ActingContext);
   // C++98 [class.dtor]p2:
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index e3f48a6573e3a9..11da4a3fe8057f 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -13213,14 +13213,14 @@ bool TreeTransform<Derived>::TransformOverloadExprDecls(OverloadExpr *Old,
     if (R.empty()) {
       // If a 'template' keyword was used, a lookup that finds only non-template
       // names is an error.
-      getSema().Diag(R.getNameLoc(), diag::err_template_kw_refers_to_non_template)
-          << R.getLookupName()
-          << Old->getQualifierLoc().getSourceRange()
-          << Old->hasTemplateKeyword()
-          << Old->getTemplateKeywordLoc();
-      getSema().Diag(FoundDecl->getLocation(), diag::note_template_kw_refers_to_non_template)
+      getSema().Diag(R.getNameLoc(),
+                     diag::err_template_kw_refers_to_non_template)
+          << R.getLookupName() << Old->getQualifierLoc().getSourceRange()
+          << Old->hasTemplateKeyword() << Old->getTemplateKeywordLoc();
+      getSema().Diag(FoundDecl->getLocation(),
+                     diag::note_template_kw_refers_to_non_template)
           << R.getLookupName();
-        return true;
+      return true;
     }
   }
 
diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
index 739f495510dee5..c08deb903f129b 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -1569,8 +1569,9 @@ TEST_P(ASTMatchersTest, IsArrow_MatchesMemberVariablesViaArrow) {
       matches("class Y { void x() { y; } int y; };", memberExpr(isArrow())));
   EXPECT_TRUE(notMatches("class Y { void x() { (*this).y; } int y; };",
                          memberExpr(isArrow())));
-  EXPECT_TRUE(matches("template <class T> class Y { void x() { this->m; } int m; };",
-                         memberExpr(isArrow())));
+  EXPECT_TRUE(
+      matches("template <class T> class Y { void x() { this->m; } int m; };",
+              memberExpr(isArrow())));
   EXPECT_TRUE(
       notMatches("template <class T> class Y { void x() { (*this).m; } };",
                  cxxDependentScopeMemberExpr(isArrow())));

>From 6ee8267a7b505b1e3247cdce914b98e905997b75 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Thu, 7 Mar 2024 12:43:15 -0500
Subject: [PATCH 08/25] [FOLD] more tests

---
 .../temp.res/temp.dep/temp.dep.type/p4.cpp    | 383 +++++++++++++++---
 1 file changed, 323 insertions(+), 60 deletions(-)

diff --git a/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp b/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp
index 7b36e3ad3b0131..2649addf1175ac 100644
--- a/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp
+++ b/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp
@@ -1,71 +1,334 @@
 // RUN: %clang_cc1 -Wno-unused-value -verify %s
 
 namespace N0 {
-  template<typename T>
   struct A {
-    int x;
-    void f();
-    using X = int;
-
-    void not_instantiated(A *a, A &b) {
-      x;
-      f();
-      new X;
-
-      this->x;
-      this->f();
-      this->A::x;
-      this->A::f();
-
-      a->x;
-      a->f();
-      a->A::x;
-      a->A::f();
-
-      (*this).x;
-      (*this).f();
-      (*this).A::x;
-      (*this).A::f();
-
-      b.x;
-      b.f();
-      b.A::x;
-      b.A::f();
-
-      A::x;
-      A::f();
-      new A::X;
-
-      y; // expected-error{{use of undeclared identifier 'y'}}
-      g(); // expected-error{{use of undeclared identifier 'g'}}
-      new Y; // expected-error{{unknown type name 'Y'}}
-
-      this->y; // expected-error{{no member named 'y' in 'A<T>'}}
-      this->g(); // expected-error{{no member named 'g' in 'A<T>'}}
-      this->A::y; // expected-error{{no member named 'y' in 'A<T>'}}
-      this->A::g(); // expected-error{{no member named 'g' in 'A<T>'}}
-
-      a->y; // expected-error{{no member named 'y' in 'A<T>'}}
-      a->g(); // expected-error{{no member named 'g' in 'A<T>'}}
-      a->A::y; // expected-error{{no member named 'y' in 'A<T>'}}
-      a->A::g(); // expected-error{{no member named 'g' in 'A<T>'}}
+    int x0;
+    static int x1;
+    int x2;
+    static int x3;
+
+    void f0();
+    static void f1();
+    void f2();
+    static void f3();
+
+    using M0 = int;
+    using M1 = int;
+
+    struct C0 { };
+    struct C1 { };
+  };
+
+  template<typename T>
+  struct B : A {
+    int x4;
+    static int x5;
+
+    using A::x2;
+    using A::x3;
+
+    void f4();
+    static void f5();
+
+    using A::f2;
+    using A::f3;
+
+    using M2 = int;
+
+    using A::M1;
+
+    struct C2 { };
+
+    using A::C1;
+
+    void not_instantiated(B *a, B &b) {
+      // All of the following should be found in the current instantiation.
+
+      new M0;
+      new B::M0;
+      new A::M0;
+      new B::A::M0;
+      new C0;
+      new B::C0;
+      new A::C0;
+      new B::A::C0;
+      new M1;
+      new B::M1;
+      new A::M1;
+      new B::A::M1;
+      new C1;
+      new B::C1;
+      new A::C1;
+      new B::A::C1;
+      new M2;
+      new B::M2;
+      new C2;
+      new B::C2;
+
+      x0;
+      B::x0;
+      A::x0;
+      B::A::x0;
+      x1;
+      B::x1;
+      A::x1;
+      B::A::x1;
+      x2;
+      B::x2;
+      A::x2;
+      B::A::x2;
+      x3;
+      B::x3;
+      A::x3;
+      B::A::x3;
+      x4;
+      B::x4;
+      x5;
+      B::x5;
+
+      f0();
+      B::f0();
+      A::f0();
+      B::A::f0();
+      f1();
+      B::f1();
+      A::f1();
+      B::A::f1();
+      f2();
+      B::f2();
+      A::f2();
+      B::A::f2();
+      f3();
+      B::f3();
+      A::f3();
+      B::A::f3();
+      f4();
+      B::f4();
+      f5();
+      B::f5();
+
+      this->x0;
+      this->B::x0;
+      this->A::x0;
+      this->B::A::x0;
+      this->x1;
+      this->B::x1;
+      this->A::x1;
+      this->B::A::x1;
+      this->x2;
+      this->B::x2;
+      this->A::x2;
+      this->B::A::x2;
+      this->x3;
+      this->B::x3;
+      this->A::x3;
+      this->B::A::x3;
+      this->x4;
+      this->B::x4;
+      this->x5;
+      this->B::x5;
+
+      this->f0();
+      this->B::f0();
+      this->A::f0();
+      this->B::A::f0();
+      this->f1();
+      this->B::f1();
+      this->A::f1();
+      this->B::A::f1();
+      this->f2();
+      this->B::f2();
+      this->A::f2();
+      this->B::A::f2();
+      this->f3();
+      this->B::f3();
+      this->A::f3();
+      this->B::A::f3();
+      this->f4();
+      this->B::f4();
+      this->f5();
+      this->B::f5();
+
+      a->x0;
+      a->B::x0;
+      a->A::x0;
+      a->B::A::x0;
+      a->x1;
+      a->B::x1;
+      a->A::x1;
+      a->B::A::x1;
+      a->x2;
+      a->B::x2;
+      a->A::x2;
+      a->B::A::x2;
+      a->x3;
+      a->B::x3;
+      a->A::x3;
+      a->B::A::x3;
+      a->x4;
+      a->B::x4;
+      a->x5;
+      a->B::x5;
+
+      a->f0();
+      a->B::f0();
+      a->A::f0();
+      a->B::A::f0();
+      a->f1();
+      a->B::f1();
+      a->A::f1();
+      a->B::A::f1();
+      a->f2();
+      a->B::f2();
+      a->A::f2();
+      a->B::A::f2();
+      a->f3();
+      a->B::f3();
+      a->A::f3();
+      a->B::A::f3();
+      a->f4();
+      a->B::f4();
+      a->f5();
+      a->B::f5();
+
+      (*this).x0;
+      (*this).B::x0;
+      (*this).A::x0;
+      (*this).B::A::x0;
+      (*this).x1;
+      (*this).B::x1;
+      (*this).A::x1;
+      (*this).B::A::x1;
+      (*this).x2;
+      (*this).B::x2;
+      (*this).A::x2;
+      (*this).B::A::x2;
+      (*this).x3;
+      (*this).B::x3;
+      (*this).A::x3;
+      (*this).B::A::x3;
+      (*this).x4;
+      (*this).B::x4;
+      (*this).x5;
+      (*this).B::x5;
+
+      (*this).f0();
+      (*this).B::f0();
+      (*this).A::f0();
+      (*this).B::A::f0();
+      (*this).f1();
+      (*this).B::f1();
+      (*this).A::f1();
+      (*this).B::A::f1();
+      (*this).f2();
+      (*this).B::f2();
+      (*this).A::f2();
+      (*this).B::A::f2();
+      (*this).f3();
+      (*this).B::f3();
+      (*this).A::f3();
+      (*this).B::A::f3();
+      (*this).f4();
+      (*this).B::f4();
+      (*this).f5();
+      (*this).B::f5();
+
+      b.x0;
+      b.B::x0;
+      b.A::x0;
+      b.B::A::x0;
+      b.x1;
+      b.B::x1;
+      b.A::x1;
+      b.B::A::x1;
+      b.x2;
+      b.B::x2;
+      b.A::x2;
+      b.B::A::x2;
+      b.x3;
+      b.B::x3;
+      b.A::x3;
+      b.B::A::x3;
+      b.x4;
+      b.B::x4;
+      b.x5;
+      b.B::x5;
+
+      b.f0();
+      b.B::f0();
+      b.A::f0();
+      b.B::A::f0();
+      b.f1();
+      b.B::f1();
+      b.A::f1();
+      b.B::A::f1();
+      b.f2();
+      b.B::f2();
+      b.A::f2();
+      b.B::A::f2();
+      b.f3();
+      b.B::f3();
+      b.A::f3();
+      b.B::A::f3();
+      b.f4();
+      b.B::f4();
+      b.f5();
+      b.B::f5();
+
+      // None of the following should be found in the current instantiation.
+
+      new M3; // expected-error{{unknown type name 'M3'}}
+      new B::M3; // expected-error{{no type named 'M3' in 'B<T>'}}
+      new A::M3; // expected-error{{no type named 'M3' in 'N0::A'}}
+      new B::A::M3; // expected-error{{no type named 'M3' in 'N0::A'}}
+
+      x6; // expected-error{{use of undeclared identifier 'x6'}}
+      B::x6; // expected-error{{no member named 'x6' in 'B<T>'}}
+      A::x6; // expected-error{{no member named 'x6' in 'N0::A'}}
+      B::A::x6; // expected-error{{no member named 'x6' in 'N0::A'}}
+      f6(); // expected-error{{use of undeclared identifier 'f6'}}
+      B::f6(); // expected-error{{no member named 'f6' in 'B<T>'}}
+      A::f6(); // expected-error{{no member named 'f6' in 'N0::A'}}
+      B::A::f6(); // expected-error{{no member named 'f6' in 'N0::A'}}
+
+      this->x6; // expected-error{{no member named 'x6' in 'B<T>'}}
+      this->B::x6; // expected-error{{no member named 'x6' in 'B<T>'}}
+      this->A::x6; // expected-error{{no member named 'x6' in 'N0::A'}}
+      this->B::A::x6; // expected-error{{no member named 'x6' in 'N0::A'}}
+      this->f6(); // expected-error{{no member named 'f6' in 'B<T>'}}
+      this->B::f6(); // expected-error{{no member named 'f6' in 'B<T>'}}
+      this->A::f6(); // expected-error{{no member named 'f6' in 'N0::A'}}
+      this->B::A::f6(); // expected-error{{no member named 'f6' in 'N0::A'}}
+
+      a->x6; // expected-error{{no member named 'x6' in 'B<T>'}}
+      a->B::x6; // expected-error{{no member named 'x6' in 'B<T>'}}
+      a->A::x6; // expected-error{{no member named 'x6' in 'N0::A'}}
+      a->B::A::x6; // expected-error{{no member named 'x6' in 'N0::A'}}
+      a->f6(); // expected-error{{no member named 'f6' in 'B<T>'}}
+      a->B::f6(); // expected-error{{no member named 'f6' in 'B<T>'}}
+      a->A::f6(); // expected-error{{no member named 'f6' in 'N0::A'}}
+      a->B::A::f6(); // expected-error{{no member named 'f6' in 'N0::A'}}
 
       // FIXME: An overloaded unary 'operator*' is built for these
       // even though the operand is a pointer (to a dependent type).
       // Type::isOverloadableType should return false for such cases.
-      (*this).y;
-      (*this).g();
-      (*this).A::y;
-      (*this).A::g();
-
-      b.y; // expected-error{{no member named 'y' in 'A<T>'}}
-      b.g(); // expected-error{{no member named 'g' in 'A<T>'}}
-      b.A::y; // expected-error{{no member named 'y' in 'A<T>'}}
-      b.A::g(); // expected-error{{no member named 'g' in 'A<T>'}}
-
-      A::y; // expected-error{{no member named 'y' in 'A<T>'}}
-      A::g(); // expected-error{{no member named 'g' in 'A<T>'}}
-      new A::Y; // expected-error{{no type named 'Y' in 'A<T>'}}
+      (*this).x6;
+      (*this).B::x6;
+      (*this).A::x6;
+      (*this).B::A::x6;
+      (*this).f6();
+      (*this).B::f6();
+      (*this).A::f6();
+      (*this).B::A::f6();
+
+      b.x6; // expected-error{{no member named 'x6' in 'B<T>'}}
+      b.B::x6; // expected-error{{no member named 'x6' in 'B<T>'}}
+      b.A::x6; // expected-error{{no member named 'x6' in 'N0::A'}}
+      b.B::A::x6; // expected-error{{no member named 'x6' in 'N0::A'}}
+      b.f6(); // expected-error{{no member named 'f6' in 'B<T>'}}
+      b.B::f6(); // expected-error{{no member named 'f6' in 'B<T>'}}
+      b.A::f6(); // expected-error{{no member named 'f6' in 'N0::A'}}
+      b.B::A::f6(); // expected-error{{no member named 'f6' in 'N0::A'}}
     }
   };
 } // namespace N0

>From d7e7aa3554d94436b8a888beefc6eacd10fe432d Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Thu, 7 Mar 2024 14:21:10 -0500
Subject: [PATCH 09/25] [FOLD] LookupParsedName takes ObjectType

---
 clang/include/clang/Sema/Sema.h           |  5 +-
 clang/lib/Parse/ParseDecl.cpp             |  2 +-
 clang/lib/Sema/HLSLExternalSemaSource.cpp |  4 +-
 clang/lib/Sema/SemaAttr.cpp               |  5 +-
 clang/lib/Sema/SemaDecl.cpp               |  6 +--
 clang/lib/Sema/SemaDeclCXX.cpp            |  6 +--
 clang/lib/Sema/SemaExpr.cpp               |  5 +-
 clang/lib/Sema/SemaExprCXX.cpp            |  2 +-
 clang/lib/Sema/SemaExprMember.cpp         | 24 +++++++--
 clang/lib/Sema/SemaLookup.cpp             | 62 +++++++++++++++--------
 clang/lib/Sema/SemaOpenMP.cpp             | 16 ++++--
 clang/lib/Sema/SemaTemplate.cpp           |  4 +-
 12 files changed, 95 insertions(+), 46 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 1ca523ec88c2f9..4a8c14d1dd56b6 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -7471,7 +7471,10 @@ class Sema final : public SemaBase {
                            bool InUnqualifiedLookup = false);
   bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
                            CXXScopeSpec &SS);
-  bool LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS,
+  bool LookupParsedName(LookupResult &R,
+                        Scope *S,
+                        CXXScopeSpec *SS,
+                        QualType ObjectType,
                         bool AllowBuiltinCreation = false,
                         bool EnteringContext = false);
   ObjCProtocolDecl *LookupProtocol(
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 05ad5ecbfaa0cf..96c61ae4a86f23 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2998,7 +2998,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
         << TokenName << TagName << getLangOpts().CPlusPlus
         << FixItHint::CreateInsertion(Tok.getLocation(), FixitTagName);
 
-      if (Actions.LookupParsedName(R, getCurScope(), SS)) {
+      if (Actions.LookupParsedName(R, getCurScope(), SS, /*ObjectType=*/QualType())) {
         for (LookupResult::iterator I = R.begin(), IEnd = R.end();
              I != IEnd; ++I)
           Diag((*I)->getLocation(), diag::note_decl_hiding_tag_type)
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index 1a1febf7a35241..f6a93c378acf4b 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -131,7 +131,9 @@ struct BuiltinTypeDeclBuilder {
     DeclarationNameInfo NameInfo =
         DeclarationNameInfo(DeclarationName(&II), SourceLocation());
     LookupResult R(S, NameInfo, Sema::LookupOrdinaryName);
-    S.LookupParsedName(R, S.getCurScope(), &SS, false);
+    S.LookupParsedName(R, S.getCurScope(), &SS,
+                       /*ObjectType=*/QualType(),
+                       /*AllowBuiltinCreation*/false);
     assert(R.isSingleResult() &&
            "Since this is a builtin it should always resolve!");
     auto *VD = cast<ValueDecl>(R.getFoundDecl());
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index a5dd158808f26b..adbcf8eba9d114 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -837,7 +837,10 @@ void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope,
 
   IdentifierInfo *Name = IdTok.getIdentifierInfo();
   LookupResult Lookup(*this, Name, IdTok.getLocation(), LookupOrdinaryName);
-  LookupParsedName(Lookup, curScope, nullptr, true);
+  LookupParsedName(Lookup, curScope,
+                   /*SS=*/nullptr,
+                   /*ObjectType=*/QualType(),
+                   /*AllowBuiltinCreation*/true);
 
   if (Lookup.empty()) {
     Diag(PragmaLoc, diag::warn_pragma_unused_undeclared_var)
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index e0745fe9a45367..17eec0581b183d 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -832,7 +832,7 @@ static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result,
                                     IdentifierInfo *&Name,
                                     SourceLocation NameLoc) {
   LookupResult R(SemaRef, Name, NameLoc, Sema::LookupTagName);
-  SemaRef.LookupParsedName(R, S, &SS);
+  SemaRef.LookupParsedName(R, S, &SS, /*ObjectType=*/QualType());
   if (TagDecl *Tag = R.getAsSingle<TagDecl>()) {
     StringRef FixItTagName;
     switch (Tag->getTagKind()) {
@@ -869,7 +869,7 @@ static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result,
 
     // Replace lookup results with just the tag decl.
     Result.clear(Sema::LookupTagName);
-    SemaRef.LookupParsedName(Result, S, &SS);
+    SemaRef.LookupParsedName(Result, S, &SS, /*ObjectType=*/QualType());
     return true;
   }
 
@@ -896,7 +896,7 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
   }
 
   LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName);
-  LookupParsedName(Result, S, &SS, !CurMethod);
+  LookupParsedName(Result, S, &SS, /*ObjectType=*/QualType(), /*AllowBuiltinCreation*/!CurMethod);
 
   if (SS.isInvalid())
     return NameClassification::Error();
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index abdbc9d8830c03..4d5836720a651f 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -4517,7 +4517,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
                               DS.getBeginLoc(), DS.getEllipsisLoc());
   } else {
     LookupResult R(*this, MemberOrBase, IdLoc, LookupOrdinaryName);
-    LookupParsedName(R, S, &SS);
+    LookupParsedName(R, S, &SS, /*ObjectType=*/QualType());
 
     TypeDecl *TyD = R.getAsSingle<TypeDecl>();
     if (!TyD) {
@@ -12262,7 +12262,7 @@ Decl *Sema::ActOnUsingDirective(Scope *S, SourceLocation UsingLoc,
 
   // Lookup namespace name.
   LookupResult R(*this, NamespcName, IdentLoc, LookupNamespaceName);
-  LookupParsedName(R, S, &SS);
+  LookupParsedName(R, S, &SS, /*ObjectType=*/QualType());
   if (R.isAmbiguous())
     return nullptr;
 
@@ -13721,7 +13721,7 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc,
 
   // Lookup the namespace name.
   LookupResult R(*this, Ident, IdentLoc, LookupNamespaceName);
-  LookupParsedName(R, S, &SS);
+  LookupParsedName(R, S, &SS, /*ObjectType=*/QualType());
 
   if (R.isAmbiguous())
     return nullptr;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 125dce65117f11..089b3b4924172e 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2776,7 +2776,8 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
     // results until we get here but it's likely not worth it.
     bool MemberOfUnknownSpecialization;
     AssumedTemplateKind AssumedTemplate;
-    if (LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false,
+    if (LookupTemplateName(R, S, SS, /*ObjectType=*/QualType(),
+                           /*EnteringContext=*/false,
                            MemberOfUnknownSpecialization, TemplateKWLoc,
                            &AssumedTemplate))
       return ExprError();
@@ -2787,7 +2788,7 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
                                         IsAddressOfOperand, TemplateArgs);
   } else {
     bool IvarLookupFollowUp = II && !SS.isSet() && getCurMethodDecl();
-    LookupParsedName(R, S, &SS, !IvarLookupFollowUp);
+    LookupParsedName(R, S, &SS, /*ObjectType=*/QualType(), /*AllowBuiltinCreation=*/!IvarLookupFollowUp);
 
     // If the result might be in a dependent base class, this is a dependent
     // id-expression.
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 779a41620033dc..c1cb03e4ec7ae2 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -9157,7 +9157,7 @@ Sema::CheckMicrosoftIfExistsSymbol(Scope *S,
   // Do the redeclaration lookup in the current scope.
   LookupResult R(*this, TargetNameInfo, Sema::LookupAnyName,
                  RedeclarationKind::NotForRedeclaration);
-  LookupParsedName(R, S, &SS);
+  LookupParsedName(R, S, &SS, /*ObjectType=*/QualType());
   R.suppressDiagnostics();
 
   switch (R.getResultKind()) {
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index b0b9f2e395b023..7676d9118173b6 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -718,6 +718,7 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
                                      CXXScopeSpec &SS, bool HasTemplateArgs,
                                      SourceLocation TemplateKWLoc,
                                      TypoExpr *&TE) {
+  #if 1
   DeclContext *DC = SemaRef.computeDeclContext(RTy);
   // If the object expression is dependent and isn't the current instantiation,
   // lookup will not find anything and we must defer until instantiation.
@@ -725,6 +726,7 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
     R.setNotFoundInCurrentInstantiation();
     return false;
   }
+  #endif
 
   // FIXME: Should this use Name.isDependentName()?
   if (DeclarationName Name = R.getLookupName();
@@ -741,15 +743,21 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
           OpLoc, RTy, diag::err_typecheck_incomplete_tag, BaseRange))
     return true;
 
+  // LookupTemplateName/LookupParsedName don't expect these both to exist simultaneously.
+  QualType ObjectType = SS.isSet() ? QualType() : RTy;
   if (HasTemplateArgs || TemplateKWLoc.isValid()) {
-    // LookupTemplateName doesn't expect these both to exist simultaneously.
-    QualType ObjectType = SS.isSet() ? QualType() : RTy;
-
     bool MOUS;
-    return SemaRef.LookupTemplateName(R, nullptr, SS, ObjectType, false, MOUS,
+    return SemaRef.LookupTemplateName(R,
+                                      /*S=*/nullptr,
+                                      SS,
+                                      ObjectType,
+                                      /*EnteringContext=*/false,
+                                      MOUS,
                                       TemplateKWLoc);
   }
-
+  #if 0
+  SemaRef.LookupParsedName(R, /*S=*/nullptr, &SS, ObjectType);
+  #else
   if (SS.isSet()) {
     // If the member name was a qualified-id, look into the
     // nested-name-specifier.
@@ -778,12 +786,18 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
 
   // The record definition is complete, now look up the member.
   SemaRef.LookupQualifiedName(R, DC, SS);
+  #endif
 
   if (!R.empty() || R.wasNotFoundInCurrentInstantiation())
     return false;
 
   DeclarationName Typo = R.getLookupName();
   SourceLocation TypoLoc = R.getNameLoc();
+  #if 0
+  DeclContext *DC = SS.isSet()
+      ? SemaRef.computeDeclContext(SS)
+      : SemaRef.computeDeclContext(RTy);
+  #endif
 
   struct QueryState {
     Sema &SemaRef;
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 55af414df39f51..be88debe4c0751 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -2717,39 +2717,57 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
 /// context of the scope-specifier SS (if present).
 ///
 /// @returns True if any decls were found (but possibly ambiguous)
-bool Sema::LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS,
-                            bool AllowBuiltinCreation, bool EnteringContext) {
+bool Sema::LookupParsedName(LookupResult &R,
+                            Scope *S,
+                            CXXScopeSpec *SS,
+                            QualType ObjectType,
+                            bool AllowBuiltinCreation,
+                            bool EnteringContext) {
   if (SS && SS->isInvalid()) {
     // When the scope specifier is invalid, don't even look for
     // anything.
     return false;
   }
 
-  if (SS && SS->isSet()) {
-    NestedNameSpecifier *NNS = SS->getScopeRep();
-    if (NNS->getKind() == NestedNameSpecifier::Super)
+  // Determine where to perform name lookup
+  DeclContext *DC = nullptr;
+  if (!ObjectType.isNull()) {
+    // This nested-name-specifier occurs in a member access expression, e.g.,
+    // x->B::f, and we are looking into the type of the object.
+    assert((!SS || SS->isEmpty()) && "ObjectType and scope specifier cannot coexist");
+    DC = computeDeclContext(ObjectType);
+    assert(((!DC && ObjectType->isDependentType()) ||
+            !ObjectType->isIncompleteType() ||
+            !ObjectType->getAs<TagType>() ||
+            ObjectType->castAs<TagType>()->isBeingDefined()) &&
+           "Caller should have completed object type");
+  } else if (SS && SS->isNotEmpty()) {
+    if (NestedNameSpecifier *NNS = SS->getScopeRep();
+        NNS->getKind() == NestedNameSpecifier::Super)
       return LookupInSuper(R, NNS->getAsRecordDecl());
-
-    if (DeclContext *DC = computeDeclContext(*SS, EnteringContext)) {
-      // We have resolved the scope specifier to a particular declaration
-      // contex, and will perform name lookup in that context.
+    // This nested-name-specifier occurs after another nested-name-specifier,
+    // so long into the context associated with the prior nested-name-specifier.
+    if (DC = computeDeclContext(*SS, EnteringContext)) {
+      // The declaration context must be complete.
       if (!DC->isDependentContext() && RequireCompleteDeclContext(*SS, DC))
         return false;
-
       R.setContextRange(SS->getRange());
-      return LookupQualifiedName(R, DC);
     }
-
-    // We could not resolve the scope specified to a specific declaration
-    // context, which means that SS refers to an unknown specialization.
-    // Name lookup can't find anything in this case.
-    R.setNotFoundInCurrentInstantiation();
-    R.setContextRange(SS->getRange());
-    return false;
+  } else {
+    // Perform unqualified name lookup starting in the given scope.
+    return LookupName(R, S, AllowBuiltinCreation);
   }
 
-  // Perform unqualified name lookup starting in the given scope.
-  return LookupName(R, S, AllowBuiltinCreation);
+  // If we were able to compute a declaration context, perform qualified name
+  // lookup in that context.
+  if (DC)
+    return LookupQualifiedName(R, DC);
+
+  // We could not resolve the scope specified to a specific declaration
+  // context, which means that SS refers to an unknown specialization.
+  // Name lookup can't find anything in this case.
+  R.setNotFoundInCurrentInstantiation();
+  return false;
 }
 
 /// Perform qualified name lookup into all base classes of the given
@@ -5018,7 +5036,9 @@ static void LookupPotentialTypoResult(Sema &SemaRef,
     return;
   }
 
-  SemaRef.LookupParsedName(Res, S, SS, /*AllowBuiltinCreation=*/false,
+  SemaRef.LookupParsedName(Res, S, SS,
+                           /*ObjectType=*/QualType(),
+                           /*AllowBuiltinCreation=*/false,
                            EnteringContext);
 
   // Fake ivar lookup; this should really be part of
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 5ba09926acf2b9..69b057cd832b06 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -3061,7 +3061,9 @@ ExprResult SemaOpenMP::ActOnOpenMPIdExpression(Scope *CurScope,
                                                OpenMPDirectiveKind Kind) {
   ASTContext &Context = getASTContext();
   LookupResult Lookup(SemaRef, Id, Sema::LookupOrdinaryName);
-  SemaRef.LookupParsedName(Lookup, CurScope, &ScopeSpec, true);
+  SemaRef.LookupParsedName(Lookup, CurScope, &ScopeSpec,
+                           /*ObjectType=*/QualType(),
+                           /*AllowBuiltinCreation=*/true);
 
   if (Lookup.isAmbiguous())
     return ExprError();
@@ -7407,7 +7409,9 @@ void SemaOpenMP::ActOnStartOfFunctionDefinitionInOpenMPDeclareVariantScope(
   const IdentifierInfo *BaseII = D.getIdentifier();
   LookupResult Lookup(SemaRef, DeclarationName(BaseII), D.getIdentifierLoc(),
                       Sema::LookupOrdinaryName);
-  SemaRef.LookupParsedName(Lookup, S, &D.getCXXScopeSpec());
+  SemaRef.LookupParsedName(Lookup, S,
+                           &D.getCXXScopeSpec(),
+                           /*ObjectType=*/QualType());
 
   TypeSourceInfo *TInfo = SemaRef.GetTypeForDeclarator(D);
   QualType FType = TInfo->getType();
@@ -19311,7 +19315,7 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range,
   if (S) {
     LookupResult Lookup(SemaRef, ReductionId, Sema::LookupOMPReductionName);
     Lookup.suppressDiagnostics();
-    while (S && SemaRef.LookupParsedName(Lookup, S, &ReductionIdScopeSpec)) {
+    while (S && SemaRef.LookupParsedName(Lookup, S, &ReductionIdScopeSpec, /*ObjectType=*/QualType())) {
       NamedDecl *D = Lookup.getRepresentativeDecl();
       do {
         S = S->getParent();
@@ -22181,7 +22185,7 @@ static ExprResult buildUserDefinedMapperRef(Sema &SemaRef, Scope *S,
   LookupResult Lookup(SemaRef, MapperId, Sema::LookupOMPMapperName);
   Lookup.suppressDiagnostics();
   if (S) {
-    while (S && SemaRef.LookupParsedName(Lookup, S, &MapperIdScopeSpec)) {
+    while (S && SemaRef.LookupParsedName(Lookup, S, &MapperIdScopeSpec, /*ObjectType=*/QualType())) {
       NamedDecl *D = Lookup.getRepresentativeDecl();
       while (S && !S->isDeclScope(D))
         S = S->getParent();
@@ -23498,7 +23502,9 @@ void SemaOpenMP::DiagnoseUnterminatedOpenMPDeclareTarget() {
 NamedDecl *SemaOpenMP::lookupOpenMPDeclareTargetName(
     Scope *CurScope, CXXScopeSpec &ScopeSpec, const DeclarationNameInfo &Id) {
   LookupResult Lookup(SemaRef, Id, Sema::LookupOrdinaryName);
-  SemaRef.LookupParsedName(Lookup, CurScope, &ScopeSpec, true);
+  SemaRef.LookupParsedName(Lookup, CurScope, &ScopeSpec,
+                           /*ObjectType=*/QualType(),
+                           /*AllowBuiltinCreation=*/true);
 
   if (Lookup.isAmbiguous())
     return nullptr;
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index bbcb7c33a98579..85bc1c9d6161f4 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -5816,7 +5816,7 @@ bool Sema::CheckTemplateTypeArgument(
 
     if (auto *II = NameInfo.getName().getAsIdentifierInfo()) {
       LookupResult Result(*this, NameInfo, LookupOrdinaryName);
-      LookupParsedName(Result, CurScope, &SS);
+      LookupParsedName(Result, CurScope, &SS, /*ObjectType=*/QualType());
 
       if (Result.getAsSingle<TypeDecl>() ||
           Result.getResultKind() ==
@@ -11179,7 +11179,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
                            : TSK_ExplicitInstantiationDeclaration;
 
   LookupResult Previous(*this, NameInfo, LookupOrdinaryName);
-  LookupParsedName(Previous, S, &D.getCXXScopeSpec());
+  LookupParsedName(Previous, S, &D.getCXXScopeSpec(), /*ObjectType=*/QualType());
 
   if (!R->isFunctionType()) {
     // C++ [temp.explicit]p1:

>From a1edc7af212e9e4caf00b8f20773593998a6bbb1 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Fri, 8 Mar 2024 10:09:40 -0500
Subject: [PATCH 10/25] [FOLD] use LookupParsedName for class member access

---
 clang/lib/Sema/SemaExprMember.cpp | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 7676d9118173b6..e521a71bd93bcc 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -718,7 +718,7 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
                                      CXXScopeSpec &SS, bool HasTemplateArgs,
                                      SourceLocation TemplateKWLoc,
                                      TypoExpr *&TE) {
-  #if 1
+  #if 0
   DeclContext *DC = SemaRef.computeDeclContext(RTy);
   // If the object expression is dependent and isn't the current instantiation,
   // lookup will not find anything and we must defer until instantiation.
@@ -747,15 +747,18 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
   QualType ObjectType = SS.isSet() ? QualType() : RTy;
   if (HasTemplateArgs || TemplateKWLoc.isValid()) {
     bool MOUS;
-    return SemaRef.LookupTemplateName(R,
+    bool Invalid = SemaRef.LookupTemplateName(R,
                                       /*S=*/nullptr,
                                       SS,
                                       ObjectType,
                                       /*EnteringContext=*/false,
                                       MOUS,
                                       TemplateKWLoc);
+    if (MOUS)
+      R.setNotFoundInCurrentInstantiation();
+    return Invalid;
   }
-  #if 0
+  #if 1
   SemaRef.LookupParsedName(R, /*S=*/nullptr, &SS, ObjectType);
   #else
   if (SS.isSet()) {
@@ -793,7 +796,7 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
 
   DeclarationName Typo = R.getLookupName();
   SourceLocation TypoLoc = R.getNameLoc();
-  #if 0
+  #if 1
   DeclContext *DC = SS.isSet()
       ? SemaRef.computeDeclContext(SS)
       : SemaRef.computeDeclContext(RTy);

>From 85c5f53be35f6c6c316962ee9577f6306b3830f9 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Fri, 8 Mar 2024 11:45:40 -0500
Subject: [PATCH 11/25] [FOLD] update tests

---
 clang/test/CXX/drs/dr2xx.cpp       | 10 +++++-----
 clang/test/CXX/drs/dr3xx.cpp       | 16 ++++++++--------
 clang/test/SemaCXX/member-expr.cpp |  4 ++--
 3 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/clang/test/CXX/drs/dr2xx.cpp b/clang/test/CXX/drs/dr2xx.cpp
index 5d3e8ce4bea3bc..2b3131be33057a 100644
--- a/clang/test/CXX/drs/dr2xx.cpp
+++ b/clang/test/CXX/drs/dr2xx.cpp
@@ -561,9 +561,9 @@ namespace cwg244 { // cwg244: 11
     B_ptr->B_alias::~B();
     B_ptr->B_alias::~B_alias();
     B_ptr->cwg244::~B();
-    // expected-error at -1 {{qualified member access refers to a member in namespace 'cwg244'}}
+    // expected-error at -1 {{no member named '~B' in namespace 'cwg244'}}
     B_ptr->cwg244::~B_alias();
-    // expected-error at -1 {{qualified member access refers to a member in namespace 'cwg244'}}
+    // expected-error at -1 {{no member named '~B' in namespace 'cwg244'}}
   }
 
   template<typename T, typename U>
@@ -836,7 +836,7 @@ namespace cwg258 { // cwg258: 2.8
 
 namespace cwg259 { // cwg259: 4
   template<typename T> struct A {};
-  template struct A<int>; // #cwg259-A-int 
+  template struct A<int>; // #cwg259-A-int
   template struct A<int>;
   // expected-error at -1 {{duplicate explicit instantiation of 'A<int>'}}
   //   expected-note@#cwg259-A-int {{previous explicit instantiation is here}}
@@ -997,7 +997,7 @@ namespace cwg275 { // cwg275: no
     // expected-error at -1 {{no function template matches function template specialization 'f'}}
   }
 
-  template <class T> void g(T) {} // #cwg275-g 
+  template <class T> void g(T) {} // #cwg275-g
 
   template <> void N::f(char) {}
   template <> void f(int) {}
@@ -1164,7 +1164,7 @@ namespace cwg285 { // cwg285: yes
 namespace cwg286 { // cwg286: 2.8
   template<class T> struct A {
     class C {
-      template<class T2> struct B {}; // #cwg286-B 
+      template<class T2> struct B {}; // #cwg286-B
     };
   };
 
diff --git a/clang/test/CXX/drs/dr3xx.cpp b/clang/test/CXX/drs/dr3xx.cpp
index 3e9228fe21fb64..94227dc031c6ab 100644
--- a/clang/test/CXX/drs/dr3xx.cpp
+++ b/clang/test/CXX/drs/dr3xx.cpp
@@ -34,7 +34,7 @@ namespace cwg301 { // cwg301: 3.5
     bool b = (void(*)(S, S))operator- < (void(*)(S, S))operator-;
     // cxx98-17-warning at -1 {{ordered comparison of function pointers ('void (*)(S, S)' and 'void (*)(S, S)')}}
     // cxx20-23-error at -2 {{expected '>'}}
-    //   cxx20-23-note at -3 {{to match this '<'}} 
+    //   cxx20-23-note at -3 {{to match this '<'}}
     bool c = (void(*)(S, S))operator+ < (void(*)(S, S))operator-;
     // expected-error at -1 {{expected '>'}}
     //   expected-note at -2 {{to match this '<'}}
@@ -642,7 +642,7 @@ namespace cwg339 { // cwg339: 2.8
   char xxx(int);
   char (&xxx(float))[2];
 
-  template<class T> A<sizeof(xxx((T)0))> f(T) {} // #cwg339-f 
+  template<class T> A<sizeof(xxx((T)0))> f(T) {} // #cwg339-f
 
   void test() {
     A<1> a = f(0);
@@ -828,7 +828,7 @@ namespace cwg352 { // cwg352: 2.8
     void g(A::E e) {
       foo(e, &arg);
       // expected-error at -1 {{no matching function for call to 'foo'}}
-      //   expected-note@#cwg352-foo {{candidate template ignored: couldn't infer template argument 'R'}} 
+      //   expected-note@#cwg352-foo {{candidate template ignored: couldn't infer template argument 'R'}}
 
       using A::foo;
       foo<int, int>(e, &arg); // ok, uses non-template
@@ -929,7 +929,7 @@ namespace cwg352 { // cwg352: 2.8
 
   namespace example5 {
     template<int I> class A {};
-    template<int I> void g(A<I+1>); // #cwg352-g 
+    template<int I> void g(A<I+1>); // #cwg352-g
     template<int I> void f(A<I>, A<I+1>);
     void h(A<1> a1, A<2> a2) {
       g(a1);
@@ -1256,7 +1256,7 @@ namespace cwg373 { // cwg373: 5
     }
   };
 
-  struct A { struct B {}; }; // #cwg373-A 
+  struct A { struct B {}; }; // #cwg373-A
   namespace X = A::B;
   // expected-error at -1 {{expected namespace name}}
   //   expected-note@#cwg373-A {{'A' declared here}}
@@ -1608,7 +1608,7 @@ namespace cwg395 { // cwg395: 3.0
     // expected-error at -2 {{conversion function cannot have any parameters}}
     // expected-error at -3 {{cannot specify any part of a return type in the declaration of a conversion function}}
     // expected-error at -4 {{conversion function cannot convert to a function type}}
-  
+
   };
 
   struct null1_t {
@@ -1721,9 +1721,9 @@ namespace cwg399 { // cwg399: 11
     B_ptr->B_alias::~B();
     B_ptr->B_alias::~B_alias();
     B_ptr->cwg399::~B();
-    // expected-error at -1 {{qualified member access refers to a member in namespace 'cwg399'}}
+    // expected-error at -1 {{no member named '~B' in namespace 'cwg399'}}
     B_ptr->cwg399::~B_alias();
-    // expected-error at -1 {{qualified member access refers to a member in namespace 'cwg399'}}
+    // expected-error at -1 {{no member named '~B' in namespace 'cwg399'}}
   }
 
   template<typename T, typename U>
diff --git a/clang/test/SemaCXX/member-expr.cpp b/clang/test/SemaCXX/member-expr.cpp
index 75c9ef0caa2e00..0596e40f6c2f6a 100644
--- a/clang/test/SemaCXX/member-expr.cpp
+++ b/clang/test/SemaCXX/member-expr.cpp
@@ -40,8 +40,8 @@ namespace C {
 }
 
 void test2(X *xp) {
-  xp->::i = 7; // expected-error{{qualified member access refers to a member in the global namespace}}
-  xp->C::i = 7; // expected-error{{qualified member access refers to a member in namespace 'C'}}
+  xp->::i = 7; // expected-error{{'i' is not a member of class 'X'}}
+  xp->C::i = 7; // expected-error{{'C::i' is not a member of class 'X'}}
 }
 
 

>From a13a77cb53309cd7f0eb30701efe298c7153e19b Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Fri, 8 Mar 2024 11:47:20 -0500
Subject: [PATCH 12/25] [FOLD] discard invalid nested-name-specifiers

---
 clang/include/clang/Sema/Lookup.h |  2 +-
 clang/lib/Sema/SemaExprMember.cpp | 23 ++++++++++++++++++++---
 2 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/clang/include/clang/Sema/Lookup.h b/clang/include/clang/Sema/Lookup.h
index 0db5b847038ffd..437578c5fa982d 100644
--- a/clang/include/clang/Sema/Lookup.h
+++ b/clang/include/clang/Sema/Lookup.h
@@ -499,7 +499,7 @@ class LookupResult {
   /// Note that while no result was found in the current instantiation,
   /// there were dependent base classes that could not be searched.
   void setNotFoundInCurrentInstantiation() {
-    assert(ResultKind == NotFound && Decls.empty());
+    assert((ResultKind == NotFound || ResultKind == NotFoundInCurrentInstantiation) && Decls.empty());
     ResultKind = NotFoundInCurrentInstantiation;
   }
 
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index e521a71bd93bcc..1d5d16cec1f9f6 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -858,6 +858,9 @@ ExprResult Sema::BuildMemberReferenceExpr(
     ActOnMemberAccessExtraArgs *ExtraArgs) {
   LookupResult R(*this, NameInfo, LookupMemberName);
 
+  if (SS.isInvalid())
+    SS.clear();
+
   // Implicit member accesses.
   if (!Base) {
     TypoExpr *TE = nullptr;
@@ -1057,7 +1060,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
                                const Scope *S,
                                bool SuppressQualifierCheck,
                                ActOnMemberAccessExtraArgs *ExtraArgs) {
-
+  assert(!SS.isInvalid() && "nested-name-specifier cannot be invalid");
   if (R.wasNotFoundInCurrentInstantiation() ||
       (SS.isValid() && !computeDeclContext(SS, false))) {
     return ActOnDependentMemberExpr(BaseExpr, BaseExprType, IsArrow, OpLoc, SS,
@@ -1102,7 +1105,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
   if (R.empty()) {
     // Rederive where we looked up.
     DeclContext *DC = (SS.isSet() ? computeDeclContext(SS, false)
-                                  : BaseType->getAsRecordDecl());
+                                  : computeDeclContext(BaseType));
+                                  // : BaseType->getAsRecordDecl());
 
     if (ExtraArgs) {
       ExprResult RetryExpr;
@@ -1129,7 +1133,10 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
       }
     }
 
-    if (DC) {
+    if (SS.isInvalid() || (SS.isNotEmpty() && !DC)) {
+      Diag(R.getNameLoc(), diag::err_undeclared_use)
+            << MemberName << SS.getRange();
+    } else if (DC) {
       Diag(R.getNameLoc(), diag::err_no_member)
           << MemberName << DC
           << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
@@ -1139,6 +1146,16 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
           << MemberName << BaseExprType
           << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
     }
+
+    if (DC) {
+    } else {
+      #if 0
+      // FIXME: Is this needed?
+      Diag(R.getNameLoc(), diag::err_no_member)
+          << MemberName << BaseExprType
+          << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
+      #endif
+    }
     return ExprError();
   }
 

>From a76387d8da3dbd669dd32da16b8aa74a5ef3b618 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Fri, 8 Mar 2024 13:58:04 -0500
Subject: [PATCH 13/25] [FOLD]

---
 clang/include/clang/Sema/Sema.h |  6 ++++++
 clang/lib/Sema/SemaLookup.cpp   | 19 ++++++++++---------
 clang/lib/Sema/SemaTemplate.cpp | 26 +++++++++++++++++---------
 3 files changed, 33 insertions(+), 18 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 4a8c14d1dd56b6..bd677a29aa7931 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -8889,6 +8889,12 @@ class Sema final : public SemaBase {
       bool EnteringContext, bool &MemberOfUnknownSpecialization,
       RequiredTemplateKind RequiredTemplate = SourceLocation(),
       AssumedTemplateKind *ATK = nullptr, bool AllowTypoCorrection = true);
+  
+  bool LookupTemplateName(
+      LookupResult &R, Scope *S, CXXScopeSpec &SS, QualType ObjectType,
+      bool EnteringContext,
+      RequiredTemplateKind RequiredTemplate = SourceLocation(),
+      AssumedTemplateKind *ATK = nullptr, bool AllowTypoCorrection = true);
 
   TemplateNameKind isTemplateName(Scope *S, CXXScopeSpec &SS,
                                   bool hasTemplateKeyword,
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index be88debe4c0751..9fef1fa75151a0 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -2723,19 +2723,19 @@ bool Sema::LookupParsedName(LookupResult &R,
                             QualType ObjectType,
                             bool AllowBuiltinCreation,
                             bool EnteringContext) {
-  if (SS && SS->isInvalid()) {
-    // When the scope specifier is invalid, don't even look for
-    // anything.
+  // When the scope specifier is invalid, don't even look for anything.
+  if (SS && SS->isInvalid())
     return false;
-  }
 
   // Determine where to perform name lookup
   DeclContext *DC = nullptr;
+  bool IsDependent = false;
   if (!ObjectType.isNull()) {
     // This nested-name-specifier occurs in a member access expression, e.g.,
     // x->B::f, and we are looking into the type of the object.
     assert((!SS || SS->isEmpty()) && "ObjectType and scope specifier cannot coexist");
     DC = computeDeclContext(ObjectType);
+    IsDependent = !DC && ObjectType->isDependentType();
     assert(((!DC && ObjectType->isDependentType()) ||
             !ObjectType->isIncompleteType() ||
             !ObjectType->getAs<TagType>() ||
@@ -2753,6 +2753,7 @@ bool Sema::LookupParsedName(LookupResult &R,
         return false;
       R.setContextRange(SS->getRange());
     }
+    IsDependent = !DC && isDependentScopeSpecifier(*SS);
   } else {
     // Perform unqualified name lookup starting in the given scope.
     return LookupName(R, S, AllowBuiltinCreation);
@@ -2762,11 +2763,11 @@ bool Sema::LookupParsedName(LookupResult &R,
   // lookup in that context.
   if (DC)
     return LookupQualifiedName(R, DC);
-
-  // We could not resolve the scope specified to a specific declaration
-  // context, which means that SS refers to an unknown specialization.
-  // Name lookup can't find anything in this case.
-  R.setNotFoundInCurrentInstantiation();
+  else if (IsDependent)
+    // We could not resolve the scope specified to a specific declaration
+    // context, which means that SS refers to an unknown specialization.
+    // Name lookup can't find anything in this case.
+    R.setNotFoundInCurrentInstantiation();
   return false;
 }
 
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 85bc1c9d6161f4..3f4fd0bf7df307 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -320,15 +320,12 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
 bool Sema::isDeductionGuideName(Scope *S, const IdentifierInfo &Name,
                                 SourceLocation NameLoc, CXXScopeSpec &SS,
                                 ParsedTemplateTy *Template /*=nullptr*/) {
-  bool MemberOfUnknownSpecialization = false;
-
   // We could use redeclaration lookup here, but we don't need to: the
   // syntactic form of a deduction guide is enough to identify it even
   // if we can't look up the template name at all.
   LookupResult R(*this, DeclarationName(&Name), NameLoc, LookupOrdinaryName);
   if (LookupTemplateName(R, S, SS, /*ObjectType*/ QualType(),
-                         /*EnteringContext*/ false,
-                         MemberOfUnknownSpecialization))
+                         /*EnteringContext*/ false))
     return false;
 
   if (R.empty()) return false;
@@ -374,6 +371,19 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II,
   return true;
 }
 
+bool Sema::LookupTemplateName(LookupResult &Found,
+                              Scope *S, CXXScopeSpec &SS,
+                              QualType ObjectType,
+                              bool EnteringContext,
+                              RequiredTemplateKind RequiredTemplate,
+                              AssumedTemplateKind *ATK,
+                              bool AllowTypoCorrection) {
+  bool MemberOfUnknownSpecialization;
+  return LookupTemplateName(Found, S, SS, ObjectType, EnteringContext,
+                            MemberOfUnknownSpecialization, RequiredTemplate,
+                            ATK, AllowTypoCorrection);
+}
+
 bool Sema::LookupTemplateName(LookupResult &Found,
                               Scope *S, CXXScopeSpec &SS,
                               QualType ObjectType,
@@ -5595,10 +5605,9 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS,
       RequireCompleteDeclContext(SS, DC))
     return BuildDependentDeclRefExpr(SS, TemplateKWLoc, NameInfo, TemplateArgs);
 
-  bool MemberOfUnknownSpecialization;
   LookupResult R(*this, NameInfo, LookupOrdinaryName);
   if (LookupTemplateName(R, (Scope *)nullptr, SS, QualType(),
-                         /*Entering*/false, MemberOfUnknownSpecialization,
+                         /*Entering*/false,
                          TemplateKWLoc))
     return ExprError();
 
@@ -5720,14 +5729,13 @@ TemplateNameKind Sema::ActOnTemplateName(Scope *S,
     DeclarationNameInfo DNI = GetNameFromUnqualifiedId(Name);
     LookupResult R(*this, DNI.getName(), Name.getBeginLoc(),
                    LookupOrdinaryName);
-    bool MOUS;
     // Tell LookupTemplateName that we require a template so that it diagnoses
     // cases where it finds a non-template.
     RequiredTemplateKind RTK = TemplateKWLoc.isValid()
                                    ? RequiredTemplateKind(TemplateKWLoc)
                                    : TemplateNameIsRequired;
-    if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext, MOUS,
-                            RTK, nullptr, /*AllowTypoCorrection=*/false) &&
+    if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext,
+                            RTK, /*ATK=*/nullptr, /*AllowTypoCorrection=*/false) &&
         !R.isAmbiguous()) {
       if (LookupCtx)
         Diag(Name.getBeginLoc(), diag::err_no_member)

>From ff078e4f4a29a6bb92e48f423b852ab105836716 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Mon, 11 Mar 2024 07:20:00 -0400
Subject: [PATCH 14/25] [FOLD]

---
 clang/lib/Sema/SemaExpr.cpp       | 3 +--
 clang/lib/Sema/SemaExprMember.cpp | 5 +----
 clang/lib/Sema/SemaTemplate.cpp   | 2 ++
 3 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 089b3b4924172e..015c03699b93eb 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2782,8 +2782,7 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
                            &AssumedTemplate))
       return ExprError();
 
-    if (MemberOfUnknownSpecialization ||
-        (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation))
+    if (R.wasNotFoundInCurrentInstantiation())
       return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo,
                                         IsAddressOfOperand, TemplateArgs);
   } else {
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 1d5d16cec1f9f6..f96af4d94b2e71 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -747,16 +747,13 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
   QualType ObjectType = SS.isSet() ? QualType() : RTy;
   if (HasTemplateArgs || TemplateKWLoc.isValid()) {
     bool MOUS;
-    bool Invalid = SemaRef.LookupTemplateName(R,
+    return SemaRef.LookupTemplateName(R,
                                       /*S=*/nullptr,
                                       SS,
                                       ObjectType,
                                       /*EnteringContext=*/false,
                                       MOUS,
                                       TemplateKWLoc);
-    if (MOUS)
-      R.setNotFoundInCurrentInstantiation();
-    return Invalid;
   }
   #if 1
   SemaRef.LookupParsedName(R, /*S=*/nullptr, &SS, ObjectType);
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 3f4fd0bf7df307..d7407a7dddb0d4 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) {
     TemplateResult = TemplateTy::make(Context.getAssumedTemplateName(TName));
@@ -559,6 +560,7 @@ bool Sema::LookupTemplateName(LookupResult &Found,
   if (Found.empty()) {
     if (IsDependent) {
       MemberOfUnknownSpecialization = true;
+      Found.setNotFoundInCurrentInstantiation();
       return false;
     }
 

>From 1e218873c6d67f065144fb81569c90d3f1c59978 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Tue, 19 Mar 2024 08:03:18 -0400
Subject: [PATCH 15/25] [FOLD] cleanup

---
 clang/lib/Sema/SemaExprMember.cpp | 63 ++++---------------------------
 1 file changed, 7 insertions(+), 56 deletions(-)

diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index f96af4d94b2e71..8fdc62bff53034 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -718,16 +718,6 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
                                      CXXScopeSpec &SS, bool HasTemplateArgs,
                                      SourceLocation TemplateKWLoc,
                                      TypoExpr *&TE) {
-  #if 0
-  DeclContext *DC = SemaRef.computeDeclContext(RTy);
-  // If the object expression is dependent and isn't the current instantiation,
-  // lookup will not find anything and we must defer until instantiation.
-  if (!DC) {
-    R.setNotFoundInCurrentInstantiation();
-    return false;
-  }
-  #endif
-
   // FIXME: Should this use Name.isDependentName()?
   if (DeclarationName Name = R.getLookupName();
       Name.getNameKind() == DeclarationName::CXXConversionFunctionName &&
@@ -755,49 +745,18 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
                                       MOUS,
                                       TemplateKWLoc);
   }
-  #if 1
-  SemaRef.LookupParsedName(R, /*S=*/nullptr, &SS, ObjectType);
-  #else
-  if (SS.isSet()) {
-    // If the member name was a qualified-id, look into the
-    // nested-name-specifier.
-    DC = SemaRef.computeDeclContext(SS, false);
-    // We tried to look into a dependent context that is not the current
-    // instantiation. Defer lookup until instantiation.
-    if (!DC) {
-      R.setNotFoundInCurrentInstantiation();
-      return false;
-    }
-
-    if (SemaRef.RequireCompleteDeclContext(SS, DC)) {
-      SemaRef.Diag(SS.getRange().getEnd(), diag::err_typecheck_incomplete_tag)
-          << SS.getRange() << DC;
-      return true;
-    }
-
-    assert(DC && "Cannot handle non-computable dependent contexts in lookup");
-
-    if (!isa<TypeDecl>(DC)) {
-      SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_nonclass)
-          << DC << SS.getRange();
-      return true;
-    }
-  }
 
-  // The record definition is complete, now look up the member.
-  SemaRef.LookupQualifiedName(R, DC, SS);
-  #endif
+  SemaRef.LookupParsedName(R, /*S=*/nullptr, &SS, ObjectType);
 
   if (!R.empty() || R.wasNotFoundInCurrentInstantiation())
     return false;
 
   DeclarationName Typo = R.getLookupName();
   SourceLocation TypoLoc = R.getNameLoc();
-  #if 1
+  // Recompute the lookup context.
   DeclContext *DC = SS.isSet()
       ? SemaRef.computeDeclContext(SS)
       : SemaRef.computeDeclContext(RTy);
-  #endif
 
   struct QueryState {
     Sema &SemaRef;
@@ -1059,7 +1018,11 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
                                ActOnMemberAccessExtraArgs *ExtraArgs) {
   assert(!SS.isInvalid() && "nested-name-specifier cannot be invalid");
   if (R.wasNotFoundInCurrentInstantiation() ||
+  #if 0
       (SS.isValid() && !computeDeclContext(SS, false))) {
+  #else
+      false) {
+  #endif
     return ActOnDependentMemberExpr(BaseExpr, BaseExprType, IsArrow, OpLoc, SS,
                                     TemplateKWLoc, FirstQualifierInScope,
                                     R.getLookupNameInfo(), TemplateArgs);
@@ -1103,8 +1066,6 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
     // Rederive where we looked up.
     DeclContext *DC = (SS.isSet() ? computeDeclContext(SS, false)
                                   : computeDeclContext(BaseType));
-                                  // : BaseType->getAsRecordDecl());
-
     if (ExtraArgs) {
       ExprResult RetryExpr;
       if (!IsArrow && BaseExpr && !BaseExpr->isTypeDependent()) {
@@ -1130,7 +1091,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
       }
     }
 
-    if (SS.isInvalid() || (SS.isNotEmpty() && !DC)) {
+    if (SS.isNotEmpty() && !DC) {
       Diag(R.getNameLoc(), diag::err_undeclared_use)
             << MemberName << SS.getRange();
     } else if (DC) {
@@ -1143,16 +1104,6 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
           << MemberName << BaseExprType
           << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
     }
-
-    if (DC) {
-    } else {
-      #if 0
-      // FIXME: Is this needed?
-      Diag(R.getNameLoc(), diag::err_no_member)
-          << MemberName << BaseExprType
-          << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
-      #endif
-    }
     return ExprError();
   }
 

>From 1161d24ae5add5cdfbfc8c605d08b458d64bc1dc Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Tue, 19 Mar 2024 08:03:43 -0400
Subject: [PATCH 16/25] [FOLD] format

---
 clang/include/clang/Sema/Lookup.h         |  4 +++-
 clang/include/clang/Sema/Sema.h           | 20 +++++++++-----------
 clang/lib/Parse/ParseDecl.cpp             |  3 ++-
 clang/lib/Sema/HLSLExternalSemaSource.cpp |  2 +-
 clang/lib/Sema/SemaAttr.cpp               |  2 +-
 clang/lib/Sema/SemaDecl.cpp               |  3 ++-
 clang/lib/Sema/SemaExpr.cpp               |  3 ++-
 clang/lib/Sema/SemaExprMember.cpp         | 23 ++++++++++-------------
 clang/lib/Sema/SemaLookup.cpp             | 16 ++++++----------
 clang/lib/Sema/SemaOpenMP.cpp             |  6 ++++--
 clang/lib/Sema/SemaTemplate.cpp           | 16 +++++++---------
 11 files changed, 47 insertions(+), 51 deletions(-)

diff --git a/clang/include/clang/Sema/Lookup.h b/clang/include/clang/Sema/Lookup.h
index 437578c5fa982d..b0a08a05ac6a0a 100644
--- a/clang/include/clang/Sema/Lookup.h
+++ b/clang/include/clang/Sema/Lookup.h
@@ -499,7 +499,9 @@ class LookupResult {
   /// Note that while no result was found in the current instantiation,
   /// there were dependent base classes that could not be searched.
   void setNotFoundInCurrentInstantiation() {
-    assert((ResultKind == NotFound || ResultKind == NotFoundInCurrentInstantiation) && Decls.empty());
+    assert((ResultKind == NotFound ||
+            ResultKind == NotFoundInCurrentInstantiation) &&
+           Decls.empty());
     ResultKind = NotFoundInCurrentInstantiation;
   }
 
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index bd677a29aa7931..6b04b86d45f7f8 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -7471,11 +7471,8 @@ class Sema final : public SemaBase {
                            bool InUnqualifiedLookup = false);
   bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
                            CXXScopeSpec &SS);
-  bool LookupParsedName(LookupResult &R,
-                        Scope *S,
-                        CXXScopeSpec *SS,
-                        QualType ObjectType,
-                        bool AllowBuiltinCreation = false,
+  bool LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS,
+                        QualType ObjectType, bool AllowBuiltinCreation = false,
                         bool EnteringContext = false);
   ObjCProtocolDecl *LookupProtocol(
       IdentifierInfo *II, SourceLocation IdLoc,
@@ -8889,12 +8886,13 @@ class Sema final : public SemaBase {
       bool EnteringContext, bool &MemberOfUnknownSpecialization,
       RequiredTemplateKind RequiredTemplate = SourceLocation(),
       AssumedTemplateKind *ATK = nullptr, bool AllowTypoCorrection = true);
-  
-  bool LookupTemplateName(
-      LookupResult &R, Scope *S, CXXScopeSpec &SS, QualType ObjectType,
-      bool EnteringContext,
-      RequiredTemplateKind RequiredTemplate = SourceLocation(),
-      AssumedTemplateKind *ATK = nullptr, bool AllowTypoCorrection = true);
+
+  bool
+  LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS,
+                     QualType ObjectType, bool EnteringContext,
+                     RequiredTemplateKind RequiredTemplate = SourceLocation(),
+                     AssumedTemplateKind *ATK = nullptr,
+                     bool AllowTypoCorrection = true);
 
   TemplateNameKind isTemplateName(Scope *S, CXXScopeSpec &SS,
                                   bool hasTemplateKeyword,
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 96c61ae4a86f23..efba0e33506d15 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2998,7 +2998,8 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
         << TokenName << TagName << getLangOpts().CPlusPlus
         << FixItHint::CreateInsertion(Tok.getLocation(), FixitTagName);
 
-      if (Actions.LookupParsedName(R, getCurScope(), SS, /*ObjectType=*/QualType())) {
+      if (Actions.LookupParsedName(R, getCurScope(), SS,
+                                   /*ObjectType=*/QualType())) {
         for (LookupResult::iterator I = R.begin(), IEnd = R.end();
              I != IEnd; ++I)
           Diag((*I)->getLocation(), diag::note_decl_hiding_tag_type)
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index f6a93c378acf4b..f3556792127305 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -133,7 +133,7 @@ struct BuiltinTypeDeclBuilder {
     LookupResult R(S, NameInfo, Sema::LookupOrdinaryName);
     S.LookupParsedName(R, S.getCurScope(), &SS,
                        /*ObjectType=*/QualType(),
-                       /*AllowBuiltinCreation*/false);
+                       /*AllowBuiltinCreation*/ false);
     assert(R.isSingleResult() &&
            "Since this is a builtin it should always resolve!");
     auto *VD = cast<ValueDecl>(R.getFoundDecl());
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index adbcf8eba9d114..8b788376cdcca7 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -840,7 +840,7 @@ void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope,
   LookupParsedName(Lookup, curScope,
                    /*SS=*/nullptr,
                    /*ObjectType=*/QualType(),
-                   /*AllowBuiltinCreation*/true);
+                   /*AllowBuiltinCreation*/ true);
 
   if (Lookup.empty()) {
     Diag(PragmaLoc, diag::warn_pragma_unused_undeclared_var)
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 17eec0581b183d..b31e7b3aaaf576 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -896,7 +896,8 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
   }
 
   LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName);
-  LookupParsedName(Result, S, &SS, /*ObjectType=*/QualType(), /*AllowBuiltinCreation*/!CurMethod);
+  LookupParsedName(Result, S, &SS, /*ObjectType=*/QualType(),
+                   /*AllowBuiltinCreation*/ !CurMethod);
 
   if (SS.isInvalid())
     return NameClassification::Error();
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 015c03699b93eb..eface618e08cd4 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2787,7 +2787,8 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
                                         IsAddressOfOperand, TemplateArgs);
   } else {
     bool IvarLookupFollowUp = II && !SS.isSet() && getCurMethodDecl();
-    LookupParsedName(R, S, &SS, /*ObjectType=*/QualType(), /*AllowBuiltinCreation=*/!IvarLookupFollowUp);
+    LookupParsedName(R, S, &SS, /*ObjectType=*/QualType(),
+                     /*AllowBuiltinCreation=*/!IvarLookupFollowUp);
 
     // If the result might be in a dependent base class, this is a dependent
     // id-expression.
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 8fdc62bff53034..77d388832a5e3c 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -733,16 +733,14 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
           OpLoc, RTy, diag::err_typecheck_incomplete_tag, BaseRange))
     return true;
 
-  // LookupTemplateName/LookupParsedName don't expect these both to exist simultaneously.
+  // LookupTemplateName/LookupParsedName don't expect these both to exist
+  // simultaneously.
   QualType ObjectType = SS.isSet() ? QualType() : RTy;
   if (HasTemplateArgs || TemplateKWLoc.isValid()) {
     bool MOUS;
     return SemaRef.LookupTemplateName(R,
-                                      /*S=*/nullptr,
-                                      SS,
-                                      ObjectType,
-                                      /*EnteringContext=*/false,
-                                      MOUS,
+                                      /*S=*/nullptr, SS, ObjectType,
+                                      /*EnteringContext=*/false, MOUS,
                                       TemplateKWLoc);
   }
 
@@ -754,9 +752,8 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
   DeclarationName Typo = R.getLookupName();
   SourceLocation TypoLoc = R.getNameLoc();
   // Recompute the lookup context.
-  DeclContext *DC = SS.isSet()
-      ? SemaRef.computeDeclContext(SS)
-      : SemaRef.computeDeclContext(RTy);
+  DeclContext *DC = SS.isSet() ? SemaRef.computeDeclContext(SS)
+                               : SemaRef.computeDeclContext(RTy);
 
   struct QueryState {
     Sema &SemaRef;
@@ -1018,11 +1015,11 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
                                ActOnMemberAccessExtraArgs *ExtraArgs) {
   assert(!SS.isInvalid() && "nested-name-specifier cannot be invalid");
   if (R.wasNotFoundInCurrentInstantiation() ||
-  #if 0
+#if 0
       (SS.isValid() && !computeDeclContext(SS, false))) {
-  #else
+#else
       false) {
-  #endif
+#endif
     return ActOnDependentMemberExpr(BaseExpr, BaseExprType, IsArrow, OpLoc, SS,
                                     TemplateKWLoc, FirstQualifierInScope,
                                     R.getLookupNameInfo(), TemplateArgs);
@@ -1093,7 +1090,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
 
     if (SS.isNotEmpty() && !DC) {
       Diag(R.getNameLoc(), diag::err_undeclared_use)
-            << MemberName << SS.getRange();
+          << MemberName << SS.getRange();
     } else if (DC) {
       Diag(R.getNameLoc(), diag::err_no_member)
           << MemberName << DC
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 9fef1fa75151a0..4ba56ea7478345 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -2717,11 +2717,8 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
 /// context of the scope-specifier SS (if present).
 ///
 /// @returns True if any decls were found (but possibly ambiguous)
-bool Sema::LookupParsedName(LookupResult &R,
-                            Scope *S,
-                            CXXScopeSpec *SS,
-                            QualType ObjectType,
-                            bool AllowBuiltinCreation,
+bool Sema::LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS,
+                            QualType ObjectType, bool AllowBuiltinCreation,
                             bool EnteringContext) {
   // When the scope specifier is invalid, don't even look for anything.
   if (SS && SS->isInvalid())
@@ -2733,12 +2730,12 @@ bool Sema::LookupParsedName(LookupResult &R,
   if (!ObjectType.isNull()) {
     // This nested-name-specifier occurs in a member access expression, e.g.,
     // x->B::f, and we are looking into the type of the object.
-    assert((!SS || SS->isEmpty()) && "ObjectType and scope specifier cannot coexist");
+    assert((!SS || SS->isEmpty()) &&
+           "ObjectType and scope specifier cannot coexist");
     DC = computeDeclContext(ObjectType);
     IsDependent = !DC && ObjectType->isDependentType();
     assert(((!DC && ObjectType->isDependentType()) ||
-            !ObjectType->isIncompleteType() ||
-            !ObjectType->getAs<TagType>() ||
+            !ObjectType->isIncompleteType() || !ObjectType->getAs<TagType>() ||
             ObjectType->castAs<TagType>()->isBeingDefined()) &&
            "Caller should have completed object type");
   } else if (SS && SS->isNotEmpty()) {
@@ -5039,8 +5036,7 @@ static void LookupPotentialTypoResult(Sema &SemaRef,
 
   SemaRef.LookupParsedName(Res, S, SS,
                            /*ObjectType=*/QualType(),
-                           /*AllowBuiltinCreation=*/false,
-                           EnteringContext);
+                           /*AllowBuiltinCreation=*/false, EnteringContext);
 
   // Fake ivar lookup; this should really be part of
   // LookupParsedName.
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 69b057cd832b06..96b124ebae26b3 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -19315,7 +19315,8 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range,
   if (S) {
     LookupResult Lookup(SemaRef, ReductionId, Sema::LookupOMPReductionName);
     Lookup.suppressDiagnostics();
-    while (S && SemaRef.LookupParsedName(Lookup, S, &ReductionIdScopeSpec, /*ObjectType=*/QualType())) {
+    while (S && SemaRef.LookupParsedName(Lookup, S, &ReductionIdScopeSpec,
+                                         /*ObjectType=*/QualType())) {
       NamedDecl *D = Lookup.getRepresentativeDecl();
       do {
         S = S->getParent();
@@ -22185,7 +22186,8 @@ static ExprResult buildUserDefinedMapperRef(Sema &SemaRef, Scope *S,
   LookupResult Lookup(SemaRef, MapperId, Sema::LookupOMPMapperName);
   Lookup.suppressDiagnostics();
   if (S) {
-    while (S && SemaRef.LookupParsedName(Lookup, S, &MapperIdScopeSpec, /*ObjectType=*/QualType())) {
+    while (S && SemaRef.LookupParsedName(Lookup, S, &MapperIdScopeSpec,
+                                         /*ObjectType=*/QualType())) {
       NamedDecl *D = Lookup.getRepresentativeDecl();
       while (S && !S->isDeclScope(D))
         S = S->getParent();
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index d7407a7dddb0d4..33e57ec2d965ef 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -372,10 +372,8 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II,
   return true;
 }
 
-bool Sema::LookupTemplateName(LookupResult &Found,
-                              Scope *S, CXXScopeSpec &SS,
-                              QualType ObjectType,
-                              bool EnteringContext,
+bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS,
+                              QualType ObjectType, bool EnteringContext,
                               RequiredTemplateKind RequiredTemplate,
                               AssumedTemplateKind *ATK,
                               bool AllowTypoCorrection) {
@@ -5609,8 +5607,7 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS,
 
   LookupResult R(*this, NameInfo, LookupOrdinaryName);
   if (LookupTemplateName(R, (Scope *)nullptr, SS, QualType(),
-                         /*Entering*/false,
-                         TemplateKWLoc))
+                         /*Entering*/ false, TemplateKWLoc))
     return ExprError();
 
   if (R.isAmbiguous())
@@ -5736,8 +5733,8 @@ TemplateNameKind Sema::ActOnTemplateName(Scope *S,
     RequiredTemplateKind RTK = TemplateKWLoc.isValid()
                                    ? RequiredTemplateKind(TemplateKWLoc)
                                    : TemplateNameIsRequired;
-    if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext,
-                            RTK, /*ATK=*/nullptr, /*AllowTypoCorrection=*/false) &&
+    if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext, RTK,
+                            /*ATK=*/nullptr, /*AllowTypoCorrection=*/false) &&
         !R.isAmbiguous()) {
       if (LookupCtx)
         Diag(Name.getBeginLoc(), diag::err_no_member)
@@ -11189,7 +11186,8 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
                            : TSK_ExplicitInstantiationDeclaration;
 
   LookupResult Previous(*this, NameInfo, LookupOrdinaryName);
-  LookupParsedName(Previous, S, &D.getCXXScopeSpec(), /*ObjectType=*/QualType());
+  LookupParsedName(Previous, S, &D.getCXXScopeSpec(),
+                   /*ObjectType=*/QualType());
 
   if (!R->isFunctionType()) {
     // C++ [temp.explicit]p1:

>From 1e2a144f2433a12abbe9432b444e5f3fd3eeac47 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Thu, 4 Apr 2024 15:34:40 -0400
Subject: [PATCH 17/25] [FOLD] cleanups

---
 clang/lib/Parse/ParseDecl.cpp             |  3 +--
 clang/lib/Sema/HLSLExternalSemaSource.cpp |  9 +++++----
 clang/lib/Sema/SemaAttr.cpp               |  5 +----
 clang/lib/Sema/SemaDecl.cpp               |  2 +-
 clang/lib/Sema/SemaExpr.cpp               |  8 +++-----
 clang/lib/Sema/SemaExprMember.cpp         | 24 ++++++++---------------
 clang/lib/Sema/SemaOverload.cpp           |  3 ---
 7 files changed, 19 insertions(+), 35 deletions(-)

diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index efba0e33506d15..53a33fa4add54e 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2998,8 +2998,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
         << TokenName << TagName << getLangOpts().CPlusPlus
         << FixItHint::CreateInsertion(Tok.getLocation(), FixitTagName);
 
-      if (Actions.LookupParsedName(R, getCurScope(), SS,
-                                   /*ObjectType=*/QualType())) {
+      if (Actions.LookupName(R, getCurScope())) {
         for (LookupResult::iterator I = R.begin(), IEnd = R.end();
              I != IEnd; ++I)
           Diag((*I)->getLocation(), diag::note_decl_hiding_tag_type)
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index f3556792127305..bb283c54b3d29c 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -126,14 +126,15 @@ struct BuiltinTypeDeclBuilder {
 
   static DeclRefExpr *lookupBuiltinFunction(ASTContext &AST, Sema &S,
                                             StringRef Name) {
-    CXXScopeSpec SS;
     IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
     DeclarationNameInfo NameInfo =
         DeclarationNameInfo(DeclarationName(&II), SourceLocation());
     LookupResult R(S, NameInfo, Sema::LookupOrdinaryName);
-    S.LookupParsedName(R, S.getCurScope(), &SS,
-                       /*ObjectType=*/QualType(),
-                       /*AllowBuiltinCreation*/ false);
+    // AllowBuiltinCreation is false but LookupDirect will create
+    // the builtin when searching the global scope anyways...
+    S.LookupName(R, S.getCurScope());
+    // FIXME: If the builtin function was user-declared in global scope,
+    // this assert *will* fail. Should this call LookupBuiltin instead?
     assert(R.isSingleResult() &&
            "Since this is a builtin it should always resolve!");
     auto *VD = cast<ValueDecl>(R.getFoundDecl());
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index 8b788376cdcca7..a83b1e8afadbc6 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -837,10 +837,7 @@ void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope,
 
   IdentifierInfo *Name = IdTok.getIdentifierInfo();
   LookupResult Lookup(*this, Name, IdTok.getLocation(), LookupOrdinaryName);
-  LookupParsedName(Lookup, curScope,
-                   /*SS=*/nullptr,
-                   /*ObjectType=*/QualType(),
-                   /*AllowBuiltinCreation*/ true);
+  LookupName(Lookup, curScope, /*AllowBuiltinCreation=*/true);
 
   if (Lookup.empty()) {
     Diag(PragmaLoc, diag::warn_pragma_unused_undeclared_var)
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index b31e7b3aaaf576..4e275dc15fbb4e 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -897,7 +897,7 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
 
   LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName);
   LookupParsedName(Result, S, &SS, /*ObjectType=*/QualType(),
-                   /*AllowBuiltinCreation*/ !CurMethod);
+                   /*AllowBuiltinCreation=*/!CurMethod);
 
   if (SS.isInvalid())
     return NameClassification::Error();
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index eface618e08cd4..c053cd6a647499 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2752,8 +2752,8 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
   if (isBoundsAttrContext() && !getLangOpts().CPlusPlus && S->isClassScope()) {
     // See if this is reference to a field of struct.
     LookupResult R(*this, NameInfo, LookupMemberName);
-    // LookupParsedName handles a name lookup from within anonymous struct.
-    if (LookupParsedName(R, S, &SS)) {
+    // LookupName handles a name lookup from within anonymous struct.
+    if (LookupName(R, S)) {
       if (auto *VD = dyn_cast<ValueDecl>(R.getFoundDecl())) {
         QualType type = VD->getType().getNonReferenceType();
         // This will eventually be translated into MemberExpr upon
@@ -2774,11 +2774,9 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
     // lookup to determine that it was a template name in the first place. If
     // this becomes a performance hit, we can work harder to preserve those
     // results until we get here but it's likely not worth it.
-    bool MemberOfUnknownSpecialization;
     AssumedTemplateKind AssumedTemplate;
     if (LookupTemplateName(R, S, SS, /*ObjectType=*/QualType(),
-                           /*EnteringContext=*/false,
-                           MemberOfUnknownSpecialization, TemplateKWLoc,
+                           /*EnteringContext=*/false, TemplateKWLoc,
                            &AssumedTemplate))
       return ExprError();
 
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 77d388832a5e3c..ed9d45db43c068 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -736,13 +736,10 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
   // LookupTemplateName/LookupParsedName don't expect these both to exist
   // simultaneously.
   QualType ObjectType = SS.isSet() ? QualType() : RTy;
-  if (HasTemplateArgs || TemplateKWLoc.isValid()) {
-    bool MOUS;
+  if (HasTemplateArgs || TemplateKWLoc.isValid())
     return SemaRef.LookupTemplateName(R,
                                       /*S=*/nullptr, SS, ObjectType,
-                                      /*EnteringContext=*/false, MOUS,
-                                      TemplateKWLoc);
-  }
+                                      /*EnteringContext=*/false, TemplateKWLoc);
 
   SemaRef.LookupParsedName(R, /*S=*/nullptr, &SS, ObjectType);
 
@@ -1014,16 +1011,10 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
                                bool SuppressQualifierCheck,
                                ActOnMemberAccessExtraArgs *ExtraArgs) {
   assert(!SS.isInvalid() && "nested-name-specifier cannot be invalid");
-  if (R.wasNotFoundInCurrentInstantiation() ||
-#if 0
-      (SS.isValid() && !computeDeclContext(SS, false))) {
-#else
-      false) {
-#endif
+  if (R.wasNotFoundInCurrentInstantiation())
     return ActOnDependentMemberExpr(BaseExpr, BaseExprType, IsArrow, OpLoc, SS,
                                     TemplateKWLoc, FirstQualifierInScope,
                                     R.getLookupNameInfo(), TemplateArgs);
-  }
 
   QualType BaseType = BaseExprType;
   if (IsArrow) {
@@ -1032,6 +1023,11 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
   }
   R.setBaseObjectType(BaseType);
 
+  assert((SS.isEmpty()
+              ? !BaseType->isDependentType() || computeDeclContext(BaseType)
+              : !isDependentScopeSpecifier(SS) || computeDeclContext(SS)) &&
+         "dependent lookup context that isn't the current instantiation?");
+
   // C++1z [expr.ref]p2:
   //   For the first option (dot) the first expression shall be a glvalue [...]
   if (!IsArrow && BaseExpr && BaseExpr->isPRValue()) {
@@ -1331,10 +1327,6 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
 
   QualType BaseType = BaseExpr.get()->getType();
 
-#if 0
-  assert(!BaseType->isDependentType());
-#endif
-
   DeclarationName MemberName = R.getLookupName();
   SourceLocation MemberLoc = R.getNameLoc();
 
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 965194e9df175b..04cd9e78739d20 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -5805,10 +5805,7 @@ static ImplicitConversionSequence TryObjectArgumentInitialization(
     return ICS;
   }
 
-// FIXME: Should this check getAsRecordDecl instead?
-#if 0
   assert(FromType->isRecordType());
-#endif
 
   QualType ClassType = S.Context.getTypeDeclType(ActingContext);
   // C++98 [class.dtor]p2:

>From 9d279b4bae121aa25ea0f77c5bd0a60f2f0aa697 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Mon, 8 Apr 2024 07:23:49 -0400
Subject: [PATCH 18/25] [FOLD] update clang-tidy tests

---
 .../checkers/cppcoreguidelines/owning-memory.cpp     |  2 ++
 .../checkers/modernize/use-equals-default-copy.cpp   | 12 ++++++++++++
 2 files changed, 14 insertions(+)

diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/owning-memory.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/owning-memory.cpp
index 574efe7bd91478..ae61b17ca14d20 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/owning-memory.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/owning-memory.cpp
@@ -309,6 +309,8 @@ struct HeapArray {                                          // Ok, since destruc
 
   HeapArray(HeapArray &&other) : _data(other._data), size(other.size) { // Ok
     other._data = nullptr;                                              // Ok
+    // CHECK-NOTES: [[@LINE-1]]:5: warning: expected assignment source to be of type 'gsl::owner<>'; got 'std::nullptr_t'
+    // FIXME: This warning is emitted because an ImplicitCastExpr for the NullToPointer conversion isn't created for dependent types.
     other.size = 0;
   }
 
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-equals-default-copy.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-equals-default-copy.cpp
index 559031cf4d9bda..4abb9c8555970e 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-equals-default-copy.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-equals-default-copy.cpp
@@ -260,6 +260,8 @@ template <class T>
 struct Template {
   Template() = default;
   Template(const Template &Other) : Field(Other.Field) {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
+  // CHECK-FIXES: Template(const Template &Other)  = default;
   Template &operator=(const Template &Other);
   void foo(const T &t);
   int Field;
@@ -269,8 +271,12 @@ Template<T> &Template<T>::operator=(const Template<T> &Other) {
   Field = Other.Field;
   return *this;
 }
+// CHECK-MESSAGES: :[[@LINE-4]]:27: warning: use '= default'
+// CHECK-FIXES: Template<T> &Template<T>::operator=(const Template<T> &Other) = default;
+
 Template<int> T1;
 
+
 // Dependent types.
 template <class T>
 struct DT1 {
@@ -284,6 +290,9 @@ DT1<T> &DT1<T>::operator=(const DT1<T> &Other) {
   Field = Other.Field;
   return *this;
 }
+// CHECK-MESSAGES: :[[@LINE-4]]:17: warning: use '= default'
+// CHECK-FIXES: DT1<T> &DT1<T>::operator=(const DT1<T> &Other) = default;
+
 DT1<int> Dt1;
 
 template <class T>
@@ -303,6 +312,9 @@ DT2<T> &DT2<T>::operator=(const DT2<T> &Other) {
 struct T {
   typedef int TT;
 };
+// CHECK-MESSAGES: :[[@LINE-8]]:17: warning: use '= default'
+// CHECK-FIXES: DT2<T> &DT2<T>::operator=(const DT2<T> &Other) = default;
+
 DT2<T> Dt2;
 
 // Default arguments.

>From 857419d8080da341ba53f513ecadde38d8a6ef5f Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Mon, 8 Apr 2024 07:55:31 -0400
Subject: [PATCH 19/25] [FOLD] update clangd unit-tests

---
 clang-tools-extra/clangd/unittests/FindTargetTests.cpp    | 8 ++++----
 .../clangd/unittests/SemanticHighlightingTests.cpp        | 2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
index 799a549ff0816e..94437857cecca6 100644
--- a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
+++ b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
@@ -854,7 +854,7 @@ TEST_F(TargetDeclTest, DependentExprs) {
           }
         };
       )cpp";
-  EXPECT_DECLS("CXXDependentScopeMemberExpr", "void foo()");
+  EXPECT_DECLS("MemberExpr", "void foo()");
 
   // Similar to above but base expression involves a function call.
   Code = R"cpp(
@@ -872,7 +872,7 @@ TEST_F(TargetDeclTest, DependentExprs) {
           }
         };
       )cpp";
-  EXPECT_DECLS("CXXDependentScopeMemberExpr", "void foo()");
+  EXPECT_DECLS("MemberExpr", "void foo()");
 
   // Similar to above but uses a function pointer.
   Code = R"cpp(
@@ -891,7 +891,7 @@ TEST_F(TargetDeclTest, DependentExprs) {
           }
         };
       )cpp";
-  EXPECT_DECLS("CXXDependentScopeMemberExpr", "void foo()");
+  EXPECT_DECLS("MemberExpr", "void foo()");
 
   // Base expression involves a member access into this.
   Code = R"cpp(
@@ -962,7 +962,7 @@ TEST_F(TargetDeclTest, DependentExprs) {
           void Foo() { this->[[find]](); }
         };
   )cpp";
-  EXPECT_DECLS("CXXDependentScopeMemberExpr", "void find()");
+  EXPECT_DECLS("MemberExpr", "void find()");
 }
 
 TEST_F(TargetDeclTest, DependentTypes) {
diff --git a/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp b/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
index 4156921d83edf8..30b9b1902aa9c7 100644
--- a/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
+++ b/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
@@ -621,7 +621,7 @@ sizeof...($TemplateParameter[[Elements]]);
       struct $Class_def[[Foo]] {
         int $Field_decl[[Waldo]];
         void $Method_def[[bar]]() {
-          $Class[[Foo]]().$Field_dependentName[[Waldo]];
+          $Class[[Foo]]().$Field[[Waldo]];
         }
         template $Bracket[[<]]typename $TemplateParameter_def[[U]]$Bracket[[>]]
         void $Method_def[[bar1]]() {

>From 2a3563d7097f838166ff612799e14a2a3e103652 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Mon, 8 Apr 2024 09:00:56 -0400
Subject: [PATCH 20/25] [FOLD] show correct lookup context source range in
 diagnostics

---
 clang/lib/Sema/SemaExprMember.cpp | 26 ++++++++++----------------
 1 file changed, 10 insertions(+), 16 deletions(-)

diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index ed9d45db43c068..1676d4f1b67771 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -774,7 +774,8 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
                                        << Typo << DC << DroppedSpecifier
                                        << SS.getRange());
         } else {
-          SemaRef.Diag(TypoLoc, diag::err_no_member) << Typo << DC << BaseRange;
+          SemaRef.Diag(TypoLoc, diag::err_no_member)
+              << Typo << DC << (SS.isSet() ? SS.getRange() : BaseRange);
         }
       },
       [=](Sema &SemaRef, TypoExpr *TE, TypoCorrection TC) mutable {
@@ -1057,8 +1058,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
 
   if (R.empty()) {
     // Rederive where we looked up.
-    DeclContext *DC = (SS.isSet() ? computeDeclContext(SS, false)
-                                  : computeDeclContext(BaseType));
+    DeclContext *DC =
+        (SS.isSet() ? computeDeclContext(SS) : computeDeclContext(BaseType));
     if (ExtraArgs) {
       ExprResult RetryExpr;
       if (!IsArrow && BaseExpr && !BaseExpr->isTypeDependent()) {
@@ -1084,19 +1085,12 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
       }
     }
 
-    if (SS.isNotEmpty() && !DC) {
-      Diag(R.getNameLoc(), diag::err_undeclared_use)
-          << MemberName << SS.getRange();
-    } else if (DC) {
-      Diag(R.getNameLoc(), diag::err_no_member)
-          << MemberName << DC
-          << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
-    } else {
-      // FIXME: Is this needed?
-      Diag(R.getNameLoc(), diag::err_no_member)
-          << MemberName << BaseExprType
-          << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
-    }
+    assert(DC);
+    Diag(R.getNameLoc(), diag::err_no_member)
+        << MemberName << DC
+        << (SS.isSet()
+                ? SS.getRange()
+                : (BaseExpr ? BaseExpr->getSourceRange() : SourceRange()));
     return ExprError();
   }
 

>From 336023e1bcb943ce5eadb05edafb928c71095378 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Mon, 8 Apr 2024 10:02:43 -0400
Subject: [PATCH 21/25] [FOLD] don't ignore invalid nested name specifiers

---
 clang/lib/Sema/SemaExprMember.cpp              | 2 +-
 clang/test/CXX/temp/temp.res/temp.local/p3.cpp | 3 +--
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 1676d4f1b67771..059180d8239fcf 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -810,7 +810,7 @@ ExprResult Sema::BuildMemberReferenceExpr(
   LookupResult R(*this, NameInfo, LookupMemberName);
 
   if (SS.isInvalid())
-    SS.clear();
+    return ExprError();
 
   // Implicit member accesses.
   if (!Base) {
diff --git a/clang/test/CXX/temp/temp.res/temp.local/p3.cpp b/clang/test/CXX/temp/temp.res/temp.local/p3.cpp
index 87589e1e5bcdc8..b9b29d22736e23 100644
--- a/clang/test/CXX/temp/temp.res/temp.local/p3.cpp
+++ b/clang/test/CXX/temp/temp.res/temp.local/p3.cpp
@@ -16,8 +16,7 @@ template <class T> struct Derived: Base<int>, Base<char> {
   void g(X0 *t) {
     t->Derived::Base<T>::f();
     t->Base<T>::f();
-    t->Base::f(); // expected-error{{member 'Base' found in multiple base classes of different types}} \
-    // expected-error{{no member named 'f' in 'X0'}}
+    t->Base::f(); // expected-error{{member 'Base' found in multiple base classes of different types}}
   }
 };
 

>From ee9da18d1793acd1fedaf403ad38d0a54dc14918 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Mon, 8 Apr 2024 10:23:27 -0400
Subject: [PATCH 22/25] [FOLD] add tests

---
 .../temp.res/temp.dep/temp.dep.type/p4.cpp    | 21 +++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp b/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp
index 2649addf1175ac..89d0b203b0f309 100644
--- a/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp
+++ b/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp
@@ -371,3 +371,24 @@ namespace N1 {
     }
   };
 } // namespace N1
+
+namespace N2 {
+  template<typename T>
+  struct A {
+    struct B {
+      using C = A;
+
+      void not_instantiated(A *a, B *b) {
+        b->x; // expected-error{{no member named 'x' in 'N2::A::B'}}
+        b->B::x; // expected-error{{no member named 'x' in 'N2::A::B'}}
+        a->B::C::x; // expected-error{{no member named 'x' in 'A<T>'}}
+      }
+    };
+
+    void not_instantiated(A *a, B *b) {
+      b->x;
+      b->B::x;
+      a->B::C::x;
+    }
+  };
+}

>From f545abdc7b5f61ac894ae7a28f6b1a5d8c8bed91 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Thu, 18 Apr 2024 08:40:43 -0400
Subject: [PATCH 23/25] [FOLD] format

---
 clang/lib/Sema/SemaOpenMP.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 96b124ebae26b3..f712ae7fb0801f 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -7409,8 +7409,7 @@ void SemaOpenMP::ActOnStartOfFunctionDefinitionInOpenMPDeclareVariantScope(
   const IdentifierInfo *BaseII = D.getIdentifier();
   LookupResult Lookup(SemaRef, DeclarationName(BaseII), D.getIdentifierLoc(),
                       Sema::LookupOrdinaryName);
-  SemaRef.LookupParsedName(Lookup, S,
-                           &D.getCXXScopeSpec(),
+  SemaRef.LookupParsedName(Lookup, S, &D.getCXXScopeSpec(),
                            /*ObjectType=*/QualType());
 
   TypeSourceInfo *TInfo = SemaRef.GetTypeForDeclarator(D);

>From b6f1ee46fbe16b75d84d07a543e9a51c0a65b0df Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Mon, 22 Apr 2024 11:49:52 -0400
Subject: [PATCH 24/25] [FOLD] remove LookupTemplateName overload with
 MemberOfUnknownSpecialization out parameter

---
 clang/include/clang/Sema/Sema.h |  5 -----
 clang/lib/Sema/SemaTemplate.cpp | 18 +-----------------
 2 files changed, 1 insertion(+), 22 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 6b04b86d45f7f8..aa182b15e66ecc 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -8881,11 +8881,6 @@ class Sema final : public SemaBase {
     /// functions (but no function templates).
     FoundFunctions,
   };
-  bool LookupTemplateName(
-      LookupResult &R, Scope *S, CXXScopeSpec &SS, QualType ObjectType,
-      bool EnteringContext, bool &MemberOfUnknownSpecialization,
-      RequiredTemplateKind RequiredTemplate = SourceLocation(),
-      AssumedTemplateKind *ATK = nullptr, bool AllowTypoCorrection = true);
 
   bool
   LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS,
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 33e57ec2d965ef..72bf6370ca821a 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -210,7 +210,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
   AssumedTemplateKind AssumedTemplate;
   LookupResult R(*this, TName, Name.getBeginLoc(), LookupOrdinaryName);
   if (LookupTemplateName(R, S, SS, ObjectType, EnteringContext,
-                         MemberOfUnknownSpecialization, SourceLocation(),
+                         /*RequiredTemplate=*/SourceLocation(),
                          &AssumedTemplate,
                          /*AllowTypoCorrection=*/!Disambiguation))
     return TNK_Non_template;
@@ -377,20 +377,6 @@ bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS,
                               RequiredTemplateKind RequiredTemplate,
                               AssumedTemplateKind *ATK,
                               bool AllowTypoCorrection) {
-  bool MemberOfUnknownSpecialization;
-  return LookupTemplateName(Found, S, SS, ObjectType, EnteringContext,
-                            MemberOfUnknownSpecialization, RequiredTemplate,
-                            ATK, AllowTypoCorrection);
-}
-
-bool Sema::LookupTemplateName(LookupResult &Found,
-                              Scope *S, CXXScopeSpec &SS,
-                              QualType ObjectType,
-                              bool EnteringContext,
-                              bool &MemberOfUnknownSpecialization,
-                              RequiredTemplateKind RequiredTemplate,
-                              AssumedTemplateKind *ATK,
-                              bool AllowTypoCorrection) {
   if (ATK)
     *ATK = AssumedTemplateKind::None;
 
@@ -400,7 +386,6 @@ bool Sema::LookupTemplateName(LookupResult &Found,
   Found.setTemplateNameLookup(true);
 
   // Determine where to perform name lookup
-  MemberOfUnknownSpecialization = false;
   DeclContext *LookupCtx = nullptr;
   bool IsDependent = false;
   if (!ObjectType.isNull()) {
@@ -557,7 +542,6 @@ bool Sema::LookupTemplateName(LookupResult &Found,
   FilterAcceptableTemplateNames(Found, AllowFunctionTemplatesInLookup);
   if (Found.empty()) {
     if (IsDependent) {
-      MemberOfUnknownSpecialization = true;
       Found.setNotFoundInCurrentInstantiation();
       return false;
     }

>From 92c0aa29e4342ede2c98df258a2631cf48b31add Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Thu, 25 Apr 2024 09:17:53 -0400
Subject: [PATCH 25/25] [FOLD] add release note

---
 clang/docs/ReleaseNotes.rst | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 0bad03eda8cb54..e70d0e68f4c988 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -375,6 +375,18 @@ Improvements to Clang's diagnostics
 
 - Clang now diagnoses requires expressions with explicit object parameters.
 
+- Clang now looks up members of the current instantiation in the template definition context
+  if the current instantiation has no dependent base classes.
+
+  .. code-block:: c++
+
+     template<typename T>
+     struct A {
+       int f() {
+         return this->x; // error: no member named 'x' in 'A<T>'
+       }
+     };
+
 Improvements to Clang's time-trace
 ----------------------------------
 



More information about the cfe-commits mailing list