https://github.com/iamaayushrivastava updated https://github.com/llvm/llvm-project/pull/200161
>From 4e3bbd2452e89acf1f15e8b0d1fdd60488207a3a 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 c9bc613a7c4ea..1f51b37af56a4 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2540,12 +2540,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 e09a7d1c40267a3d745af82b41bf5e15c6c826da 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 1f51b37af56a4..4cd4a9391165c 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1767,13 +1767,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; @@ -1842,6 +1843,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 80aaf581c682abd672aa46f71048cdb2636289fd 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 4cd4a9391165c..0e4572eeef599 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1769,11 +1769,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 c381f975e3b7182e116673a03ca65130ab336497 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] Use int as recovery type and restore asserts in VisitVarTemplatePartialSpecializationDecl --- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 0e4572eeef599..46203637922eb 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1771,7 +1771,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) @@ -2548,15 +2549,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
