From ed9ce2ed1bb5167f6705c26adcd6c58cf653f5a0 Mon Sep 17 00:00:00 2001
From: Sergey Fedorov <barracuda@macos-powerpc.org>
Date: Thu, 23 Jul 2026 03:37:26 +0000
Subject: [PATCH 21/30] 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 <noreply@anthropic.com>
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 7ede5849..61ea15eb 100644
--- a/src/trans/target.cpp
+++ b/src/trans/target.cpp
@@ -2563,7 +2563,12 @@ std::pair<unsigned,bool> 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

