[tint][utils] Add casting constructor to Slice

Change-Id: Ia4629ec81c33d8b0e045a0ab42aa4c9818b75c4b
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/136200
Kokoro: Kokoro <noreply+kokoro@google.com>
Auto-Submit: Ben Clayton <bclayton@google.com>
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/utils/slice.h b/src/tint/utils/slice.h
index ad4dbcf..485bac9 100644
--- a/src/tint/utils/slice.h
+++ b/src/tint/utils/slice.h
@@ -117,6 +117,15 @@
     /// Constructor
     Slice(EmptyType) {}  // NOLINT
 
+    /// Copy constructor with covariance / const conversion
+    /// @param other the vector to copy
+    /// @see CanReinterpretSlice for rules about conversion
+    template <typename U,
+              typename = std::enable_if_t<CanReinterpretSlice<ReinterpretMode::kSafe, T, U>>>
+    Slice(const Slice<U>& other) {  // NOLINT(runtime/explicit)
+        *this = other.template Reinterpret<T, ReinterpretMode::kSafe>();
+    }
+
     /// Constructor
     /// @param d pointer to the first element in the slice
     /// @param l total number of elements in the slice
diff --git a/src/tint/utils/slice_test.cc b/src/tint/utils/slice_test.cc
index 6a4493c..319b678 100644
--- a/src/tint/utils/slice_test.cc
+++ b/src/tint/utils/slice_test.cc
@@ -72,6 +72,21 @@
     EXPECT_TRUE(slice.IsEmpty());
 }
 
+TEST(TintSliceTest, CtorCast) {
+    C1* elements[3];
+
+    Slice<C1*> slice_a;
+    slice_a.data = &elements[0];
+    slice_a.len = 3;
+    slice_a.cap = 3;
+
+    Slice<const C0*> slice_b(slice_a);
+    EXPECT_EQ(slice_b.data, Bitcast<const C0**>(&elements[0]));
+    EXPECT_EQ(slice_b.len, 3u);
+    EXPECT_EQ(slice_b.cap, 3u);
+    EXPECT_FALSE(slice_b.IsEmpty());
+}
+
 TEST(TintSliceTest, CtorEmpty) {
     Slice<int> slice{Empty};
     EXPECT_EQ(slice.data, nullptr);