From 0d258516cb88b4f54f672b1c7b4f11002aabd83d Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 6 May 2015 19:17:01 +1200 Subject: [PATCH 1/2] Proper spans for for loop expansion --- src/libsyntax/codemap.rs | 4 ++- src/libsyntax/diagnostic.rs | 11 +++++--- src/libsyntax/ext/expand.rs | 51 ++++++++++++++++++++++++++++++------- 3 files changed, 52 insertions(+), 14 deletions(-) diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 348bf6f51bb7c..c692babfacc44 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -235,7 +235,9 @@ pub enum MacroFormat { /// e.g. #[derive(...)] MacroAttribute, /// e.g. `format!()` - MacroBang + MacroBang, + /// Expansion performed by the compiler (libsyntax::expand). + CompilerExpansion, } #[derive(Clone, Hash, Debug)] diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index aa649b4d99ac5..66ddd73101e26 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -770,12 +770,15 @@ fn print_macro_backtrace(w: &mut EmitterWriter, |span| cm.span_to_string(span)); let (pre, post) = match ei.callee.format { codemap::MacroAttribute => ("#[", "]"), - codemap::MacroBang => ("", "!") + codemap::MacroBang => ("", "!"), + codemap::CompilerExpansion => ("", ""), }; try!(print_diagnostic(w, &ss, Note, - &format!("in expansion of {}{}{}", pre, - ei.callee.name, - post), None)); + &format!("in expansion of {}{}{}", + pre, + ei.callee.name, + post), + None)); let ss = cm.span_to_string(ei.call_site); try!(print_diagnostic(w, &ss, Note, "expansion site", None)); Ok(Some(ei.call_site)) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 05499959b7585..c49e094152b70 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -19,7 +19,7 @@ use ext::build::AstBuilder; use attr; use attr::AttrMetaMethods; use codemap; -use codemap::{Span, Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute}; +use codemap::{Span, Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute, CompilerExpansion}; use ext::base::*; use feature_gate::{self, Features}; use fold; @@ -34,6 +34,18 @@ use visit::Visitor; use std_inject; pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { + fn push_compiler_expansion(fld: &mut MacroExpander, span: Span, expansion_desc: &str) { + fld.cx.bt_push(ExpnInfo { + call_site: span, + callee: NameAndSpan { + name: expansion_desc.to_string(), + format: CompilerExpansion, + allow_internal_unstable: true, + span: None, + }, + }); + } + e.and_then(|ast::Expr {id, node, span}| match node { // expr_mac should really be expr_ext or something; it's the // entry-point for all syntax extensions. @@ -77,6 +89,8 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { // } // } + push_compiler_expansion(fld, span, "while let expansion"); + // ` => ` let pat_arm = { let body_expr = fld.cx.expr_block(body); @@ -98,7 +112,9 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { // `[opt_ident]: loop { ... }` let loop_block = fld.cx.block_expr(match_expr); let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld); - fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident)) + let result = fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident)); + fld.cx.bt_pop(); + result } // Desugar ExprIfLet @@ -112,6 +128,8 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { // _ => [ | ()] // } + push_compiler_expansion(fld, span, "if let expansion"); + // ` => ` let pat_arm = { let body_expr = fld.cx.expr_block(body); @@ -173,13 +191,16 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { ast::MatchSource::IfLetDesugar { contains_else_clause: contains_else_clause, })); - fld.fold_expr(match_expr) + let result = fld.fold_expr(match_expr); + fld.cx.bt_pop(); + result } // Desugar support for ExprIfLet in the ExprIf else position ast::ExprIf(cond, blk, elseopt) => { let elseopt = elseopt.map(|els| els.and_then(|els| match els.node { ast::ExprIfLet(..) => { + push_compiler_expansion(fld, span, "if let expansion"); // wrap the if-let expr in a block let span = els.span; let blk = P(ast::Block { @@ -189,7 +210,9 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { rules: ast::DefaultBlock, span: span }); - fld.cx.expr_block(blk) + let result = fld.cx.expr_block(blk); + fld.cx.bt_pop(); + result } _ => P(els) })); @@ -221,6 +244,10 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { // result // } + push_compiler_expansion(fld, span, "for loop expansion"); + + let span = fld.new_span(span); + // expand let head = fld.fold_expr(head); @@ -235,10 +262,11 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { rename_fld.fold_ident(ident) }; - let pat_span = pat.span; - // `:;std::option::Option::Some() => ` + let pat_span = fld.new_span(pat.span); + // `::std::option::Option::Some() => ` let pat_arm = { let body_expr = fld.cx.expr_block(body); + let pat = noop_fold_pat(pat, fld); let some_pat = fld.cx.pat_some(pat_span, pat); fld.cx.arm(pat_span, vec![some_pat], body_expr) @@ -304,20 +332,25 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { // `{ let result = ...; result }` let result_ident = token::gensym_ident("result"); - fld.cx.expr_block( + let result = fld.cx.expr_block( fld.cx.block_all( span, vec![fld.cx.stmt_let(span, false, result_ident, match_expr)], - Some(fld.cx.expr_ident(span, result_ident)))) + Some(fld.cx.expr_ident(span, result_ident)))); + fld.cx.bt_pop(); + result } ast::ExprClosure(capture_clause, fn_decl, block) => { + push_compiler_expansion(fld, span, "closure expansion"); let (rewritten_fn_decl, rewritten_block) = expand_and_rename_fn_decl_and_block(fn_decl, block, fld); let new_node = ast::ExprClosure(capture_clause, rewritten_fn_decl, rewritten_block); - P(ast::Expr{id:id, node: new_node, span: fld.new_span(span)}) + let result = P(ast::Expr{id:id, node: new_node, span: fld.new_span(span)}); + fld.cx.bt_pop(); + result } _ => { From edb2ee510b08b0fadedd3cb56b188cf69ecf2a6a Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 12 May 2015 12:42:45 +1200 Subject: [PATCH 2/2] Tests --- src/test/compile-fail/for-expn-2.rs | 18 ++++++++++++++++++ src/test/compile-fail/for-expn.rs | 19 +++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 src/test/compile-fail/for-expn-2.rs create mode 100644 src/test/compile-fail/for-expn.rs diff --git a/src/test/compile-fail/for-expn-2.rs b/src/test/compile-fail/for-expn-2.rs new file mode 100644 index 0000000000000..6b1dbf9d2d0ba --- /dev/null +++ b/src/test/compile-fail/for-expn-2.rs @@ -0,0 +1,18 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we get an expansion stack for `for` loops. + +// error-pattern:in expansion of for loop expansion + +fn main() { + for t in &foo { + } +} diff --git a/src/test/compile-fail/for-expn.rs b/src/test/compile-fail/for-expn.rs new file mode 100644 index 0000000000000..43776d75a47f4 --- /dev/null +++ b/src/test/compile-fail/for-expn.rs @@ -0,0 +1,19 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that an error on a sub-expresson in a for loop has the correct span. + +fn main() { + // Odd formatting to make sure we get the right span. + for t in & + foo //~ ERROR unresolved name `foo` + { + } +}