`#[vm::pyclass]` / `#[vm::pymethod]` causes infinite loop in macro expansion
@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ả
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 check — rustc 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
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- 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.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của RustPython/RustPython
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
RustPython/RustPython#8470 · 2 bình luận ·
-
C-bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
RustPython/RustPython#7995 · 5 bình luận ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
RustPython/RustPython#5577 ·
-
C-bug
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 68/100
RustPython/RustPython#8685 · 7 bình luận · 1 reaction ·
-
C-compat
RustPython/RustPython#8496 · 1 bình luận · 1 người được giao ·
Tất cả issue của RustPython/RustPython
Issue tương tự
-
Accept -c in more positions Đang mởarea: compat bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
-
area: dogs bug priority: P3 silent failure test-code
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 88/100
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 70/100
MystenLabs/sui#28056 · 1 bình luận ·
-
type/bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
Luminous-Dynamics/mycelix#2577 ·