diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs index 0a30033778b38..d2d0dd3387fbc 100644 --- a/library/core/src/slice/iter/macros.rs +++ b/library/core/src/slice/iter/macros.rs @@ -124,12 +124,10 @@ macro_rules! iterator { fn next(&mut self) -> Option<$elem> { // could be implemented with slices, but this avoids bounds checks - // SAFETY: `assume` calls are safe since a slice's start pointer - // must be non-null, and slices over non-ZSTs must also have a - // non-null end pointer. The call to `next_unchecked!` is safe - // since we check if the iterator is empty first. + // SAFETY: `assume` call is safe because slices over non-ZSTs must + // have a non-null end pointer. The call to `next_unchecked!` is + // safe since we check if the iterator is empty first. unsafe { - assume(!self.ptr.as_ptr().is_null()); if !::IS_ZST { assume(!self.end.is_null()); } @@ -339,12 +337,10 @@ macro_rules! iterator { fn next_back(&mut self) -> Option<$elem> { // could be implemented with slices, but this avoids bounds checks - // SAFETY: `assume` calls are safe since a slice's start pointer must be non-null, - // and slices over non-ZSTs must also have a non-null end pointer. - // The call to `next_back_unchecked!` is safe since we check if the iterator is - // empty first. + // SAFETY: `assume` call is safe because slices over non-ZSTs must + // have a non-null end pointer. The call to `next_back_unchecked!` + // is safe since we check if the iterator is empty first. unsafe { - assume(!self.ptr.as_ptr().is_null()); if !::IS_ZST { assume(!self.end.is_null()); } diff --git a/tests/codegen/slice-iter-nonnull.rs b/tests/codegen/slice-iter-nonnull.rs new file mode 100644 index 0000000000000..392e433807640 --- /dev/null +++ b/tests/codegen/slice-iter-nonnull.rs @@ -0,0 +1,42 @@ +// no-system-llvm +// compile-flags: -O +// ignore-debug (these add extra checks that make it hard to verify) +#![crate_type = "lib"] + +// The slice iterator used to `assume` that the `start` pointer was non-null. +// That ought to be unneeded, though, since the type is `NonNull`, so this test +// confirms that the appropriate metadata is included to denote that. + +// CHECK-LABEL: @slice_iter_next( +#[no_mangle] +pub fn slice_iter_next<'a>(it: &mut std::slice::Iter<'a, u32>) -> Option<&'a u32> { + // CHECK: %[[ENDP:.+]] = getelementptr{{.+}}ptr %it,{{.+}} 1 + // CHECK: %[[END:.+]] = load ptr, ptr %[[ENDP]] + // CHECK-SAME: !nonnull + // CHECK-SAME: !noundef + // CHECK: %[[START:.+]] = load ptr, ptr %it, + // CHECK-SAME: !nonnull + // CHECK-SAME: !noundef + // CHECK: icmp eq ptr %[[START]], %[[END]] + + // CHECK: store ptr{{.+}}, ptr %it, + + it.next() +} + +// CHECK-LABEL: @slice_iter_next_back( +#[no_mangle] +pub fn slice_iter_next_back<'a>(it: &mut std::slice::Iter<'a, u32>) -> Option<&'a u32> { + // CHECK: %[[ENDP:.+]] = getelementptr{{.+}}ptr %it,{{.+}} 1 + // CHECK: %[[END:.+]] = load ptr, ptr %[[ENDP]] + // CHECK-SAME: !nonnull + // CHECK-SAME: !noundef + // CHECK: %[[START:.+]] = load ptr, ptr %it, + // CHECK-SAME: !nonnull + // CHECK-SAME: !noundef + // CHECK: icmp eq ptr %[[START]], %[[END]] + + // CHECK: store ptr{{.+}}, ptr %[[ENDP]], + + it.next_back() +}