Skip to content

Incorrect linked_list::CursorMut::pop_front behavior: Index Is Not Updated as Expected #147616

@daddinuz

Description

@daddinuz

When using linked_list::CursorMut, calling pop_front while the cursor is positioned at the front node does not update the index correctly. After popping the front element, I expect the index to reflect the new position of the current element, but instead it remains unchanged or becomes inconsistent.

example 1

#![feature(linked_list_cursors)]

use std::collections::LinkedList;

fn main() {
    let mut l = LinkedList::from_iter([0, 1, 2]);
    let mut c = l.cursor_front_mut();
    
    c.move_next();
    println!("index: {:?} current: {:?}", c.index(), c.current()); // index: Some(1), current: Some(1)
    
    // index is decremented since we removed an item before the current one
    c.pop_front();
    println!("index: {:?} current: {:?}", c.index(), c.current()); // index: Some(0), current: Some(1)
    
    // Unexpected behavior: current is at the front, but index is incremented
    c.pop_front();
    println!("index: {:?} current: {:?}", c.index(), c.current()); // index: Some(1), current: Some(2), but expected index: Some(0)
}

minimal reproduction

#![feature(linked_list_cursors)]

use std::collections::LinkedList;

fn main() {
    let mut l = LinkedList::from_iter([0, 1]);
    let mut c = l.cursor_front_mut();

    println!("index: {:?} current: {:?}", c.index(), c.current()); // index: Some(0), current: Some(0)

    // Unexpected behavior: after removing the front (which is also current), index goes at 1
    c.pop_front();
    println!("index: {:?} current: {:?}", c.index(), c.current()); // index: Some(1), current: Some(1), but expected index: Some(0)
}

link to playground: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2024&gist=aa3317b89922e9ed623525807c8b90c2

Expected Behavior

When popping the front element and the cursor's current element becomes the new front, index() should return Some(0).

Current Behavior

index() returns a wrong index value (Some(1) in these examples), which is misleading because the cursor is now logically positioned at the new front.

Meta

rustc +nightly --version --verbose:

rustc 1.92.0-nightly (be0ade2b6 2025-10-11)
binary: rustc
commit-hash: be0ade2b602bdfe37a3cc259fcc79e8624dcba94
commit-date: 2025-10-11
host: x86_64-unknown-linux-gnu
release: 1.92.0-nightly
LLVM version: 21.1.2

Proposed Change

The current code: https://github.com/rust-lang/rust/blob/ff6dc928c5e33ce8e65c6911a790b9efcb5ef53a/library/alloc/src/collections/linked_list.rs#L1845C5-L1864C6

My change proposal:

#[unstable(feature = "linked_list_cursors", issue = "58533")]
    pub fn pop_front(&mut self) -> Option<T> {
        // We can't check if current is empty, we must check the list directly.
        // It is possible for `self.current == None` and the list to be
        // non-empty.
        if self.list.is_empty() {
            None
        } else {
            // We can't point to the node that we pop. Copying the behavior of
            // `remove_current`, we move on to the next node in the sequence.
            // If the list is of length 1 then we end pointing to the "ghost"
            // node at index 0, which is expected.
            if self.list.head == self.current {
                self.move_next();
            }

            self.index = self.index.saturating_sub(1);
            self.list.pop_front()
        }
    }

If this issue makes sense and the expected behavior above is correct, I’d be happy to open a pull request with the fix.

Thank you for the amazing work you all do on Rust

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.T-libsRelevant to the library team, which will review and decide on the PR/issue.needs-triageThis issue may need triage. Remove it if it has been sufficiently triaged.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions