[clang] [clang] fix typo-correction for template name lookup (PR #208586)
Matheus Izvekov via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 9 17:05:31 PDT 2026
https://github.com/mizvekov updated https://github.com/llvm/llvm-project/pull/208586
>From c56b452a4e258f3d5899ca556f54316f60dc1e35 Mon Sep 17 00:00:00 2001
From: Matheus Izvekov <mizvekov at gmail.com>
Date: Thu, 9 Jul 2026 20:18:38 -0300
Subject: [PATCH] [clang] fix typo-correction for template name lookup
Only consider candidates which are templates.
Disable spell checking for a DR test in order to not introduce noise,
as spell checking is never helpful in those.
Fixes #207498
---
clang/docs/ReleaseNotes.md | 1 +
clang/lib/Sema/SemaTemplate.cpp | 20 +++++++++++++++++++-
clang/test/CXX/drs/cwg5xx.cpp | 14 +++++++-------
clang/test/SemaCXX/typo-correction.cpp | 22 ++++++++++++++++++++++
4 files changed, 49 insertions(+), 8 deletions(-)
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 92e63585e492a..5c044b8272789 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -836,6 +836,7 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the
- Clang no longer errors on overloads with different ref-qualifiers and constraints. (#GH120812)
- Fixed a crash when a default argument is passed to an explicit object parameter. (#GH176639)
- Fixed an alias template CTAD crash.
+- Improvements to typo correction involving template names. (#GH207498)
- Correctly diagnose uses of `co_await` / `co_yield` in the default argument of nested function declarations. (#GH98923)
- Fixed a crash when diagnosing an invalid static member function with an explicit object parameter (#GH177741)
- Clang incorrectly instantiated variable specializations outside of the immediate context. (#GH54439)
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index ad0e653e254dd..43bcd0bfb9e17 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -515,7 +515,25 @@ bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS,
// to correct any typos.
DeclarationName Name = Found.getLookupName();
Found.clear();
- QualifiedLookupValidatorCCC FilterCCC(!SS.isEmpty());
+
+ class TemplateNameLookupValidatorCCC final
+ : public QualifiedLookupValidatorCCC {
+ public:
+ using QualifiedLookupValidatorCCC::QualifiedLookupValidatorCCC;
+
+ bool ValidateCandidate(const TypoCorrection &Candidate) final {
+ if (const NamedDecl *ND = Candidate.getCorrectionDecl();
+ !ND || !isa<TemplateDecl>(ND))
+ return false;
+ return QualifiedLookupValidatorCCC::ValidateCandidate(Candidate);
+ }
+
+ std::unique_ptr<CorrectionCandidateCallback> clone() final {
+ return std::make_unique<TemplateNameLookupValidatorCCC>(*this);
+ }
+ };
+
+ TemplateNameLookupValidatorCCC FilterCCC(!SS.isEmpty());
FilterCCC.WantTypeSpecifiers = false;
FilterCCC.WantExpressionKeywords = false;
FilterCCC.WantRemainingKeywords = false;
diff --git a/clang/test/CXX/drs/cwg5xx.cpp b/clang/test/CXX/drs/cwg5xx.cpp
index 935f3c7e41dc3..4062fcc04ce3d 100644
--- a/clang/test/CXX/drs/cwg5xx.cpp
+++ b/clang/test/CXX/drs/cwg5xx.cpp
@@ -1,10 +1,10 @@
-// RUN: %clang_cc1 -std=c++98 %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,cxx98-23,cxx98-11,cxx98-14,cxx98-17,cxx98
-// RUN: %clang_cc1 -std=c++11 %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,cxx98-23,cxx98-11,cxx98-14,cxx98-17,since-cxx11
-// RUN: %clang_cc1 -std=c++14 %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,cxx98-23,cxx98-14,cxx98-17,since-cxx11
-// RUN: %clang_cc1 -std=c++17 %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,cxx98-23,since-cxx17,cxx98-17,since-cxx11
-// RUN: %clang_cc1 -std=c++20 %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,cxx98-23,since-cxx20,since-cxx17,since-cxx11
-// RUN: %clang_cc1 -std=c++23 %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,cxx98-23,since-cxx23,since-cxx20,since-cxx17,since-cxx11
-// RUN: %clang_cc1 -std=c++2c %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,since-cxx26,since-cxx23,since-cxx20,since-cxx17,since-cxx11
+// RUN: %clang_cc1 -std=c++98 %s -fexceptions -fcxx-exceptions -pedantic-errors -fno-spell-checking -verify-directives -verify=expected,cxx98-23,cxx98-11,cxx98-14,cxx98-17,cxx98
+// RUN: %clang_cc1 -std=c++11 %s -fexceptions -fcxx-exceptions -pedantic-errors -fno-spell-checking -verify-directives -verify=expected,cxx98-23,cxx98-11,cxx98-14,cxx98-17,since-cxx11
+// RUN: %clang_cc1 -std=c++14 %s -fexceptions -fcxx-exceptions -pedantic-errors -fno-spell-checking -verify-directives -verify=expected,cxx98-23,cxx98-14,cxx98-17,since-cxx11
+// RUN: %clang_cc1 -std=c++17 %s -fexceptions -fcxx-exceptions -pedantic-errors -fno-spell-checking -verify-directives -verify=expected,cxx98-23,since-cxx17,cxx98-17,since-cxx11
+// RUN: %clang_cc1 -std=c++20 %s -fexceptions -fcxx-exceptions -pedantic-errors -fno-spell-checking -verify-directives -verify=expected,cxx98-23,since-cxx20,since-cxx17,since-cxx11
+// RUN: %clang_cc1 -std=c++23 %s -fexceptions -fcxx-exceptions -pedantic-errors -fno-spell-checking -verify-directives -verify=expected,cxx98-23,since-cxx23,since-cxx20,since-cxx17,since-cxx11
+// RUN: %clang_cc1 -std=c++2c %s -fexceptions -fcxx-exceptions -pedantic-errors -fno-spell-checking -verify-directives -verify=expected,since-cxx26,since-cxx23,since-cxx20,since-cxx17,since-cxx11
#if __cplusplus == 199711L
#define static_assert(...) __extension__ _Static_assert(__VA_ARGS__)
diff --git a/clang/test/SemaCXX/typo-correction.cpp b/clang/test/SemaCXX/typo-correction.cpp
index d0478706021c7..9f124bec76cc2 100644
--- a/clang/test/SemaCXX/typo-correction.cpp
+++ b/clang/test/SemaCXX/typo-correction.cpp
@@ -805,3 +805,25 @@ namespace GH206992 {
::~F<void> {};
// expected-error at -1 {{destructor name 'F' does not refer to a template}}
}; // namespace GH206992
+
+namespace GH207498_1 {
+ void foo();
+ namespace N {
+ namespace S {}
+ template <class> void foo() {}
+ // expected-note at -1 {{'N::foo' declared here}}
+ };
+ template void N::S::foo<float>();
+ // expected-error at -1 {{no template named 'foo' in namespace 'GH207498_1::N::S'; did you mean 'N::foo'?}}
+} // namespace GH207498_1
+
+namespace GH207498_2 {
+ template <class> void foo() {}
+ // expected-note at -1 {{'foo' declared here}}
+ namespace N {
+ namespace S {}
+ void foo();
+ };
+ template void N::S::foo<float>();
+ // expected-error at -1 {{no template named 'foo' in namespace 'GH207498_2::N::S'; did you mean simply 'foo'?}}
+} // namespace GH207498_2
More information about the cfe-commits
mailing list