Auto merge of #24003 - rprichard:span-fixes, r=huonw

* 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.

r?  alexcrichton

Addresses #23459
This commit is contained in:
bors 2015-04-12 06:48:28 +00:00
commit feeb23d42e
13 changed files with 172 additions and 23 deletions

View file

@ -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 {
@ -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 {
@ -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 }

View file

@ -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;
@ -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) };
}

View file

@ -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

View file

@ -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
}

View file

@ -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
}

View file

@ -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
}