Author: Aayush Shrivastava Date: 2026-07-01T22:27:26-03:00 New Revision: 24e7deef7363d5dce2255c5350645b927e5e3313
URL: https://github.com/llvm/llvm-project/commit/24e7deef7363d5dce2255c5350645b927e5e3313 DIFF: https://github.com/llvm/llvm-project/commit/24e7deef7363d5dce2255c5350645b927e5e3313.diff LOG: [clang] Fix crash in VisitVarTemplatePartialSpecializationDecl on failed instantiation (#200161) Fixes #198890 When a class template is explicitly instantiated and a member variable template's type involves a substitution failure (e.g. `typename T::type` with `T=int`), `VisitVarDecl` returned `nullptr`, causing `VisitVarTemplateDecl` to bail out before registering the `VarTemplateDecl` in the owner's lookup table. A subsequent call to `VisitVarTemplatePartialSpecializationDecl` then hit an assert (`!Found.empty()`) on the empty lookup result. Fix: When `SubstType` fails and `InstantiatingVarTemplate=true`, recover by using `int` as the type (via `getTrivialTypeSourceInfo(IntTy)`) and mark the resulting `VarDecl` invalid. This ensures `VisitVarTemplateDecl` always receives a valid `VarDecl` and finishes registering the `VarTemplateDecl`, preserving the invariant the asserts rely on. A regression test is added in `clang/test/SemaTemplate/GH198890.cpp`. Added: clang/test/SemaTemplate/GH198890.cpp Modified: clang/docs/ReleaseNotes.md clang/lib/Sema/SemaTemplateInstantiateDecl.cpp Removed: ################################################################################ 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 324d6bf3857c7..37ef4acd5d3d9 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1760,13 +1760,19 @@ 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) { + if (!InstantiatingVarTemplate) + return nullptr; + 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) << D->isStaticDataMember() << TSI->getType(); - return nullptr; + if (!InstantiatingVarTemplate) + return nullptr; + Invalid = true; } DeclContext *DC = Owner; @@ -1835,6 +1841,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 new file mode 100644 index 0000000000000..84a0b4d674fe5 --- /dev/null +++ b/clang/test/SemaTemplate/GH198890.cpp @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c++14 -verify %s + +// GitHub issue #198890: crash in VisitVarTemplatePartialSpecializationDecl +// when the primary member variable template fails to instantiate. +// +// 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 { + +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 *>; // 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}} + +} // namespace GH198890 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
