Attempting to compile some example.cpp containing the following:
#include <array>
void test() {
thread_local int arr[10];
static_assert(std::size(arr) < 100);
}
MSVC 19.35.32215 tells me:
1>example.cpp(5,34): error C2131: expression did not evaluate to a constant 1>example.cpp(5,29): message : failure was caused by non-constant arguments or reference to a non-constant symbol 1>example.cpp(5,29): message : see usage of 'arr'
The same snippet not containing the thread_local specifier, compiles just fine.
For reference, this is Visual C++ where I have experimented with trying to enforce standard compliance (/std:c++20), and /sdl is used as well -- these changes do not eliminate the compilation error. Also, http://godbolt.org gives me the same error when using MSVC "latest", but, more importantly, latest Clang, for instance, compiles the otherwise problematic snippet just fine.
I don't know how to get the full cl command line as used by the IDE when building my solution through the Visual Studio 2022 GUI I am using, but I do get the same compilation error if I drop to a VS developer command prompt environment and invoke cl directly: cl /c example.cpp (with or without /std:c++20) gets me the same error, basically:
Microsoft (R) C/C++ Optimizing Compiler Version 19.35.32215 for x86 Copyright (C) Microsoft Corporation. All rights reserved. example.cpp example.cpp(5): error C2131: expression did not evaluate to a constant example.cpp(5): note: failure was caused by non-constant arguments or reference to a non-constant symbol example.cpp(5): note: see usage of 'arr'
I fail to see why thread-local storage for arr should prevent the compiler from deducing its size given the declaration, and subsequently perform static_assert as expected? Am I missing some subtle property of modern C++ here?
This seems to be a MSVC bug. The code is fine and should compile. The storage duration of arr should be irrelevant. As suggested in the comments under the question, you should report it.
Just referencing a non-constexpr variable of object type doesn't cause an expression to not be a (core) constant expression and you are neither applying an lvalue-to-rvalue conversion to arr or its subobjects, nor are you producing a pointer or lvalue to it or any of its subobjects as a result of the constant expression. The result of std::size(arr) is only dependent on its (deduced) template argument.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With