diff options
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/ext/asm.rs | 7 | ||||
| -rw-r--r-- | src/libsyntax/ext/base.rs | 9 | ||||
| -rw-r--r-- | src/libsyntax/ext/concat_idents.rs | 9 | ||||
| -rw-r--r-- | src/libsyntax/ext/expand.rs | 60 | ||||
| -rw-r--r-- | src/libsyntax/ext/log_syntax.rs | 8 | ||||
| -rw-r--r-- | src/libsyntax/ext/trace_macros.rs | 10 | ||||
| -rw-r--r-- | src/libsyntax/feature_gate.rs | 252 | ||||
| -rw-r--r-- | src/libsyntax/lib.rs | 4 | ||||
| -rw-r--r-- | src/libsyntax/print/pprust.rs | 10 |
9 files changed, 294 insertions, 75 deletions
diff --git a/src/libsyntax/ext/asm.rs b/src/libsyntax/ext/asm.rs index 1ceda2e08dd..d8cba139fb5 100644 --- a/src/libsyntax/ext/asm.rs +++ b/src/libsyntax/ext/asm.rs @@ -18,6 +18,7 @@ use codemap; use codemap::Span; use ext::base; use ext::base::*; +use feature_gate; use parse::token::InternedString; use parse::token; use ptr::P; @@ -48,6 +49,12 @@ static OPTIONS: &'static [&'static str] = &["volatile", "alignstack", "intel"]; pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> Box<base::MacResult+'cx> { + if !cx.ecfg.enable_asm() { + feature_gate::emit_feature_err( + &cx.parse_sess.span_diagnostic, "asm", sp, feature_gate::EXPLAIN_ASM); + return DummyResult::expr(sp); + } + let mut p = cx.new_parser_from_tts(tts); let mut asm = InternedString::new(""); let mut asm_str_style = None; diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 083039995ee..8800ffd1e9b 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -439,7 +439,8 @@ impl BlockInfo { /// The base map of methods for expanding syntax extension /// AST nodes into full ASTs -fn initial_syntax_expander_table(ecfg: &expand::ExpansionConfig) -> SyntaxEnv { +fn initial_syntax_expander_table<'feat>(ecfg: &expand::ExpansionConfig<'feat>) + -> SyntaxEnv { // utility function to simplify creating NormalTT syntax extensions fn builtin_normal_expander(f: MacroExpanderFn) -> SyntaxExtension { NormalTT(box f, None) @@ -470,7 +471,7 @@ fn initial_syntax_expander_table(ecfg: &expand::ExpansionConfig) -> SyntaxEnv { syntax_expanders.insert(intern("deriving"), Decorator(box ext::deriving::expand_deprecated_deriving)); - if ecfg.enable_quotes { + if ecfg.enable_quotes() { // Quasi-quoting expanders syntax_expanders.insert(intern("quote_tokens"), builtin_normal_expander( @@ -541,7 +542,7 @@ pub struct ExtCtxt<'a> { pub parse_sess: &'a parse::ParseSess, pub cfg: ast::CrateConfig, pub backtrace: ExpnId, - pub ecfg: expand::ExpansionConfig, + pub ecfg: expand::ExpansionConfig<'a>, pub use_std: bool, pub mod_path: Vec<ast::Ident> , @@ -554,7 +555,7 @@ pub struct ExtCtxt<'a> { impl<'a> ExtCtxt<'a> { pub fn new(parse_sess: &'a parse::ParseSess, cfg: ast::CrateConfig, - ecfg: expand::ExpansionConfig) -> ExtCtxt<'a> { + ecfg: expand::ExpansionConfig<'a>) -> ExtCtxt<'a> { let env = initial_syntax_expander_table(&ecfg); ExtCtxt { parse_sess: parse_sess, diff --git a/src/libsyntax/ext/concat_idents.rs b/src/libsyntax/ext/concat_idents.rs index 364cacd735c..63a8bd9ddf1 100644 --- a/src/libsyntax/ext/concat_idents.rs +++ b/src/libsyntax/ext/concat_idents.rs @@ -12,12 +12,21 @@ use ast; use codemap::Span; use ext::base::*; use ext::base; +use feature_gate; use parse::token; use parse::token::{str_to_ident}; use ptr::P; pub fn expand_syntax_ext<'cx>(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> Box<base::MacResult+'cx> { + if !cx.ecfg.enable_concat_idents() { + feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic, + "concat_idents", + sp, + feature_gate::EXPLAIN_CONCAT_IDENTS); + return base::DummyResult::expr(sp); + } + let mut res_str = String::new(); for (i, e) in tts.iter().enumerate() { if i & 1 == 1 { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index fd98f42c2ab..6b7cecee815 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -22,6 +22,7 @@ use attr::AttrMetaMethods; use codemap; use codemap::{Span, Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute}; use ext::base::*; +use feature_gate::{Features}; use fold; use fold::*; use parse; @@ -1408,28 +1409,63 @@ fn new_span(cx: &ExtCtxt, sp: Span) -> Span { } } -pub struct ExpansionConfig { +pub struct ExpansionConfig<'feat> { pub crate_name: String, - pub enable_quotes: bool, + pub features: Option<&'feat Features>, pub recursion_limit: usize, } -impl ExpansionConfig { - pub fn default(crate_name: String) -> ExpansionConfig { +impl<'feat> ExpansionConfig<'feat> { + pub fn default(crate_name: String) -> ExpansionConfig<'static> { ExpansionConfig { crate_name: crate_name, - enable_quotes: false, + features: None, recursion_limit: 64, } } + + pub fn enable_quotes(&self) -> bool { + match self.features { + Some(&Features { allow_quote: true, .. }) => true, + _ => false, + } + } + + pub fn enable_asm(&self) -> bool { + match self.features { + Some(&Features { allow_asm: true, .. }) => true, + _ => false, + } + } + + pub fn enable_log_syntax(&self) -> bool { + match self.features { + Some(&Features { allow_log_syntax: true, .. }) => true, + _ => false, + } + } + + pub fn enable_concat_idents(&self) -> bool { + match self.features { + Some(&Features { allow_concat_idents: true, .. }) => true, + _ => false, + } + } + + pub fn enable_trace_macros(&self) -> bool { + match self.features { + Some(&Features { allow_trace_macros: true, .. }) => true, + _ => false, + } + } } -pub fn expand_crate(parse_sess: &parse::ParseSess, - cfg: ExpansionConfig, - // these are the macros being imported to this crate: - imported_macros: Vec<ast::MacroDef>, - user_exts: Vec<NamedSyntaxExtension>, - c: Crate) -> Crate { +pub fn expand_crate<'feat>(parse_sess: &parse::ParseSess, + cfg: ExpansionConfig<'feat>, + // these are the macros being imported to this crate: + imported_macros: Vec<ast::MacroDef>, + user_exts: Vec<NamedSyntaxExtension>, + c: Crate) -> Crate { let mut cx = ExtCtxt::new(parse_sess, c.config.clone(), cfg); cx.use_std = std_inject::use_std(&c); @@ -1598,7 +1634,7 @@ mod test { // these following tests are quite fragile, in that they don't test what // *kind* of failure occurs. - fn test_ecfg() -> ExpansionConfig { + fn test_ecfg() -> ExpansionConfig<'static> { ExpansionConfig::default("test".to_string()) } diff --git a/src/libsyntax/ext/log_syntax.rs b/src/libsyntax/ext/log_syntax.rs index 30301e3b8cc..8173dd93f74 100644 --- a/src/libsyntax/ext/log_syntax.rs +++ b/src/libsyntax/ext/log_syntax.rs @@ -11,12 +11,20 @@ use ast; use codemap; use ext::base; +use feature_gate; use print; pub fn expand_syntax_ext<'cx>(cx: &'cx mut base::ExtCtxt, sp: codemap::Span, tts: &[ast::TokenTree]) -> Box<base::MacResult+'cx> { + if !cx.ecfg.enable_log_syntax() { + feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic, + "log_syntax", + sp, + feature_gate::EXPLAIN_LOG_SYNTAX); + return base::DummyResult::any(sp); + } cx.print_backtrace(); diff --git a/src/libsyntax/ext/trace_macros.rs b/src/libsyntax/ext/trace_macros.rs index 76f7b7b0d7b..3fcc6a8d692 100644 --- a/src/libsyntax/ext/trace_macros.rs +++ b/src/libsyntax/ext/trace_macros.rs @@ -12,6 +12,7 @@ use ast; use codemap::Span; use ext::base::ExtCtxt; use ext::base; +use feature_gate; use parse::token::keywords; @@ -19,6 +20,15 @@ pub fn expand_trace_macros(cx: &mut ExtCtxt, sp: Span, tt: &[ast::TokenTree]) -> Box<base::MacResult+'static> { + if !cx.ecfg.enable_trace_macros() { + feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic, + "trace_macros", + sp, + feature_gate::EXPLAIN_TRACE_MACROS); + return base::DummyResult::any(sp); + } + + match tt { [ast::TtToken(_, ref tok)] if tok.is_keyword(keywords::True) => { cx.set_trace_macros(true); diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index fd1ca11818c..3bebba15a57 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -23,6 +23,7 @@ //! becomes stable. use self::Status::*; +use self::AttributeType::*; use abi::RustIntrinsic; use ast::NodeId; @@ -35,7 +36,6 @@ use visit; use visit::Visitor; use parse::token::{self, InternedString}; -use std::slice; use std::ascii::AsciiExt; // If you change this list without updating src/doc/reference.md, @cmr will be sad @@ -133,6 +133,12 @@ static KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[ // Allows using the unsafe_no_drop_flag attribute (unlikely to // switch to Accepted; see RFC 320) ("unsafe_no_drop_flag", "1.0.0", Active), + + // Allows the use of custom attributes; RFC 572 + ("custom_attribute", "1.0.0", Active), + + // Allows the use of rustc_* attributes; RFC 572 + ("rustc_attrs", "1.0.0", Active), ]; // (changing above list without updating src/doc/reference.md makes @cmr sad) @@ -152,12 +158,148 @@ enum Status { Accepted, } +// Attributes that have a special meaning to rustc or rustdoc +pub static KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[ + // Normal attributes + + ("warn", Normal), + ("allow", Normal), + ("forbid", Normal), + ("deny", Normal), + + ("macro_reexport", Normal), + ("macro_use", Normal), + ("macro_export", Normal), + ("plugin_registrar", Normal), + + ("cfg", Normal), + ("main", Normal), + ("start", Normal), + ("test", Normal), + ("bench", Normal), + ("simd", Normal), + ("repr", Normal), + ("path", Normal), + ("abi", Normal), + ("unsafe_destructor", Normal), + ("automatically_derived", Normal), + ("no_mangle", Normal), + ("no_link", Normal), + ("derive", Normal), + ("should_fail", Normal), + ("ignore", Normal), + ("no_implicit_prelude", Normal), + ("reexport_test_harness_main", Normal), + ("link_args", Normal), + ("macro_escape", Normal), + + + ("staged_api", Gated("staged_api", + "staged_api is for use by rustc only")), + ("plugin", Gated("plugin", + "compiler plugins are experimental \ + and possibly buggy")), + ("no_std", Gated("no_std", + "no_std is experimental")), + ("lang", Gated("lang_items", + "language items are subject to change")), + ("linkage", Gated("linkage", + "the `linkage` attribute is experimental \ + and not portable across platforms")), + ("thread_local", Gated("thread_local", + "`#[thread_local]` is an experimental feature, and does not \ + currently handle destructors. There is no corresponding \ + `#[task_local]` mapping to the task model")), + + ("rustc_on_unimplemented", Gated("on_unimplemented", + "the `#[rustc_on_unimplemented]` attribute \ + is an experimental feature")), + ("rustc_variance", Gated("rustc_attrs", + "the `#[rustc_variance]` attribute \ + is an experimental feature")), + ("rustc_error", Gated("rustc_attrs", + "the `#[rustc_error]` attribute \ + is an experimental feature")), + ("rustc_move_fragments", Gated("rustc_attrs", + "the `#[rustc_move_fragments]` attribute \ + is an experimental feature")), + + // FIXME: #14408 whitelist docs since rustdoc looks at them + ("doc", Whitelisted), + + // FIXME: #14406 these are processed in trans, which happens after the + // lint pass + ("cold", Whitelisted), + ("export_name", Whitelisted), + ("inline", Whitelisted), + ("link", Whitelisted), + ("link_name", Whitelisted), + ("link_section", Whitelisted), + ("no_builtins", Whitelisted), + ("no_mangle", Whitelisted), + ("no_split_stack", Whitelisted), + ("no_stack_check", Whitelisted), + ("packed", Whitelisted), + ("static_assert", Whitelisted), + ("no_debug", Whitelisted), + ("omit_gdb_pretty_printer_section", Whitelisted), + ("unsafe_no_drop_flag", Whitelisted), + + // used in resolve + ("prelude_import", Whitelisted), + + // FIXME: #14407 these are only looked at on-demand so we can't + // guarantee they'll have already been checked + ("deprecated", Whitelisted), + ("must_use", Whitelisted), + ("stable", Whitelisted), + ("unstable", Whitelisted), + + // FIXME: #19470 this shouldn't be needed forever + ("old_orphan_check", Whitelisted), + ("old_impl_check", Whitelisted), + ("rustc_paren_sugar", Whitelisted), // FIXME: #18101 temporary unboxed closure hack + + // Crate level attributes + ("crate_name", CrateLevel), + ("crate_type", CrateLevel), + ("crate_id", CrateLevel), + ("feature", CrateLevel), + ("no_start", CrateLevel), + ("no_main", CrateLevel), + ("no_builtins", CrateLevel), + ("recursion_limit", CrateLevel), +]; + +#[derive(PartialEq, Copy)] +pub enum AttributeType { + /// Normal, builtin attribute that is consumed + /// by the compiler before the unused_attribute check + Normal, + + /// Builtin attribute that may not be consumed by the compiler + /// before the unused_attribute check. These attributes + /// will be ignored by the unused_attribute lint + Whitelisted, + + /// Is gated by a given feature gate and reason + /// These get whitelisted too + Gated(&'static str, &'static str), + + /// Builtin attribute that is only allowed at the crate level + CrateLevel, +} + /// A set of features to be used by later passes. pub struct Features { pub unboxed_closures: bool, pub rustc_diagnostic_macros: bool, pub visible_private_types: bool, - pub quote: bool, + pub allow_quote: bool, + pub allow_asm: bool, + pub allow_log_syntax: bool, + pub allow_concat_idents: bool, + pub allow_trace_macros: bool, pub old_orphan_check: bool, pub simd_ffi: bool, pub unmarked_api: bool, @@ -173,7 +315,11 @@ impl Features { unboxed_closures: false, rustc_diagnostic_macros: false, visible_private_types: false, - quote: false, + allow_quote: false, + allow_asm: false, + allow_log_syntax: false, + allow_concat_idents: false, + allow_trace_macros: false, old_orphan_check: false, simd_ffi: false, unmarked_api: false, @@ -222,6 +368,18 @@ pub fn emit_feature_warn(diag: &SpanHandler, feature: &str, span: Span, explain: } } +pub const EXPLAIN_ASM: &'static str = + "inline assembly is not stable enough for use and is subject to change"; + +pub const EXPLAIN_LOG_SYNTAX: &'static str = + "`log_syntax!` is not stable enough for use and is subject to change"; + +pub const EXPLAIN_CONCAT_IDENTS: &'static str = + "`concat_idents` is not stable enough for use and is subject to change"; + +pub const EXPLAIN_TRACE_MACROS: &'static str = + "`trace_macros` is not stable enough for use and is subject to change"; + struct MacroVisitor<'a> { context: &'a Context<'a> } @@ -231,24 +389,28 @@ impl<'a, 'v> Visitor<'v> for MacroVisitor<'a> { let ast::MacInvocTT(ref path, _, _) = mac.node; let id = path.segments.last().unwrap().identifier; + // Issue 22234: If you add a new case here, make sure to also + // add code to catch the macro during or after expansion. + // + // We still keep this MacroVisitor (rather than *solely* + // relying on catching cases during or after expansion) to + // catch uses of these macros within conditionally-compiled + // code, e.g. `#[cfg]`-guarded functions. + 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"); + self.context.gate_feature("asm", path.span, EXPLAIN_ASM); } 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"); + self.context.gate_feature("log_syntax", path.span, EXPLAIN_LOG_SYNTAX); } 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"); + self.context.gate_feature("trace_macros", path.span, EXPLAIN_TRACE_MACROS); } 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"); + self.context.gate_feature("concat_idents", path.span, EXPLAIN_CONCAT_IDENTS); } } } @@ -274,22 +436,6 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { } fn visit_item(&mut self, i: &ast::Item) { - for attr in &i.attrs { - if attr.name() == "thread_local" { - self.gate_feature("thread_local", i.span, - "`#[thread_local]` is an experimental feature, and does not \ - currently handle destructors. There is no corresponding \ - `#[task_local]` mapping to the task model"); - } else if attr.name() == "linkage" { - self.gate_feature("linkage", i.span, - "the `linkage` attribute is experimental \ - and not portable across platforms") - } else if attr.name() == "rustc_on_unimplemented" { - self.gate_feature("on_unimplemented", i.span, - "the `#[rustc_on_unimplemented]` attribute \ - is an experimental feature") - } - } match i.node { ast::ItemExternCrate(_) => { if attr::contains_name(&i.attrs[], "macro_reexport") { @@ -463,30 +609,27 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { } fn visit_attribute(&mut self, attr: &ast::Attribute) { - if attr.check_name("staged_api") { - self.gate_feature("staged_api", attr.span, - "staged_api is for use by rustc only"); - } else if attr.check_name("plugin") { - self.gate_feature("plugin", attr.span, - "compiler plugins are experimental \ - and possibly buggy"); - } - - if attr::contains_name(slice::ref_slice(attr), "lang") { - self.gate_feature("lang_items", - attr.span, - "language items are subject to change"); - } - - if attr.check_name("no_std") { - self.gate_feature("no_std", attr.span, - "no_std is experimental"); + let name = &*attr.name(); + for &(n, ty) in KNOWN_ATTRIBUTES { + if n == name { + if let Gated(gate, desc) = ty { + self.gate_feature(gate, attr.span, desc); + } + return; + } } - - if attr.check_name("unsafe_no_drop_flag") { - self.gate_feature("unsafe_no_drop_flag", attr.span, - "unsafe_no_drop_flag has unstable semantics \ - and may be removed in the future"); + if name.starts_with("rustc_") { + self.gate_feature("rustc_attrs", attr.span, + "unless otherwise specified, attributes \ + with the prefix `rustc_` \ + are reserved for internal compiler diagnostics"); + } else { + self.gate_feature("custom_attribute", attr.span, + format!("The attribute `{}` is currently \ + unknown to the the compiler and \ + may have meaning \ + added to it in the future", + name).as_slice()); } } @@ -591,11 +734,18 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::C check(&mut cx, krate); + // FIXME (pnkfelix): Before adding the 99th entry below, change it + // to a single-pass (instead of N calls to `.has_feature`). + Features { unboxed_closures: cx.has_feature("unboxed_closures"), rustc_diagnostic_macros: cx.has_feature("rustc_diagnostic_macros"), visible_private_types: cx.has_feature("visible_private_types"), - quote: cx.has_feature("quote"), + allow_quote: cx.has_feature("quote"), + allow_asm: cx.has_feature("asm"), + allow_log_syntax: cx.has_feature("log_syntax"), + allow_concat_idents: cx.has_feature("concat_idents"), + allow_trace_macros: cx.has_feature("trace_macros"), old_orphan_check: cx.has_feature("old_orphan_check"), simd_ffi: cx.has_feature("simd_ffi"), unmarked_api: cx.has_feature("unmarked_api"), diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index f4b0c867f42..e8bdcd62b58 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -30,9 +30,9 @@ #![feature(env)] #![feature(hash)] #![feature(int_uint)] -#![feature(io)] +#![feature(old_io)] #![feature(libc)] -#![feature(path)] +#![feature(old_path)] #![feature(quote, unsafe_destructor)] #![feature(rustc_private)] #![feature(staged_api)] diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 583095e1574..4b021f2434f 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2761,15 +2761,13 @@ impl<'a> State<'a> { ast::LitStr(ref st, style) => self.print_string(&st, style), ast::LitByte(byte) => { let mut res = String::from_str("b'"); - ascii::escape_default(byte, |c| res.push(c as char)); + res.extend(ascii::escape_default(byte).map(|c| c as char)); res.push('\''); word(&mut self.s, &res[]) } ast::LitChar(ch) => { let mut res = String::from_str("'"); - for c in ch.escape_default() { - res.push(c); - } + res.extend(ch.escape_default()); res.push('\''); word(&mut self.s, &res[]) } @@ -2809,8 +2807,8 @@ impl<'a> State<'a> { ast::LitBinary(ref v) => { let mut escaped: String = String::new(); for &ch in &**v { - ascii::escape_default(ch as u8, - |ch| escaped.push(ch as char)); + escaped.extend(ascii::escape_default(ch as u8) + .map(|c| c as char)); } word(&mut self.s, &format!("b\"{}\"", escaped)[]) } |
