Avoid evaluating dbg!() arguments in a closure.
The dbg!() macro should behave like a function call in how it evaluates
its arguments, and captures by Rust closures are not fully compatible
with path-specific borrowing. Specifically:
let borrow = &mut obj.foo;
dbg!("{}", obj.bar);
would fail because the closure inside dbg!() would borrow all of obj
instead of just obj.foo.
Fix this by using the format_args!() macro to evaluate the dbg!()
arguments and produce an fmt::Arguments object which can be safely
passed to the thread-local closure for printing.
The arguments are still evaluated inside an if { .. } which
constant-folds away in release builds.
This commit is contained in:
@@ -15,7 +15,7 @@ use std::env;
|
|||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Write, BufWriter};
|
use std::io::{self, Write};
|
||||||
use std::sync::atomic;
|
use std::sync::atomic;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
||||||
@@ -56,20 +56,18 @@ fn initialize() -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
thread_local! {
|
thread_local! {
|
||||||
static WRITER : RefCell<BufWriter<File>> = RefCell::new(open_file());
|
static WRITER : RefCell<io::BufWriter<File>> = RefCell::new(open_file());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute a closure with mutable access to the tracing file writer.
|
/// Write a line with the given format arguments.
|
||||||
///
|
///
|
||||||
/// This is for use by the `dbg!` macro.
|
/// This is for use by the `dbg!` macro.
|
||||||
pub fn with_writer<F, R>(f: F) -> R
|
pub fn writeln_with_format_args(args: fmt::Arguments) -> io::Result<()> {
|
||||||
where F: FnOnce(&mut Write) -> R
|
WRITER.with(|rc| writeln!(*rc.borrow_mut(), "{}", args))
|
||||||
{
|
|
||||||
WRITER.with(|rc| f(&mut *rc.borrow_mut()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Open the tracing file for the current thread.
|
/// Open the tracing file for the current thread.
|
||||||
fn open_file() -> BufWriter<File> {
|
fn open_file() -> io::BufWriter<File> {
|
||||||
let file = match thread::current().name() {
|
let file = match thread::current().name() {
|
||||||
None => File::create("cretonne.dbg"),
|
None => File::create("cretonne.dbg"),
|
||||||
Some(name) => {
|
Some(name) => {
|
||||||
@@ -83,7 +81,7 @@ fn open_file() -> BufWriter<File> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.expect("Can't open tracing file");
|
.expect("Can't open tracing file");
|
||||||
BufWriter::new(file)
|
io::BufWriter::new(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write a line to the debug trace file if tracing is enabled.
|
/// Write a line to the debug trace file if tracing is enabled.
|
||||||
@@ -95,7 +93,7 @@ macro_rules! dbg {
|
|||||||
if $crate::dbg::enabled() {
|
if $crate::dbg::enabled() {
|
||||||
// Drop the error result so we don't get compiler errors for ignoring it.
|
// Drop the error result so we don't get compiler errors for ignoring it.
|
||||||
// What are you going to do, log the error?
|
// What are you going to do, log the error?
|
||||||
$crate::dbg::with_writer(|w| { writeln!(w, $($arg)+).ok(); })
|
$crate::dbg::writeln_with_format_args(format_args!($($arg)+)).ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user