Repository navigation
Windows: clang + MSVC STL 14.51 rejects std::find over a 24-byte trivially-comparable type (_Find_vectorized 'unexpected size') #609
Description
Activity
Traced to the source. It is a known, open MSVC STL regression — microsoft/STL#6294, filed 2026-05-20, labelled
bug, still open — so this note is now just a signpost. Nothing for mcpp to fix, but the chain is worth having here because the error text points into<xutility>with no hint of where the variable actually is.The chain, from microsoft/STL's own source
The admitting guard is clang-only, and inert under MSVC (
stl/inc/xutility):#ifdef __clang__ template <class _Elem1, class _Elem2> constexpr bool _Is_same_and_builtin_trivially_equality_comparable = is_same_v<_Elem1, _Elem2> && __is_trivially_equality_comparable(_Elem1); #else template <class _Elem1, class _Elem2> constexpr bool _Is_same_and_builtin_trivially_equality_comparable = false; #endif
It feeds
_Vector_alg_in_find_is_safe, which checks contiguity, volatility and element compatibility — and no upper size bound. The dispatch site then adds only_Is_sized && _VECTORIZED_FINDfor elements that are not 1 or 2 bytes. What receives the call implements four sizes:template <class _Ty, class _TVal> _Ty* _Find_vectorized(_Ty* const _First, _Ty* const _Last, const _TVal _Val) noexcept { if constexpr (sizeof(_Ty) == 1) { ... } else if constexpr (sizeof(_Ty) == 2) { ... } ... else { static_assert(false, "unexpected size"); } }
So the guard says "bitwise-comparable, let it through" and the implementation says "I only do 1/2/4/8". The disagreement is unreachable under MSVC — that branch is hardcoded
false— which is why it shipped.#6294 identifies the regression as coming from microsoft/STL#5479 (and PR #5767), the change that added the clang path to optimize more cases.
Neither side's newer version helps
Checked rather than assumed.
MSVC STL
maintoday still has it: no size exclusion in_Vector_alg_in_find_is_safe, and the#ifdef __clang__block unchanged.clang is not the variable either. The builtin behaves the same across versions — measured locally with a 24-byte struct in both forms:
clang 22.1.8 sizeof = 24 defaulted operator== __is_trivially_equality_comparable = 1 clang 22.1.8 sizeof = 24 explicit operator== __is_trivially_equality_comparable = 0Same answers from an LLVM 20-based compiler. So upgrading the toolchain does not move this, and clang is answering its own builtin correctly — a defaulted
==on a padding-free struct is bitwise-comparable. The bug is that the STL treats that as a licence to vectorize at any size.What actually avoids it
Three levers, and only one of them is available to a downstream today:
level action owner status standard library exclude sizes other than 1/2/4/8 from the guard microsoft/STL #6294, open, no timeline application give the type an explicit operator==instead of= defaultthe package one line, works now CI pin image + MSVC toolset mcpp-index done, mcpplibs/mcpp-index#388 The middle row is the practical one and is confirmed by the table above: the trait flips to
0and the type stops being eligible for the vectorized path. #6294's own repro shows the same — a hand-writtenoperator==compiles, the defaulted one does not, for otherwise identical structs.A CI pin only protects CI. Anyone building with clang against a current MSVC STL still hits this, which is the part worth knowing before reaching for a toolchain pin as the fix.
- added 4 commits that reference this issue
on Sep 11, 2026 Documented in mcpp 2026.9.12.2 (#619). mcpp itself has no defect here; microsoft/STL#6294 is open upstream.
mcpp is the tool that assembles clang with the MSVC STL, so docs/20 (and its Chinese copy) gains a "Known Toolchain Hazard" section stating:
- the error text;
- the affected STL release (14.51);
- the upstream issue;
- the two workarounds measured downstream: an explicit
operator==on the element type, or an older runner image.
Closing as documented upstream tracking.
Filing this as a note for later, not a request — the defect is in the toolchain combination, not in mcpp. But mcpp is what puts that combination together on Windows, so this is where a downstream hitting it will look.
What happens
mcpp builds Windows with clang targeting
x86_64-pc-windows-msvc— the MSVC ABI, the MSVC STL, and clang as the front end. On a runner image carrying MSVC STL 14.51 (Visual Studio 18), compiling a translation unit that callsstd::findover a 24-byte type fails inside the standard library:The element type is unremarkable:
24 bytes, no padding, trivially copyable, defaulted
operator==.Why it happens
MSVC STL's vectorized
std::findis guarded by a trait deciding whether the element type can be compared bitwise. That guard admits this type under clang, and the helper it then dispatches to implements the 1/2/4/8-byte cases andstatic_asserts on everything else. Guard and implementation disagree about what "vectorizable" means, and only clang is present to notice — MSVC's own front end does not take this path.It is version-specific, and that is the useful part
windows-2022windows-latest(VS 18)static_assertfailureSo it is not the package's code and not a descriptor problem — it is this STL release against clang.
Blast radius, measured
On the
mcpp-indexshard where this surfaced, 13 of 14 members compiled fine on the 14.51 image; one did not. So it is narrow — it only bites code that instantiatesstd::findover a trivially-comparable type larger than 8 bytes. The narrowness is what makes it awkward: on a rolling image label, the set of affected packages changes underneath you, and the failure shows up attributed to whichever descriptor happened to change that week.What was done downstream
mcpp-indexpinned its Windows leg fromwindows-latesttowindows-2022(mcpplibs/mcpp-index#385), which is also what the affected project's own mcpp CI already does. That is a workaround, not a fix, and the pin should be lifted once clang and MSVC STL agree again.Why it is filed here
Nothing for mcpp to change today. But anyone who hits this will hit it through
mcpp buildon Windows and will reasonably start here, and the error points into<xutility>with no hint that the STL version is the variable. A note in this tracker is the cheapest way to shorten that search. Feel free to close or relabel as upstream-tracking.