mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-22 13:34:47 +00:00
9b6339e4b9
Add `debug-refcell` feature to libcore See https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Attaching.20backtraces.20to.20RefCell/near/226273614 for some background discussion This PR adds a new off-by-default feature `debug-refcell` to libcore. When enabled, this feature stores additional debugging information in `RefCell`. This information is included in the panic message when `borrow()` or `borrow_mut()` panics, to make it easier to track down the source of the issue. Currently, we store the caller location for the earliest active borrow. This has a number of advantages: * There is only a constant amount of overhead per `RefCell` * We don't need any heap memory, so it can easily be implemented in core * Since we are storing the *earliest* active borrow, we don't need any extra logic in the `Drop` implementation for `Ref` and `RefMut` Limitations: * We only store the caller location, not a full `Backtrace`. Until we get support for `Backtrace` in libcore, this is the best tha we can do. * The captured location is only displayed when `borrow()` or `borrow_mut()` panics. If a crate calls `try_borrow().unwrap()` or `try_borrow_mut().unwrap()`, this extra information will be lost. To make testing easier, I've enabled the `debug-refcell` feature by default. I'm not sure how to write a test for this feature - we would need to rebuild core from the test framework, and create a separate sysroot. Since this feature will be off-by-default, users will need to use `xargo` or `cargo -Z build-std` to enable this feature. For users using a prebuilt standard library, this feature will be disabled with zero overhead. I've created a simple test program: ```rust use std::cell::RefCell; fn main() { let _ = std::panic::catch_unwind(|| { let val = RefCell::new(true); let _first = val.borrow(); let _second = val.borrow(); let _third = val.borrow_mut(); }); let _ = std::panic::catch_unwind(|| { let val = RefCell::new(true); let first = val.borrow_mut(); drop(first); let _second = val.borrow_mut(); let _thid = val.borrow(); }); } ``` which produces the following output: ``` thread 'main' panicked at 'already borrowed: BorrowMutError at refcell_test.rs:6:26', refcell_test.rs:8:26 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace thread 'main' panicked at 'already mutably borrowed: BorrowError at refcell_test.rs:16:27', refcell_test.rs:18:25 ```
34 lines
693 B
TOML
34 lines
693 B
TOML
[package]
|
|
authors = ["The Rust Project Developers"]
|
|
name = "core"
|
|
version = "0.0.0"
|
|
license = "MIT OR Apache-2.0"
|
|
repository = "https://github.com/rust-lang/rust.git"
|
|
description = "The Rust Core Library"
|
|
autotests = false
|
|
autobenches = false
|
|
edition = "2018"
|
|
|
|
[lib]
|
|
test = false
|
|
bench = false
|
|
|
|
[[test]]
|
|
name = "coretests"
|
|
path = "tests/lib.rs"
|
|
|
|
[[bench]]
|
|
name = "corebenches"
|
|
path = "benches/lib.rs"
|
|
test = true
|
|
|
|
[dev-dependencies]
|
|
rand = "0.7"
|
|
|
|
[features]
|
|
# Make panics and failed asserts immediately abort without formatting any message
|
|
panic_immediate_abort = []
|
|
# Make `RefCell` store additional debugging information, which is printed out when
|
|
# a borrow error occurs
|
|
debug_refcell = []
|