Skip to content

Minor tweaks to refcell logging #142216

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

nealsid
Copy link

@nealsid nealsid commented Jun 8, 2025

  • Fix the logging when debug_refcell is enabled so the location is output as a string rather than a sequence of bytes
  • Avoid logging an empty struct when debug_refcell is disabled
  • Make the panic error message consistent with the compiler borrow-checking error messages

@rustbot
Copy link
Collaborator

rustbot commented Jun 8, 2025

r? @tgross35

rustbot has assigned @tgross35.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jun 8, 2025
@tgross35
Copy link
Contributor

tgross35 commented Jun 9, 2025

Thank you for the PR!

The wording isn't quite accurate because panic_already_borrowed now says "...because it is also borrowed as immutable", but borrow_mut will also fail if there is an existing mutable borrow. The current messages aren't ideal either because

let cell = RefCell::new(0u32);
let b = (cell.borrow_mut(), cell.borrow_mut());
drop(b);

also prints "already borrowed: BorrowMutError" rather than the more accurate "already mutably borrowed: BorrowMutError", but it still works.

So I think the original wording of "already (mutably) borrowed (here: {err:?})" is probably fine to keep. We could alternatively add track mutably/immutably in the error type, but I don't expect that to be worth it since the # Panics API docs are pretty easy to locate (by comparison, with the rustc error it might not be as obvious that you are mutably/immutably borrowing because e.g. it's in a function signature).

Fix the logging when debug_refcell is enabled so the location is output as a string rather than a sequence of bytes

Mind commenting the before and after here? Location's debug should just print the file, line, and column.

