`#[vm::pyclass]` / `#[vm::pymethod]` causes infinite loop in macro expansion

Đang mở
#8,097 0 bình luận 1 reaction 2 người được giao Xem trên GitHub

@youknowone đang làm issue này rồi.

Từ ngày 13/6/2026.

Đánh giá

Issue này chưa được đánh giá.

Mô tả

C-bug

Summary

cargo check hangs indefinitely — no error, just a rustc process pegged at 100% CPU —
when any #[pyclass] or #[pymethod] attribute is written with a path prefix such as
#[vm::pymethod].

Affected: rustpython-derive-impl 0.5.0 on rustc 1.96.0 / aarch64-apple-darwin

Root cause

attrs_to_content_items (crates/derive-impl/src/pyclass.rs ~line 1986) scans the
attribute list of each impl item with a Peekable iterator. peek() reads the current
element without advancing; only next() moves forward. The loop places iter.next()
after an early continue, so it is skipped whenever get_ident() returns None:

while let Some((_, attr)) = iter.peek() {
    let attr_name = if let Some(ident) = attr.get_ident() {
        ident.to_string()
    } else {
        continue;   // ← iter.next() skipped; same attribute peeked forever
    };
    // ...
    iter.next();    // ← never reached when get_ident() returns None
}

syn::Attribute::get_ident() only returns Some(name) for single-word attribute names
like pymethod. For a prefixed name like vm::pymethod it returns None, because
vm::pymethod is two path segments, not one. That None triggers continue, the
iterator never advances, and the loop spins forever.

Writing #[pymethod] (no prefix) works fine because get_ident() returns
Some("pymethod"), which hits the break in ALL_ALLOWED_NAMES.

Minimal reproduction

Cargo.toml:

[package]
name = "reproduce-pyclass-hang"
version = "0.1.0"
edition = "2021"

[dependencies]
rustpython-vm = { version = "0.5", default-features = false, features = ["compiler", "gc"] }

src/lib.rs:

use rustpython_vm as vm;

#[derive(Debug, vm::PyPayload)]
struct Item { value: i64 }

#[vm::pyclass]
impl Item {
    #[vm::pymethod]         // ← qualified path triggers the hang
    fn value(&self) -> i64 { self.value }
}

Run cargo checkrustc pegs a CPU core indefinitely with no output.

Fix

Move iter.next() outside the if let so it always fires, even when get_ident()
returns None. Unrecognised attribute paths are then simply skipped over.

// crates/derive-impl/src/pyclass.rs  (~line 1986)
while let Some((_, attr)) = iter.peek() {
    // Wrap in if-let so multi-segment paths (e.g. vm::pymethod) that return
    // None from get_ident() are skipped instead of looping forever.
    if let Some(ident) = attr.get_ident() {
        let attr_name = ident.to_string();
        if attr_name == "cfg" {
            cfgs.push(attr.clone());
        } else if ALL_ALLOWED_NAMES.contains(&attr_name.as_str()) {
            break;
        }
    }
    iter.next();
}
Ngôn ngữ chính
Rust
Star
22.4k
Fork
1.5k
Merge trung bình
15 giờ 18 phút
Pull request đã merge (30 ngày)
172

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của RustPython/RustPython

Tất cả issue của RustPython/RustPython

Issue tương tự

Thêm issue về Rust

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.