[llvm-branch-commits] [clang] [clang] Backport: NestedNameSpecifier typo correction fix (PR #183821)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Sat Feb 28 01:25:10 PST 2026


https://github.com/dyung updated https://github.com/llvm/llvm-project/pull/183821

>From ee4e391b2740c01685917328d345061ae0c059d8 Mon Sep 17 00:00:00 2001
From: Matheus Izvekov <mizvekov at gmail.com>
Date: Thu, 12 Feb 2026 18:00:02 -0300
Subject: [PATCH] [clang] Backport: NestedNameSpecifier typo correction fix

This stops typo correction from considering template parameters
as candidates for a NestedNameSpecifier when it has a prefix itself.

I think this is better than the alternative of accepting these candidates,
but otherwise droping the prefix, because it seems more far-fetched that
someone would actually try to refer to a template parameter this way.

Since this regression was never released, there are no release notes.

Backport from #181239

Fixes #167120
---
 clang/lib/Sema/SemaCXXScopeSpec.cpp | 15 +++++++++++----
 clang/test/SemaCXX/GH167120.cpp     |  5 +++++
 2 files changed, 16 insertions(+), 4 deletions(-)
 create mode 100644 clang/test/SemaCXX/GH167120.cpp

diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp
index 17ae7ca5627a9..fdbd46c109243 100644
--- a/clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -381,11 +381,17 @@ namespace {
 class NestedNameSpecifierValidatorCCC final
     : public CorrectionCandidateCallback {
 public:
-  explicit NestedNameSpecifierValidatorCCC(Sema &SRef)
-      : SRef(SRef) {}
+  explicit NestedNameSpecifierValidatorCCC(Sema &SRef, bool HasQualifier)
+      : SRef(SRef), HasQualifier(HasQualifier) {}
 
   bool ValidateCandidate(const TypoCorrection &candidate) override {
-    return SRef.isAcceptableNestedNameSpecifier(candidate.getCorrectionDecl());
+    const NamedDecl *ND = candidate.getCorrectionDecl();
+    if (!SRef.isAcceptableNestedNameSpecifier(ND))
+      return false;
+    // A template type parameter cannot have a nested name specifier.
+    if (HasQualifier && isa<TemplateTypeParmDecl>(ND))
+      return false;
+    return true;
   }
 
   std::unique_ptr<CorrectionCandidateCallback> clone() override {
@@ -394,6 +400,7 @@ class NestedNameSpecifierValidatorCCC final
 
  private:
   Sema &SRef;
+  bool HasQualifier;
 };
 
 }
@@ -596,7 +603,7 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
     // different kind of error, so look for typos.
     DeclarationName Name = Found.getLookupName();
     Found.clear();
-    NestedNameSpecifierValidatorCCC CCC(*this);
+    NestedNameSpecifierValidatorCCC CCC(*this, /*HasQualifier=*/!SS.isEmpty());
     if (TypoCorrection Corrected = CorrectTypo(
             Found.getLookupNameInfo(), Found.getLookupKind(), S, &SS, CCC,
             CorrectTypoKind::ErrorRecovery, LookupCtx, EnteringContext)) {
diff --git a/clang/test/SemaCXX/GH167120.cpp b/clang/test/SemaCXX/GH167120.cpp
new file mode 100644
index 0000000000000..90251c635cc3d
--- /dev/null
+++ b/clang/test/SemaCXX/GH167120.cpp
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+namespace foo {}
+template <class type> foo::typel::x f();
+// expected-error at -1 {{no member named 'typel' in namespace 'foo'}}



More information about the llvm-branch-commits mailing list