diff --git a/syntex/src/lib.rs b/syntex/src/lib.rs index 22214220..1a94f036 100644 --- a/syntex/src/lib.rs +++ b/syntex/src/lib.rs @@ -196,7 +196,7 @@ impl Registry { let features = feature_gate::get_features( &sess.span_diagnostic, - &krate); + &krate.attrs); let krate = self.pre_expansion_passes.iter() .fold(krate, |krate, f| (f)(krate)); @@ -205,9 +205,8 @@ impl Registry { ecfg.features = Some(&features); let cfg = Vec::new(); - let mut gated_cfgs = Vec::new(); let mut macro_loader = SyntexMacroLoader::new(self.macros.clone()); - let ecx = ExtCtxt::new(&sess, cfg, ecfg, &mut gated_cfgs, &mut macro_loader); + let ecx = ExtCtxt::new(&sess, cfg, ecfg, &mut macro_loader); let (krate, _) = expand::expand_crate(ecx, self.syntax_exts, krate); diff --git a/syntex_syntax/src/ast.rs b/syntex_syntax/src/ast.rs index ad3b7d8b..876ae55d 100644 --- a/syntex_syntax/src/ast.rs +++ b/syntex_syntax/src/ast.rs @@ -60,10 +60,6 @@ impl Name { pub fn as_str(self) -> token::InternedString { token::InternedString::new_from_name(self) } - - pub fn unhygienize(self) -> Name { - token::intern(&self.as_str()) - } } impl fmt::Debug for Name { diff --git a/syntex_syntax/src/attr.rs b/syntex_syntax/src/attr.rs index c3c3deea..e36e1580 100644 --- a/syntex_syntax/src/attr.rs +++ b/syntex_syntax/src/attr.rs @@ -20,12 +20,11 @@ use ast::{Stmt, StmtKind, DeclKind}; use ast::{Expr, Item, Local, Decl}; use codemap::{Span, Spanned, spanned, dummy_spanned}; use codemap::BytePos; -use config::CfgDiag; use errors::Handler; -use feature_gate::{GatedCfg, GatedCfgAttr}; +use feature_gate::{Features, GatedCfg}; use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; use parse::token::InternedString; -use parse::token; +use parse::{ParseSess, token}; use ptr::P; use std::cell::{RefCell, Cell}; @@ -365,35 +364,29 @@ pub fn requests_inline(attrs: &[Attribute]) -> bool { } /// Tests if a cfg-pattern matches the cfg set -pub fn cfg_matches(cfgs: &[P], - cfg: &ast::MetaItem, - diag: &mut T) -> bool { +pub fn cfg_matches(cfgs: &[P], cfg: &ast::MetaItem, + sess: &ParseSess, features: Option<&Features>) + -> bool { match cfg.node { ast::MetaItemKind::List(ref pred, ref mis) if &pred[..] == "any" => - mis.iter().any(|mi| cfg_matches(cfgs, &mi, diag)), + mis.iter().any(|mi| cfg_matches(cfgs, &mi, sess, features)), ast::MetaItemKind::List(ref pred, ref mis) if &pred[..] == "all" => - mis.iter().all(|mi| cfg_matches(cfgs, &mi, diag)), + mis.iter().all(|mi| cfg_matches(cfgs, &mi, sess, features)), ast::MetaItemKind::List(ref pred, ref mis) if &pred[..] == "not" => { if mis.len() != 1 { - diag.emit_error(|diagnostic| { - diagnostic.span_err(cfg.span, "expected 1 cfg-pattern"); - }); + sess.span_diagnostic.span_err(cfg.span, "expected 1 cfg-pattern"); return false; } - !cfg_matches(cfgs, &mis[0], diag) + !cfg_matches(cfgs, &mis[0], sess, features) } ast::MetaItemKind::List(ref pred, _) => { - diag.emit_error(|diagnostic| { - diagnostic.span_err(cfg.span, - &format!("invalid predicate `{}`", pred)); - }); + sess.span_diagnostic.span_err(cfg.span, &format!("invalid predicate `{}`", pred)); false }, ast::MetaItemKind::Word(_) | ast::MetaItemKind::NameValue(..) => { - diag.flag_gated(|feature_gated_cfgs| { - feature_gated_cfgs.extend( - GatedCfg::gate(cfg).map(GatedCfgAttr::GatedCfg)); - }); + if let (Some(features), Some(gated_cfg)) = (features, GatedCfg::gate(cfg)) { + gated_cfg.check_and_emit(sess, features); + } contains(cfgs, cfg) } } diff --git a/syntex_syntax/src/codemap.rs b/syntex_syntax/src/codemap.rs index febc847d..29bbcf6b 100644 --- a/syntex_syntax/src/codemap.rs +++ b/syntex_syntax/src/codemap.rs @@ -21,10 +21,11 @@ pub use self::ExpnFormat::*; use std::cell::{Cell, RefCell}; use std::ops::{Add, Sub}; -use std::path::Path; +use std::path::{Path,PathBuf}; use std::rc::Rc; use std::cmp; +use std::env; use std::{fmt, fs}; use std::io::{self, Read}; @@ -508,6 +509,8 @@ pub struct FileMap { /// originate from files has names between angle brackets by convention, /// e.g. `` pub name: FileName, + /// The absolute path of the file that the source came from. + pub abs_path: Option, /// The complete source code pub src: Option>, /// The start position of this source in the CodeMap @@ -522,11 +525,12 @@ pub struct FileMap { impl Encodable for FileMap { fn encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_struct("FileMap", 5, |s| { + s.emit_struct("FileMap", 6, |s| { try!(s.emit_struct_field("name", 0, |s| self.name.encode(s))); - try!(s.emit_struct_field("start_pos", 1, |s| self.start_pos.encode(s))); - try!(s.emit_struct_field("end_pos", 2, |s| self.end_pos.encode(s))); - try!(s.emit_struct_field("lines", 3, |s| { + try!(s.emit_struct_field("abs_path", 1, |s| self.abs_path.encode(s))); + try!(s.emit_struct_field("start_pos", 2, |s| self.start_pos.encode(s))); + try!(s.emit_struct_field("end_pos", 3, |s| self.end_pos.encode(s))); + try!(s.emit_struct_field("lines", 4, |s| { let lines = self.lines.borrow(); // store the length try!(s.emit_u32(lines.len() as u32)); @@ -572,7 +576,7 @@ impl Encodable for FileMap { Ok(()) })); - s.emit_struct_field("multibyte_chars", 4, |s| { + s.emit_struct_field("multibyte_chars", 5, |s| { (*self.multibyte_chars.borrow()).encode(s) }) }) @@ -582,11 +586,13 @@ impl Encodable for FileMap { impl Decodable for FileMap { fn decode(d: &mut D) -> Result { - d.read_struct("FileMap", 5, |d| { + d.read_struct("FileMap", 6, |d| { let name: String = try!(d.read_struct_field("name", 0, |d| Decodable::decode(d))); - let start_pos: BytePos = try!(d.read_struct_field("start_pos", 1, |d| Decodable::decode(d))); - let end_pos: BytePos = try!(d.read_struct_field("end_pos", 2, |d| Decodable::decode(d))); - let lines: Vec = try!(d.read_struct_field("lines", 3, |d| { + let abs_path: Option = + try!(d.read_struct_field("abs_path", 1, |d| Decodable::decode(d))); + let start_pos: BytePos = try!(d.read_struct_field("start_pos", 2, |d| Decodable::decode(d))); + let end_pos: BytePos = try!(d.read_struct_field("end_pos", 3, |d| Decodable::decode(d))); + let lines: Vec = try!(d.read_struct_field("lines", 4, |d| { let num_lines: u32 = try!(Decodable::decode(d)); let mut lines = Vec::with_capacity(num_lines as usize); @@ -615,9 +621,10 @@ impl Decodable for FileMap { Ok(lines) })); let multibyte_chars: Vec = - try!(d.read_struct_field("multibyte_chars", 4, |d| Decodable::decode(d))); + try!(d.read_struct_field("multibyte_chars", 5, |d| Decodable::decode(d))); Ok(FileMap { name: name, + abs_path: abs_path, start_pos: start_pos, end_pos: end_pos, src: None, @@ -703,6 +710,9 @@ pub trait FileLoader { /// Query the existence of a file. fn file_exists(&self, path: &Path) -> bool; + /// Return an absolute path to a file, if possible. + fn abs_path(&self, path: &Path) -> Option; + /// Read the contents of an UTF-8 file into memory. fn read_file(&self, path: &Path) -> io::Result; } @@ -715,6 +725,16 @@ impl FileLoader for RealFileLoader { fs::metadata(path).is_ok() } + fn abs_path(&self, path: &Path) -> Option { + if path.is_absolute() { + Some(path.to_path_buf()) + } else { + env::current_dir() + .ok() + .map(|cwd| cwd.join(path)) + } + } + fn read_file(&self, path: &Path) -> io::Result { let mut src = String::new(); try!(try!(fs::File::open(path)).read_to_string(&mut src)); @@ -755,7 +775,8 @@ impl CodeMap { pub fn load_file(&self, path: &Path) -> io::Result> { let src = try!(self.file_loader.read_file(path)); - Ok(self.new_filemap(path.to_str().unwrap().to_string(), src)) + let abs_path = self.file_loader.abs_path(path).map(|p| p.to_str().unwrap().to_string()); + Ok(self.new_filemap(path.to_str().unwrap().to_string(), abs_path, src)) } fn next_start_pos(&self) -> usize { @@ -770,7 +791,8 @@ impl CodeMap { /// Creates a new filemap without setting its line information. If you don't /// intend to set the line information yourself, you should use new_filemap_and_lines. - pub fn new_filemap(&self, filename: FileName, mut src: String) -> Rc { + pub fn new_filemap(&self, filename: FileName, abs_path: Option, + mut src: String) -> Rc { let start_pos = self.next_start_pos(); let mut files = self.files.borrow_mut(); @@ -783,6 +805,7 @@ impl CodeMap { let filemap = Rc::new(FileMap { name: filename, + abs_path: abs_path, src: Some(Rc::new(src)), start_pos: Pos::from_usize(start_pos), end_pos: Pos::from_usize(end_pos), @@ -796,8 +819,11 @@ impl CodeMap { } /// Creates a new filemap and sets its line information. - pub fn new_filemap_and_lines(&self, filename: &str, src: &str) -> Rc { - let fm = self.new_filemap(filename.to_string(), src.to_owned()); + pub fn new_filemap_and_lines(&self, filename: &str, abs_path: Option<&str>, + src: &str) -> Rc { + let fm = self.new_filemap(filename.to_string(), + abs_path.map(|s| s.to_owned()), + src.to_owned()); let mut byte_pos: u32 = fm.start_pos.0; for line in src.lines() { // register the start of this line @@ -816,6 +842,7 @@ impl CodeMap { /// information for things inlined from other crates. pub fn new_imported_filemap(&self, filename: FileName, + abs_path: Option, source_len: usize, mut file_local_lines: Vec, mut file_local_multibyte_chars: Vec) @@ -836,6 +863,7 @@ impl CodeMap { let filemap = Rc::new(FileMap { name: filename, + abs_path: abs_path, src: None, start_pos: start_pos, end_pos: end_pos, @@ -1422,6 +1450,7 @@ mod tests { fn t1 () { let cm = CodeMap::new(); let fm = cm.new_filemap("blork.rs".to_string(), + None, "first line.\nsecond line".to_string()); fm.next_line(BytePos(0)); // Test we can get lines with partial line info. @@ -1438,6 +1467,7 @@ mod tests { fn t2 () { let cm = CodeMap::new(); let fm = cm.new_filemap("blork.rs".to_string(), + None, "first line.\nsecond line".to_string()); // TESTING *REALLY* BROKEN BEHAVIOR: fm.next_line(BytePos(0)); @@ -1448,10 +1478,13 @@ mod tests { fn init_code_map() -> CodeMap { let cm = CodeMap::new(); let fm1 = cm.new_filemap("blork.rs".to_string(), + None, "first line.\nsecond line".to_string()); let fm2 = cm.new_filemap("empty.rs".to_string(), + None, "".to_string()); let fm3 = cm.new_filemap("blork2.rs".to_string(), + None, "first line.\nsecond line".to_string()); fm1.next_line(BytePos(0)); @@ -1514,8 +1547,10 @@ mod tests { // € is a three byte utf8 char. let fm1 = cm.new_filemap("blork.rs".to_string(), + None, "fir€st €€€€ line.\nsecond line".to_string()); let fm2 = cm.new_filemap("blork2.rs".to_string(), + None, "first line€€.\n€ second line".to_string()); fm1.next_line(BytePos(0)); @@ -1583,7 +1618,7 @@ mod tests { let cm = CodeMap::new(); let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n"; let selection = " \n ~~\n~~~\n~~~~~ \n \n"; - cm.new_filemap_and_lines("blork.rs", inputtext); + cm.new_filemap_and_lines("blork.rs", None, inputtext); let span = span_from_selection(inputtext, selection); // check that we are extracting the text we thought we were extracting diff --git a/syntex_syntax/src/config.rs b/syntex_syntax/src/config.rs index c164e89c..0e5d6841 100644 --- a/syntex_syntax/src/config.rs +++ b/syntex_syntax/src/config.rs @@ -9,50 +9,33 @@ // except according to those terms. use attr::{AttrMetaMethods, HasAttrs}; -use errors::Handler; -use feature_gate::GatedCfgAttr; +use feature_gate::{emit_feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_features, GateIssue}; use fold::Folder; use {ast, fold, attr}; use codemap::{Spanned, respan}; +use parse::{ParseSess, token}; use ptr::P; use util::small_vector::SmallVector; -pub trait CfgFolder: fold::Folder { - // Check if a node with the given attributes is in this configuration. - fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool; - - // Update a node before checking if it is in this configuration (used to implement `cfg_attr`). - fn process_attrs(&mut self, node: T) -> T { node } - - // Visit attributes on expression and statements (but not attributes on items in blocks). - fn visit_stmt_or_expr_attrs(&mut self, _attrs: &[ast::Attribute]) {} - - // Visit unremovable (non-optional) expressions -- c.f. `fold_expr` vs `fold_opt_expr`. - fn visit_unremovable_expr(&mut self, _expr: &ast::Expr) {} +/// A folder that strips out items that do not belong in the current configuration. +pub struct StripUnconfigured<'a> { + pub config: &'a ast::CrateConfig, + pub should_test: bool, + pub sess: &'a ParseSess, + pub features: Option<&'a Features>, +} +impl<'a> StripUnconfigured<'a> { fn configure(&mut self, node: T) -> Option { - let node = self.process_attrs(node); + let node = self.process_cfg_attrs(node); if self.in_cfg(node.attrs()) { Some(node) } else { None } } -} - -/// A folder that strips out items that do not belong in the current -/// configuration. -pub struct StripUnconfigured<'a> { - diag: CfgDiagReal<'a, 'a>, - config: &'a ast::CrateConfig, -} -impl<'a> StripUnconfigured<'a> { - pub fn new(config: &'a ast::CrateConfig, - diagnostic: &'a Handler, - feature_gated_cfgs: &'a mut Vec) - -> Self { - StripUnconfigured { - config: config, - diag: CfgDiagReal { diag: diagnostic, feature_gated_cfgs: feature_gated_cfgs }, - } + fn process_cfg_attrs(&mut self, node: T) -> T { + node.map_attrs(|attrs| { + attrs.into_iter().filter_map(|attr| self.process_cfg_attr(attr)).collect() + }) } fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Option { @@ -64,7 +47,7 @@ impl<'a> StripUnconfigured<'a> { Some(attr_list) => attr_list, None => { let msg = "expected `#[cfg_attr(, )]`"; - self.diag.diag.span_err(attr.span, msg); + self.sess.span_diagnostic.span_err(attr.span, msg); return None; } }; @@ -72,13 +55,13 @@ impl<'a> StripUnconfigured<'a> { (2, Some(cfg), Some(mi)) => (cfg, mi), _ => { let msg = "expected `#[cfg_attr(, )]`"; - self.diag.diag.span_err(attr.span, msg); + self.sess.span_diagnostic.span_err(attr.span, msg); return None; } }; - if attr::cfg_matches(self.config, &cfg, &mut self.diag) { - Some(respan(mi.span, ast::Attribute_ { + if attr::cfg_matches(self.config, &cfg, self.sess, self.features) { + self.process_cfg_attr(respan(mi.span, ast::Attribute_ { id: attr::mk_attr_id(), style: attr.node.style, value: mi.clone(), @@ -88,61 +71,73 @@ impl<'a> StripUnconfigured<'a> { None } } -} -impl<'a> CfgFolder for StripUnconfigured<'a> { - // Determine if an item should be translated in the current crate - // configuration based on the item's attributes + // Determine if a node with the given attributes should be included in this configuation. fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool { attrs.iter().all(|attr| { + // When not compiling with --test we should not compile the #[test] functions + if !self.should_test && is_test_or_bench(attr) { + return false; + } + let mis = match attr.node.value.node { ast::MetaItemKind::List(_, ref mis) if is_cfg(&attr) => mis, _ => return true }; if mis.len() != 1 { - self.diag.emit_error(|diagnostic| { - diagnostic.span_err(attr.span, "expected 1 cfg-pattern"); - }); + self.sess.span_diagnostic.span_err(attr.span, "expected 1 cfg-pattern"); return true; } - attr::cfg_matches(self.config, &mis[0], &mut self.diag) - }) - } - - fn process_attrs(&mut self, node: T) -> T { - node.map_attrs(|attrs| { - attrs.into_iter().filter_map(|attr| self.process_cfg_attr(attr)).collect() + attr::cfg_matches(self.config, &mis[0], self.sess, self.features) }) } + // Visit attributes on expression and statements (but not attributes on items in blocks). fn visit_stmt_or_expr_attrs(&mut self, attrs: &[ast::Attribute]) { // flag the offending attributes for attr in attrs.iter() { - self.diag.feature_gated_cfgs.push(GatedCfgAttr::GatedAttr(attr.span)); - } - } - - fn visit_unremovable_expr(&mut self, expr: &ast::Expr) { - if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a)) { - let msg = "removing an expression is not supported in this position"; - self.diag.diag.span_err(attr.span, msg); + if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) { + emit_feature_err(&self.sess.span_diagnostic, + "stmt_expr_attributes", + attr.span, + GateIssue::Language, + EXPLAIN_STMT_ATTR_SYNTAX); + } } } } // Support conditional compilation by transforming the AST, stripping out // any items that do not belong in the current configuration -pub fn strip_unconfigured_items(diagnostic: &Handler, krate: ast::Crate, - feature_gated_cfgs: &mut Vec) - -> ast::Crate -{ - let config = &krate.config.clone(); - StripUnconfigured::new(config, diagnostic, feature_gated_cfgs).fold_crate(krate) +pub fn strip_unconfigured_items(mut krate: ast::Crate, sess: &ParseSess, should_test: bool) + -> (ast::Crate, Features) { + let features; + { + let mut strip_unconfigured = StripUnconfigured { + config: &krate.config.clone(), + should_test: should_test, + sess: sess, + features: None, + }; + + let err_count = sess.span_diagnostic.err_count(); + let krate_attrs = strip_unconfigured.process_cfg_attrs(krate.attrs.clone()); + features = get_features(&sess.span_diagnostic, &krate_attrs); + if err_count < sess.span_diagnostic.err_count() { + krate.attrs = krate_attrs.clone(); // Avoid reconfiguring malformed `cfg_attr`s + } + + strip_unconfigured.features = Some(&features); + krate = strip_unconfigured.fold_crate(krate); + krate.attrs = krate_attrs; + } + + (krate, features) } -impl fold::Folder for T { +impl<'a> fold::Folder for StripUnconfigured<'a> { fn fold_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod { ast::ForeignMod { abi: foreign_mod.abi, @@ -195,6 +190,7 @@ impl fold::Folder for T { fn fold_expr(&mut self, expr: P) -> P { self.visit_stmt_or_expr_attrs(expr.attrs()); + // If an expr is valid to cfg away it will have been removed by the // outer stmt or expression folder before descending in here. // Anything else is always required, and thus has to error out @@ -202,8 +198,12 @@ impl fold::Folder for T { // // NB: This is intentionally not part of the fold_expr() function // in order for fold_opt_expr() to be able to avoid this check - self.visit_unremovable_expr(&expr); - let expr = self.process_attrs(expr); + if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a) || is_test_or_bench(a)) { + let msg = "removing an expression is not supported in this position"; + self.sess.span_diagnostic.span_err(attr.span, msg); + } + + let expr = self.process_cfg_attrs(expr); fold_expr(self, expr) } @@ -247,9 +247,15 @@ impl fold::Folder for T { self.configure(item).map(|item| fold::noop_fold_trait_item(item, self)) .unwrap_or(SmallVector::zero()) } + + fn fold_interpolated(&mut self, nt: token::Nonterminal) -> token::Nonterminal { + // Don't configure interpolated AST (c.f. #34171). + // Interpolated AST will get configured once the surrounding tokens are parsed. + nt + } } -fn fold_expr(folder: &mut F, expr: P) -> P { +fn fold_expr(folder: &mut StripUnconfigured, expr: P) -> P { expr.map(|ast::Expr {id, span, node, attrs}| { fold::noop_fold_expr(ast::Expr { id: id, @@ -271,21 +277,6 @@ fn is_cfg(attr: &ast::Attribute) -> bool { attr.check_name("cfg") } -pub trait CfgDiag { - fn emit_error(&mut self, f: F) where F: FnMut(&Handler); - fn flag_gated(&mut self, f: F) where F: FnMut(&mut Vec); -} - -pub struct CfgDiagReal<'a, 'b> { - pub diag: &'a Handler, - pub feature_gated_cfgs: &'b mut Vec, -} - -impl<'a, 'b> CfgDiag for CfgDiagReal<'a, 'b> { - fn emit_error(&mut self, mut f: F) where F: FnMut(&Handler) { - f(self.diag) - } - fn flag_gated(&mut self, mut f: F) where F: FnMut(&mut Vec) { - f(self.feature_gated_cfgs) - } +fn is_test_or_bench(attr: &ast::Attribute) -> bool { + attr.check_name("test") || attr.check_name("bench") } diff --git a/syntex_syntax/src/errors/emitter.rs b/syntex_syntax/src/errors/emitter.rs index 67ce655e..57e3fac3 100644 --- a/syntex_syntax/src/errors/emitter.rs +++ b/syntex_syntax/src/errors/emitter.rs @@ -668,7 +668,7 @@ mod test { tolv dreizehn "; - let file = cm.new_filemap_and_lines("dummy.txt", content); + let file = cm.new_filemap_and_lines("dummy.txt", None, content); let start = file.lines.borrow()[10]; let end = file.lines.borrow()[11]; let sp = mk_sp(start, end); @@ -694,7 +694,7 @@ mod test { let cm = CodeMap::new(); let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n"; let selection = " \n ~~\n~~~\n~~~~~ \n \n"; - cm.new_filemap_and_lines("blork.rs", inputtext); + cm.new_filemap_and_lines("blork.rs", None, inputtext); let sp = span_from_selection(inputtext, selection); let msp: MultiSpan = sp.into(); @@ -717,7 +717,7 @@ mod test { let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n"; let selection1 = " \n \n \n \n ~ \n"; // intentionally out of order let selection2 = " \n ~~\n~~~\n~~~~~ \n \n"; - cm.new_filemap_and_lines("blork.rs", inputtext); + cm.new_filemap_and_lines("blork.rs", None, inputtext); let sp1 = span_from_selection(inputtext, selection1); let sp2 = span_from_selection(inputtext, selection2); let msp: MultiSpan = MultiSpan::from_spans(vec![sp1, sp2]); @@ -757,7 +757,7 @@ mod test { assert_eq!(&cm.span_to_snippet(sp).unwrap(), expected); sp }; - cm.new_filemap_and_lines("dummy.txt", inp); + cm.new_filemap_and_lines("dummy.txt", None, inp); let sp1 = span(sp1, "aaaaaa"); let sp2 = span(sp2, "bbbbbb"); let sp3 = span(sp3, "ccccc"); @@ -802,7 +802,7 @@ mod test { ddd__eee_\n\ elided\n\ __f_gg"; - let file = cm.new_filemap_and_lines("dummy.txt", inp); + let file = cm.new_filemap_and_lines("dummy.txt", None, inp); let span = |lo, hi, (off_lo, off_hi)| { let lines = file.lines.borrow(); diff --git a/syntex_syntax/src/errors/snippet/test.rs b/syntex_syntax/src/errors/snippet/test.rs index 51fe4572..79e40a09 100644 --- a/syntex_syntax/src/errors/snippet/test.rs +++ b/syntex_syntax/src/errors/snippet/test.rs @@ -88,7 +88,7 @@ fn foo() { "; let cm = Rc::new(CodeMap::new()); - let foo = cm.new_filemap_and_lines("foo.rs", file_text); + let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); let span_bar = cm.span_substr(&foo, file_text, "bar", 0); let mut snippet = SnippetData::new(cm, Some(span_bar)); @@ -113,7 +113,7 @@ fn foo() { "#; let cm = Rc::new(CodeMap::new()); - let foo = cm.new_filemap_and_lines("foo.rs", file_text); + let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); let span_vec0 = cm.span_substr(&foo, file_text, "vec", 0); let span_vec1 = cm.span_substr(&foo, file_text, "vec", 1); let span_semi = cm.span_substr(&foo, file_text, ";", 0); @@ -173,12 +173,12 @@ fn bar() { "#; let cm = Rc::new(CodeMap::new()); - let foo_map = cm.new_filemap_and_lines("foo.rs", file_text_foo); + let foo_map = cm.new_filemap_and_lines("foo.rs", None, file_text_foo); let span_foo_vec0 = cm.span_substr(&foo_map, file_text_foo, "vec", 0); let span_foo_vec1 = cm.span_substr(&foo_map, file_text_foo, "vec", 1); let span_foo_semi = cm.span_substr(&foo_map, file_text_foo, ";", 0); - let bar_map = cm.new_filemap_and_lines("bar.rs", file_text_bar); + let bar_map = cm.new_filemap_and_lines("bar.rs", None, file_text_bar); let span_bar_vec0 = cm.span_substr(&bar_map, file_text_bar, "vec", 0); let span_bar_vec1 = cm.span_substr(&bar_map, file_text_bar, "vec", 1); let span_bar_semi = cm.span_substr(&bar_map, file_text_bar, ";", 0); @@ -235,7 +235,7 @@ fn foo() { "#; let cm = Rc::new(CodeMap::new()); - let foo = cm.new_filemap_and_lines("foo.rs", file_text); + let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); let span_data0 = cm.span_substr(&foo, file_text, "data", 0); let span_data1 = cm.span_substr(&foo, file_text, "data", 1); let span_rbrace = cm.span_substr(&foo, file_text, "}", 3); @@ -274,7 +274,7 @@ fn foo() { "#; let cm = Rc::new(CodeMap::new()); - let foo = cm.new_filemap_and_lines("foo.rs", file_text); + let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); let span0 = cm.span_substr(&foo, file_text, "vec.push", 0); let span1 = cm.span_substr(&foo, file_text, "vec", 0); let span2 = cm.span_substr(&foo, file_text, "ec.push", 0); @@ -312,7 +312,7 @@ fn foo() { "#; let cm = Rc::new(CodeMap::new()); - let foo = cm.new_filemap_and_lines("foo.rs", file_text); + let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); let span_vec0 = cm.span_substr(&foo, file_text, "vec", 0); let span_vec1 = cm.span_substr(&foo, file_text, "vec", 1); let span_semi = cm.span_substr(&foo, file_text, ";", 0); @@ -354,7 +354,7 @@ fn foo() { "#; let cm = Rc::new(CodeMap::new()); - let foo = cm.new_filemap_and_lines("foo.rs", file_text); + let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); let span_vec0 = cm.span_substr(&foo, file_text, "vec", 3); let span_vec1 = cm.span_substr(&foo, file_text, "vec", 8); @@ -393,7 +393,7 @@ fn foo() { "#; let cm = Rc::new(CodeMap::new()); - let foo = cm.new_filemap_and_lines("foo.rs", file_text); + let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); let mut snippet = SnippetData::new(cm.clone(), None); for i in 0..4 { @@ -427,7 +427,7 @@ impl SomeTrait for () { "#; let cm = Rc::new(CodeMap::new()); - let foo = cm.new_filemap_and_lines("foo.rs", file_text); + let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); let mut snippet = SnippetData::new(cm.clone(), None); let fn_span = cm.span_substr(&foo, file_text, "fn", 0); @@ -456,7 +456,7 @@ fn span_overlap_label() { "#; let cm = Rc::new(CodeMap::new()); - let foo = cm.new_filemap_and_lines("foo.rs", file_text); + let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); let mut snippet = SnippetData::new(cm.clone(), None); let fn_span = cm.span_substr(&foo, file_text, "fn foo(x: u32)", 0); @@ -491,7 +491,7 @@ fn span_overlap_label2() { "#; let cm = Rc::new(CodeMap::new()); - let foo = cm.new_filemap_and_lines("foo.rs", file_text); + let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); let mut snippet = SnippetData::new(cm.clone(), None); let fn_span = cm.span_substr(&foo, file_text, "fn foo(x", 0); @@ -529,7 +529,7 @@ fn span_overlap_label3() { "#; let cm = Rc::new(CodeMap::new()); - let foo = cm.new_filemap_and_lines("foo.rs", file_text); + let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); let mut snippet = SnippetData::new(cm.clone(), None); @@ -578,7 +578,7 @@ fn main() { let cm = Rc::new(CodeMap::new()); - let foo = cm.new_filemap_and_lines("foo.rs", file_text); + let foo = cm.new_filemap_and_lines("foo.rs", None, file_text); let mut rbrace_span = cm.span_substr(&foo, file_text, "}", 1); rbrace_span.lo = rbrace_span.hi; diff --git a/syntex_syntax/src/ext/base.rs b/syntex_syntax/src/ext/base.rs index edd28d11..6b9c8d21 100644 --- a/syntex_syntax/src/ext/base.rs +++ b/syntex_syntax/src/ext/base.rs @@ -18,7 +18,6 @@ use errors::DiagnosticBuilder; use ext; use ext::expand; use ext::tt::macro_rules; -use feature_gate::GatedCfgAttr; use parse; use parse::parser; use parse::token; @@ -95,6 +94,16 @@ impl Annotatable { _ => panic!("expected Item") } } + + pub fn fold_with(self, folder: &mut F) -> SmallVector { + match self { + Annotatable::Item(item) => folder.fold_item(item).map(Annotatable::Item), + Annotatable::ImplItem(item) => + folder.fold_impl_item(item.unwrap()).map(|item| Annotatable::ImplItem(P(item))), + Annotatable::TraitItem(item) => + folder.fold_trait_item(item.unwrap()).map(|item| Annotatable::TraitItem(P(item))), + } + } } // A more flexible ItemDecorator. @@ -572,7 +581,6 @@ pub struct ExtCtxt<'a> { pub backtrace: ExpnId, pub ecfg: expand::ExpansionConfig<'a>, pub crate_root: Option<&'static str>, - pub feature_gated_cfgs: &'a mut Vec, pub loader: &'a mut MacroLoader, pub mod_path: Vec , @@ -589,7 +597,6 @@ pub struct ExtCtxt<'a> { impl<'a> ExtCtxt<'a> { pub fn new(parse_sess: &'a parse::ParseSess, cfg: ast::CrateConfig, ecfg: expand::ExpansionConfig<'a>, - feature_gated_cfgs: &'a mut Vec, loader: &'a mut MacroLoader) -> ExtCtxt<'a> { let env = initial_syntax_expander_table(&ecfg); @@ -600,7 +607,6 @@ impl<'a> ExtCtxt<'a> { mod_path: Vec::new(), ecfg: ecfg, crate_root: None, - feature_gated_cfgs: feature_gated_cfgs, exported_macros: Vec::new(), loader: loader, syntax_env: env, @@ -633,22 +639,6 @@ impl<'a> ExtCtxt<'a> { } pub fn backtrace(&self) -> ExpnId { self.backtrace } - /// Original span that caused the current exapnsion to happen. - pub fn original_span(&self) -> Span { - let mut expn_id = self.backtrace; - let mut call_site = None; - loop { - match self.codemap().with_expn_info(expn_id, |ei| ei.map(|ei| ei.call_site)) { - None => break, - Some(cs) => { - call_site = Some(cs); - expn_id = cs.expn_id; - } - } - } - call_site.expect("missing expansion backtrace") - } - /// Returns span for the macro which originally caused the current expansion to happen. /// /// Stops backtracing at include! boundary. @@ -960,6 +950,6 @@ impl SyntaxEnv { pub fn is_crate_root(&mut self) -> bool { // The first frame is pushed in `SyntaxEnv::new()` and the second frame is // pushed when folding the crate root pseudo-module (c.f. noop_fold_crate). - self.chain.len() == 2 + self.chain.len() <= 2 } } diff --git a/syntex_syntax/src/ext/expand.rs b/syntex_syntax/src/ext/expand.rs index bd26cf98..cdc8fa98 100644 --- a/syntex_syntax/src/ext/expand.rs +++ b/syntex_syntax/src/ext/expand.rs @@ -42,6 +42,7 @@ trait MacroGenerable: Sized { // Fold this node or list of nodes using the given folder. fn fold_with(self, folder: &mut F) -> Self; + fn visit_with<'v, V: Visitor<'v>>(&'v self, visitor: &mut V); // Return a placeholder expansion to allow compilation to continue after an erroring expansion. fn dummy(span: Span) -> Self; @@ -51,7 +52,9 @@ trait MacroGenerable: Sized { } macro_rules! impl_macro_generable { - ($($ty:ty: $kind_name:expr, .$make:ident, $(.$fold:ident)* $(lift .$fold_elt:ident)*, + ($($ty:ty: $kind_name:expr, .$make:ident, + $(.$fold:ident)* $(lift .$fold_elt:ident)*, + $(.$visit:ident)* $(lift .$visit_elt:ident)*, |$span:ident| $dummy:expr;)*) => { $( impl MacroGenerable for $ty { fn kind_name() -> &'static str { $kind_name } @@ -60,21 +63,27 @@ macro_rules! impl_macro_generable { $( folder.$fold(self) )* $( self.into_iter().flat_map(|item| folder. $fold_elt (item)).collect() )* } + fn visit_with<'v, V: Visitor<'v>>(&'v self, visitor: &mut V) { + $( visitor.$visit(self) )* + $( for item in self.as_slice() { visitor. $visit_elt (item) } )* + } fn dummy($span: Span) -> Self { $dummy } } )* } } impl_macro_generable! { - P: "expression", .make_expr, .fold_expr, |span| DummyResult::raw_expr(span); - P: "pattern", .make_pat, .fold_pat, |span| P(DummyResult::raw_pat(span)); - P: "type", .make_ty, .fold_ty, |span| DummyResult::raw_ty(span); - SmallVector: - "impl item", .make_impl_items, lift .fold_impl_item, |_span| SmallVector::zero(); - SmallVector>: - "item", .make_items, lift .fold_item, |_span| SmallVector::zero(); + P: "pattern", .make_pat, .fold_pat, .visit_pat, |span| P(DummyResult::raw_pat(span)); + P: "type", .make_ty, .fold_ty, .visit_ty, |span| DummyResult::raw_ty(span); + P: + "expression", .make_expr, .fold_expr, .visit_expr, |span| DummyResult::raw_expr(span); SmallVector: - "statement", .make_stmts, lift .fold_stmt, |_span| SmallVector::zero(); + "statement", .make_stmts, lift .fold_stmt, lift .visit_stmt, |_span| SmallVector::zero(); + SmallVector>: + "item", .make_items, lift .fold_item, lift .visit_item, |_span| SmallVector::zero(); + SmallVector: + "impl item", .make_impl_items, lift .fold_impl_item, lift .visit_impl_item, + |_span| SmallVector::zero(); } impl MacroGenerable for Option> { @@ -86,6 +95,9 @@ impl MacroGenerable for Option> { fn fold_with(self, folder: &mut F) -> Self { self.and_then(|expr| folder.fold_opt_expr(expr)) } + fn visit_with<'v, V: Visitor<'v>>(&'v self, visitor: &mut V) { + self.as_ref().map(|expr| visitor.visit_expr(expr)); + } } pub fn expand_expr(expr: ast::Expr, fld: &mut MacroExpander) -> P { @@ -250,14 +262,8 @@ fn expand_mac_invoc(mac: ast::Mac, ident: Option, attrs: Vec { @@ -341,6 +347,7 @@ fn expand_mac_invoc(mac: ast::Mac, ident: Option, attrs: Vec { - // We need to error on `#[macro_use] extern crate` when it isn't at the - // crate root, because `$crate` won't work properly. - let allows_macros = fld.cx.syntax_env.is_crate_root(); - for def in fld.cx.loader.load_crate(&it, allows_macros) { - fld.cx.insert_macro(def); - } - SmallVector::one(it) - }, _ => noop_fold_item(it, fld), }.into_iter().map(|i| Annotatable::Item(i)).collect(), @@ -808,8 +806,6 @@ fn decorate(a: Annotatable, fld: &mut MacroExpander) -> SmallVector let mut decorator_items = SmallVector::zero(); let mut new_attrs = Vec::new(); expand_decorators(a.clone(), fld, &mut decorator_items, &mut new_attrs); - let decorator_items = - decorator_items.into_iter().flat_map(|a| expand_annotatable(a, fld)).collect(); let mut new_items = SmallVector::one(a.fold_attrs(new_attrs)); new_items.push_all(decorator_items); @@ -970,9 +966,46 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } fn strip_unconfigured(&mut self) -> StripUnconfigured { - StripUnconfigured::new(&self.cx.cfg, - &self.cx.parse_sess.span_diagnostic, - self.cx.feature_gated_cfgs) + StripUnconfigured { + config: &self.cx.cfg, + should_test: self.cx.ecfg.should_test, + sess: self.cx.parse_sess, + features: self.cx.ecfg.features, + } + } + + fn load_macros(&mut self, node: &T) { + struct MacroLoadingVisitor<'a, 'b: 'a>{ + cx: &'a mut ExtCtxt<'b>, + at_crate_root: bool, + } + + impl<'a, 'b, 'v> Visitor<'v> for MacroLoadingVisitor<'a, 'b> { + fn visit_mac(&mut self, _: &'v ast::Mac) {} + fn visit_item(&mut self, item: &'v ast::Item) { + if let ast::ItemKind::ExternCrate(..) = item.node { + // We need to error on `#[macro_use] extern crate` when it isn't at the + // crate root, because `$crate` won't work properly. + for def in self.cx.loader.load_crate(item, self.at_crate_root) { + self.cx.insert_macro(def); + } + } else { + let at_crate_root = ::std::mem::replace(&mut self.at_crate_root, false); + visit::walk_item(self, item); + self.at_crate_root = at_crate_root; + } + } + fn visit_block(&mut self, block: &'v ast::Block) { + let at_crate_root = ::std::mem::replace(&mut self.at_crate_root, false); + visit::walk_block(self, block); + self.at_crate_root = at_crate_root; + } + } + + node.visit_with(&mut MacroLoadingVisitor { + at_crate_root: self.cx.syntax_env.is_crate_root(), + cx: self.cx, + }); } } @@ -1076,6 +1109,7 @@ pub struct ExpansionConfig<'feat> { pub features: Option<&'feat Features>, pub recursion_limit: usize, pub trace_mac: bool, + pub should_test: bool, // If false, strip `#[test]` nodes } macro_rules! feature_tests { @@ -1098,6 +1132,7 @@ impl<'feat> ExpansionConfig<'feat> { features: None, recursion_limit: 64, trace_mac: false, + should_test: false, } } @@ -1115,7 +1150,7 @@ impl<'feat> ExpansionConfig<'feat> { pub fn expand_crate(mut cx: ExtCtxt, user_exts: Vec, - c: Crate) -> (Crate, HashSet) { + mut c: Crate) -> (Crate, HashSet) { if std_inject::no_core(&c) { cx.crate_root = None; } else if std_inject::no_std(&c) { @@ -1130,6 +1165,10 @@ pub fn expand_crate(mut cx: ExtCtxt, expander.cx.syntax_env.insert(name, extension); } + let items = SmallVector::many(c.module.items); + expander.load_macros(&items); + c.module.items = items.into(); + let err_count = cx.parse_sess.span_diagnostic.err_count(); let mut ret = expander.fold_crate(c); ret.exported_macros = expander.cx.exported_macros.clone(); @@ -1262,8 +1301,8 @@ mod tests { src, Vec::new(), &sess).unwrap(); // should fail: - let (mut gated_cfgs, mut loader) = (vec![], DummyMacroLoader); - let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut gated_cfgs, &mut loader); + let mut loader = DummyMacroLoader; + let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader); expand_crate(ecx, vec![], crate_ast); } @@ -1277,8 +1316,8 @@ mod tests { "".to_string(), src, Vec::new(), &sess).unwrap(); - let (mut gated_cfgs, mut loader) = (vec![], DummyMacroLoader); - let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut gated_cfgs, &mut loader); + let mut loader = DummyMacroLoader; + let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader); expand_crate(ecx, vec![], crate_ast); } @@ -1291,8 +1330,8 @@ mod tests { "".to_string(), src, Vec::new(), &sess).unwrap(); - let (mut gated_cfgs, mut loader) = (vec![], DummyMacroLoader); - let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut gated_cfgs, &mut loader); + let mut loader = DummyMacroLoader; + let ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader); expand_crate(ecx, vec![], crate_ast); } @@ -1300,8 +1339,8 @@ mod tests { let ps = parse::ParseSess::new(); let crate_ast = panictry!(string_to_parser(&ps, crate_str).parse_crate_mod()); // the cfg argument actually does matter, here... - let (mut gated_cfgs, mut loader) = (vec![], DummyMacroLoader); - let ecx = ExtCtxt::new(&ps, vec![], test_ecfg(), &mut gated_cfgs, &mut loader); + let mut loader = DummyMacroLoader; + let ecx = ExtCtxt::new(&ps, vec![], test_ecfg(), &mut loader); expand_crate(ecx, vec![], crate_ast).0 } diff --git a/syntex_syntax/src/ext/source_util.rs b/syntex_syntax/src/ext/source_util.rs index 3e375e17..fd229d77 100644 --- a/syntex_syntax/src/ext/source_util.rs +++ b/syntex_syntax/src/ext/source_util.rs @@ -154,7 +154,7 @@ pub fn expand_include_str(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) // dependency information let filename = format!("{}", file.display()); let interned = token::intern_and_get_ident(&src[..]); - cx.codemap().new_filemap_and_lines(&filename, &src); + cx.codemap().new_filemap_and_lines(&filename, None, &src); base::MacEager::expr(cx.expr_str(sp, interned)) } @@ -185,7 +185,7 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) // Add this input file to the code map to make it available as // dependency information, but don't enter it's contents let filename = format!("{}", file.display()); - cx.codemap().new_filemap_and_lines(&filename, ""); + cx.codemap().new_filemap_and_lines(&filename, None, ""); base::MacEager::expr(cx.expr_lit(sp, ast::LitKind::ByteStr(Rc::new(bytes)))) } diff --git a/syntex_syntax/src/feature_gate.rs b/syntex_syntax/src/feature_gate.rs index 86c4a338..550eb0a5 100644 --- a/syntex_syntax/src/feature_gate.rs +++ b/syntex_syntax/src/feature_gate.rs @@ -34,10 +34,10 @@ use codemap::{CodeMap, Span}; use errors::Handler; use visit; use visit::{FnKind, Visitor}; +use parse::ParseSess; use parse::token::InternedString; use std::ascii::AsciiExt; -use std::cmp; macro_rules! setter { ($field: ident) => {{ @@ -603,60 +603,12 @@ const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)] ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)), ]; -#[derive(Debug, Eq, PartialEq)] -pub enum GatedCfgAttr { - GatedCfg(GatedCfg), - GatedAttr(Span), -} - #[derive(Debug, Eq, PartialEq)] pub struct GatedCfg { span: Span, index: usize, } -impl Ord for GatedCfgAttr { - fn cmp(&self, other: &GatedCfgAttr) -> cmp::Ordering { - let to_tup = |s: &GatedCfgAttr| match *s { - GatedCfgAttr::GatedCfg(ref gated_cfg) => { - (gated_cfg.span.lo.0, gated_cfg.span.hi.0, gated_cfg.index) - } - GatedCfgAttr::GatedAttr(ref span) => { - (span.lo.0, span.hi.0, GATED_CFGS.len()) - } - }; - to_tup(self).cmp(&to_tup(other)) - } -} - -impl PartialOrd for GatedCfgAttr { - fn partial_cmp(&self, other: &GatedCfgAttr) -> Option { - Some(self.cmp(other)) - } -} - -impl GatedCfgAttr { - pub fn check_and_emit(&self, - diagnostic: &Handler, - features: &Features, - codemap: &CodeMap) { - match *self { - GatedCfgAttr::GatedCfg(ref cfg) => { - cfg.check_and_emit(diagnostic, features, codemap); - } - GatedCfgAttr::GatedAttr(span) => { - if !features.stmt_expr_attributes { - emit_feature_err(diagnostic, - "stmt_expr_attributes", - span, - GateIssue::Language, - EXPLAIN_STMT_ATTR_SYNTAX); - } - } - } - } -} - impl GatedCfg { pub fn gate(cfg: &ast::MetaItem) -> Option { let name = cfg.name(); @@ -669,12 +621,11 @@ impl GatedCfg { } }) } - fn check_and_emit(&self, - diagnostic: &Handler, - features: &Features, - codemap: &CodeMap) { + + pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) { let (cfg, feature, has_feature) = GATED_CFGS[self.index]; - if !has_feature(features) && !codemap.span_allows_unstable(self.span) { + if !has_feature(features) && !sess.codemap().span_allows_unstable(self.span) { + let diagnostic = &sess.span_diagnostic; let explain = format!("`cfg({})` is experimental and subject to change", cfg); emit_feature_err(diagnostic, feature, self.span, GateIssue::Language, &explain); } @@ -810,7 +761,7 @@ pub fn emit_feature_err(diag: &Handler, feature: &str, span: Span, issue: GateIs const EXPLAIN_BOX_SYNTAX: &'static str = "box expression syntax is experimental; you can call `Box::new` instead."; -const EXPLAIN_STMT_ATTR_SYNTAX: &'static str = +pub const EXPLAIN_STMT_ATTR_SYNTAX: &'static str = "attributes on non-item statements and expressions are experimental."; pub const EXPLAIN_ASM: &'static str = @@ -1142,10 +1093,10 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { } } -pub fn get_features(span_handler: &Handler, krate: &ast::Crate) -> Features { +pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> Features { let mut features = Features::new(); - for attr in &krate.attrs { + for attr in krate_attrs { if !attr.check_name("feature") { continue } @@ -1188,21 +1139,19 @@ pub fn get_features(span_handler: &Handler, krate: &ast::Crate) -> Features { features } -pub fn check_crate(cm: &CodeMap, span_handler: &Handler, krate: &ast::Crate, +pub fn check_crate(krate: &ast::Crate, + sess: &ParseSess, + features: &Features, plugin_attributes: &[(String, AttributeType)], - unstable: UnstableFeatures) -> Features { - maybe_stage_features(span_handler, krate, unstable); - let features = get_features(span_handler, krate); - { - let ctx = Context { - features: &features, - span_handler: span_handler, - cm: cm, - plugin_attributes: plugin_attributes, - }; - visit::walk_crate(&mut PostExpansionVisitor { context: &ctx }, krate); - } - features + unstable: UnstableFeatures) { + maybe_stage_features(&sess.span_diagnostic, krate, unstable); + let ctx = Context { + features: features, + span_handler: &sess.span_diagnostic, + cm: sess.codemap(), + plugin_attributes: plugin_attributes, + }; + visit::walk_crate(&mut PostExpansionVisitor { context: &ctx }, krate); } #[derive(Clone, Copy)] diff --git a/syntex_syntax/src/parse/lexer/comments.rs b/syntex_syntax/src/parse/lexer/comments.rs index 629edced..06d255d5 100644 --- a/syntex_syntax/src/parse/lexer/comments.rs +++ b/syntex_syntax/src/parse/lexer/comments.rs @@ -346,7 +346,7 @@ pub fn gather_comments_and_literals(span_diagnostic: &errors::Handler, srdr.read_to_end(&mut src).unwrap(); let src = String::from_utf8(src).unwrap(); let cm = CodeMap::new(); - let filemap = cm.new_filemap(path, src); + let filemap = cm.new_filemap(path, None, src); let mut rdr = lexer::StringReader::new_raw(span_diagnostic, filemap); let mut comments: Vec = Vec::new(); diff --git a/syntex_syntax/src/parse/lexer/mod.rs b/syntex_syntax/src/parse/lexer/mod.rs index da35df40..37ab1605 100644 --- a/syntex_syntax/src/parse/lexer/mod.rs +++ b/syntex_syntax/src/parse/lexer/mod.rs @@ -1700,7 +1700,7 @@ mod tests { span_handler: &'a errors::Handler, teststr: String) -> StringReader<'a> { - let fm = cm.new_filemap("zebra.rs".to_string(), teststr); + let fm = cm.new_filemap("zebra.rs".to_string(), None, teststr); StringReader::new(span_handler, fm) } diff --git a/syntex_syntax/src/parse/mod.rs b/syntex_syntax/src/parse/mod.rs index c96d0022..d641ca8f 100644 --- a/syntex_syntax/src/parse/mod.rs +++ b/syntex_syntax/src/parse/mod.rs @@ -178,7 +178,7 @@ pub fn new_parser_from_source_str<'a>(sess: &'a ParseSess, name: String, source: String) -> Parser<'a> { - filemap_to_parser(sess, sess.codemap().new_filemap(name, source), cfg) + filemap_to_parser(sess, sess.codemap().new_filemap(name, None, source), cfg) } /// Create a new parser, handling errors as appropriate diff --git a/syntex_syntax/src/parse/parser.rs b/syntex_syntax/src/parse/parser.rs index 1f590ac0..dbf2fb05 100644 --- a/syntex_syntax/src/parse/parser.rs +++ b/syntex_syntax/src/parse/parser.rs @@ -5437,18 +5437,15 @@ impl<'a> Parser<'a> { name: String, id_sp: Span) -> PResult<'a, (ast::ItemKind, Vec )> { let mut included_mod_stack = self.sess.included_mod_stack.borrow_mut(); - match included_mod_stack.iter().position(|p| *p == path) { - Some(i) => { - let mut err = String::from("circular modules: "); - let len = included_mod_stack.len(); - for p in &included_mod_stack[i.. len] { - err.push_str(&p.to_string_lossy()); - err.push_str(" -> "); - } - err.push_str(&path.to_string_lossy()); - return Err(self.span_fatal(id_sp, &err[..])); - } - None => () + if let Some(i) = included_mod_stack.iter().position(|p| *p == path) { + let mut err = String::from("circular modules: "); + let len = included_mod_stack.len(); + for p in &included_mod_stack[i.. len] { + err.push_str(&p.to_string_lossy()); + err.push_str(" -> "); + } + err.push_str(&path.to_string_lossy()); + return Err(self.span_fatal(id_sp, &err[..])); } included_mod_stack.push(path.clone()); drop(included_mod_stack); diff --git a/syntex_syntax/src/print/pprust.rs b/syntex_syntax/src/print/pprust.rs index 49ff847d..59dbd483 100644 --- a/syntex_syntax/src/print/pprust.rs +++ b/syntex_syntax/src/print/pprust.rs @@ -1031,7 +1031,7 @@ impl<'a> State<'a> { try!(word(&mut self.s, "_")); } ast::TyKind::ImplicitSelf => { - unreachable!(); + try!(word(&mut self.s, "Self")); } ast::TyKind::Mac(ref m) => { try!(self.print_mac(m, token::Paren)); @@ -1403,8 +1403,9 @@ impl<'a> State<'a> { try!(self.commasep( Inconsistent, struct_def.fields(), |s, field| { - try!(s.print_visibility(&field.vis)); try!(s.maybe_print_comment(field.span.lo)); + try!(s.print_outer_attributes(&field.attrs)); + try!(s.print_visibility(&field.vis)); s.print_type(&field.ty) } )); @@ -2459,12 +2460,9 @@ impl<'a> State<'a> { } } try!(self.print_ident(path1.node)); - match *sub { - Some(ref p) => { - try!(word(&mut self.s, "@")); - try!(self.print_pat(&p)); - } - None => () + if let Some(ref p) = *sub { + try!(word(&mut self.s, "@")); + try!(self.print_pat(&p)); } } PatKind::TupleStruct(ref path, ref elts, ddpos) => { @@ -3008,20 +3006,19 @@ impl<'a> State<'a> { Some(cm) => cm, _ => return Ok(()) }; - match self.next_comment() { - Some(ref cmnt) => { - if (*cmnt).style != comments::Trailing { return Ok(()) } - let span_line = cm.lookup_char_pos(span.hi); - let comment_line = cm.lookup_char_pos((*cmnt).pos); - let mut next = (*cmnt).pos + BytePos(1); - match next_pos { None => (), Some(p) => next = p } - if span.hi < (*cmnt).pos && (*cmnt).pos < next && - span_line.line == comment_line.line { - try!(self.print_comment(cmnt)); - self.cur_cmnt_and_lit.cur_cmnt += 1; - } + if let Some(ref cmnt) = self.next_comment() { + if (*cmnt).style != comments::Trailing { return Ok(()) } + let span_line = cm.lookup_char_pos(span.hi); + let comment_line = cm.lookup_char_pos((*cmnt).pos); + let mut next = (*cmnt).pos + BytePos(1); + if let Some(p) = next_pos { + next = p; + } + if span.hi < (*cmnt).pos && (*cmnt).pos < next && + span_line.line == comment_line.line { + try!(self.print_comment(cmnt)); + self.cur_cmnt_and_lit.cur_cmnt += 1; } - _ => () } Ok(()) } diff --git a/syntex_syntax/src/test.rs b/syntex_syntax/src/test.rs index 2ac4aac6..ca6ed76d 100644 --- a/syntex_syntax/src/test.rs +++ b/syntex_syntax/src/test.rs @@ -81,7 +81,7 @@ pub fn modify_for_testing(sess: &ParseSess, if should_test { generate_test_harness(sess, reexport_test_harness_main, krate, span_diagnostic) } else { - strip_test_functions(krate) + krate } } @@ -270,14 +270,12 @@ fn generate_test_harness(sess: &ParseSess, let mut cleaner = EntryPointCleaner { depth: 0 }; let krate = cleaner.fold_crate(krate); - let mut feature_gated_cfgs = vec![]; let mut loader = DummyMacroLoader; let mut cx: TestCtxt = TestCtxt { sess: sess, span_diagnostic: sd, ext_cx: ExtCtxt::new(sess, vec![], ExpansionConfig::default("test".to_string()), - &mut feature_gated_cfgs, &mut loader), path: Vec::new(), testfns: Vec::new(), @@ -306,19 +304,6 @@ fn generate_test_harness(sess: &ParseSess, return res; } -fn strip_test_functions(krate: ast::Crate) -> ast::Crate { - // When not compiling with --test we should not compile the - // #[test] functions - struct StripTests; - impl config::CfgFolder for StripTests { - fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool { - !attr::contains_name(attrs, "test") && !attr::contains_name(attrs, "bench") - } - } - - StripTests.fold_crate(krate) -} - /// Craft a span that will be ignored by the stability lint's /// call to codemap's is_internal check. /// The expanded code calls some unstable functions in the test crate. diff --git a/syntex_syntax/src/util/interner.rs b/syntex_syntax/src/util/interner.rs index 8e203580..7295b36a 100644 --- a/syntex_syntax/src/util/interner.rs +++ b/syntex_syntax/src/util/interner.rs @@ -47,9 +47,8 @@ impl Interner { pub fn intern(&self, val: T) -> Name { let mut map = self.map.borrow_mut(); - match (*map).get(&val) { - Some(&idx) => return idx, - None => (), + if let Some(&idx) = (*map).get(&val) { + return idx; } let mut vect = self.vect.borrow_mut(); @@ -161,9 +160,8 @@ impl StrInterner { pub fn intern(&self, val: &str) -> Name { let mut map = self.map.borrow_mut(); - match map.get(val) { - Some(&idx) => return idx, - None => (), + if let Some(&idx) = map.get(val) { + return idx; } let new_idx = Name(self.len() as u32); diff --git a/syntex_syntax/src/util/parser_testing.rs b/syntex_syntax/src/util/parser_testing.rs index ae07212d..43e8fb08 100644 --- a/syntex_syntax/src/util/parser_testing.rs +++ b/syntex_syntax/src/util/parser_testing.rs @@ -19,7 +19,7 @@ use std::iter::Peekable; /// Map a string to tts, using a made-up filename: pub fn string_to_tts(source_str: String) -> Vec { let ps = ParseSess::new(); - filemap_to_tts(&ps, ps.codemap().new_filemap("bogofile".to_string(), source_str)) + filemap_to_tts(&ps, ps.codemap().new_filemap("bogofile".to_string(), None, source_str)) } /// Map string to parser (via tts) diff --git a/syntex_syntax/src/util/small_vector.rs b/syntex_syntax/src/util/small_vector.rs index 8b07b21c..893646f1 100644 --- a/syntex_syntax/src/util/small_vector.rs +++ b/syntex_syntax/src/util/small_vector.rs @@ -29,6 +29,16 @@ enum SmallVectorRepr { Many(Vec), } +impl Into> for SmallVector { + fn into(self) -> Vec { + match self.repr { + Zero => Vec::new(), + One(t) => vec![t], + Many(vec) => vec, + } + } +} + impl FromIterator for SmallVector { fn from_iter>(iter: I) -> SmallVector { let mut v = SmallVector::zero(); @@ -136,6 +146,15 @@ impl SmallVector { } pub fn is_empty(&self) -> bool { self.len() == 0 } + + pub fn map U>(self, mut f: F) -> SmallVector { + let repr = match self.repr { + Zero => Zero, + One(t) => One(f(t)), + Many(vec) => Many(vec.into_iter().map(f).collect()), + }; + SmallVector { repr: repr } + } } impl IntoIterator for SmallVector { diff --git a/syntex_syntax/src/visit.rs b/syntex_syntax/src/visit.rs index c388721e..fa4164a9 100644 --- a/syntex_syntax/src/visit.rs +++ b/syntex_syntax/src/visit.rs @@ -193,6 +193,9 @@ pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod) { } pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) { + for attr in local.attrs.as_attr_slice() { + visitor.visit_attribute(attr); + } visitor.visit_pat(&local.pat); walk_opt!(visitor, visit_ty, &local.ty); walk_opt!(visitor, visit_expr, &local.init); @@ -643,6 +646,9 @@ pub fn walk_mac<'v, V: Visitor<'v>>(_: &mut V, _: &'v Mac) { } pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { + for attr in expression.attrs.as_attr_slice() { + visitor.visit_attribute(attr); + } match expression.node { ExprKind::Box(ref subexpression) => { visitor.visit_expr(subexpression)