[C++] Fix a crash with __thread and dependent types (#140542)
We were checking whether the initializer is a valid constant expression
even if the variable was dependent. Now we delay that checking until
after the template has been instantiated.
Fixes #140509
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 4a3c1be..472b70b 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -558,6 +558,9 @@
between different Unicode character types (``char8_t``, ``char16_t``, ``char32_t``).
This warning only triggers in C++ as these types are aliases in C. (#GH138526)
+- Fixed a crash when checking a ``__thread``-specified variable declaration
+ with a dependent type in C++. (#GH140509)
+
Improvements to Clang's time-trace
----------------------------------
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index d47c1d3..ad0e274 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -14608,6 +14608,10 @@
std::optional<bool> CacheHasConstInit;
const Expr *CacheCulprit = nullptr;
auto checkConstInit = [&]() mutable {
+ const Expr *Init = var->getInit();
+ if (Init->isInstantiationDependent())
+ return true;
+
if (!CacheHasConstInit)
CacheHasConstInit = var->getInit()->isConstantInitializer(
Context, var->getType()->isReferenceType(), &CacheCulprit);
diff --git a/clang/test/SemaCXX/thread-specifier.cpp b/clang/test/SemaCXX/thread-specifier.cpp
new file mode 100644
index 0000000..2b909ec
--- /dev/null
+++ b/clang/test/SemaCXX/thread-specifier.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++23 -verify %s
+
+namespace GH140509 {
+template <typename T>
+void not_instantiated() {
+ static __thread T my_wrapper;
+}
+
+template <typename T>
+void instantiated() {
+ static __thread T my_wrapper = T{}; // expected-error {{initializer for thread-local variable must be a constant expression}} \
+ expected-note {{use 'thread_local' to allow this}}
+}
+
+template <typename T>
+void nondependent_var() {
+ // Verify that the dependence of the initializer is what really matters.
+ static __thread int my_wrapper = T{};
+}
+
+struct S {
+ S() {}
+};
+
+void f() {
+ instantiated<int>();
+ instantiated<S>(); // expected-note {{in instantiation of function template specialization 'GH140509::instantiated<GH140509::S>' requested here}}
+ nondependent_var<int>();
+}
+} // namespace GH140509