From 1da334e15cc1ee442f34cf47a1bf7beff0b0ea0b Mon Sep 17 00:00:00 2001 From: Yilin Chen <1479826151@qq.com> Date: Mon, 26 Oct 2026 10:32:22 +0800 Subject: [PATCH] Remove ignore-unsafe tidy check in alloc/linklist --- library/alloc/src/collections/linked_list.rs | 156 ++++++++++++++----- 1 file changed, 115 insertions(+), 41 deletions(-) diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index 1d0cfa59d04fa..bb6c5db0f374b 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -168,8 +168,8 @@ impl LinkedList { /// Adds the given node to the front of the list. /// /// # Safety - /// `node` must point to a valid node in the list's allocator. - /// This method takes ownership of the node, so the pointer should not be used again. + /// + /// `node` must point to a valid owned node in the list's allocator. #[inline] unsafe fn push_front_node(&mut self, node: NonNull>) { // SAFETY: This method takes care not to create mutable references to @@ -213,8 +213,8 @@ impl LinkedList { /// Adds the given node to the back of the list. /// /// # Safety - /// `node` must point to a valid node in the list's allocator. - /// This method takes ownership of the node, so the pointer should not be used again. + /// + /// `node` must point to a valid owned node in the list's allocator. #[inline] unsafe fn push_back_node(&mut self, node: NonNull>) { // SAFETY: This method takes care not to create mutable references to @@ -257,10 +257,12 @@ impl LinkedList { /// Unlinks the specified node from the current list. /// - /// Warning: this will not check that the provided node belongs to the current list. - /// /// This method takes care not to create mutable references to `element`, to /// maintain validity of aliasing pointers. + /// + /// # Safety + /// + /// The provided node must belong to the current list. #[inline] unsafe fn unlink_node(&mut self, mut node: NonNull>) { // SAFETY: This is ours now, we can create a &mut. @@ -268,14 +270,14 @@ impl LinkedList { // Not creating new mutable (unique!) references overlapping `element`. match node.prev { - // ignore-tidy-undocumented-unsafe + // SAFETY: `prev` is a live node in this list. Some(prev) => unsafe { (*prev.as_ptr()).next = node.next }, // this node is the head node None => self.head = node.next, }; match node.next { - // ignore-tidy-undocumented-unsafe + // SAFETY: `next` is a live node in this list. Some(next) => unsafe { (*next.as_ptr()).prev = node.prev }, // this node is the tail node None => self.tail = node.prev, @@ -286,7 +288,14 @@ impl LinkedList { /// Splices a series of nodes between two existing nodes. /// - /// Warning: this will not check that the provided node belongs to the two existing lists. + /// # Safety + /// + /// * The provided nodes must belong to the two existing lists. + /// * `splice_length` must be exactly the number of nodes between `splice_start` and `splice_end`, inclusive. + /// * `splice_start` and `splice_end` must be in the same list, and `splice_start` must precede `splice_end`. + /// * If `existing_prev` is `None`, then `existing_next` must be the head node in `self`. + /// If `existing_next` is `None`, then `existing_prev` must be the end node in `self`. + /// In other case, `existing_prev` must be the predecessor of `existing_next` in `self`. #[inline] unsafe fn splice_nodes( &mut self, @@ -299,7 +308,7 @@ impl LinkedList { // This method takes care not to create multiple mutable references to whole nodes at the same time, // to maintain validity of aliasing pointers into `element`. if let Some(mut existing_prev) = existing_prev { - // ignore-tidy-undocumented-unsafe + // SAFETY: `existing_prev` points to a live node owned by `self`, which don't have any other mutable references. unsafe { existing_prev.as_mut().next = Some(splice_start); } @@ -307,14 +316,15 @@ impl LinkedList { self.head = Some(splice_start); } if let Some(mut existing_next) = existing_next { - // ignore-tidy-undocumented-unsafe + // SAFETY: `existing_next` points to a live node owned by `self`, which don't have any other mutable references. unsafe { existing_next.as_mut().prev = Some(splice_end); } } else { self.tail = Some(splice_end); } - // ignore-tidy-undocumented-unsafe + // SAFETY: This method takes care not to create multiple mutable references to whole nodes at the same time, + // to maintain validity of aliasing pointers into `element`. unsafe { splice_start.as_mut().prev = existing_prev; splice_end.as_mut().next = existing_next; @@ -340,6 +350,16 @@ impl LinkedList { } } + /// Splits this list before `split_node`. + /// + /// `self` retains `split_node` and all nodes after it, while the returned list contains all + /// nodes before `split_node`. If `split_node` is `None`, all nodes are moved into the returned + /// list and `self` is left empty. + /// + /// # Safety + /// + /// * If `split_node` is `Some`, it must point to a node in `self`. + /// * If `split_node` is `Some`, `at` must equal its zero-based index in `self`. #[inline] unsafe fn split_off_before_node( &mut self, @@ -353,12 +373,12 @@ impl LinkedList { if let Some(mut split_node) = split_node { let first_part_head; let first_part_tail; - // ignore-tidy-undocumented-unsafe + // SAFETY: `split_node` points to a live node in `self`, which don't have any other mutable references. unsafe { first_part_tail = split_node.as_mut().prev.take(); } if let Some(mut tail) = first_part_tail { - // ignore-tidy-undocumented-unsafe + // SAFETY: `tail` is the live predecessor of `split_node`, which don't have any other mutable references. unsafe { tail.as_mut().next = None; } @@ -385,6 +405,16 @@ impl LinkedList { } } + /// Splits this list after `split_node`. + /// + /// `self` retains `split_node` and all nodes before it, while the returned list contains all + /// nodes after `split_node`. If `split_node` is `None`, all nodes are moved into the returned + /// list and `self` is left empty. + /// + /// # Safety + /// + /// * If `split_node` is `Some`, it must point to a node in `self`. + /// * If `split_node` is `Some`, `at` must equal its zero-based index in `self` plus one. #[inline] unsafe fn split_off_after_node( &mut self, @@ -399,12 +429,12 @@ impl LinkedList { if let Some(mut split_node) = split_node { let second_part_head; let second_part_tail; - // ignore-tidy-undocumented-unsafe + // SAFETY: `split_node` points to a live node in `self`, which don't have any other mutable references. unsafe { second_part_head = split_node.as_mut().next.take(); } if let Some(mut head) = second_part_head { - // ignore-tidy-undocumented-unsafe + // SAFETY: `head` is the live successor of `split_node`, which don't have any other mutable references. unsafe { head.as_mut().prev = None; } @@ -755,7 +785,7 @@ impl LinkedList { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_confusables("first")] pub fn front(&self) -> Option<&T> { - // ignore-tidy-undocumented-unsafe + // SAFETY: `self` is immutable borrowed, so the head node can be immutable borrowed as well. unsafe { self.head.as_ref().map(|node| &node.as_ref().element) } } @@ -785,7 +815,7 @@ impl LinkedList { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] pub fn front_mut(&mut self) -> Option<&mut T> { - // ignore-tidy-undocumented-unsafe + // SAFETY: `self` is mutable borrowed, so the head node can be mutable borrowed as well. unsafe { self.head.as_mut().map(|node| &mut node.as_mut().element) } } @@ -809,7 +839,7 @@ impl LinkedList { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] pub fn back(&self) -> Option<&T> { - // ignore-tidy-undocumented-unsafe + // SAFETY: `self` is immutable borrowed, so the tail node can be immutable borrowed as well. unsafe { self.tail.as_ref().map(|node| &node.as_ref().element) } } @@ -838,7 +868,7 @@ impl LinkedList { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn back_mut(&mut self) -> Option<&mut T> { - // ignore-tidy-undocumented-unsafe + // SAFETY: `self` is mutable borrowed, so the tail node can be mutable borrowed as well. unsafe { self.tail.as_mut().map(|node| &mut node.as_mut().element) } } @@ -1040,7 +1070,7 @@ impl LinkedList { } iter.tail }; - // ignore-tidy-undocumented-unsafe + // SAFETY: `split_node` is a valid node in `self`, and `at` is `index_of(split_node) + 1`. unsafe { self.split_off_after_node(split_node, at) } } @@ -1444,7 +1474,7 @@ impl<'a, T, A: Allocator> Cursor<'a, T, A> { self.index = 0; } // We had a previous element, so let's go to its next - // ignore-tidy-undocumented-unsafe + // SAFETY: `current` is a pointer to a live node in `list`, which don't have mutable reference. Some(current) => unsafe { self.current = current.as_ref().next; self.index += 1; @@ -1466,7 +1496,7 @@ impl<'a, T, A: Allocator> Cursor<'a, T, A> { self.index = self.list.len().saturating_sub(1); } // Have a prev. Yield it and go to the previous element. - // ignore-tidy-undocumented-unsafe + // SAFETY: `current` is a pointer to a live node in `list`, which don't have mutable reference. Some(current) => unsafe { self.current = current.as_ref().prev; self.index = self.index.checked_sub(1).unwrap_or_else(|| self.list.len()); @@ -1482,7 +1512,7 @@ impl<'a, T, A: Allocator> Cursor<'a, T, A> { #[must_use] #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn current(&self) -> Option<&'a T> { - // ignore-tidy-undocumented-unsafe + // SAFETY: If `self.current` is `Some`, then `current` is a pointer to a live node in `list`. unsafe { self.current.map(|current| &(*current.as_ptr()).element) } } @@ -1494,7 +1524,9 @@ impl<'a, T, A: Allocator> Cursor<'a, T, A> { #[must_use] #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn peek_next(&self) -> Option<&'a T> { - // ignore-tidy-undocumented-unsafe + // SAFETY: If `self.current` is `Some`, then `current` is a pointer to a live node in `list`, + // and `current` does not have mutable reference. + // If `next` is `Some`, then we can get inner pointer which points at a live node in `list`. unsafe { let next = match self.current { None => self.list.head, @@ -1512,7 +1544,9 @@ impl<'a, T, A: Allocator> Cursor<'a, T, A> { #[must_use] #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn peek_prev(&self) -> Option<&'a T> { - // ignore-tidy-undocumented-unsafe + // SAFETY: If `self.current` is `Some`, then `current` is a pointer to a live node in `list`, + // and `current` does not have mutable reference. + // If `prev` is `Some`, then we can get inner pointer which points at a live node in `list`. unsafe { let prev = match self.current { None => self.list.tail, @@ -1576,7 +1610,7 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> { self.index = 0; } // We had a previous element, so let's go to its next - // ignore-tidy-undocumented-unsafe + // SAFETY: `current` is a pointer to a live node in `list`, which don't have mutable reference. Some(current) => unsafe { self.current = current.as_ref().next; self.index += 1; @@ -1598,7 +1632,7 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> { self.index = self.list.len().saturating_sub(1); } // Have a prev. Yield it and go to the previous element. - // ignore-tidy-undocumented-unsafe + // SAFETY: `current` is a pointer to a live node in `list`, which don't have mutable reference. Some(current) => unsafe { self.current = current.as_ref().prev; self.index = self.index.checked_sub(1).unwrap_or_else(|| self.list.len()); @@ -1614,7 +1648,7 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> { #[must_use] #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn current(&mut self) -> Option<&mut T> { - // ignore-tidy-undocumented-unsafe + // SAFETY: If `self.current` is `Some`, then `current` is a pointer to a live node in `list`. unsafe { self.current.map(|current| &mut (*current.as_ptr()).element) } } @@ -1625,7 +1659,9 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> { /// element of the `LinkedList` then this returns `None`. #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn peek_next(&mut self) -> Option<&mut T> { - // ignore-tidy-undocumented-unsafe + // SAFETY: If `self.current` is `Some`, then `current` is a pointer to a live node in `list`, + // and `current` does not have mutable reference. + // If `next` is `Some`, then we can get inner pointer which points at a live node in `list`. unsafe { let next = match self.current { None => self.list.head, @@ -1642,7 +1678,9 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> { /// element of the `LinkedList` then this returns `None`. #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn peek_prev(&mut self) -> Option<&mut T> { - // ignore-tidy-undocumented-unsafe + // SAFETY: If `self.current` is `Some`, then `current` is a pointer to a live node in `list`, + // and `current` does not have mutable reference. + // If `prev` is `Some`, then we can get inner pointer which points at a live node in `list`. unsafe { let prev = match self.current { None => self.list.tail, @@ -1688,7 +1726,15 @@ impl<'a, T> CursorMut<'a, T> { let Some((splice_head, splice_tail, splice_len)) = list.detach_all_nodes() else { return; }; - // ignore-tidy-undocumented-unsafe + // SAFETY: + // * If `self.current` is `Some`, then `node` is a pointer to a live node in `list` + // and don't have mutable reference. + // * `self.current` (possible `None`) and `node_next` belong to `self.list`, + // while `splice_head` and `splice_tail` belong to `list`. + // * `splice_len` is the length of the new nodes to be spliced in. + // * `splice_head` and `splice_tail` are the head and tail of the new nodes to be spliced in. + // * If `self.current` is `None`, then `node_next` is the head of the list. + // If `self.current` is `Some`, then `node_next` is the next node after `self.current`. unsafe { let node_next = match self.current { None => self.list.head, @@ -1712,7 +1758,15 @@ impl<'a, T> CursorMut<'a, T> { Some(parts) => parts, _ => return, }; - // ignore-tidy-undocumented-unsafe + // SAFETY: + // * If `self.current` is `Some`, then `node` is a pointer to a live node in `list` + // and don't have mutable reference. + // * `self.current` (possible `None`) and `node_prev` belong to `self.list`, + // while `splice_head` and `splice_tail` belong to `list`. + // * `splice_len` is the length of the new nodes to be spliced in. + // * `splice_head` and `splice_tail` are the head and tail of the new nodes to be spliced in. + // * If `self.current` is `None`, then `node_prev` is the tail of the list. + // If `self.current` is `Some`, then `node_prev` is the previous node before `self.current`. unsafe { let node_prev = match self.current { None => self.list.tail, @@ -1733,7 +1787,15 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> { pub fn insert_after(&mut self, item: T) { let spliced_node = Box::into_non_null_with_allocator(Box::new_in(Node::new(item), &self.list.alloc)).0; - // ignore-tidy-undocumented-unsafe + // SAFETY: + // * If `self.current` is `Some`, then `node` is a pointer to a live node in `list` + // and don't have mutable reference. + // * `self.current` (possible `None`) and `node_next` belong to `self.list`, + // while `spliced_node` does not belong to any list. + // * This method only inserts one node, so `spliced_node` is both the head and tail of the new nodes to be spliced in. + // * The length of the new nodes to be spliced in is 1. + // * If `self.current` is `None`, then `node_next` is the head of the list. + // If `self.current` is `Some`, then `node_next` is the next node after `self.current`. unsafe { let node_next = match self.current { None => self.list.head, @@ -1755,7 +1817,15 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> { pub fn insert_before(&mut self, item: T) { let spliced_node = Box::into_non_null_with_allocator(Box::new_in(Node::new(item), &self.list.alloc)).0; - // ignore-tidy-undocumented-unsafe + // SAFETY: + // * If `self.current` is `Some`, then `node` is a pointer to a live node in `list` + // and don't have mutable reference. + // * `self.current` (possible `None`) and `node_prev` belong to `self.list`, + // while `spliced_node` does not belong to any list. + // * This method only inserts one node, so `spliced_node` is both the head and tail of the new nodes to be spliced in. + // * The length of the new nodes to be spliced in is 1. + // * If `self.current` is `None`, then `node_prev` is the tail of the list. + // If `self.current` is `Some`, then `node_prev` is the previous node before `self.current`. unsafe { let node_prev = match self.current { None => self.list.tail, @@ -1776,7 +1846,8 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> { #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn remove_current(&mut self) -> Option { let unlinked_node = self.current?; - // ignore-tidy-undocumented-unsafe + // SAFETY: `unlinked_node` is a pointer to a live node owned by `self.list`. + // It is safe to unlink it and construct a `Box` from it. unsafe { self.current = unlinked_node.as_ref().next; self.list.unlink_node(unlinked_node); @@ -1798,7 +1869,8 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> { A: AllocatorClone, { let mut unlinked_node = self.current?; - // ignore-tidy-undocumented-unsafe + // SAFETY: `unlinked_node` is a pointer to a live node owned by `self.list`. + // It is safe to unlink it. Also, `unlinked_node` does not have any mutable reference. unsafe { self.current = unlinked_node.as_ref().next; self.list.unlink_node(unlinked_node); @@ -1831,7 +1903,8 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> { // The "ghost" non-element's index has changed to 0. self.index = 0; } - // ignore-tidy-undocumented-unsafe + // SAFETY: If `self.current` is `Some`, it contains a pointer to a live node in `list`, + // and `split_off_idx` is `self.index + 1`. unsafe { self.list.split_off_after_node(self.current, split_off_idx) } } @@ -1848,7 +1921,8 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> { { let split_off_idx = self.index; self.index = 0; - // ignore-tidy-undocumented-unsafe + // SAFETY: If `self.current` is `Some`, it contains a pointer to a live node in `list`, + // and `split_off_idx` is the index of `self.current`. unsafe { self.list.split_off_before_node(self.current, split_off_idx) } } @@ -2020,7 +2094,7 @@ where fn next(&mut self) -> Option { while let Some(mut node) = self.it { - // ignore-tidy-undocumented-unsafe + // SAFETY: `node` is a pointer to a live node in `list`, which don't have mutable reference. unsafe { self.it = node.as_ref().next; self.idx += 1; @@ -2048,7 +2122,7 @@ where A: Allocator, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // ignore-tidy-undocumented-unsafe + // SAFETY: If `node` is `Some`, then `node` is a pointer to a live node in `list`. let peek = self.it.map(|node| unsafe { &node.as_ref().element }); f.debug_struct("ExtractIf").field("peek", &peek).finish_non_exhaustive() }