about summary refs log tree commit diff
path: root/src/libsyntax/ext
diff options
context:
space:
mode:
authorRyan Prichard <ryan.prichard@gmail.com>2015-04-03 01:27:04 -0700
committerRyan Prichard <ryan.prichard@gmail.com>2015-04-11 16:00:58 -0700
commit0f46e4f1f23368f4615a9847671e3a91b2ebaf18 (patch)
tree23795acb7872118fdbcce722b0448004d06be9cd /src/libsyntax/ext
parent6790b0e51967b1487728d155e0800a1ed03a30d3 (diff)
downloadrust-0f46e4f1f23368f4615a9847671e3a91b2ebaf18.tar.gz
rust-0f46e4f1f23368f4615a9847671e3a91b2ebaf18.zip
Propagate macro backtraces more often, improve formatting diagnostics
 * In noop_fold_expr, call new_span in these cases:
    - ExprMethodCall's identifier
    - ExprField's identifier
    - ExprTupField's integer

   Calling new_span for ExprMethodCall's identifier is necessary to print
   an acceptable diagnostic for write!(&2, ""). We see this error:

       <std macros>:2:20: 2:66 error: type `&mut _` does not implement any method in scope named `write_fmt`
       <std macros>:2 ( & mut * $ dst ) . write_fmt ( format_args ! ( $ ( $ arg ) * ) ) )
                                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

   With this change, we also see a macro expansion backtrace leading to
   the write!(&2, "") call site.

 * After fully expanding a macro, we replace the expansion expression's
   span with the original span. Call fld.new_span to add a backtrace to
   this span. (Note that I'm call new_span after bt.pop(), so the macro
   just expanded isn't on the backtrace.)

   The motivating example for this change is println!("{}"). The format
   string literal is concat!($fmt, "arg") and is inside the libstd macro.
   We need to see the backtrace to find the println! call site.

 * Add a backtrace to the format_args! format expression span.

Addresses #23459
Diffstat (limited to 'src/libsyntax/ext')
-rw-r--r--src/libsyntax/ext/expand.rs2
-rw-r--r--src/libsyntax/ext/format.rs8
2 files changed, 7 insertions, 3 deletions
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 5f4ec01791c..b65798b8a49 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -55,7 +55,7 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
             fully_expanded.map(|e| ast::Expr {
                 id: ast::DUMMY_NODE_ID,
                 node: e.node,
-                span: span,
+                span: fld.new_span(span),
             })
         }
 
diff --git a/src/libsyntax/ext/format.rs b/src/libsyntax/ext/format.rs
index 1d99a475b32..513bbf6c77b 100644
--- a/src/libsyntax/ext/format.rs
+++ b/src/libsyntax/ext/format.rs
@@ -17,6 +17,7 @@ use ext::base::*;
 use ext::base;
 use ext::build::AstBuilder;
 use fmt_macros as parse;
+use fold::Folder;
 use parse::token::special_idents;
 use parse::token;
 use ptr::P;
@@ -649,6 +650,10 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
                                     names: HashMap<String, P<ast::Expr>>)
                                     -> P<ast::Expr> {
     let arg_types: Vec<_> = (0..args.len()).map(|_| None).collect();
+    // Expand the format literal so that efmt.span will have a backtrace. This
+    // is essential for locating a bug when the format literal is generated in
+    // a macro. (e.g. println!("{}"), which uses concat!($fmt, "\n")).
+    let efmt = ecx.expander().fold_expr(efmt);
     let mut cx = Context {
         ecx: ecx,
         args: args,
@@ -663,9 +668,8 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
         pieces: Vec::new(),
         str_pieces: Vec::new(),
         all_pieces_simple: true,
-        fmtsp: sp,
+        fmtsp: efmt.span,
     };
-    cx.fmtsp = efmt.span;
     let fmt = match expr_to_string(cx.ecx,
                                    efmt,
                                    "format argument must be a string literal.") {