diff options
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/codemap.rs | 32 | ||||
| -rw-r--r-- | src/libsyntax/feature_gate.rs | 123 |
2 files changed, 120 insertions, 35 deletions
diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 6b9af29c604..e61afb8b193 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -563,6 +563,38 @@ impl CodeMap { ExpnId(i) => f(Some(&(*self.expansions.borrow())[i as uint])) } } + + /// Check if a span is "internal" to a macro. This means that it is entirely generated by a + /// macro expansion and contains no code that was passed in as an argument. + pub fn span_is_internal(&self, span: Span) -> bool { + // first, check if the given expression was generated by a macro or not + // we need to go back the expn_info tree to check only the arguments + // of the initial macro call, not the nested ones. + let mut is_internal = false; + let mut expnid = span.expn_id; + while self.with_expn_info(expnid, |expninfo| { + match expninfo { + Some(ref info) => { + // save the parent expn_id for next loop iteration + expnid = info.call_site.expn_id; + if info.callee.span.is_none() { + // it's a compiler built-in, we *really* don't want to mess with it + // so we skip it, unless it was called by a regular macro, in which case + // we will handle the caller macro next turn + is_internal = true; + true // continue looping + } else { + // was this expression from the current macro arguments ? + is_internal = !( span.lo > info.call_site.lo && + span.hi < info.call_site.hi ); + true // continue looping + } + }, + _ => false // stop looping + } + }) { /* empty while loop body */ } + return is_internal; + } } #[cfg(test)] diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 4607520655e..b2c2d7eb626 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -24,7 +24,7 @@ use ast::NodeId; use ast; use attr; use attr::AttrMetaMethods; -use codemap::Span; +use codemap::{CodeMap, Span}; use diagnostic::SpanHandler; use visit; use visit::Visitor; @@ -127,6 +127,7 @@ impl Features { struct Context<'a> { features: Vec<&'static str>, span_handler: &'a SpanHandler, + cm: &'a CodeMap, } impl<'a> Context<'a> { @@ -144,7 +145,71 @@ impl<'a> Context<'a> { } } -impl<'a, 'v> Visitor<'v> for Context<'a> { +struct MacroVisitor<'a> { + context: &'a Context<'a> +} + +impl<'a, 'v> Visitor<'v> for MacroVisitor<'a> { + fn visit_view_item(&mut self, i: &ast::ViewItem) { + match i.node { + ast::ViewItemExternCrate(..) => { + for attr in i.attrs.iter() { + if attr.name().get() == "phase"{ + self.context.gate_feature("phase", attr.span, + "compile time crate loading is \ + experimental and possibly buggy"); + } + } + }, + _ => { } + } + visit::walk_view_item(self, i) + } + + fn visit_mac(&mut self, macro: &ast::Mac) { + let ast::MacInvocTT(ref path, _, _) = macro.node; + let id = path.segments.last().unwrap().identifier; + + if id == token::str_to_ident("macro_rules") { + self.context.gate_feature("macro_rules", path.span, "macro definitions are \ + not stable enough for use and are subject to change"); + } + + else if id == token::str_to_ident("asm") { + self.context.gate_feature("asm", path.span, "inline assembly is not \ + stable enough for use and is subject to change"); + } + + else if id == token::str_to_ident("log_syntax") { + self.context.gate_feature("log_syntax", path.span, "`log_syntax!` is not \ + stable enough for use and is subject to change"); + } + + else if id == token::str_to_ident("trace_macros") { + self.context.gate_feature("trace_macros", path.span, "`trace_macros` is not \ + stable enough for use and is subject to change"); + } + + else if id == token::str_to_ident("concat_idents") { + self.context.gate_feature("concat_idents", path.span, "`concat_idents` is not \ + stable enough for use and is subject to change"); + } + } +} + +struct PostExpansionVisitor<'a> { + context: &'a Context<'a> +} + +impl<'a> PostExpansionVisitor<'a> { + fn gate_feature(&self, feature: &str, span: Span, explain: &str) { + if !self.context.cm.span_is_internal(span) { + self.context.gate_feature(feature, span, explain) + } + } +} + +impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { fn visit_name(&mut self, sp: Span, name: ast::Name) { if !token::get_name(name).get().is_ascii() { self.gate_feature("non_ascii_idents", sp, @@ -217,7 +282,7 @@ impl<'a, 'v> Visitor<'v> for Context<'a> { } ast::ItemImpl(_, _, _, _, ref items) => { - if attr::contains_name(i.attrs.as_slice(), + if attr::contains_name(i.attrs[], "unsafe_destructor") { self.gate_feature("unsafe_destructor", i.span, @@ -256,36 +321,6 @@ impl<'a, 'v> Visitor<'v> for Context<'a> { } } - fn visit_mac(&mut self, macro: &ast::Mac) { - let ast::MacInvocTT(ref path, _, _) = macro.node; - let id = path.segments.last().unwrap().identifier; - - if id == token::str_to_ident("macro_rules") { - self.gate_feature("macro_rules", path.span, "macro definitions are \ - not stable enough for use and are subject to change"); - } - - else if id == token::str_to_ident("asm") { - self.gate_feature("asm", path.span, "inline assembly is not \ - stable enough for use and is subject to change"); - } - - else if id == token::str_to_ident("log_syntax") { - self.gate_feature("log_syntax", path.span, "`log_syntax!` is not \ - stable enough for use and is subject to change"); - } - - else if id == token::str_to_ident("trace_macros") { - self.gate_feature("trace_macros", path.span, "`trace_macros` is not \ - stable enough for use and is subject to change"); - } - - else if id == token::str_to_ident("concat_idents") { - self.gate_feature("concat_idents", path.span, "`concat_idents` is not \ - stable enough for use and is subject to change"); - } - } - fn visit_foreign_item(&mut self, i: &ast::ForeignItem) { if attr::contains_name(i.attrs[], "linkage") { self.gate_feature("linkage", i.span, @@ -371,10 +406,15 @@ impl<'a, 'v> Visitor<'v> for Context<'a> { } } -pub fn check_crate(span_handler: &SpanHandler, krate: &ast::Crate) -> (Features, Vec<Span>) { +fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::Crate, + check: F) + -> (Features, Vec<Span>) + where F: FnOnce(&mut Context, &ast::Crate) +{ let mut cx = Context { features: Vec::new(), span_handler: span_handler, + cm: cm, }; let mut unknown_features = Vec::new(); @@ -419,7 +459,7 @@ pub fn check_crate(span_handler: &SpanHandler, krate: &ast::Crate) -> (Features, } } - visit::walk_crate(&mut cx, krate); + check(&mut cx, krate); (Features { default_type_params: cx.has_feature("default_type_params"), @@ -432,3 +472,16 @@ pub fn check_crate(span_handler: &SpanHandler, krate: &ast::Crate) -> (Features, }, unknown_features) } + +pub fn check_crate_macros(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::Crate) +-> (Features, Vec<Span>) { + check_crate_inner(cm, span_handler, krate, + |ctx, krate| visit::walk_crate(&mut MacroVisitor { context: ctx }, krate)) +} + +pub fn check_crate(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::Crate) +-> (Features, Vec<Span>) { + check_crate_inner(cm, span_handler, krate, + |ctx, krate| visit::walk_crate(&mut PostExpansionVisitor { context: ctx }, + krate)) +} |
