Skip to content

Commit ace204a

Browse files
committed
auto merge of #12349 : edwardw/rust/debug-expansion, r=huonw
Currently, the format_args! macro and its downstream macros in turn expand to series of let statements, one for each of its arguments, and then the invocation of the macro function. If one or more of the arguments are RefCell's, the enclosing statement for the temporary of the let is the let itself, which leads to scope problem. This patch changes let's to a match expression. Closes #12239.
2 parents 99f8380 + 111e092 commit ace204a

File tree

6 files changed

+65
-13
lines changed

6 files changed

+65
-13
lines changed

src/librustc/middle/ty.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4142,7 +4142,7 @@ pub fn enum_variants(cx: ctxt, id: ast::DefId) -> @~[@VariantInfo] {
41424142
.span_err(e.span,
41434143
format!("expected \
41444144
constant: {}",
4145-
(*err)));
4145+
*err));
41464146
}
41474147
},
41484148
None => {}

src/librustc/middle/typeck/check/method.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1303,15 +1303,15 @@ impl<'a> LookupContext<'a> {
13031303
self.tcx().sess.span_note(
13041304
span,
13051305
format!("candidate \\#{} is `{}`",
1306-
(idx+1u),
1306+
idx+1u,
13071307
ty::item_path_str(self.tcx(), did)));
13081308
}
13091309

13101310
fn report_param_candidate(&self, idx: uint, did: DefId) {
13111311
self.tcx().sess.span_note(
13121312
self.expr.span,
13131313
format!("candidate \\#{} derives from the bound `{}`",
1314-
(idx+1u),
1314+
idx+1u,
13151315
ty::item_path_str(self.tcx(), did)));
13161316
}
13171317

@@ -1320,7 +1320,7 @@ impl<'a> LookupContext<'a> {
13201320
self.expr.span,
13211321
format!("candidate \\#{} derives from the type of the receiver, \
13221322
which is the trait `{}`",
1323-
(idx+1u),
1323+
idx+1u,
13241324
ty::item_path_str(self.tcx(), did)));
13251325
}
13261326

src/librustc/middle/typeck/check/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3551,7 +3551,7 @@ pub fn check_enum_variants(ccx: @CrateCtxt,
35513551
ccx.tcx.sess.span_err(e.span, "expected signed integer constant");
35523552
}
35533553
Err(ref err) => {
3554-
ccx.tcx.sess.span_err(e.span, format!("expected constant: {}", (*err)));
3554+
ccx.tcx.sess.span_err(e.span, format!("expected constant: {}", *err));
35553555
}
35563556
}
35573557
},

src/librustc/util/ppaux.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,11 @@ pub fn note_and_explain_region(cx: ctxt,
4949
(ref str, Some(span)) => {
5050
cx.sess.span_note(
5151
span,
52-
format!("{}{}{}", prefix, (*str), suffix));
52+
format!("{}{}{}", prefix, *str, suffix));
5353
}
5454
(ref str, None) => {
5555
cx.sess.note(
56-
format!("{}{}{}", prefix, (*str), suffix));
56+
format!("{}{}{}", prefix, *str, suffix));
5757
}
5858
}
5959
}

src/libsyntax/ext/format.rs

+40-6
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,8 @@ impl<'a> Context<'a> {
607607
let mut lets = ~[];
608608
let mut locals = ~[];
609609
let mut names = vec::from_fn(self.name_positions.len(), |_| None);
610+
let mut pats = ~[];
611+
let mut heads = ~[];
610612

611613
// First, declare all of our methods that are statics
612614
for &method in self.method_statics.iter() {
@@ -653,8 +655,8 @@ impl<'a> Context<'a> {
653655
if self.arg_types[i].is_none() { continue } // error already generated
654656

655657
let name = self.ecx.ident_of(format!("__arg{}", i));
656-
let e = self.ecx.expr_addr_of(e.span, e);
657-
lets.push(self.ecx.stmt_let(e.span, false, name, e));
658+
pats.push(self.ecx.pat_ident(e.span, name));
659+
heads.push(self.ecx.expr_addr_of(e.span, e));
658660
locals.push(self.format_arg(e.span, Exact(i),
659661
self.ecx.expr_ident(e.span, name)));
660662
}
@@ -664,8 +666,8 @@ impl<'a> Context<'a> {
664666
}
665667

666668
let lname = self.ecx.ident_of(format!("__arg{}", *name));
667-
let e = self.ecx.expr_addr_of(e.span, e);
668-
lets.push(self.ecx.stmt_let(e.span, false, lname, e));
669+
pats.push(self.ecx.pat_ident(e.span, lname));
670+
heads.push(self.ecx.expr_addr_of(e.span, e));
669671
names[*self.name_positions.get(name)] =
670672
Some(self.format_arg(e.span,
671673
Named((*name).clone()),
@@ -706,8 +708,40 @@ impl<'a> Context<'a> {
706708
let res = self.ecx.expr_ident(self.fmtsp, resname);
707709
let result = self.ecx.expr_call(extra.span, extra, ~[
708710
self.ecx.expr_addr_of(extra.span, res)]);
709-
self.ecx.expr_block(self.ecx.block(self.fmtsp, lets,
710-
Some(result)))
711+
let body = self.ecx.expr_block(self.ecx.block(self.fmtsp, lets,
712+
Some(result)));
713+
714+
// Constructs an AST equivalent to:
715+
//
716+
// match (&arg0, &arg1) {
717+
// (tmp0, tmp1) => body
718+
// }
719+
//
720+
// It was:
721+
//
722+
// let tmp0 = &arg0;
723+
// let tmp1 = &arg1;
724+
// body
725+
//
726+
// Because of #11585 the new temporary lifetime rule, the enclosing
727+
// statements for these temporaries become the let's themselves.
728+
// If one or more of them are RefCell's, RefCell borrow() will also
729+
// end there; they don't last long enough for body to use them. The
730+
// match expression solves the scope problem.
731+
//
732+
// Note, it may also very well be transformed to:
733+
//
734+
// match arg0 {
735+
// ref tmp0 => {
736+
// match arg1 => {
737+
// ref tmp1 => body } } }
738+
//
739+
// But the nested match expression is proved to perform not as well
740+
// as series of let's; the first approach does.
741+
let pat = self.ecx.pat(self.fmtsp, ast::PatTup(pats));
742+
let arm = self.ecx.arm(self.fmtsp, ~[pat], body);
743+
let head = self.ecx.expr(self.fmtsp, ast::ExprTup(heads));
744+
self.ecx.expr_match(self.fmtsp, head, ~[arm])
711745
}
712746

713747
fn format_arg(&self, sp: Span, argno: Position, arg: @ast::Expr)

src/test/run-pass/format-ref-cell.rs

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::cell::RefCell;
12+
13+
pub fn main() {
14+
let name = RefCell::new("rust");
15+
let what = RefCell::new("rocks");
16+
let msg = format!("{name:?} {:?}", what.borrow().get(), name=name.borrow().get());
17+
assert_eq!(msg, ~"&\"rust\" &\"rocks\"");
18+
}

0 commit comments

Comments
 (0)