[clang] [clang] fix typo correction crash with template destructor names (PR #207101)

Matheus Izvekov via cfe-commits cfe-commits at lists.llvm.org
Wed Jul 1 16:53:31 PDT 2026


https://github.com/mizvekov updated https://github.com/llvm/llvm-project/pull/207101

>From e7876923da0a80f2a8fe5d1d9f0c552f5a140cf3 Mon Sep 17 00:00:00 2001
From: Matheus Izvekov <mizvekov at gmail.com>
Date: Wed, 1 Jul 2026 20:30:15 -0300
Subject: [PATCH] [clang] fix typo correction crash with template destructor
 names

Disables typo correction for template destructor names,
as typo correction is not aware of destructors and would
provide suugestions which would form an invalid name.

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

Fixes #206992
---
 clang/include/clang/Sema/Sema.h        |  2 +-
 clang/lib/Parse/ParseExprCXX.cpp       |  8 ++++----
 clang/lib/Parse/ParseTemplate.cpp      | 15 +++++++--------
 clang/lib/Sema/SemaTemplate.cpp        | 18 +++++++-----------
 clang/test/SemaCXX/typo-correction.cpp |  6 ++++++
 5 files changed, 25 insertions(+), 24 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index ebb775ffbb758..2df85771573e2 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11529,7 +11529,7 @@ class Sema final : public SemaBase {
                                   ParsedType ObjectType, bool EnteringContext,
                                   TemplateTy &Template,
                                   bool &MemberOfUnknownSpecialization,
-                                  bool Disambiguation = false);
+                                  bool AllowTypoCorrection = true);
 
   /// Try to resolve an undeclared template name as a type template.
   ///
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index ae49fc20e36f2..6b8ab6ce89909 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -496,7 +496,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
               getCurScope(), SS,
               /*hasTemplateKeyword=*/false, TemplateName, ObjectType,
               EnteringContext, Template, MemberOfUnknownSpecialization,
-              Disambiguation)) {
+              /*AllowTypoCorrection=*/!Disambiguation)) {
         // If lookup didn't find anything, we treat the name as a template-name
         // anyway. C++20 requires this, and in prior language modes it improves
         // error recovery. But before we commit to this, check that we actually
@@ -2276,9 +2276,9 @@ bool Parser::ParseUnqualifiedIdTemplateId(
           EnteringContext, Template, /*AllowInjectedClassName*/ true);
     } else {
       TNK = Actions.isTemplateName(getCurScope(), SS, TemplateKWLoc.isValid(),
-                                   TemplateName, ObjectType,
-                                   EnteringContext, Template,
-                                   MemberOfUnknownSpecialization);
+                                   TemplateName, ObjectType, EnteringContext,
+                                   Template, MemberOfUnknownSpecialization,
+                                   /*AllowTypoCorrection=*/false);
 
       if (TNK == TNK_Non_template && !Id.DestructorName.get()) {
         Diag(NameLoc, diag::err_destructor_template_id)
diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp
index 330a9c6aea0c5..735a9bd1f9f1c 100644
--- a/clang/lib/Parse/ParseTemplate.cpp
+++ b/clang/lib/Parse/ParseTemplate.cpp
@@ -563,14 +563,13 @@ bool Parser::TryAnnotateTypeConstraint() {
 
     TemplateTy PossibleConcept;
     bool MemberOfUnknownSpecialization = false;
-    auto TNK = Actions.isTemplateName(getCurScope(), SS,
-                                      /*hasTemplateKeyword=*/false,
-                                      PossibleConceptName,
-                                      /*ObjectType=*/ParsedType(),
-                                      /*EnteringContext=*/false,
-                                      PossibleConcept,
-                                      MemberOfUnknownSpecialization,
-                                      /*Disambiguation=*/true);
+    auto TNK = Actions.isTemplateName(
+        getCurScope(), SS,
+        /*hasTemplateKeyword=*/false, PossibleConceptName,
+        /*ObjectType=*/ParsedType(),
+        /*EnteringContext=*/false, PossibleConcept,
+        MemberOfUnknownSpecialization,
+        /*AllowTypoCorrection=*/false);
     if (MemberOfUnknownSpecialization || !PossibleConcept ||
         TNK != TNK_Concept_template) {
       if (SS.isNotEmpty())
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 4f5eb36406f65..9fe6a2ae209e8 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -175,15 +175,12 @@ bool Sema::hasAnyAcceptableTemplateNames(LookupResult &R,
   return false;
 }
 
-TemplateNameKind Sema::isTemplateName(Scope *S,
-                                      CXXScopeSpec &SS,
-                                      bool hasTemplateKeyword,
-                                      const UnqualifiedId &Name,
-                                      ParsedType ObjectTypePtr,
-                                      bool EnteringContext,
-                                      TemplateTy &TemplateResult,
-                                      bool &MemberOfUnknownSpecialization,
-                                      bool Disambiguation) {
+TemplateNameKind
+Sema::isTemplateName(Scope *S, CXXScopeSpec &SS, bool hasTemplateKeyword,
+                     const UnqualifiedId &Name, ParsedType ObjectTypePtr,
+                     bool EnteringContext, TemplateTy &TemplateResult,
+                     bool &MemberOfUnknownSpecialization,
+                     bool AllowTypoCorrection) {
   assert(getLangOpts().CPlusPlus && "No template names in C!");
 
   DeclarationName TName;
@@ -213,8 +210,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
   LookupResult R(*this, TName, Name.getBeginLoc(), LookupOrdinaryName);
   if (LookupTemplateName(R, S, SS, ObjectType, EnteringContext,
                          /*RequiredTemplate=*/SourceLocation(),
-                         &AssumedTemplate,
-                         /*AllowTypoCorrection=*/!Disambiguation))
+                         &AssumedTemplate, AllowTypoCorrection))
     return TNK_Non_template;
   MemberOfUnknownSpecialization = R.wasNotFoundInCurrentInstantiation();
 
diff --git a/clang/test/SemaCXX/typo-correction.cpp b/clang/test/SemaCXX/typo-correction.cpp
index 7bf5daacbc7b7..d0478706021c7 100644
--- a/clang/test/SemaCXX/typo-correction.cpp
+++ b/clang/test/SemaCXX/typo-correction.cpp
@@ -799,3 +799,9 @@ namespace GH204561 {
 
   template int x<int &>;
 } // namespace GH204561
+
+namespace GH206992 {
+  template <class> struct F {};
+  ::~F<void> {};
+  // expected-error at -1 {{destructor name 'F' does not refer to a template}}
+}; // namespace GH206992



More information about the cfe-commits mailing list