[clang] [Clang] Improve error recovery for invalid alias templates (PR #235456)

via cfe-commits cfe-commits at lists.llvm.org
Sun Oct 25 07:28:03 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Devansh (Dash198)

<details>
<summary>Changes</summary>

This PR builds on the approach explored in #<!-- -->142278  to address incorrect error recovery when a class definition appears within an alias template.

Fixes #<!-- -->91564   

Initial attempt to change the underlying type of the invalid `TemplateTypeParmDecl` to `int` triggered an assertion as template type parameter declarations are expected to retain their `TemplateTypeParmType` representation.

Instead, the declarations in the template-parameter scope are invalidated when the invalid class definition parsing begins and then any subsequent references to the invalid template type parameters are recovered as `int` explicitly in `Sema::getTypeName`.

Note on AI assistance: An LLM was used to help diagnose the crash encountered during the initial approach, understand the relevant Clang codebase, and trace the source files and code paths involved in the issue.

---
Full diff: https://github.com/llvm/llvm-project/pull/235456.diff


2 Files Affected:

- (modified) clang/lib/Sema/SemaDecl.cpp (+18-1) 
- (modified) clang/test/SemaCXX/concept-crash-on-diagnostic.cpp (+15) 


``````````diff
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 6aae0b57df0f99..037a74af032755 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -544,11 +544,18 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
           SS ? SS->getWithLocInContext(Context) : NestedNameSpecifierLoc(),
           NameLoc);
     } else {
-      T = Context.getTypeDeclType(TD);
+      // For invalid TTP mark them as integers to avoid incorrect error recovery
+      if(auto *TTP = dyn_cast<TemplateTypeParmDecl>(TD);
+          TTP && TTP->isInvalidDecl())
+        T = Context.IntTy;
+      else
+        T = Context.getTypeDeclType(TD);
       if (!WantNontrivialTypeSourceInfo)
         return ParsedType::make(T);
       if (isa<ObjCTypeParamType>(T))
         TLB.push<ObjCTypeParamTypeLoc>(T).setNameLoc(NameLoc);
+      else if (T->isBuiltinType())
+        TLB.pushTrivial(Context, T, NameLoc);
       else
         TLB.pushTypeSpec(T).setNameLoc(NameLoc);
     }
@@ -19324,6 +19331,16 @@ void Sema::ActOnTagStartDefinition(Scope *S, Decl *TagD) {
   AdjustDeclIfTemplate(TagD);
   TagDecl *Tag = cast<TagDecl>(TagD);
 
+  // If class is defined within the alias template then mark the parameters of
+  // the template as invalid first to avoid incorrect error recovery.
+  if (Scope *Parent = S->getParent();
+      Parent && Parent->isTypeAliasScope() &&
+      Parent->isTemplateParamScope()){
+    for (Decl *D : Parent->decls()){
+      D->setInvalidDecl();
+    }
+  }
+
   // Enter the tag context.
   PushDeclContext(S, Tag);
 
diff --git a/clang/test/SemaCXX/concept-crash-on-diagnostic.cpp b/clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
index a021267b45d2fe..1083adaf1ca480 100644
--- a/clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
+++ b/clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
@@ -86,3 +86,18 @@ static_assert(requires { requires bar<int>; });
 // expected-note at -5 {{because 'bar<int>' would be invalid}}
 
 }
+
+namespace GH91564 {
+
+template <class T> using A = struct B { // expected-error {{'GH91564::B' cannot be defined in a type alias template}}
+  template <class> void f() requires (T()); // expected-error {{atomic constraint must be of type 'bool' (found 'int')}} expected-note {{explicit instantiation refers here}}
+};
+template void B::f<void>(); // expected-error {{explicit instantiation of undefined function template 'f'}}
+
+template <class T> using C = struct D { // expected-error {{'GH91564::D' cannot be defined in a type alias template}}
+  using E = T;
+};
+template <class> void g() requires (D::E()); // expected-error {{atomic constraint must be of type 'bool' (found 'D::E' (aka 'int'))}} expected-note {{explicit instantiation refers here}}
+template void g<void>(); // expected-error {{explicit instantiation of undefined function template 'g'}}
+
+} // namespace GH91564

``````````

</details>


https://github.com/llvm/llvm-project/pull/235456


More information about the cfe-commits mailing list