@@ -787,16 +787,24 @@ impl Display for BorrowMutError {
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
#[track_caller]
#[cold]
fn panic_already_borrowed(err: BorrowMutError) -> ! {
panic!("already borrowed: {:?}", err)
fn panic_already_borrowed(_err: BorrowMutError) -> ! {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small nit, this can be _err -> err since it is used

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_err is used in one code path (when debug_refcell is enabled) but not the other, the reason being is that when debug_refcell is disabled, BorrowError/BorrowMutError are empty structs.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, but whether or not something gets used on all branches doesn't affect liveliness - one is enough. It would be different if the comptime #[cfg(...)] was used rather than the runtime cfg!() (semantically runtime at least, even though it's gone with the most basic optimizations) but there won't be any dead_code warnings here.

@tgross35
Copy link
Contributor

tgross35 commented Jun 9, 2025

@rustbot author for the above

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 9, 2025
@rustbot
Copy link
Collaborator

rustbot commented Jun 9, 2025

Reminder, once the PR becomes ready for a review, use @rustbot ready.

@nealsid
Copy link
Author

nealsid commented Jun 10, 2025

Fix the logging when debug_refcell is enabled so the location is output as a string rather than a sequence of bytes

Mind commenting the before and after here? Location's debug should just print the file, line, and column.

Location only implements Display, not Debug (link). Below is the output if you enable debug_refcell and cause a panic today:

     Running `target\debug\refcell-test.exe`
Hello, world! RefCell { value: 5 }

thread 'main' panicked at src\main.rs:11:15:
already borrowed: BorrowMutError { location: Location { file_bytes_with_nul: [115, 114, 99, 92, 109, 97, 105, 110, 46, 114, 115, 0], line: 8, col: 15 } }
stack backtrace:
   0: std::panicking::begin_panic_handler
             at C:\Users\neals\rust\library\std\src\panicking.rs:697
   1: core::panicking::panic_fmt
             at C:\Users\neals\rust\library\core\src\panicking.rs:75
   2: core::cell::panic_already_borrowed
             at C:\Users\neals\rust\library\core\src\cell.rs:791
   3: core::cell::RefCell<i32>::borrow_mut<i32>
             at C:\Users\neals\rust\library\core\src\cell.rs:1083
   4: refcell_test::main
             at .\src\main.rs:11
   5: core::ops::function::FnOnce::call_once<void (*)(),tuple$<> >
             at C:\Users\neals\rust\library\core\src\ops\function.rs:250
   6: core::hint::black_box
             at C:\Users\neals\rust\library\core\src\hint.rs:482
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
error: process didn't exit successfully: `target\debug\refcell-test.exe` (exit code: 101)
PS C:\Users\neals\refcell-test>

@nealsid
Copy link
Author

nealsid commented Jun 10, 2025

The panic output after my proposed change (I haven't reverted the first logging change yet, this is just meant to show the change in Location's output):

     Running `target\debug\refcell-test.exe`
Hello, world! RefCell { value: 5 }

thread 'main' panicked at src\main.rs:11:15:
cannot borrow as mutable because it is also borrowed as immutable here BorrowMutError { location: src\main.rs:8:15 }
stack backtrace:
   0: std::panicking::begin_panic_handler
             at C:\Users\neals\rust\library\std\src\panicking.rs:697
   1: core::panicking::panic_fmt
             at C:\Users\neals\rust\library\core\src\panicking.rs:75
   2: core::cell::panic_already_borrowed
             at C:\Users\neals\rust\library\core\src\cell.rs:792
   3: core::cell::RefCell<i32>::borrow_mut<i32>
             at C:\Users\neals\rust\library\core\src\cell.rs:1091
   4: refcell_test::main
             at .\src\main.rs:11
   5: core::ops::function::FnOnce::call_once<void (*)(),tuple$<> >
             at C:\Users\neals\rust\library\core\src\ops\function.rs:250
   6: core::hint::black_box
             at C:\Users\neals\rust\library\core\src\hint.rs:482
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
error: process didn't exit successfully: `target\debug\refcell-test.exe` (exit code: 101)
PS C:\Users\neals\refcell-test>

@nealsid
Copy link
Author

nealsid commented Jun 10, 2025

Thank you for the PR!

The wording isn't quite accurate because panic_already_borrowed now says "...because it is also borrowed as immutable", but borrow_mut will also fail if there is an existing mutable borrow. The current messages aren't ideal either because

let cell = RefCell::new(0u32);
let b = (cell.borrow_mut(), cell.borrow_mut());
drop(b);

also prints "already borrowed: BorrowMutError" rather than the more accurate "already mutably borrowed: BorrowMutError", but it still works.

So I think the original wording of "already (mutably) borrowed (here: {err:?})" is probably fine to keep. We could alternatively add track mutably/immutably in the error type, but I don't expect that to be worth it since the # Panics API docs are pretty easy to locate (by comparison, with the rustc error it might not be as obvious that you are mutably/immutably borrowing because e.g. it's in a function signature).

Sounds good, thanks! I'll revert that part of the logging.

Your example code made me think of another potential issue:

    let v = RefCell::new(5);
    let w = v.borrow();
    let y = v.borrow();
    drop(w);
    let x = v.borrow_mut();

In this case, the RefCell will track the location of the borrow for w (since it tracks the first borrow: link) and log that in the panic, although y is the conflicting borrow when borrow_mut() is called on the last line. Is that something that should be fixed?

@tgross35
Copy link
Contributor

Location only implements Display, not Debug (link). Below is the output if you enable debug_refcell and cause a panic today:

It does implement Debug via the derive, but you're right that it just prints the bag of bytes. Looks like this is a very recent regression #135054. We should fix the Debug implementation instead since that affects more than this, so you can actually drop the format_args!("{}", self.location) here.

Opened #142279 to track that.

In this case, the RefCell will track the location of the borrow for w (since it tracks the first borrow: link) and log that in the panic, although y is the conflicting borrow when borrow_mut() is called on the last line. Is that something that should be fixed?

It would be nice, but there isn't an easy way to do this is there? We would need to store multiple locations since we can't tell which will get released last, which would mean keeping some kind of location collection rather than just incrementing/decrementing the borrow count.

- Fix the logging when debug_refcell is enabled so the location is output as a string rather than a sequence of bytes
- Avoid logging an empty struct when debug_refcell is disabled
- Make the panic error message consistent with the compiler borrow-checking error messages
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants