about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--library/core/src/option.rs24
-rw-r--r--tests/codegen/option-as-slice.rs35
2 files changed, 51 insertions, 8 deletions
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 8ec7716012f..1a8fe1e6051 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -770,6 +770,13 @@ impl<T> Option<T> {
         }
     }
 
+    #[inline]
+    const fn len(&self) -> usize {
+        // Using the intrinsic avoids emitting a branch to get the 0 or 1.
+        let discriminant: isize = crate::intrinsics::discriminant_value(self);
+        discriminant as usize
+    }
+
     /// Returns a slice of the contained value, if any. If this is `None`, an
     /// empty slice is returned. This can be useful to have a single type of
     /// iterator over an `Option` or slice.
@@ -812,7 +819,7 @@ impl<T> Option<T> {
         unsafe {
             slice::from_raw_parts(
                 (self as *const Self).byte_add(core::mem::offset_of!(Self, Some.0)).cast(),
-                self.is_some() as usize,
+                self.len(),
             )
         }
     }
@@ -869,7 +876,7 @@ impl<T> Option<T> {
         unsafe {
             slice::from_raw_parts_mut(
                 (self as *mut Self).byte_add(core::mem::offset_of!(Self, Some.0)).cast(),
-                self.is_some() as usize,
+                self.len(),
             )
         }
     }
@@ -2242,10 +2249,8 @@ impl<A> Iterator for Item<A> {
 
     #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
-        match self.opt {
-            Some(_) => (1, Some(1)),
-            None => (0, Some(0)),
-        }
+        let len = self.len();
+        (len, Some(len))
     }
 }
 
@@ -2256,7 +2261,12 @@ impl<A> DoubleEndedIterator for Item<A> {
     }
 }
 
-impl<A> ExactSizeIterator for Item<A> {}
+impl<A> ExactSizeIterator for Item<A> {
+    #[inline]
+    fn len(&self) -> usize {
+        self.opt.len()
+    }
+}
 impl<A> FusedIterator for Item<A> {}
 unsafe impl<A> TrustedLen for Item<A> {}
 
diff --git a/tests/codegen/option-as-slice.rs b/tests/codegen/option-as-slice.rs
index 65637a2495d..cfa479aa4b2 100644
--- a/tests/codegen/option-as-slice.rs
+++ b/tests/codegen/option-as-slice.rs
@@ -14,6 +14,14 @@ pub fn u64_opt_as_slice(o: &Option<u64>) -> &[u64] {
     // CHECK-NOT: br
     // CHECK-NOT: switch
     // CHECK-NOT: icmp
+    // CHECK: %[[LEN:.+]] = load i64,{{.+}} !range ![[META_U64:.+]], !noundef
+    // CHECK-NOT: select
+    // CHECK-NOT: br
+    // CHECK-NOT: switch
+    // CHECK-NOT: icmp
+    // CHECK: %[[T0:.+]] = insertvalue { ptr, i64 } poison, ptr %{{.+}}, 0
+    // CHECK-NEXT: %[[T1:.+]] = insertvalue { ptr, i64 } %[[T0]], i64 %[[LEN]], 1
+    // CHECK-NEXT: ret { ptr, i64 } %[[T1]]
     o.as_slice()
 }
 
@@ -25,10 +33,35 @@ pub fn nonzero_u64_opt_as_slice(o: &Option<NonZero<u64>>) -> &[NonZero<u64>] {
     // CHECK-NOT: switch
     // CHECK-NOT: icmp
     // CHECK: %[[NZ:.+]] = icmp ne i64 %{{.+}}, 0
-    // CHECK-NEXT: zext i1 %[[NZ]] to i64
+    // CHECK-NEXT: %[[LEN:.+]] = zext i1 %[[NZ]] to i64
     // CHECK-NOT: select
     // CHECK-NOT: br
     // CHECK-NOT: switch
     // CHECK-NOT: icmp
+    // CHECK: %[[T0:.+]] = insertvalue { ptr, i64 } poison, ptr %o, 0
+    // CHECK-NEXT: %[[T1:.+]] = insertvalue { ptr, i64 } %[[T0]], i64 %[[LEN]], 1
+    // CHECK-NEXT: ret { ptr, i64 } %[[T1]]
     o.as_slice()
 }
+
+// CHECK-LABEL: @u8_opt_as_slice
+#[no_mangle]
+pub fn u8_opt_as_slice(o: &Option<u8>) -> &[u8] {
+    // CHECK-NOT: select
+    // CHECK-NOT: br
+    // CHECK-NOT: switch
+    // CHECK-NOT: icmp
+    // CHECK: %[[TAG:.+]] = load i8,{{.+}} !range ![[META_U8:.+]], !noundef
+    // CHECK: %[[LEN:.+]] = zext{{.*}} i8 %[[TAG]] to i64
+    // CHECK-NOT: select
+    // CHECK-NOT: br
+    // CHECK-NOT: switch
+    // CHECK-NOT: icmp
+    // CHECK: %[[T0:.+]] = insertvalue { ptr, i64 } poison, ptr %{{.+}}, 0
+    // CHECK-NEXT: %[[T1:.+]] = insertvalue { ptr, i64 } %[[T0]], i64 %[[LEN]], 1
+    // CHECK-NEXT: ret { ptr, i64 } %[[T1]]
+    o.as_slice()
+}
+
+// CHECK: ![[META_U64]] = !{i64 0, i64 2}
+// CHECK: ![[META_U8]] = !{i8 0, i8 2}