https://github.com/iamaayushrivastava updated https://github.com/llvm/llvm-project/pull/200161
>From 4b927eda9cfaf7c1fb70499ef7e5e4fc372dc34c Mon Sep 17 00:00:00 2001 From: iamaayushrivastava <[email protected]> Date: Thu, 28 May 2026 16:57:01 +0530 Subject: [PATCH 1/4] [clang] Fix crash in VisitVarTemplatePartialSpecializationDecl --- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 9 +++-- clang/test/SemaTemplate/GH198890.cpp | 37 +++++++++++++++++++ 2 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 clang/test/SemaTemplate/GH198890.cpp diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 324d6bf3857c7..141358325dee7 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2533,12 +2533,15 @@ Decl *TemplateDeclInstantiator::VisitVarTemplatePartialSpecializationDecl( VarTemplateDecl *VarTemplate = D->getSpecializedTemplate(); - // Lookup the already-instantiated declaration and return that. + // Lookup the already-instantiated declaration in the instantiation + // of the class template and return that. DeclContext::lookup_result Found = Owner->lookup(VarTemplate->getDeclName()); - assert(!Found.empty() && "Instantiation found nothing?"); + if (Found.empty()) + return nullptr; VarTemplateDecl *InstVarTemplate = dyn_cast<VarTemplateDecl>(Found.front()); - assert(InstVarTemplate && "Instantiation did not find a variable template?"); + if (!InstVarTemplate) + return nullptr; if (VarTemplatePartialSpecializationDecl *Result = InstVarTemplate->findPartialSpecInstantiatedFromMember(D)) diff --git a/clang/test/SemaTemplate/GH198890.cpp b/clang/test/SemaTemplate/GH198890.cpp new file mode 100644 index 0000000000000..ccf1c0a136c8f --- /dev/null +++ b/clang/test/SemaTemplate/GH198890.cpp @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c++14 -verify %s + +// GitHub issue #198890 +// https://github.com/llvm/llvm-project/issues/198890 +// +// VisitVarTemplatePartialSpecializationDecl used hard assert() calls where the +// analogous VisitClassTemplatePartialSpecializationDecl used graceful null +// checks and return nullptr. In a release build (no assertions), the assert was +// compiled out and a null-pointer dereference (SIGSEGV) followed. +// +// The crash is triggered when the primary member variable template fails to +// instantiate (returning nullptr from VisitVarTemplateDecl), so that the +// subsequent lookup for the instantiated VarTemplateDecl in Owner comes back +// empty. Without the fix, VisitVarTemplatePartialSpecializationDecl would then +// dereference a null / invalid pointer via Found.front(). + +namespace GH198890 { + +// T::type does not exist for plain types like int or void. +// When Outer<int> is instantiated, substituting typename T::type for T=int +// fails, VisitVarTemplateDecl returns nullptr, and the instantiated +// VarTemplateDecl is never added to Owner. The partial specialisation is +// visited next; Owner->lookup("member") returns empty, which previously +// triggered the assert / SIGSEGV. + +template <typename T> +struct Outer { + template <typename U> + static typename T::type member; // expected-error {{type 'int' cannot be used prior to '::' because it has no members}} + + template <typename U> + static typename T::type member<U *>; // partial specialization +}; + +template struct Outer<int>; // expected-note {{in instantiation of template class 'GH198890::Outer<int>' requested here}} + +} // namespace GH198890 >From a597114a0a58faafc4965b795967b26de5aba93e Mon Sep 17 00:00:00 2001 From: iamaayushrivastava <[email protected]> Date: Fri, 29 May 2026 04:19:41 +0530 Subject: [PATCH 2/4] [clang] Fix crash in VisitVarTemplatePartialSpecializationDecl --- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 14 +++++---- clang/test/SemaTemplate/GH198890.cpp | 29 ++++++------------- 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 141358325dee7..0485322468489 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1760,13 +1760,14 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D, TypeSourceInfo *TSI = SemaRef.SubstType( D->getTypeSourceInfo(), TemplateArgs, D->getTypeSpecStartLoc(), D->getDeclName(), /*AllowDeducedTST*/ true); - if (!TSI) - return nullptr; - - if (TSI->getType()->isFunctionType()) { + bool Invalid = false; + if (!TSI) { + TSI = D->getTypeSourceInfo(); + Invalid = true; + } else if (TSI->getType()->isFunctionType()) { SemaRef.Diag(D->getLocation(), diag::err_variable_instantiates_to_function) << D->isStaticDataMember() << TSI->getType(); - return nullptr; + Invalid = true; } DeclContext *DC = Owner; @@ -1835,6 +1836,9 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D, if (SemaRef.getLangOpts().OpenACC) SemaRef.OpenACC().ActOnVariableDeclarator(Var); + if (Invalid) + Var->setInvalidDecl(); + return Var; } diff --git a/clang/test/SemaTemplate/GH198890.cpp b/clang/test/SemaTemplate/GH198890.cpp index ccf1c0a136c8f..84a0b4d674fe5 100644 --- a/clang/test/SemaTemplate/GH198890.cpp +++ b/clang/test/SemaTemplate/GH198890.cpp @@ -1,35 +1,24 @@ // RUN: %clang_cc1 -fsyntax-only -std=c++14 -verify %s -// GitHub issue #198890 -// https://github.com/llvm/llvm-project/issues/198890 +// GitHub issue #198890: crash in VisitVarTemplatePartialSpecializationDecl +// when the primary member variable template fails to instantiate. // -// VisitVarTemplatePartialSpecializationDecl used hard assert() calls where the -// analogous VisitClassTemplatePartialSpecializationDecl used graceful null -// checks and return nullptr. In a release build (no assertions), the assert was -// compiled out and a null-pointer dereference (SIGSEGV) followed. -// -// The crash is triggered when the primary member variable template fails to -// instantiate (returning nullptr from VisitVarTemplateDecl), so that the -// subsequent lookup for the instantiated VarTemplateDecl in Owner comes back -// empty. Without the fix, VisitVarTemplatePartialSpecializationDecl would then -// dereference a null / invalid pointer via Found.front(). +// When Outer<int> is instantiated, substituting typename T::type for T=int +// fails for both the primary template member and the partial specialization. +// The fix recovers from substitution failure in VisitVarDecl (marking the +// declaration invalid) so the VarTemplateDecl is still registered in the +// owner, allowing VisitVarTemplatePartialSpecializationDecl to find it via +// lookup without crashing. namespace GH198890 { -// T::type does not exist for plain types like int or void. -// When Outer<int> is instantiated, substituting typename T::type for T=int -// fails, VisitVarTemplateDecl returns nullptr, and the instantiated -// VarTemplateDecl is never added to Owner. The partial specialisation is -// visited next; Owner->lookup("member") returns empty, which previously -// triggered the assert / SIGSEGV. - template <typename T> struct Outer { template <typename U> static typename T::type member; // expected-error {{type 'int' cannot be used prior to '::' because it has no members}} template <typename U> - static typename T::type member<U *>; // partial specialization + static typename T::type member<U *>; // expected-error {{type 'int' cannot be used prior to '::' because it has no members}} }; template struct Outer<int>; // expected-note {{in instantiation of template class 'GH198890::Outer<int>' requested here}} >From e42795d83a36ca2ecbc42e3f105c85483069d404 Mon Sep 17 00:00:00 2001 From: iamaayushrivastava <[email protected]> Date: Fri, 29 May 2026 05:01:11 +0530 Subject: [PATCH 3/4] [clang] Fix regression in VisitVarDecl error recovery --- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 0485322468489..b060d889abaa5 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1762,11 +1762,15 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D, D->getDeclName(), /*AllowDeducedTST*/ true); bool Invalid = false; if (!TSI) { + if (!InstantiatingVarTemplate) + return nullptr; TSI = D->getTypeSourceInfo(); Invalid = true; } else if (TSI->getType()->isFunctionType()) { SemaRef.Diag(D->getLocation(), diag::err_variable_instantiates_to_function) << D->isStaticDataMember() << TSI->getType(); + if (!InstantiatingVarTemplate) + return nullptr; Invalid = true; } >From dff74b053162c07d059fd0f4a09153e945b410aa Mon Sep 17 00:00:00 2001 From: iamaayushrivastava <[email protected]> Date: Fri, 29 May 2026 06:22:13 +0530 Subject: [PATCH 4/4] [clang] Fix crash when member variable template type substitution fails --- clang/docs/ReleaseNotes.md | 5 +++++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 12 +++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index ba9572e2e7c59..af80d8b9d0495 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -789,6 +789,11 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the - Clang incorrectly instantiated variable specializations outside of the immediate context. (#GH54439) - Fixed a crash when pack expansions are used as arguments for non-pack parameters of built-in templates. (#GH180307) - Fixed crash instantiating class member specializations. +- Fixed a crash during class template instantiation when a member variable + template's type substitution fails (e.g. `typename T::type` with `T=int`), + which left the `VarTemplateDecl` unregistered and caused a subsequent + assertion failure when instantiating a partial specialization of that member. + (#GH198890) - Fix a problem where a substitution failure when evaluating a type requirement could directly make the program ill-formed. - Typo correction now corrects the name qualifier for invalid template names. diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index b060d889abaa5..37ef4acd5d3d9 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1764,7 +1764,8 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D, if (!TSI) { if (!InstantiatingVarTemplate) return nullptr; - TSI = D->getTypeSourceInfo(); + TSI = SemaRef.Context.getTrivialTypeSourceInfo(SemaRef.Context.IntTy, + D->getLocation()); Invalid = true; } else if (TSI->getType()->isFunctionType()) { SemaRef.Diag(D->getLocation(), diag::err_variable_instantiates_to_function) @@ -2541,15 +2542,12 @@ Decl *TemplateDeclInstantiator::VisitVarTemplatePartialSpecializationDecl( VarTemplateDecl *VarTemplate = D->getSpecializedTemplate(); - // Lookup the already-instantiated declaration in the instantiation - // of the class template and return that. + // Lookup the already-instantiated declaration and return that. DeclContext::lookup_result Found = Owner->lookup(VarTemplate->getDeclName()); - if (Found.empty()) - return nullptr; + assert(!Found.empty() && "Instantiation found nothing?"); VarTemplateDecl *InstVarTemplate = dyn_cast<VarTemplateDecl>(Found.front()); - if (!InstVarTemplate) - return nullptr; + assert(InstVarTemplate && "Instantiation did not find a variable template?"); if (VarTemplatePartialSpecializationDecl *Result = InstVarTemplate->findPartialSpecInstantiatedFromMember(D)) _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
