about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libsyntax/ext/base.rs8
-rw-r--r--src/libsyntax/ext/expand.rs47
-rw-r--r--src/libsyntax/ext/tt/macro_rules.rs8
-rw-r--r--src/libsyntax/parse/parser.rs7
-rw-r--r--src/test/compile-fail/macro-expanded-mod.rs23
-rw-r--r--src/test/compile-fail/macro_expanded_mod_helper/foo/bar.rs11
-rw-r--r--src/test/compile-fail/macro_expanded_mod_helper/foo/mod.rs13
7 files changed, 113 insertions, 4 deletions
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 2a9d96fa861..c0306b8494b 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -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> {
@@ -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,
         }
     }
 
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index e8e042c1321..e8098cfff45 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -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)
     }
@@ -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 {
@@ -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 {
@@ -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 {
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index c641c478a6b..77bae4cb3f6 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -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;
@@ -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.
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index b5d29a0d6db..e166a367219 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -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>,
@@ -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,
@@ -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,
@@ -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 {
diff --git a/src/test/compile-fail/macro-expanded-mod.rs b/src/test/compile-fail/macro-expanded-mod.rs
new file mode 100644
index 00000000000..8e631a64f7a
--- /dev/null
+++ b/src/test/compile-fail/macro-expanded-mod.rs
@@ -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
+}
diff --git a/src/test/compile-fail/macro_expanded_mod_helper/foo/bar.rs b/src/test/compile-fail/macro_expanded_mod_helper/foo/bar.rs
new file mode 100644
index 00000000000..3ec34362da5
--- /dev/null
+++ b/src/test/compile-fail/macro_expanded_mod_helper/foo/bar.rs
@@ -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
diff --git a/src/test/compile-fail/macro_expanded_mod_helper/foo/mod.rs b/src/test/compile-fail/macro_expanded_mod_helper/foo/mod.rs
new file mode 100644
index 00000000000..25fcf11ce17
--- /dev/null
+++ b/src/test/compile-fail/macro_expanded_mod_helper/foo/mod.rs
@@ -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);