Skip to content

Commit

Permalink
Auto merge of rust-lang#32006 - jseyfried:fix_expanded_mod_path, r=ni…
Browse files Browse the repository at this point in the history
…komatsakis

This PR changes the search paths for macro-expanded non-inline modules so that they match ordinary non-inline modules (fixes rust-lang#31624). This is a [breaking-change].

Right now, the search paths for a macro-expanded non-inline module are computed as if the module were declared in the top level of the file in which the macro was defined.
For example, consider `./foo/mod.rs`:
```rust
mod inconsequential { // moving the macro outside this module wouldn't change anything
    macro_rules! mod_decl {
        ($i:ident) => { mod $i; }
    }
}
```
and `./lib.rs`:
```rust
mod foo;

mod bar {
    mod_decl!(baz);
    //^ Now, rustc expects `./foo/baz.rs` (or `./foo/baz/mod.rs`)
    //| After this PR, rustc will expect `./bar/baz.rs` (or `./bar/baz/mod.rs`)
}
```
r? @alexcrichton
  • Loading branch information
bors committed Mar 4, 2016
2 parents 8e261d1 + e2aa90e commit 5b5e521
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 4 deletions.
8 changes: 8 additions & 0 deletions src/libsyntax/ext/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,10 @@ pub struct ExtCtxt<'a> {

pub syntax_env: SyntaxEnv,
pub recursion_count: usize,

pub filename: Option<String>,
pub mod_path_stack: Vec<InternedString>,
pub in_block: bool,
}

impl<'a> ExtCtxt<'a> {
Expand All @@ -570,6 +574,10 @@ impl<'a> ExtCtxt<'a> {
exported_macros: Vec::new(),
syntax_env: env,
recursion_count: 0,

filename: None,
mod_path_stack: Vec::new(),
in_block: false,
}
}

Expand Down
47 changes: 45 additions & 2 deletions src/libsyntax/ext/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1183,6 +1183,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
}

impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
fn fold_crate(&mut self, c: Crate) -> Crate {
self.cx.filename = Some(self.cx.parse_sess.codemap().span_to_filename(c.span));
noop_fold_crate(c, self)
}

fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
expand_expr(expr, self)
}
Expand All @@ -1192,7 +1197,27 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
}

fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
expand_item(item, self)
use std::mem::replace;
let result;
if let ast::ItemKind::Mod(ast::Mod { inner, .. }) = item.node {
if item.span.contains(inner) {
self.push_mod_path(item.ident, &item.attrs);
result = expand_item(item, self);
self.pop_mod_path();
} else {
let filename = if inner != codemap::DUMMY_SP {
Some(self.cx.parse_sess.codemap().span_to_filename(inner))
} else { None };
let orig_filename = replace(&mut self.cx.filename, filename);
let orig_mod_path_stack = replace(&mut self.cx.mod_path_stack, Vec::new());
result = expand_item(item, self);
self.cx.filename = orig_filename;
self.cx.mod_path_stack = orig_mod_path_stack;
}
} else {
result = expand_item(item, self);
}
result
}

fn fold_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind {
Expand All @@ -1204,7 +1229,10 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
}

fn fold_block(&mut self, block: P<Block>) -> P<Block> {
expand_block(block, self)
let was_in_block = ::std::mem::replace(&mut self.cx.in_block, true);
let result = expand_block(block, self);
self.cx.in_block = was_in_block;
result
}

fn fold_arm(&mut self, arm: ast::Arm) -> ast::Arm {
Expand All @@ -1230,6 +1258,21 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
}
}

impl<'a, 'b> MacroExpander<'a, 'b> {
fn push_mod_path(&mut self, id: Ident, attrs: &[ast::Attribute]) {
let default_path = id.name.as_str();
let file_path = match ::attr::first_attr_value_str_by_name(attrs, "path") {
Some(d) => d,
None => default_path,
};
self.cx.mod_path_stack.push(file_path)
}

fn pop_mod_path(&mut self) {
self.cx.mod_path_stack.pop().unwrap();
}
}

fn new_span(cx: &ExtCtxt, sp: Span) -> Span {
/* this discards information in the case of macro-defining macros */
Span {
Expand Down
8 changes: 7 additions & 1 deletion src/libsyntax/ext/tt/macro_rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use ext::tt::macro_parser::{Success, Error, Failure};
use ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal};
use ext::tt::macro_parser::parse;
use parse::lexer::new_tt_reader;
use parse::parser::Parser;
use parse::parser::{Parser, Restrictions};
use parse::token::{self, special_idents, gensym_ident, NtTT, Token};
use parse::token::Token::*;
use print;
Expand Down Expand Up @@ -195,6 +195,12 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
imported_from,
rhs);
let mut p = Parser::new(cx.parse_sess(), cx.cfg(), Box::new(trncbr));
p.filename = cx.filename.clone();
p.mod_path_stack = cx.mod_path_stack.clone();
p.restrictions = match cx.in_block {
true => Restrictions::NO_NONINLINE_MOD,
false => Restrictions::empty(),
};
p.check_unknown_macro_variable();
// Let the context choose how to interpret the result.
// Weird, but useful for X-macros.
Expand Down
7 changes: 6 additions & 1 deletion src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ pub struct Parser<'a> {
/// extra detail when the same error is seen twice
pub obsolete_set: HashSet<ObsoleteSyntax>,
/// Used to determine the path to externally loaded source files
pub filename: Option<String>,
pub mod_path_stack: Vec<InternedString>,
/// Stack of spans of open delimiters. Used for error message.
pub open_braces: Vec<Span>,
Expand Down Expand Up @@ -354,6 +355,9 @@ impl<'a> Parser<'a> {
{
let tok0 = rdr.real_token();
let span = tok0.sp;
let filename = if span != codemap::DUMMY_SP {
Some(sess.codemap().span_to_filename(span))
} else { None };
let placeholder = TokenAndSpan {
tok: token::Underscore,
sp: span,
Expand Down Expand Up @@ -382,6 +386,7 @@ impl<'a> Parser<'a> {
quote_depth: 0,
obsolete_set: HashSet::new(),
mod_path_stack: Vec::new(),
filename: filename,
open_braces: Vec::new(),
owns_directory: true,
root_module_name: None,
Expand Down Expand Up @@ -5325,7 +5330,7 @@ impl<'a> Parser<'a> {
id: ast::Ident,
outer_attrs: &[ast::Attribute],
id_sp: Span) -> PResult<'a, ModulePathSuccess> {
let mut prefix = PathBuf::from(&self.sess.codemap().span_to_filename(self.span));
let mut prefix = PathBuf::from(self.filename.as_ref().unwrap());
prefix.pop();
let mut dir_path = prefix;
for part in &self.mod_path_stack {
Expand Down
23 changes: 23 additions & 0 deletions src/test/compile-fail/macro-expanded-mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2016 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.

// Test that macro-expanded non-inline modules behave correctly

macro_rules! mod_decl {
($i:ident) => { mod $i; }
}

mod macro_expanded_mod_helper {
mod_decl!(foo); // This should search in the folder `macro_expanded_mod_helper`
}

fn main() {
mod_decl!(foo); //~ ERROR Cannot declare a non-inline module inside a block
}
11 changes: 11 additions & 0 deletions src/test/compile-fail/macro_expanded_mod_helper/foo/bar.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright 2016 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.

// ignore-test
13 changes: 13 additions & 0 deletions src/test/compile-fail/macro_expanded_mod_helper/foo/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright 2016 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.

// ignore-test

mod_decl!(bar);

0 comments on commit 5b5e521

Please sign in to comment.