From af7ca85a124d15b2689bbaf76c44043e25e67e9e Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Thu, 23 Jul 2026 03:37:26 +0000 Subject: [PATCH 17/25] trans: fix variant lookup for negative enum discriminants in literals The VariantMode::Values reader compared the tag read from an encoded literal (truncated to the tag width, e.g. 0xFF for a repr(i8) tag of -1) against the discriminant list, which stores values sign-extended to 64 bits - so any negative-discriminant enum value inside an encoded literal (e.g. a const-evaluated core::cmp::Ordering::Less) failed with "Invalid enum tag: 255". Compare modulo the tag width. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_013wCVW89GjmNyYviEcANPHM --- src/trans/target.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/trans/target.cpp b/src/trans/target.cpp index e9d60e3d..a1210e16 100644 --- a/src/trans/target.cpp +++ b/src/trans/target.cpp @@ -2567,7 +2567,12 @@ std::pair TypeRepr::get_enum_variant(const Span& sp, const Static } TU_ARMA(Values, ve) { auto v = lit.slice( this->get_offset(sp, resolve, ve.field), ve.field.size).read_uint(ve.field.size); - auto it = std::find(ve.values.begin(), ve.values.end(), v.truncate_u64()); + // Compare modulo the tag width: negative discriminants (e.g. `Ordering::Less + // = -1`, repr(i8)) are stored sign-extended to 64 bits in `values`, while the + // encoded tag is just the truncated bytes. + uint64_t mask = ve.field.size >= 8 ? ~0ull : ((1ull << (8*ve.field.size)) - 1); + uint64_t vv = v.truncate_u64() & mask; + auto it = std::find_if(ve.values.begin(), ve.values.end(), [&](uint64_t x){ return (x & mask) == vv; }); ASSERT_BUG(sp, it != ve.values.end(), "Invalid enum tag: " << v); var_idx = it - ve.values.begin(); DEBUG("VariantMode::Values - #" << var_idx); -- 2.43.0