Skip to content
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

Propagate macro backtraces more often, improve formatting diagnostics #24003

Merged
merged 5 commits into from
Apr 12, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/libsyntax/codemap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -871,7 +871,7 @@ impl CodeMap {
F: FnOnce(Option<&ExpnInfo>) -> T,
{
match id {
NO_EXPANSION => f(None),
NO_EXPANSION | COMMAND_LINE_EXPN => f(None),
ExpnId(i) => f(Some(&(*self.expansions.borrow())[i as usize]))
}
}
Expand Down
7 changes: 3 additions & 4 deletions src/libsyntax/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -465,22 +465,21 @@ fn emit(dst: &mut EmitterWriter, cm: &codemap::CodeMap, rsp: RenderSpan,
match rsp {
FullSpan(_) => {
try!(highlight_lines(dst, cm, sp, lvl, cm.span_to_lines(sp)));
try!(print_macro_backtrace(dst, cm, sp));
}
EndSpan(_) => {
try!(end_highlight_lines(dst, cm, sp, lvl, cm.span_to_lines(sp)));
try!(print_macro_backtrace(dst, cm, sp));
}
Suggestion(_, ref suggestion) => {
try!(highlight_suggestion(dst, cm, sp, suggestion));
try!(print_macro_backtrace(dst, cm, sp));
}
FileLine(..) => {
// no source text in this case!
}
}

if sp != COMMAND_LINE_SP {
try!(print_macro_backtrace(dst, cm, sp));
}

match code {
Some(code) =>
match dst.registry.as_ref().and_then(|registry| registry.find_description(code)) {
Expand Down
10 changes: 0 additions & 10 deletions src/libsyntax/ext/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,6 @@ impl<'a> ExtCtxt<'a> {
None => self.bug("missing top span")
})
}
pub fn print_backtrace(&self) { }
pub fn backtrace(&self) -> ExpnId { self.backtrace }
pub fn original_span(&self) -> Span {
let mut expn_id = self.backtrace;
Expand Down Expand Up @@ -700,7 +699,6 @@ impl<'a> ExtCtxt<'a> {
/// substitute; we never hit resolve/type-checking so the dummy
/// value doesn't have to match anything)
pub fn span_fatal(&self, sp: Span, msg: &str) -> ! {
self.print_backtrace();
panic!(self.parse_sess.span_diagnostic.span_fatal(sp, msg));
}

Expand All @@ -710,35 +708,27 @@ impl<'a> ExtCtxt<'a> {
/// Compilation will be stopped in the near future (at the end of
/// the macro expansion phase).
pub fn span_err(&self, sp: Span, msg: &str) {
self.print_backtrace();
self.parse_sess.span_diagnostic.span_err(sp, msg);
}
pub fn span_warn(&self, sp: Span, msg: &str) {
self.print_backtrace();
self.parse_sess.span_diagnostic.span_warn(sp, msg);
}
pub fn span_unimpl(&self, sp: Span, msg: &str) -> ! {
self.print_backtrace();
self.parse_sess.span_diagnostic.span_unimpl(sp, msg);
}
pub fn span_bug(&self, sp: Span, msg: &str) -> ! {
self.print_backtrace();
self.parse_sess.span_diagnostic.span_bug(sp, msg);
}
pub fn span_note(&self, sp: Span, msg: &str) {
self.print_backtrace();
self.parse_sess.span_diagnostic.span_note(sp, msg);
}
pub fn span_help(&self, sp: Span, msg: &str) {
self.print_backtrace();
self.parse_sess.span_diagnostic.span_help(sp, msg);
}
pub fn fileline_help(&self, sp: Span, msg: &str) {
self.print_backtrace();
self.parse_sess.span_diagnostic.fileline_help(sp, msg);
}
pub fn bug(&self, msg: &str) -> ! {
self.print_backtrace();
self.parse_sess.span_diagnostic.handler().bug(msg);
}
pub fn trace_macros(&self) -> bool {
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/ext/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
})
}

Expand Down
8 changes: 6 additions & 2 deletions src/libsyntax/ext/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand All @@ -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.") {
Expand Down
2 changes: 0 additions & 2 deletions src/libsyntax/ext/log_syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ pub fn expand_syntax_ext<'cx>(cx: &'cx mut base::ExtCtxt,
return base::DummyResult::any(sp);
}

cx.print_backtrace();

println!("{}", print::pprust::tts_to_string(tts));

// any so that `log_syntax` can be invoked as an expression and item.
Expand Down
8 changes: 5 additions & 3 deletions src/libsyntax/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1176,7 +1176,7 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span}: Expr, folder: &mut T) ->
}
ExprMethodCall(i, tps, args) => {
ExprMethodCall(
respan(i.span, folder.fold_ident(i.node)),
respan(folder.new_span(i.span), folder.fold_ident(i.node)),
tps.move_map(|x| folder.fold_ty(x)),
args.move_map(|x| folder.fold_expr(x)))
}
Expand Down Expand Up @@ -1246,11 +1246,13 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span}: Expr, folder: &mut T) ->
}
ExprField(el, ident) => {
ExprField(folder.fold_expr(el),
respan(ident.span, folder.fold_ident(ident.node)))
respan(folder.new_span(ident.span),
folder.fold_ident(ident.node)))
}
ExprTupField(el, ident) => {
ExprTupField(folder.fold_expr(el),
respan(ident.span, folder.fold_usize(ident.node)))
respan(folder.new_span(ident.span),
folder.fold_usize(ident.node)))
}
ExprIndex(el, er) => {
ExprIndex(folder.fold_expr(el), folder.fold_expr(er))
Expand Down
33 changes: 33 additions & 0 deletions src/test/auxiliary/internal_unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,17 @@ pub struct Foo {
pub x: u8
}

impl Foo {
#[unstable(feature = "method")]
pub fn method(&self) {}
}

#[stable(feature = "stable", since = "1.0.0")]
pub struct Bar {
#[unstable(feature = "struct2_field")]
pub x: u8
}

#[allow_internal_unstable]
#[macro_export]
macro_rules! call_unstable_allow {
Expand All @@ -36,6 +47,18 @@ macro_rules! construct_unstable_allow {
}
}

#[allow_internal_unstable]
#[macro_export]
macro_rules! call_method_allow {
($e: expr) => { $e.method() }
}

#[allow_internal_unstable]
#[macro_export]
macro_rules! access_field_allow {
($e: expr) => { $e.x }
}

#[allow_internal_unstable]
#[macro_export]
macro_rules! pass_through_allow {
Expand All @@ -54,6 +77,16 @@ macro_rules! construct_unstable_noallow {
}
}

#[macro_export]
macro_rules! call_method_noallow {
($e: expr) => { $e.method() }
}

#[macro_export]
macro_rules! access_field_noallow {
($e: expr) => { $e.x }
}

#[macro_export]
macro_rules! pass_through_noallow {
($e: expr) => { $e }
Expand Down
6 changes: 6 additions & 0 deletions src/test/compile-fail/internal-unstable-noallow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
// aux-build:internal_unstable.rs
// error-pattern:use of unstable library feature 'function'
// error-pattern:use of unstable library feature 'struct_field'
// error-pattern:use of unstable library feature 'method'
// error-pattern:use of unstable library feature 'struct2_field'

#[macro_use]
extern crate internal_unstable;
Expand All @@ -24,4 +26,8 @@ fn main() {
call_unstable_noallow!();

construct_unstable_noallow!(0);

|x: internal_unstable::Foo| { call_method_noallow!(x) };

|x: internal_unstable::Bar| { access_field_noallow!(x) };
}
2 changes: 2 additions & 0 deletions src/test/compile-fail/internal-unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ fn main() {
// ok, the instability is contained.
call_unstable_allow!();
construct_unstable_allow!(0);
|x: internal_unstable::Foo| { call_method_allow!(x) };
|x: internal_unstable::Bar| { access_field_allow!(x) };

// bad.
pass_through_allow!(internal_unstable::unstable()); //~ ERROR use of unstable
Expand Down
57 changes: 57 additions & 0 deletions src/test/compile-fail/macro-backtrace-invalid-internals.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Macros in statement vs expression position handle backtraces differently.

macro_rules! fake_method_stmt { //~ NOTE in expansion of
() => {
1.fake() //~ ERROR does not implement any method
}
}

macro_rules! fake_field_stmt { //~ NOTE in expansion of
() => {
1.fake //~ ERROR no field with that name
}
}

macro_rules! fake_anon_field_stmt { //~ NOTE in expansion of
() => {
(1).0 //~ ERROR type was not a tuple
}
}

macro_rules! fake_method_expr { //~ NOTE in expansion of
() => {
1.fake() //~ ERROR does not implement any method
}
}

macro_rules! fake_field_expr {
() => {
1.fake
}
}

macro_rules! fake_anon_field_expr {
() => {
(1).0
}
}

fn main() {
fake_method_stmt!(); //~ NOTE expansion site
fake_field_stmt!(); //~ NOTE expansion site
fake_anon_field_stmt!(); //~ NOTE expansion site

let _ = fake_method_expr!(); //~ NOTE expansion site
let _ = fake_field_expr!(); //~ ERROR no field with that name
let _ = fake_anon_field_expr!(); //~ ERROR type was not a tuple
}
29 changes: 29 additions & 0 deletions src/test/compile-fail/macro-backtrace-nested.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// In expression position, but not statement position, when we expand a macro,
// we replace the span of the expanded expression with that of the call site.

macro_rules! nested_expr {
() => (fake)
}

macro_rules! call_nested_expr {
() => (nested_expr!())
}

macro_rules! call_nested_expr_sum { //~ NOTE in expansion of
() => { 1 + nested_expr!(); } //~ ERROR unresolved name
}

fn main() {
1 + call_nested_expr!(); //~ ERROR unresolved name
call_nested_expr_sum!(); //~ NOTE expansion site
}
29 changes: 29 additions & 0 deletions src/test/compile-fail/macro-backtrace-println.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// The `format_args!` syntax extension issues errors before code expansion
// has completed, but we still need a backtrace.

// This test includes stripped-down versions of `print!` and `println!`,
// because we can't otherwise verify the lines of the backtrace.

fn print(_args: std::fmt::Arguments) {}

macro_rules! myprint { //~ NOTE in expansion of
($($arg:tt)*) => (print(format_args!($($arg)*)));
}

macro_rules! myprintln { //~ NOTE in expansion of
($fmt:expr) => (myprint!(concat!($fmt, "\n"))); //~ ERROR invalid reference to argument `0`
}

fn main() {
myprintln!("{}"); //~ NOTE expansion site
}