tint: fix extractBits edge case

If count is highest and offset is non-zero, or vice-versa, we'd overflow
the count + offset > bit-width check. This CL fixes this case.

Bug: tint:1581
Bug: chromium:1381810
Change-Id: I6ee60ec1a13230fca6f4bb6407cd33bcc6730eb7
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/109162
Commit-Queue: Antonio Maiorano <amaiorano@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/tint/resolver/const_eval.cc b/src/tint/resolver/const_eval.cc
index 65f4d25..2c012a1 100644
--- a/src/tint/resolver/const_eval.cc
+++ b/src/tint/resolver/const_eval.cc
@@ -1901,18 +1901,18 @@
             NumberUT in_offset = args[1]->As<NumberUT>();
             NumberUT in_count = args[2]->As<NumberUT>();
 
-            constexpr UT w = sizeof(UT) * 8;
-            if ((in_offset + in_count) > w) {
-                AddError("'offset + 'count' must be less than or equal to the bit width of 'e'",
-                         source);
-                return utils::Failure;
-            }
-
             // Cast all to unsigned
             UT e = static_cast<UT>(in_e);
             UT o = static_cast<UT>(in_offset);
             UT c = static_cast<UT>(in_count);
 
+            constexpr UT w = sizeof(UT) * 8;
+            if (o > w || c > w || (o + c) > w) {
+                AddError("'offset + 'count' must be less than or equal to the bit width of 'e'",
+                         source);
+                return utils::Failure;
+            }
+
             NumberT result;
             if (c == UT{0}) {
                 // The result is 0 if c is 0
diff --git a/src/tint/resolver/const_eval_builtin_test.cc b/src/tint/resolver/const_eval_builtin_test.cc
index 80e6238..fddca38 100644
--- a/src/tint/resolver/const_eval_builtin_test.cc
+++ b/src/tint/resolver/const_eval_builtin_test.cc
@@ -1226,6 +1226,8 @@
                              std::make_tuple(33, 33),             //
                              std::make_tuple(34, 34),             //
                              std::make_tuple(1000, 1000),         //
+                             std::make_tuple(u32::Highest(), 1),  //
+                             std::make_tuple(1, u32::Highest()),  //
                              std::make_tuple(u32::Highest(), u32::Highest())));
 
 std::vector<Case> Pack4x8snormCases() {