[clang] c4ce375 - [Clang][Sema] Create LocalScope for Variable Template (#228280)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Oct 2 08:50:03 PDT 2026
Author: aokblast
Date: 2026-10-02T15:49:54Z
New Revision: c4ce375075372d10ef4688ea04555005d4efaa4a
URL: https://github.com/llvm/llvm-project/commit/c4ce375075372d10ef4688ea04555005d4efaa4a
DIFF: https://github.com/llvm/llvm-project/commit/c4ce375075372d10ef4688ea04555005d4efaa4a.diff
LOG: [Clang][Sema] Create LocalScope for Variable Template (#228280)
A variable template should create its own LocalScope, as it should be
opaque to other instantiations. This can occur when there are multiple
instantiations in the same lexical scope. The correct behavior is that
these instantiations should not be chained together.
Assisted-by: Claude # Test ReleaseNote
Fixes: #134148
Added:
Modified:
clang/docs/ReleaseNotes.md
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
clang/test/SemaTemplate/instantiate-var-template.cpp
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 6afaa6675be7c..e400e14fd20fa 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -804,6 +804,11 @@ features cannot lower the translation-unit ABI level;
take effect, causing them to be dropped from llvm.used and omitted from
the object file. (#GH226572)
+- Fixed an assertion failure when the initializer of a variable template
+ specialization with a deduced type is instantiated from inside a lambda in
+ the initializer of another specialization of the same variable template.
+ (#GH134148)
+
#### Bug Fixes to AST Handling
- Fixed a non-deterministic ordering of unused local typedefs that made
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 7e29de5be2e97..5e72f05c863a0 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -6355,6 +6355,10 @@ VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation(
if (Inst.isInvalid())
return nullptr;
+ // A variable template specialization is never a local declaration, so it
+ // must not see the locals of whatever instantiation we are currently in.
+ LocalInstantiationScope Local(*this);
+
// Instantiate the first declaration of the variable template: for a partial
// specialization of a static data member template, the first declaration may
// or may not be the declaration in the class; if it's in the class, we want
diff --git a/clang/test/SemaTemplate/instantiate-var-template.cpp b/clang/test/SemaTemplate/instantiate-var-template.cpp
index 50b7219af4bea..bc6dc3d301578 100644
--- a/clang/test/SemaTemplate/instantiate-var-template.cpp
+++ b/clang/test/SemaTemplate/instantiate-var-template.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -verify -std=c++1y %s
+// RUN: %clang_cc1 -verify -std=c++17 %s
namespace PR17846 {
template <typename T> constexpr T pi = T(3.14);
@@ -58,3 +59,36 @@ namespace GH97881_comment {
(void)sizeof(g<false>); // expected-note {{in instantiation of variable template specialization 'GH97881_comment::g'}}
}
}
+
+#if __cplusplus >= 201703L
+namespace GH134148 {
+ // The initializer of a variable template specialization with an undeduced
+ // type is instantiated eagerly, here from inside the instantiation of the
+ // lambda in another specialization's initializer. The nested instantiation
+ // must get its own local instantiation scope rather than reusing the
+ // lambda's scope, which already holds the instantiations of the lambda's
+ // own locals.
+ template <int N> constexpr auto sum = [] { return sum<N - 1> + N; }();
+ template <> constexpr auto sum<0> = 0;
+ static_assert(sum<3> == 6);
+
+ template <class T> struct Unwrap { using type = T; static constexpr int depth = 0; };
+ template <class T> struct Unwrap<T &> {
+ using type = typename Unwrap<T>::type;
+ static constexpr int depth = Unwrap<T>::depth + 1;
+ };
+
+ template <class T, class... Args>
+ constexpr auto count = [] {
+ if constexpr (Unwrap<T>::depth > 0)
+ return count<typename Unwrap<T>::type, Args...> + 1;
+ else
+ return sizeof...(Args);
+ }();
+ template <class T, int = count<T>> constexpr int use(T &&) { return count<T>; }
+
+ int f();
+ static_assert(use(f) == 1);
+ static_assert(count<int &&> == 0);
+}
+#endif
More information about the cfe-commits
mailing list