From 2f1dfe615d479f19fa1b989e014eb8d4d516a23a Mon Sep 17 00:00:00 2001 From: Leo Testard Date: Thu, 7 Apr 2016 11:15:32 +0200 Subject: [PATCH 1/5] Rewrite the feature-gate checks to use a structure instead of a list of strings. --- src/libsyntax/feature_gate.rs | 634 ++++++++++++++++++++++------------ 1 file changed, 411 insertions(+), 223 deletions(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index d8352430eb94e..7b0a0f39b24cd 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -40,6 +40,18 @@ use parse::token::InternedString; use std::ascii::AsciiExt; use std::cmp; +enum Status { + /// Represents an active feature that is currently being implemented or + /// currently being considered for addition/removal. + Active, + + /// Represents a feature which has since been removed (it was once Active) + Removed, + + /// This language feature has since been Accepted (it was once Active) + Accepted, +} + // If you change this list without updating src/doc/reference.md, @cmr will be sad // Don't ever remove anything from this list; set them to 'Removed'. // The version numbers here correspond to the version in which the current status @@ -262,16 +274,47 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Option, Status ]; // (changing above list without updating src/doc/reference.md makes @cmr sad) -enum Status { - /// Represents an active feature that is currently being implemented or - /// currently being considered for addition/removal. - Active, +#[derive(PartialEq, Copy, Clone, Debug)] +pub enum AttributeType { + /// Normal, builtin attribute that is consumed + /// by the compiler before the unused_attribute check + Normal, - /// Represents a feature which has since been removed (it was once Active) - Removed, + /// 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, - /// This language feature has since been Accepted (it was once Active) - Accepted, + /// Builtin attribute that is only allowed at the crate level + CrateLevel, +} + +pub enum AttributeGate { + /// Is gated by a given feature gate, reason + /// and function to check if enabled + Gated(&'static str, &'static str, fn(&Features) -> bool), + + /// Ungated attribute, can be used on all release channels + Ungated, +} + +// fn() is not Debug +impl ::std::fmt::Debug for AttributeGate { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + match *self { + Gated(ref name, ref expl, _) => write!(fmt, "Gated({}, {})", name, expl), + Ungated => write!(fmt, "Ungated") + } + } +} + +macro_rules! cfg_fn { + ($field: ident) => {{ + fn f(features: &Features) -> bool { + features.$field + } + f as fn(&Features) -> bool + }} } // Attributes that have a special meaning to rustc or rustdoc @@ -312,88 +355,112 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat // RFC #1445. ("structural_match", Whitelisted, Gated("structural_match", "the semantics of constant patterns is \ - not yet settled")), + not yet settled", + cfg_fn!(structural_match))), // Not used any more, but we can't feature gate it ("no_stack_check", Normal, Ungated), ("plugin", CrateLevel, Gated("plugin", "compiler plugins are experimental \ - and possibly buggy")), + and possibly buggy", + cfg_fn!(plugin))), + ("no_std", CrateLevel, Ungated), ("no_core", CrateLevel, Gated("no_core", - "no_core is experimental")), + "no_core is experimental", + cfg_fn!(no_core))), ("lang", Normal, Gated("lang_items", - "language items are subject to change")), + "language items are subject to change", + cfg_fn!(lang_items))), ("linkage", Whitelisted, Gated("linkage", "the `linkage` attribute is experimental \ - and not portable across platforms")), + and not portable across platforms", + cfg_fn!(linkage))), ("thread_local", Whitelisted, 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")), + model", + cfg_fn!(thread_local))), ("rustc_on_unimplemented", Normal, Gated("on_unimplemented", "the `#[rustc_on_unimplemented]` attribute \ - is an experimental feature")), + is an experimental feature", + cfg_fn!(on_unimplemented))), ("allocator", Whitelisted, Gated("allocator", - "the `#[allocator]` attribute is an experimental feature")), + "the `#[allocator]` attribute is an experimental feature", + cfg_fn!(allocator))), ("needs_allocator", Normal, Gated("needs_allocator", "the `#[needs_allocator]` \ attribute is an experimental \ - feature")), + feature", + cfg_fn!(needs_allocator))), ("rustc_variance", Normal, Gated("rustc_attrs", "the `#[rustc_variance]` attribute \ is just used for rustc unit tests \ - and will never be stable")), + and will never be stable", + cfg_fn!(rustc_attrs))), ("rustc_error", Whitelisted, Gated("rustc_attrs", "the `#[rustc_error]` attribute \ is just used for rustc unit tests \ - and will never be stable")), + and will never be stable", + cfg_fn!(rustc_attrs))), ("rustc_if_this_changed", Whitelisted, Gated("rustc_attrs", - "the `#[rustc_if_this_changed]` attribute \ - is just used for rustc unit tests \ - and will never be stable")), + "the `#[rustc_if_this_changed]` attribute \ + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs))), ("rustc_then_this_would_need", Whitelisted, Gated("rustc_attrs", - "the `#[rustc_if_this_changed]` attribute \ - is just used for rustc unit tests \ - and will never be stable")), + "the `#[rustc_if_this_changed]` attribute \ + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs))), ("rustc_dirty", Whitelisted, Gated("rustc_attrs", "the `#[rustc_dirty]` attribute \ is just used for rustc unit tests \ - and will never be stable")), + and will never be stable", + cfg_fn!(rustc_attrs))), ("rustc_clean", Whitelisted, Gated("rustc_attrs", "the `#[rustc_clean]` attribute \ is just used for rustc unit tests \ - and will never be stable")), + and will never be stable", + cfg_fn!(rustc_attrs))), ("rustc_symbol_name", Whitelisted, Gated("rustc_attrs", - "internal rustc attributes will never be stable")), + "internal rustc attributes will never be stable", + cfg_fn!(rustc_attrs))), ("rustc_item_path", Whitelisted, Gated("rustc_attrs", - "internal rustc attributes will never be stable")), + "internal rustc attributes will never be stable", + cfg_fn!(rustc_attrs))), ("rustc_move_fragments", Normal, Gated("rustc_attrs", "the `#[rustc_move_fragments]` attribute \ is just used for rustc unit tests \ - and will never be stable")), + and will never be stable", + cfg_fn!(rustc_attrs))), ("rustc_mir", Whitelisted, Gated("rustc_attrs", "the `#[rustc_mir]` attribute \ is just used for rustc unit tests \ - and will never be stable")), + and will never be stable", + cfg_fn!(rustc_attrs))), ("rustc_no_mir", Whitelisted, Gated("rustc_attrs", "the `#[rustc_no_mir]` attribute \ is just used to make tests pass \ - and will never be stable")), + and will never be stable", + cfg_fn!(rustc_attrs))), ("allow_internal_unstable", Normal, Gated("allow_internal_unstable", - EXPLAIN_ALLOW_INTERNAL_UNSTABLE)), + EXPLAIN_ALLOW_INTERNAL_UNSTABLE, + cfg_fn!(allow_internal_unstable))), ("fundamental", Whitelisted, Gated("fundamental", "the `#[fundamental]` attribute \ - is an experimental feature")), + is an experimental feature", + cfg_fn!(fundamental))), ("linked_from", Normal, Gated("linked_from", "the `#[linked_from]` attribute \ - is an experimental feature")), + is an experimental feature", + cfg_fn!(linked_from))), // FIXME: #14408 whitelist docs since rustdoc looks at them ("doc", Whitelisted, Ungated), @@ -403,7 +470,8 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat ("cold", Whitelisted, Ungated), ("naked", Whitelisted, Gated("naked_functions", "the `#[naked]` attribute \ - is an experimental feature")), + is an experimental feature", + cfg_fn!(naked))), ("export_name", Whitelisted, Ungated), ("inline", Whitelisted, Ungated), ("link", Whitelisted, Ungated), @@ -413,24 +481,30 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat ("no_mangle", Whitelisted, Ungated), ("no_debug", Whitelisted, Gated("no_debug", "the `#[no_debug]` attribute \ - is an experimental feature")), + is an experimental feature", + cfg_fn!(no_debug))), ("omit_gdb_pretty_printer_section", Whitelisted, Gated("omit_gdb_pretty_printer_section", "the `#[omit_gdb_pretty_printer_section]` \ attribute is just used for the Rust test \ - suite")), + suite", + cfg_fn!(omit_gdb_pretty_printer_section))), ("unsafe_no_drop_flag", Whitelisted, Gated("unsafe_no_drop_flag", "unsafe_no_drop_flag has unstable semantics \ - and may be removed in the future")), + and may be removed in the future", + cfg_fn!(unsafe_no_drop_flag))), ("unsafe_destructor_blind_to_params", Normal, Gated("dropck_parametricity", "unsafe_destructor_blind_to_params has unstable semantics \ - and may be removed in the future")), - ("unwind", Whitelisted, Gated("unwind_attributes", "#[unwind] is experimental")), + and may be removed in the future", + cfg_fn!(dropck_parametricity))), + ("unwind", Whitelisted, Gated("unwind_attributes", "#[unwind] is experimental", + cfg_fn!(unwind_attributes))), // used in resolve ("prelude_import", Whitelisted, Gated("prelude_import", - "`#[prelude_import]` is for use by rustc only")), + "`#[prelude_import]` is for use by rustc only", + cfg_fn!(prelude_import))), // FIXME: #14407 these are only looked at on-demand so we can't // guarantee they'll have already been checked @@ -441,9 +515,11 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat ("deprecated", Normal, Ungated), ("rustc_paren_sugar", Normal, Gated("unboxed_closures", - "unboxed_closures are still evolving")), + "unboxed_closures are still evolving", + cfg_fn!(unboxed_closures))), ("rustc_reflect_like", Whitelisted, Gated("reflect", - "defining reflective traits is still evolving")), + "defining reflective traits is still evolving", + cfg_fn!(reflect))), // Crate level attributes ("crate_name", CrateLevel, Ungated), @@ -456,21 +532,12 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat ("recursion_limit", CrateLevel, Ungated), ]; -macro_rules! cfg_fn { - (|$x: ident| $e: expr) => {{ - fn f($x: &Features) -> bool { - $e - } - f as fn(&Features) -> bool - }} -} // cfg(...)'s that are feature gated const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)] = &[ // (name in cfg, feature, function to check if the feature is enabled) - ("target_feature", "cfg_target_feature", cfg_fn!(|x| x.cfg_target_feature)), - ("target_vendor", "cfg_target_vendor", cfg_fn!(|x| x.cfg_target_vendor)), - ("target_thread_local", "cfg_target_thread_local", - cfg_fn!(|x| x.cfg_target_thread_local)), + ("target_feature", "cfg_target_feature", cfg_fn!(cfg_target_feature)), + ("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)), + ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)), ]; #[derive(Debug, Eq, PartialEq)] @@ -551,31 +618,6 @@ impl GatedCfg { } } - -#[derive(PartialEq, Copy, Clone, Debug)] -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, - - /// Builtin attribute that is only allowed at the crate level - CrateLevel, -} - -#[derive(PartialEq, Copy, Clone, Debug)] -pub enum AttributeGate { - /// Is gated by a given feature gate and reason - Gated(&'static str, &'static str), - - /// Ungated attribute, can be used on all release channels - Ungated, -} - /// A set of features to be used by later passes. pub struct Features { pub unboxed_closures: bool, @@ -612,6 +654,53 @@ pub struct Features { pub question_mark: bool, pub specialization: bool, pub pub_restricted: bool, + pub structural_match: bool, + pub plugin: bool, + pub lang_items: bool, + pub linkage: bool, + pub thread_local: bool, + pub on_unimplemented: bool, + pub allocator: bool, + pub needs_allocator: bool, + pub fundamental: bool, + pub linked_from: bool, + pub naked: bool, + pub no_debug: bool, + pub omit_gdb_pretty_printer_section: bool, + pub dropck_parametricity: bool, + pub unwind_attributes: bool, + pub prelude_import: bool, + pub reflect: bool, + pub no_core: bool, + pub unsafe_no_drop_flag: bool, + pub custom_derive: bool, + pub custom_attribute: bool, + pub asm: bool, + pub log_syntax: bool, + pub trace_macros: bool, + pub concat_idents: bool, + pub box_syntax: bool, + pub placement_in_syntax: bool, + pub non_ascii_idents: bool, + pub macro_reexport: bool, + pub link_args: bool, + pub intrinsics: bool, + pub platform_intrinsics: bool, + pub abi_vectorcall: bool, + pub plugin_registrar: bool, + pub start: bool, + pub main: bool, + pub simd: bool, + pub repr_simd: bool, + pub optin_builtin_traits: bool, + pub link_llvm_intrinsics: bool, + pub type_ascription: bool, + pub inclusive_range_syntax: bool, + pub advanced_slice_patterns: bool, + pub slice_patterns: bool, + pub box_patterns: bool, + pub associated_consts: bool, + pub associated_type_defaults: bool } impl Features { @@ -649,6 +738,53 @@ impl Features { question_mark: false, specialization: false, pub_restricted: false, + structural_match: false, + plugin: false, + lang_items: false, + linkage: false, + thread_local: false, + on_unimplemented: false, + allocator: false, + needs_allocator: false, + fundamental: false, + linked_from: false, + naked: false, + no_debug: false, + omit_gdb_pretty_printer_section: false, + dropck_parametricity: false, + unwind_attributes: false, + prelude_import: false, + reflect: false, + no_core: false, + unsafe_no_drop_flag: false, + custom_derive: false, + custom_attribute: false, + asm: false, + log_syntax: false, + trace_macros: false, + concat_idents: false, + box_syntax: false, + placement_in_syntax: false, + non_ascii_idents: false, + macro_reexport: false, + link_args: false, + intrinsics: false, + platform_intrinsics: false, + abi_vectorcall: false, + plugin_registrar: false, + start: false, + main: false, + simd: false, + repr_simd: false, + optin_builtin_traits: false, + link_llvm_intrinsics: false, + type_ascription: false, + inclusive_range_syntax: false, + advanced_slice_patterns: false, + slice_patterns: false, + box_patterns: false, + associated_consts: false, + associated_type_defaults: false, } } } @@ -687,36 +823,37 @@ pub fn check_for_pushpop_syntax(f: Option<&Features>, diag: &Handler, span: Span } struct Context<'a> { - features: Vec<&'static str>, + features: Features, span_handler: &'a Handler, cm: &'a CodeMap, plugin_attributes: &'a [(String, AttributeType)], } -impl<'a> Context<'a> { - fn enable_feature(&mut self, feature: &'static str) { - debug!("enabling feature: {}", feature); - self.features.push(feature); - } - - fn gate_feature(&self, feature: &str, span: Span, explain: &str) { - let has_feature = self.has_feature(feature); - debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", feature, span, has_feature); - if !has_feature && !self.cm.span_allows_unstable(span) { - emit_feature_err(self.span_handler, feature, span, GateIssue::Language, explain); +macro_rules! gate_feature_fn { + ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{ + let (cx, has_feature, span, name, explain) = ($cx, $has_feature, $span, $name, $explain); + let has_feature: bool = has_feature(&$cx.features); + debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature); + if !has_feature && !cx.cm.span_allows_unstable(span) { + emit_feature_err(cx.span_handler, name, span, GateIssue::Language, explain); } + }} +} + +macro_rules! gate_feature { + ($cx: expr, $feature: ident, $span: expr, $explain: expr) => { + gate_feature_fn!($cx, |x:&Features| x.$feature, $span, stringify!($feature), $explain) } - fn has_feature(&self, feature: &str) -> bool { - self.features.iter().any(|&n| n == feature) - } +} +impl<'a> Context<'a> { fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) { debug!("check_attribute(attr = {:?})", attr); let name = &*attr.name(); - for &(n, ty, gateage) in KNOWN_ATTRIBUTES { + for &(n, ty, ref gateage) in KNOWN_ATTRIBUTES { if n == name { - if let Gated(gate, desc) = gateage { - self.gate_feature(gate, attr.span, desc); + if let &Gated(ref name, ref desc, ref has_feature) = gateage { + gate_feature_fn!(self, has_feature, attr.span, name, desc); } debug!("check_attribute: {:?} is known, {:?}, {:?}", name, ty, gateage); return; @@ -732,26 +869,26 @@ impl<'a> Context<'a> { } } 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"); + gate_feature!(self, rustc_attrs, attr.span, + "unless otherwise specified, attributes \ + with the prefix `rustc_` \ + are reserved for internal compiler diagnostics"); } else if name.starts_with("derive_") { - self.gate_feature("custom_derive", attr.span, - "attributes of the form `#[derive_*]` are reserved \ - for the compiler"); + gate_feature!(self, custom_derive, attr.span, + "attributes of the form `#[derive_*]` are reserved \ + for the compiler"); } else { // Only run the custom attribute lint during regular // feature gate checking. Macro gating runs // before the plugin attributes are registered // so we skip this then if !is_macro { - self.gate_feature("custom_attribute", attr.span, - &format!("The attribute `{}` is currently \ - unknown to the compiler and \ - may have meaning \ - added to it in the future", - name)); + gate_feature!(self, custom_attribute, attr.span, + &format!("The attribute `{}` is currently \ + unknown to the compiler and \ + may have meaning \ + added to it in the future", + name)); } } } @@ -833,19 +970,19 @@ impl<'a, 'v> Visitor<'v> for MacroVisitor<'a> { // code, e.g. `#[cfg]`-guarded functions. if name == "asm" { - self.context.gate_feature("asm", path.span, EXPLAIN_ASM); + gate_feature!(self.context, asm, path.span, EXPLAIN_ASM); } else if name == "log_syntax" { - self.context.gate_feature("log_syntax", path.span, EXPLAIN_LOG_SYNTAX); + gate_feature!(self.context, log_syntax, path.span, EXPLAIN_LOG_SYNTAX); } else if name == "trace_macros" { - self.context.gate_feature("trace_macros", path.span, EXPLAIN_TRACE_MACROS); + gate_feature!(self.context, trace_macros, path.span, EXPLAIN_TRACE_MACROS); } else if name == "concat_idents" { - self.context.gate_feature("concat_idents", path.span, EXPLAIN_CONCAT_IDENTS); + gate_feature!(self.context, concat_idents, path.span, EXPLAIN_CONCAT_IDENTS); } } @@ -863,11 +1000,11 @@ impl<'a, 'v> Visitor<'v> for MacroVisitor<'a> { // uses in e.g. conditionalized code. if let ast::ExprKind::Box(_) = e.node { - self.context.gate_feature("box_syntax", e.span, EXPLAIN_BOX_SYNTAX); + gate_feature!(self.context, box_syntax, e.span, EXPLAIN_BOX_SYNTAX); } if let ast::ExprKind::InPlace(..) = e.node { - self.context.gate_feature("placement_in_syntax", e.span, EXPLAIN_PLACEMENT_IN); + gate_feature!(self.context, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN); } visit::walk_expr(self, e); @@ -878,12 +1015,13 @@ 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_allows_unstable(span) { - self.context.gate_feature(feature, span, explain) +macro_rules! gate_feature_post { + ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{ + let (cx, span) = ($cx, $span); + if !cx.context.cm.span_allows_unstable(span) { + gate_feature!(cx.context, $feature, span, $explain) } - } + }} } impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { @@ -895,8 +1033,8 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { fn visit_name(&mut self, sp: Span, name: ast::Name) { if !name.as_str().is_ascii() { - self.gate_feature("non_ascii_idents", sp, - "non-ascii idents are not fully supported."); + gate_feature_post!(&self, non_ascii_idents, sp, + "non-ascii idents are not fully supported."); } } @@ -904,60 +1042,59 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { match i.node { ast::ItemKind::ExternCrate(_) => { if attr::contains_name(&i.attrs[..], "macro_reexport") { - self.gate_feature("macro_reexport", i.span, - "macros reexports are experimental \ - and possibly buggy"); + gate_feature_post!(&self, macro_reexport, i.span, + "macros reexports are experimental \ + and possibly buggy"); } } ast::ItemKind::ForeignMod(ref foreign_module) => { if attr::contains_name(&i.attrs[..], "link_args") { - self.gate_feature("link_args", i.span, + gate_feature_post!(&self, link_args, i.span, "the `link_args` attribute is not portable \ across platforms, it is recommended to \ use `#[link(name = \"foo\")]` instead") } - let maybe_feature = match foreign_module.abi { - Abi::RustIntrinsic => Some(("intrinsics", "intrinsics are subject to change")), + match foreign_module.abi { + Abi::RustIntrinsic => + gate_feature_post!(&self, intrinsics, i.span, + "intrinsics are subject to change"), Abi::PlatformIntrinsic => { - Some(("platform_intrinsics", - "platform intrinsics are experimental and possibly buggy")) + gate_feature_post!(&self, platform_intrinsics, i.span, + "platform intrinsics are experimental \ + and possibly buggy") }, Abi::Vectorcall => { - Some(("abi_vectorcall", - "vectorcall is experimental and subject to change" - )) + gate_feature_post!(&self, abi_vectorcall, i.span, + "vectorcall is experimental and subject to change") } - _ => None - }; - if let Some((feature, msg)) = maybe_feature { - self.gate_feature(feature, i.span, msg) + _ => () } } ast::ItemKind::Fn(..) => { if attr::contains_name(&i.attrs[..], "plugin_registrar") { - self.gate_feature("plugin_registrar", i.span, - "compiler plugins are experimental and possibly buggy"); + gate_feature_post!(&self, plugin_registrar, i.span, + "compiler plugins are experimental and possibly buggy"); } if attr::contains_name(&i.attrs[..], "start") { - self.gate_feature("start", i.span, + gate_feature_post!(&self, start, i.span, "a #[start] function is an experimental \ feature whose signature may change \ over time"); } if attr::contains_name(&i.attrs[..], "main") { - self.gate_feature("main", i.span, - "declaration of a nonstandard #[main] \ - function may change over time, for now \ - a top-level `fn main()` is required"); + gate_feature_post!(&self, main, i.span, + "declaration of a nonstandard #[main] \ + function may change over time, for now \ + a top-level `fn main()` is required"); } } ast::ItemKind::Struct(..) => { if attr::contains_name(&i.attrs[..], "simd") { - self.gate_feature("simd", i.span, - "SIMD types are experimental and possibly buggy"); + gate_feature_post!(&self, simd, i.span, + "SIMD types are experimental and possibly buggy"); self.context.span_handler.span_warn(i.span, "the `#[simd]` attribute is deprecated, \ use `#[repr(simd)]` instead"); @@ -966,8 +1103,9 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { if attr.name() == "repr" { for item in attr.meta_item_list().unwrap_or(&[]) { if item.name() == "simd" { - self.gate_feature("repr_simd", i.span, - "SIMD types are experimental and possibly buggy"); + gate_feature_post!(&self, repr_simd, i.span, + "SIMD types are experimental \ + and possibly buggy"); } } @@ -976,19 +1114,19 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { } ast::ItemKind::DefaultImpl(..) => { - self.gate_feature("optin_builtin_traits", - i.span, - "default trait implementations are experimental \ - and possibly buggy"); + gate_feature_post!(&self, optin_builtin_traits, + i.span, + "default trait implementations are experimental \ + and possibly buggy"); } ast::ItemKind::Impl(_, polarity, _, _, _, _) => { match polarity { ast::ImplPolarity::Negative => { - self.gate_feature("optin_builtin_traits", - i.span, - "negative trait bounds are not yet fully implemented; \ - use marker types for now"); + gate_feature_post!(&self, optin_builtin_traits, + i.span, + "negative trait bounds are not yet fully implemented; \ + use marker types for now"); }, _ => {} } @@ -1001,7 +1139,7 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { } fn visit_variant_data(&mut self, s: &'v ast::VariantData, _: ast::Ident, - _: &'v ast::Generics, _: ast::NodeId, span: Span) { + _: &'v ast::Generics, _: ast::NodeId, span: Span) { if s.fields().is_empty() { if s.is_tuple() { self.context.span_handler.struct_span_err(span, "empty tuple structs and enum \ @@ -1023,7 +1161,7 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { _ => false }; if links_to_llvm { - self.gate_feature("link_llvm_intrinsics", i.span, + gate_feature_post!(&self, link_llvm_intrinsics, i.span, "linking to LLVM intrinsics is experimental"); } @@ -1033,22 +1171,19 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { fn visit_expr(&mut self, e: &ast::Expr) { match e.node { ast::ExprKind::Box(_) => { - self.gate_feature("box_syntax", - e.span, - "box expression syntax is experimental; \ - you can call `Box::new` instead."); + gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX); } ast::ExprKind::Type(..) => { - self.gate_feature("type_ascription", e.span, + gate_feature_post!(&self, type_ascription, e.span, "type ascription is experimental"); } ast::ExprKind::Range(_, _, ast::RangeLimits::Closed) => { - self.gate_feature("inclusive_range_syntax", + gate_feature_post!(&self, inclusive_range_syntax, e.span, "inclusive range syntax is experimental"); } ast::ExprKind::Try(..) => { - self.gate_feature("question_mark", e.span, "the `?` operator is not stable"); + gate_feature_post!(&self, question_mark, e.span, "the `?` operator is not stable"); } _ => {} } @@ -1058,19 +1193,19 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { fn visit_pat(&mut self, pattern: &ast::Pat) { match pattern.node { PatKind::Vec(_, Some(_), ref last) if !last.is_empty() => { - self.gate_feature("advanced_slice_patterns", + gate_feature_post!(&self, advanced_slice_patterns, pattern.span, "multiple-element slice matches anywhere \ but at the end of a slice (e.g. \ `[0, ..xs, 0]`) are experimental") } PatKind::Vec(..) => { - self.gate_feature("slice_patterns", + gate_feature_post!(&self, slice_patterns, pattern.span, "slice pattern syntax is experimental"); } PatKind::Box(..) => { - self.gate_feature("box_patterns", + gate_feature_post!(&self, box_patterns, pattern.span, "box pattern syntax is experimental"); } @@ -1088,7 +1223,7 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { // check for const fn declarations match fn_kind { FnKind::ItemFn(_, _, _, ast::Constness::Const, _, _) => { - self.gate_feature("const_fn", span, "const fn is unstable"); + gate_feature_post!(&self, const_fn, span, "const fn is unstable"); } _ => { // stability of const fn methods are covered in @@ -1100,18 +1235,18 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { match fn_kind { FnKind::ItemFn(_, _, _, _, abi, _) if abi == Abi::RustIntrinsic => { - self.gate_feature("intrinsics", + gate_feature_post!(&self, intrinsics, span, "intrinsics are subject to change") } FnKind::ItemFn(_, _, _, _, abi, _) | FnKind::Method(_, &ast::MethodSig { abi, .. }, _) => match abi { Abi::RustCall => { - self.gate_feature("unboxed_closures", span, + gate_feature_post!(&self, unboxed_closures, span, "rust-call ABI is subject to change"); }, Abi::Vectorcall => { - self.gate_feature("abi_vectorcall", span, + gate_feature_post!(&self, abi_vectorcall, span, "vectorcall is experimental and subject to change"); }, _ => {} @@ -1124,17 +1259,17 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { fn visit_trait_item(&mut self, ti: &'v ast::TraitItem) { match ti.node { ast::TraitItemKind::Const(..) => { - self.gate_feature("associated_consts", + gate_feature_post!(&self, associated_consts, ti.span, "associated constants are experimental") } ast::TraitItemKind::Method(ref sig, _) => { if sig.constness == ast::Constness::Const { - self.gate_feature("const_fn", ti.span, "const fn is unstable"); + gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable"); } } ast::TraitItemKind::Type(_, Some(_)) => { - self.gate_feature("associated_type_defaults", ti.span, + gate_feature_post!(&self, associated_type_defaults, ti.span, "associated type defaults are unstable"); } _ => {} @@ -1144,20 +1279,20 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { fn visit_impl_item(&mut self, ii: &'v ast::ImplItem) { if ii.defaultness == ast::Defaultness::Default { - self.gate_feature("specialization", + gate_feature_post!(&self, specialization, ii.span, "specialization is unstable"); } match ii.node { ast::ImplItemKind::Const(..) => { - self.gate_feature("associated_consts", + gate_feature_post!(&self, associated_consts, ii.span, "associated constants are experimental") } ast::ImplItemKind::Method(ref sig, _) => { if sig.constness == ast::Constness::Const { - self.gate_feature("const_fn", ii.span, "const fn is unstable"); + gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable"); } } _ => {} @@ -1171,7 +1306,7 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { ast::Visibility::Restricted { ref path, .. } => path.span, _ => return, }; - self.gate_feature("pub_restricted", span, "`pub(restricted)` syntax is experimental"); + gate_feature_post!(&self, pub_restricted, span, "`pub(restricted)` syntax is experimental"); } } @@ -1182,15 +1317,9 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &Handler, -> Features where F: FnOnce(&mut Context, &ast::Crate) { - let mut cx = Context { - features: Vec::new(), - span_handler: span_handler, - cm: cm, - plugin_attributes: plugin_attributes, - }; - let mut accepted_features = Vec::new(); let mut unknown_features = Vec::new(); + let mut enabled_features = Vec::new(); for attr in &krate.attrs { if !attr.check_name("feature") { @@ -1216,7 +1345,7 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &Handler, match KNOWN_FEATURES.iter() .find(|& &(n, _, _, _)| name == n) { Some(&(name, _, _, Active)) => { - cx.enable_feature(name); + enabled_features.push(name); } Some(&(_, _, _, Removed)) => { span_handler.span_err(mi.span, "feature has been removed"); @@ -1233,45 +1362,104 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &Handler, } } - check(&mut cx, krate); + let has_feature = |feature: &str| -> bool { + enabled_features.iter().any(|&n| n == feature) + }; // 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"), - 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"), - allow_internal_unstable: cx.has_feature("allow_internal_unstable"), - allow_custom_derive: cx.has_feature("custom_derive"), - allow_placement_in: cx.has_feature("placement_in_syntax"), - allow_box: cx.has_feature("box_syntax"), - allow_pushpop_unsafe: cx.has_feature("pushpop_unsafe"), - allow_inclusive_range: cx.has_feature("inclusive_range_syntax"), - simd_ffi: cx.has_feature("simd_ffi"), - unmarked_api: cx.has_feature("unmarked_api"), + let features = Features { + unboxed_closures: has_feature("unboxed_closures"), + rustc_diagnostic_macros: has_feature("rustc_diagnostic_macros"), + allow_quote: has_feature("quote"), + allow_asm: has_feature("asm"), + allow_log_syntax: has_feature("log_syntax"), + allow_concat_idents: has_feature("concat_idents"), + allow_trace_macros: has_feature("trace_macros"), + allow_internal_unstable: has_feature("allow_internal_unstable"), + allow_custom_derive: has_feature("custom_derive"), + allow_placement_in: has_feature("placement_in_syntax"), + allow_box: has_feature("box_syntax"), + allow_pushpop_unsafe: has_feature("pushpop_unsafe"), + allow_inclusive_range: has_feature("inclusive_range_syntax"), + simd_ffi: has_feature("simd_ffi"), + unmarked_api: has_feature("unmarked_api"), declared_stable_lang_features: accepted_features, declared_lib_features: unknown_features, - const_fn: cx.has_feature("const_fn"), - const_indexing: cx.has_feature("const_indexing"), - static_recursion: cx.has_feature("static_recursion"), - default_type_parameter_fallback: cx.has_feature("default_type_parameter_fallback"), - rustc_attrs: cx.has_feature("rustc_attrs"), - type_macros: cx.has_feature("type_macros"), - cfg_target_feature: cx.has_feature("cfg_target_feature"), - cfg_target_vendor: cx.has_feature("cfg_target_vendor"), - cfg_target_thread_local: cx.has_feature("cfg_target_thread_local"), - staged_api: cx.has_feature("staged_api"), - stmt_expr_attributes: cx.has_feature("stmt_expr_attributes"), - deprecated: cx.has_feature("deprecated"), - question_mark: cx.has_feature("question_mark"), - specialization: cx.has_feature("specialization"), - pub_restricted: cx.has_feature("pub_restricted"), - } + const_fn: has_feature("const_fn"), + const_indexing: has_feature("const_indexing"), + static_recursion: has_feature("static_recursion"), + default_type_parameter_fallback: has_feature("default_type_parameter_fallback"), + rustc_attrs: has_feature("rustc_attrs"), + type_macros: has_feature("type_macros"), + cfg_target_feature: has_feature("cfg_target_feature"), + cfg_target_vendor: has_feature("cfg_target_vendor"), + cfg_target_thread_local: has_feature("cfg_target_thread_local"), + staged_api: has_feature("staged_api"), + stmt_expr_attributes: has_feature("stmt_expr_attributes"), + deprecated: has_feature("deprecated"), + question_mark: has_feature("question_mark"), + specialization: has_feature("specialization"), + pub_restricted: has_feature("pub_restricted"), + structural_match: has_feature("bool"), + plugin: has_feature("plugin"), + lang_items: has_feature("lang_items"), + linkage: has_feature("linkage"), + thread_local: has_feature("thread_local"), + on_unimplemented: has_feature("on_unimplemented"), + allocator: has_feature("allocator"), + needs_allocator: has_feature("needs_allocator"), + fundamental: has_feature("fundamental"), + linked_from: has_feature("linked_from"), + naked: has_feature("naked"), + no_debug: has_feature("no_debug"), + omit_gdb_pretty_printer_section: has_feature("omit_gdb_pretty_printer_section"), + dropck_parametricity: has_feature("dropck_parametricity"), + unwind_attributes: has_feature("unwind_attributes"), + prelude_import: has_feature("prelude_import"), + reflect: has_feature("reflect"), + no_core: has_feature("no_core"), + unsafe_no_drop_flag: has_feature("unsafe_no_drop_flag"), + custom_derive: has_feature("custom_derive"), + custom_attribute: has_feature("custom_attribute"), + asm: has_feature("asm"), + log_syntax: has_feature("log_syntax"), + trace_macros: has_feature("trace_macros"), + concat_idents: has_feature("concat_idents"), + box_syntax: has_feature("box_syntax"), + placement_in_syntax: has_feature("placement_in_syntax"), + non_ascii_idents: has_feature("non_ascii_idents"), + macro_reexport: has_feature("macro_reexport"), + link_args: has_feature("link_args"), + intrinsics: has_feature("intrinsics"), + platform_intrinsics: has_feature("platform_intrinsics"), + abi_vectorcall: has_feature("abi_vectorcall"), + plugin_registrar: has_feature("plugin_registrar"), + start: has_feature("start"), + main: has_feature("main"), + simd: has_feature("simd"), + repr_simd: has_feature("repr_simd"), + optin_builtin_traits: has_feature("optin_builtin_traits"), + link_llvm_intrinsics: has_feature("link_llvm_intrinsics"), + type_ascription: has_feature("type_ascription"), + inclusive_range_syntax: has_feature("inclusive_range_syntax"), + advanced_slice_patterns: has_feature("advanced_slice_patterns"), + slice_patterns: has_feature("slice_patterns"), + box_patterns: has_feature("box_patterns"), + associated_consts: has_feature("associated_consts"), + associated_type_defaults: has_feature("associated_type_defaults"), + }; + + let mut cx = Context { + features: features, + span_handler: span_handler, + cm: cm, + plugin_attributes: plugin_attributes, + }; + + check(&mut cx, krate); + cx.features } pub fn check_crate_macros(cm: &CodeMap, span_handler: &Handler, krate: &ast::Crate) From ef1de519ff286a21e220d5839a6a5d468d296773 Mon Sep 17 00:00:00 2001 From: Leo Testard Date: Mon, 4 Apr 2016 17:08:41 +0200 Subject: [PATCH 2/5] Generate the features structure and arrays with new macros. This is more readable, safer, and allows for a much more efficient parsing. --- src/libsyntax/ext/expand.rs | 14 +- src/libsyntax/feature_gate.rs | 603 +++++++++++----------------------- 2 files changed, 196 insertions(+), 421 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index cd7b0fcfb0044..bc8d5cd770346 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1345,14 +1345,14 @@ impl<'feat> ExpansionConfig<'feat> { } feature_tests! { - fn enable_quotes = allow_quote, - fn enable_asm = allow_asm, - fn enable_log_syntax = allow_log_syntax, - fn enable_concat_idents = allow_concat_idents, - fn enable_trace_macros = allow_trace_macros, + fn enable_quotes = quote, + fn enable_asm = asm, + fn enable_log_syntax = log_syntax, + fn enable_concat_idents = concat_idents, + fn enable_trace_macros = trace_macros, fn enable_allow_internal_unstable = allow_internal_unstable, - fn enable_custom_derive = allow_custom_derive, - fn enable_pushpop_unsafe = allow_pushpop_unsafe, + fn enable_custom_derive = custom_derive, + fn enable_pushpop_unsafe = pushpop_unsafe, } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 7b0a0f39b24cd..e281e30dbc28f 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -22,7 +22,6 @@ //! gate usage is added, *do not remove it again* even once the feature //! becomes stable. -use self::Status::*; use self::AttributeType::*; use self::AttributeGate::*; @@ -40,16 +39,57 @@ use parse::token::InternedString; use std::ascii::AsciiExt; use std::cmp; -enum Status { - /// Represents an active feature that is currently being implemented or - /// currently being considered for addition/removal. - Active, +macro_rules! setter { + ($field: ident) => {{ + fn f(features: &mut Features) -> &mut bool { + &mut features.$field + } + f as fn(&mut Features) -> &mut bool + }} +} - /// Represents a feature which has since been removed (it was once Active) - Removed, +macro_rules! declare_features { + ($((active, $feature: ident, $ver: expr, $issue: expr)),+) => { + /// Represents active features that are currently being implemented or + /// currently being considered for addition/removal. + const ACTIVE_FEATURES: &'static [(&'static str, &'static str, + Option, fn(&mut Features) -> &mut bool)] = &[ + $((stringify!($feature), $ver, $issue, setter!($feature))),+ + ]; + + /// A set of features to be used by later passes. + pub struct Features { + /// spans of #![feature] attrs for stable language features. for error reporting + pub declared_stable_lang_features: Vec, + /// #![feature] attrs for non-language (library) features + pub declared_lib_features: Vec<(InternedString, Span)>, + $(pub $feature: bool),+ + } - /// This language feature has since been Accepted (it was once Active) - Accepted, + impl Features { + pub fn new() -> Features { + Features { + declared_stable_lang_features: Vec::new(), + declared_lib_features: Vec::new(), + $($feature: false),+ + } + } + } + }; + + ($((removed, $feature: ident, $ver: expr, $issue: expr)),+) => { + /// Represents features which has since been removed (it was once Active) + const REMOVED_FEATURES: &'static [(&'static str, &'static str, Option)] = &[ + $((stringify!($feature), $ver, $issue)),+ + ]; + }; + + ($((accepted, $feature: ident, $ver: expr, $issue: expr)),+) => { + /// Those language feature has since been Accepted (it was once Active) + const ACCEPTED_FEATURES: &'static [(&'static str, &'static str, Option)] = &[ + $((stringify!($feature), $ver, $issue)),+ + ]; + } } // If you change this list without updating src/doc/reference.md, @cmr will be sad @@ -57,120 +97,88 @@ enum Status { // The version numbers here correspond to the version in which the current status // was set. This is most important for knowing when a particular feature became // stable (active). -// NB: The tidy tool parses this information directly out of the source so take -// care when modifying it. -const KNOWN_FEATURES: &'static [(&'static str, &'static str, Option, Status)] = &[ - ("globs", "1.0.0", None, Accepted), - ("macro_rules", "1.0.0", None, Accepted), - ("struct_variant", "1.0.0", None, Accepted), - ("asm", "1.0.0", Some(29722), Active), - ("managed_boxes", "1.0.0", None, Removed), - ("non_ascii_idents", "1.0.0", Some(28979), Active), - ("thread_local", "1.0.0", Some(29594), Active), - ("link_args", "1.0.0", Some(29596), Active), - ("plugin_registrar", "1.0.0", Some(29597), Active), - ("log_syntax", "1.0.0", Some(29598), Active), - ("trace_macros", "1.0.0", Some(29598), Active), - ("concat_idents", "1.0.0", Some(29599), Active), +// NB: The featureck.py script parses this information directly out of the source +// so take care when modifying it. + +declare_features! ( + (active, asm, "1.0.0", Some(29722)), + (active, concat_idents, "1.0.0", Some(29599)), + (active, link_args, "1.0.0", Some(29596)), + (active, log_syntax, "1.0.0", Some(29598)), + (active, non_ascii_idents, "1.0.0", Some(28979)), + (active, plugin_registrar, "1.0.0", Some(29597)), + (active, thread_local, "1.0.0", Some(29594)), + (active, trace_macros, "1.0.0", Some(29598)), // rustc internal, for now: - ("intrinsics", "1.0.0", None, Active), - ("lang_items", "1.0.0", None, Active), + (active, intrinsics, "1.0.0", None), + (active, lang_items, "1.0.0", None), - ("simd", "1.0.0", Some(27731), Active), - ("default_type_params", "1.0.0", None, Accepted), - ("quote", "1.0.0", Some(29601), Active), - ("link_llvm_intrinsics", "1.0.0", Some(29602), Active), - ("linkage", "1.0.0", Some(29603), Active), - ("struct_inherit", "1.0.0", None, Removed), + (active, link_llvm_intrinsics, "1.0.0", Some(29602)), + (active, linkage, "1.0.0", Some(29603)), + (active, quote, "1.0.0", Some(29601)), + (active, simd, "1.0.0", Some(27731)), - ("quad_precision_float", "1.0.0", None, Removed), // rustc internal - ("rustc_diagnostic_macros", "1.0.0", None, Active), - ("unboxed_closures", "1.0.0", Some(29625), Active), - ("reflect", "1.0.0", Some(27749), Active), - ("import_shadowing", "1.0.0", None, Removed), - ("advanced_slice_patterns", "1.0.0", Some(23121), Active), - ("tuple_indexing", "1.0.0", None, Accepted), - ("associated_types", "1.0.0", None, Accepted), - ("visible_private_types", "1.0.0", None, Removed), - ("slicing_syntax", "1.0.0", None, Accepted), - ("box_syntax", "1.0.0", Some(27779), Active), - ("placement_in_syntax", "1.0.0", Some(27779), Active), + (active, rustc_diagnostic_macros, "1.0.0", None), + (active, advanced_slice_patterns, "1.0.0", Some(23121)), + (active, box_syntax, "1.0.0", Some(27779)), + (active, placement_in_syntax, "1.0.0", Some(27779)), + (active, reflect, "1.0.0", Some(27749)), + (active, unboxed_closures, "1.0.0", Some(29625)), // rustc internal. - ("pushpop_unsafe", "1.2.0", None, Active), - - ("on_unimplemented", "1.0.0", Some(29628), Active), - ("simd_ffi", "1.0.0", Some(27731), Active), - ("allocator", "1.0.0", Some(27389), Active), - ("needs_allocator", "1.4.0", Some(27389), Active), - ("linked_from", "1.3.0", Some(29629), Active), - - ("if_let", "1.0.0", None, Accepted), - ("while_let", "1.0.0", None, Accepted), - - ("plugin", "1.0.0", Some(29597), Active), - ("start", "1.0.0", Some(29633), Active), - ("main", "1.0.0", Some(29634), Active), - - ("fundamental", "1.0.0", Some(29635), Active), - - // A temporary feature gate used to enable parser extensions needed - // to bootstrap fix for #5723. - ("issue_5723_bootstrap", "1.0.0", None, Accepted), - - ("structural_match", "1.8.0", Some(31434), Active), - - // A way to temporarily opt out of opt in copy. This will *never* be accepted. - ("opt_out_copy", "1.0.0", None, Removed), + (active, pushpop_unsafe, "1.2.0", None), + + (active, allocator, "1.0.0", Some(27389)), + (active, fundamental, "1.0.0", Some(29635)), + (active, linked_from, "1.3.0", Some(29629)), + (active, main, "1.0.0", Some(29634)), + (active, needs_allocator, "1.4.0", Some(27389)), + (active, on_unimplemented, "1.0.0", Some(29628)), + (active, plugin, "1.0.0", Some(29597)), + (active, simd_ffi, "1.0.0", Some(27731)), + (active, start, "1.0.0", Some(29633)), + (active, structural_match, "1.8.0", Some(31434)), // OIBIT specific features - ("optin_builtin_traits", "1.0.0", Some(13231), Active), + (active, optin_builtin_traits, "1.0.0", Some(13231)), // macro reexport needs more discussion and stabilization - ("macro_reexport", "1.0.0", Some(29638), Active), - - // These are used to test this portion of the compiler, they don't actually - // mean anything - ("test_accepted_feature", "1.0.0", None, Accepted), - ("test_removed_feature", "1.0.0", None, Removed), + (active, macro_reexport, "1.0.0", Some(29638)), // Allows use of #[staged_api] // rustc internal - ("staged_api", "1.0.0", None, Active), + (active, staged_api, "1.0.0", None), // Allows using items which are missing stability attributes // rustc internal - ("unmarked_api", "1.0.0", None, Active), - - // Allows using #![no_std] - ("no_std", "1.0.0", None, Accepted), + (active, unmarked_api, "1.0.0", None), // Allows using #![no_core] - ("no_core", "1.3.0", Some(29639), Active), + (active, no_core, "1.3.0", Some(29639)), // Allows using `box` in patterns; RFC 469 - ("box_patterns", "1.0.0", Some(29641), Active), + (active, box_patterns, "1.0.0", Some(29641)), // Allows using the unsafe_no_drop_flag attribute (unlikely to // switch to Accepted; see RFC 320) - ("unsafe_no_drop_flag", "1.0.0", None, Active), + (active, unsafe_no_drop_flag, "1.0.0", None), // Allows using the unsafe_destructor_blind_to_params attribute; // RFC 1238 - ("dropck_parametricity", "1.3.0", Some(28498), Active), + (active, dropck_parametricity, "1.3.0", Some(28498)), // Allows the use of custom attributes; RFC 572 - ("custom_attribute", "1.0.0", Some(29642), Active), + (active, custom_attribute, "1.0.0", Some(29642)), // Allows the use of #[derive(Anything)] as sugar for // #[derive_Anything]. - ("custom_derive", "1.0.0", Some(29644), Active), + (active, custom_derive, "1.0.0", Some(29644)), // Allows the use of rustc_* attributes; RFC 572 - ("rustc_attrs", "1.0.0", Some(29642), Active), + (active, rustc_attrs, "1.0.0", Some(29642)), // Allows the use of #[allow_internal_unstable]. This is an // attribute on macro_rules! and can't use the attribute handling @@ -178,100 +186,128 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Option, Status // macros disappear). // // rustc internal - ("allow_internal_unstable", "1.0.0", None, Active), + (active, allow_internal_unstable, "1.0.0", None), // #23121. Array patterns have some hazards yet. - ("slice_patterns", "1.0.0", Some(23121), Active), - - // Allows use of unary negate on unsigned integers, e.g. -e for e: u8 - ("negate_unsigned", "1.0.0", Some(29645), Removed), + (active, slice_patterns, "1.0.0", Some(23121)), // Allows the definition of associated constants in `trait` or `impl` // blocks. - ("associated_consts", "1.0.0", Some(29646), Active), + (active, associated_consts, "1.0.0", Some(29646)), // Allows the definition of `const fn` functions. - ("const_fn", "1.2.0", Some(24111), Active), + (active, const_fn, "1.2.0", Some(24111)), // Allows indexing into constant arrays. - ("const_indexing", "1.4.0", Some(29947), Active), + (active, const_indexing, "1.4.0", Some(29947)), // Allows using #[prelude_import] on glob `use` items. // // rustc internal - ("prelude_import", "1.2.0", None, Active), + (active, prelude_import, "1.2.0", None), // Allows the definition recursive static items. - ("static_recursion", "1.3.0", Some(29719), Active), + (active, static_recursion, "1.3.0", Some(29719)), // Allows default type parameters to influence type inference. - ("default_type_parameter_fallback", "1.3.0", Some(27336), Active), + (active, default_type_parameter_fallback, "1.3.0", Some(27336)), // Allows associated type defaults - ("associated_type_defaults", "1.2.0", Some(29661), Active), + (active, associated_type_defaults, "1.2.0", Some(29661)), // Allows macros to appear in the type position. - ("type_macros", "1.3.0", Some(27245), Active), + (active, type_macros, "1.3.0", Some(27245)), // allow `repr(simd)`, and importing the various simd intrinsics - ("repr_simd", "1.4.0", Some(27731), Active), + (active, repr_simd, "1.4.0", Some(27731)), // Allows cfg(target_feature = "..."). - ("cfg_target_feature", "1.4.0", Some(29717), Active), + (active, cfg_target_feature, "1.4.0", Some(29717)), // allow `extern "platform-intrinsic" { ... }` - ("platform_intrinsics", "1.4.0", Some(27731), Active), + (active, platform_intrinsics, "1.4.0", Some(27731)), // allow `#[unwind]` // rust runtime internal - ("unwind_attributes", "1.4.0", None, Active), + (active, unwind_attributes, "1.4.0", None), // allow the use of `#[naked]` on functions. - ("naked_functions", "1.9.0", Some(32408), Active), - - // allow empty structs and enum variants with braces - ("braced_empty_structs", "1.8.0", Some(29720), Accepted), - - // allow overloading augmented assignment operations like `a += b` - ("augmented_assignments", "1.8.0", Some(28235), Accepted), + (active, naked_functions, "1.9.0", Some(32408)), // allow `#[no_debug]` - ("no_debug", "1.5.0", Some(29721), Active), + (active, no_debug, "1.5.0", Some(29721)), // allow `#[omit_gdb_pretty_printer_section]` // rustc internal. - ("omit_gdb_pretty_printer_section", "1.5.0", None, Active), + (active, omit_gdb_pretty_printer_section, "1.5.0", None), // Allows cfg(target_vendor = "..."). - ("cfg_target_vendor", "1.5.0", Some(29718), Active), + (active, cfg_target_vendor, "1.5.0", Some(29718)), // Allow attributes on expressions and non-item statements - ("stmt_expr_attributes", "1.6.0", Some(15701), Active), - - // Allows `#[deprecated]` attribute - ("deprecated", "1.9.0", Some(29935), Accepted), + (active, stmt_expr_attributes, "1.6.0", Some(15701)), // allow using type ascription in expressions - ("type_ascription", "1.6.0", Some(23416), Active), + (active, type_ascription, "1.6.0", Some(23416)), // Allows cfg(target_thread_local) - ("cfg_target_thread_local", "1.7.0", Some(29594), Active), + (active, cfg_target_thread_local, "1.7.0", Some(29594)), // rustc internal - ("abi_vectorcall", "1.7.0", None, Active), + (active, abi_vectorcall, "1.7.0", None), // a...b and ...b - ("inclusive_range_syntax", "1.7.0", Some(28237), Active), + (active, inclusive_range_syntax, "1.7.0", Some(28237)), // `expr?` - ("question_mark", "1.9.0", Some(31436), Active), + (active, question_mark, "1.9.0", Some(31436)), // impl specialization (RFC 1210) - ("specialization", "1.7.0", Some(31844), Active), + (active, specialization, "1.7.0", Some(31844)), // pub(restricted) visibilities (RFC 1422) - ("pub_restricted", "1.9.0", Some(32409), Active), -]; + (active, pub_restricted, "1.9.0", Some(32409)) +); + +declare_features! ( + (removed, import_shadowing, "1.0.0", None), + (removed, managed_boxes, "1.0.0", None), + // Allows use of unary negate on unsigned integers, e.g. -e for e: u8 + (removed, negate_unsigned, "1.0.0", Some(29645)), + // A way to temporarily opt out of opt in copy. This will *never* be accepted. + (removed, opt_out_copy, "1.0.0", None), + (removed, quad_precision_float, "1.0.0", None), + (removed, struct_inherit, "1.0.0", None), + (removed, test_removed_feature, "1.0.0", None), + (removed, visible_private_types, "1.0.0", None) +); + +declare_features! ( + (accepted, associated_types, "1.0.0", None), + // allow overloading augmented assignment operations like `a += b` + (accepted, augmented_assignments, "1.8.0", Some(28235)), + // allow empty structs and enum variants with braces + (accepted, braced_empty_structs, "1.8.0", Some(29720)), + (accepted, default_type_params, "1.0.0", None), + (accepted, globs, "1.0.0", None), + (accepted, if_let, "1.0.0", None), + // A temporary feature gate used to enable parser extensions needed + // to bootstrap fix for #5723. + (accepted, issue_5723_bootstrap, "1.0.0", None), + (accepted, macro_rules, "1.0.0", None), + // Allows using #![no_std] + (accepted, no_std, "1.0.0", None), + (accepted, slicing_syntax, "1.0.0", None), + (accepted, struct_variant, "1.0.0", None), + // These are used to test this portion of the compiler, they don't actually + // mean anything + (accepted, test_accepted_feature, "1.0.0", None), + (accepted, tuple_indexing, "1.0.0", None), + (accepted, while_let, "1.0.0", None), + // Allows `#[deprecated]` attribute + (accepted, deprecated, "1.9.0", Some(29935)) +); + // (changing above list without updating src/doc/reference.md makes @cmr sad) #[derive(PartialEq, Copy, Clone, Debug)] @@ -471,7 +507,7 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat ("naked", Whitelisted, Gated("naked_functions", "the `#[naked]` attribute \ is an experimental feature", - cfg_fn!(naked))), + cfg_fn!(naked_functions))), ("export_name", Whitelisted, Ungated), ("inline", Whitelisted, Ungated), ("link", Whitelisted, Ungated), @@ -618,177 +654,6 @@ impl GatedCfg { } } -/// A set of features to be used by later passes. -pub struct Features { - pub unboxed_closures: bool, - pub rustc_diagnostic_macros: 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 allow_internal_unstable: bool, - pub allow_custom_derive: bool, - pub allow_placement_in: bool, - pub allow_box: bool, - pub allow_pushpop_unsafe: bool, - pub allow_inclusive_range: bool, - pub simd_ffi: bool, - pub unmarked_api: bool, - /// spans of #![feature] attrs for stable language features. for error reporting - pub declared_stable_lang_features: Vec, - /// #![feature] attrs for non-language (library) features - pub declared_lib_features: Vec<(InternedString, Span)>, - pub const_fn: bool, - pub const_indexing: bool, - pub static_recursion: bool, - pub default_type_parameter_fallback: bool, - pub rustc_attrs: bool, - pub type_macros: bool, - pub cfg_target_feature: bool, - pub cfg_target_vendor: bool, - pub cfg_target_thread_local: bool, - pub staged_api: bool, - pub stmt_expr_attributes: bool, - pub deprecated: bool, - pub question_mark: bool, - pub specialization: bool, - pub pub_restricted: bool, - pub structural_match: bool, - pub plugin: bool, - pub lang_items: bool, - pub linkage: bool, - pub thread_local: bool, - pub on_unimplemented: bool, - pub allocator: bool, - pub needs_allocator: bool, - pub fundamental: bool, - pub linked_from: bool, - pub naked: bool, - pub no_debug: bool, - pub omit_gdb_pretty_printer_section: bool, - pub dropck_parametricity: bool, - pub unwind_attributes: bool, - pub prelude_import: bool, - pub reflect: bool, - pub no_core: bool, - pub unsafe_no_drop_flag: bool, - pub custom_derive: bool, - pub custom_attribute: bool, - pub asm: bool, - pub log_syntax: bool, - pub trace_macros: bool, - pub concat_idents: bool, - pub box_syntax: bool, - pub placement_in_syntax: bool, - pub non_ascii_idents: bool, - pub macro_reexport: bool, - pub link_args: bool, - pub intrinsics: bool, - pub platform_intrinsics: bool, - pub abi_vectorcall: bool, - pub plugin_registrar: bool, - pub start: bool, - pub main: bool, - pub simd: bool, - pub repr_simd: bool, - pub optin_builtin_traits: bool, - pub link_llvm_intrinsics: bool, - pub type_ascription: bool, - pub inclusive_range_syntax: bool, - pub advanced_slice_patterns: bool, - pub slice_patterns: bool, - pub box_patterns: bool, - pub associated_consts: bool, - pub associated_type_defaults: bool -} - -impl Features { - pub fn new() -> Features { - Features { - unboxed_closures: false, - rustc_diagnostic_macros: false, - allow_quote: false, - allow_asm: false, - allow_log_syntax: false, - allow_concat_idents: false, - allow_trace_macros: false, - allow_internal_unstable: false, - allow_custom_derive: false, - allow_placement_in: false, - allow_box: false, - allow_pushpop_unsafe: false, - allow_inclusive_range: false, - simd_ffi: false, - unmarked_api: false, - declared_stable_lang_features: Vec::new(), - declared_lib_features: Vec::new(), - const_fn: false, - const_indexing: false, - static_recursion: false, - default_type_parameter_fallback: false, - rustc_attrs: false, - type_macros: false, - cfg_target_feature: false, - cfg_target_vendor: false, - cfg_target_thread_local: false, - staged_api: false, - stmt_expr_attributes: false, - deprecated: false, - question_mark: false, - specialization: false, - pub_restricted: false, - structural_match: false, - plugin: false, - lang_items: false, - linkage: false, - thread_local: false, - on_unimplemented: false, - allocator: false, - needs_allocator: false, - fundamental: false, - linked_from: false, - naked: false, - no_debug: false, - omit_gdb_pretty_printer_section: false, - dropck_parametricity: false, - unwind_attributes: false, - prelude_import: false, - reflect: false, - no_core: false, - unsafe_no_drop_flag: false, - custom_derive: false, - custom_attribute: false, - asm: false, - log_syntax: false, - trace_macros: false, - concat_idents: false, - box_syntax: false, - placement_in_syntax: false, - non_ascii_idents: false, - macro_reexport: false, - link_args: false, - intrinsics: false, - platform_intrinsics: false, - abi_vectorcall: false, - plugin_registrar: false, - start: false, - main: false, - simd: false, - repr_simd: false, - optin_builtin_traits: false, - link_llvm_intrinsics: false, - type_ascription: false, - inclusive_range_syntax: false, - advanced_slice_patterns: false, - slice_patterns: false, - box_patterns: false, - associated_consts: false, - associated_type_defaults: false, - } - } -} - const EXPLAIN_BOX_SYNTAX: &'static str = "box expression syntax is experimental; you can call `Box::new` instead."; @@ -802,21 +667,21 @@ const EXPLAIN_STMT_ATTR_SYNTAX: &'static str = "attributes on non-item statements and expressions are experimental."; pub fn check_for_box_syntax(f: Option<&Features>, diag: &Handler, span: Span) { - if let Some(&Features { allow_box: true, .. }) = f { + if let Some(&Features { box_syntax: true, .. }) = f { return; } emit_feature_err(diag, "box_syntax", span, GateIssue::Language, EXPLAIN_BOX_SYNTAX); } pub fn check_for_placement_in(f: Option<&Features>, diag: &Handler, span: Span) { - if let Some(&Features { allow_placement_in: true, .. }) = f { + if let Some(&Features { placement_in_syntax: true, .. }) = f { return; } emit_feature_err(diag, "placement_in_syntax", span, GateIssue::Language, EXPLAIN_PLACEMENT_IN); } pub fn check_for_pushpop_syntax(f: Option<&Features>, diag: &Handler, span: Span) { - if let Some(&Features { allow_pushpop_unsafe: true, .. }) = f { + if let Some(&Features { pushpop_unsafe: true, .. }) = f { return; } emit_feature_err(diag, "pushpop_unsafe", span, GateIssue::Language, EXPLAIN_PUSHPOP_UNSAFE); @@ -895,15 +760,17 @@ impl<'a> Context<'a> { } fn find_lang_feature_issue(feature: &str) -> Option { - let info = KNOWN_FEATURES.iter() - .find(|t| t.0 == feature) - .unwrap(); - let issue = info.2; - if let Active = info.3 { + if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) { + let issue = info.2; // FIXME (#28244): enforce that active features have issue numbers // assert!(issue.is_some()) + issue + } else { + // search in Accepted or Removed features + ACCEPTED_FEATURES.iter().chain(REMOVED_FEATURES.iter()) + .find(|t| t.0 == feature) + .unwrap().2 } - issue } pub enum GateIssue { @@ -1317,9 +1184,7 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &Handler, -> Features where F: FnOnce(&mut Context, &ast::Crate) { - let mut accepted_features = Vec::new(); - let mut unknown_features = Vec::new(); - let mut enabled_features = Vec::new(); + let mut features = Features::new(); for attr in &krate.attrs { if !attr.check_name("feature") { @@ -1342,115 +1207,25 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &Handler, continue } }; - match KNOWN_FEATURES.iter() - .find(|& &(n, _, _, _)| name == n) { - Some(&(name, _, _, Active)) => { - enabled_features.push(name); - } - Some(&(_, _, _, Removed)) => { - span_handler.span_err(mi.span, "feature has been removed"); - } - Some(&(_, _, _, Accepted)) => { - accepted_features.push(mi.span); - } - None => { - unknown_features.push((name, mi.span)); - } + if let Some(&(_, _, _, setter)) = ACTIVE_FEATURES.iter() + .find(|& &(n, _, _, _)| name == n) { + *(setter(&mut features)) = true; + } + else if let Some(&(_, _, _)) = REMOVED_FEATURES.iter() + .find(|& &(n, _, _)| name == n) { + span_handler.span_err(mi.span, "feature has been removed"); + } + else if let Some(&(_, _, _)) = ACCEPTED_FEATURES.iter() + .find(|& &(n, _, _)| name == n) { + features.declared_stable_lang_features.push(mi.span); + } else { + features.declared_lib_features.push((name, mi.span)); } } } } } - let has_feature = |feature: &str| -> bool { - enabled_features.iter().any(|&n| n == feature) - }; - - // FIXME (pnkfelix): Before adding the 99th entry below, change it - // to a single-pass (instead of N calls to `.has_feature`). - - let features = Features { - unboxed_closures: has_feature("unboxed_closures"), - rustc_diagnostic_macros: has_feature("rustc_diagnostic_macros"), - allow_quote: has_feature("quote"), - allow_asm: has_feature("asm"), - allow_log_syntax: has_feature("log_syntax"), - allow_concat_idents: has_feature("concat_idents"), - allow_trace_macros: has_feature("trace_macros"), - allow_internal_unstable: has_feature("allow_internal_unstable"), - allow_custom_derive: has_feature("custom_derive"), - allow_placement_in: has_feature("placement_in_syntax"), - allow_box: has_feature("box_syntax"), - allow_pushpop_unsafe: has_feature("pushpop_unsafe"), - allow_inclusive_range: has_feature("inclusive_range_syntax"), - simd_ffi: has_feature("simd_ffi"), - unmarked_api: has_feature("unmarked_api"), - declared_stable_lang_features: accepted_features, - declared_lib_features: unknown_features, - const_fn: has_feature("const_fn"), - const_indexing: has_feature("const_indexing"), - static_recursion: has_feature("static_recursion"), - default_type_parameter_fallback: has_feature("default_type_parameter_fallback"), - rustc_attrs: has_feature("rustc_attrs"), - type_macros: has_feature("type_macros"), - cfg_target_feature: has_feature("cfg_target_feature"), - cfg_target_vendor: has_feature("cfg_target_vendor"), - cfg_target_thread_local: has_feature("cfg_target_thread_local"), - staged_api: has_feature("staged_api"), - stmt_expr_attributes: has_feature("stmt_expr_attributes"), - deprecated: has_feature("deprecated"), - question_mark: has_feature("question_mark"), - specialization: has_feature("specialization"), - pub_restricted: has_feature("pub_restricted"), - structural_match: has_feature("bool"), - plugin: has_feature("plugin"), - lang_items: has_feature("lang_items"), - linkage: has_feature("linkage"), - thread_local: has_feature("thread_local"), - on_unimplemented: has_feature("on_unimplemented"), - allocator: has_feature("allocator"), - needs_allocator: has_feature("needs_allocator"), - fundamental: has_feature("fundamental"), - linked_from: has_feature("linked_from"), - naked: has_feature("naked"), - no_debug: has_feature("no_debug"), - omit_gdb_pretty_printer_section: has_feature("omit_gdb_pretty_printer_section"), - dropck_parametricity: has_feature("dropck_parametricity"), - unwind_attributes: has_feature("unwind_attributes"), - prelude_import: has_feature("prelude_import"), - reflect: has_feature("reflect"), - no_core: has_feature("no_core"), - unsafe_no_drop_flag: has_feature("unsafe_no_drop_flag"), - custom_derive: has_feature("custom_derive"), - custom_attribute: has_feature("custom_attribute"), - asm: has_feature("asm"), - log_syntax: has_feature("log_syntax"), - trace_macros: has_feature("trace_macros"), - concat_idents: has_feature("concat_idents"), - box_syntax: has_feature("box_syntax"), - placement_in_syntax: has_feature("placement_in_syntax"), - non_ascii_idents: has_feature("non_ascii_idents"), - macro_reexport: has_feature("macro_reexport"), - link_args: has_feature("link_args"), - intrinsics: has_feature("intrinsics"), - platform_intrinsics: has_feature("platform_intrinsics"), - abi_vectorcall: has_feature("abi_vectorcall"), - plugin_registrar: has_feature("plugin_registrar"), - start: has_feature("start"), - main: has_feature("main"), - simd: has_feature("simd"), - repr_simd: has_feature("repr_simd"), - optin_builtin_traits: has_feature("optin_builtin_traits"), - link_llvm_intrinsics: has_feature("link_llvm_intrinsics"), - type_ascription: has_feature("type_ascription"), - inclusive_range_syntax: has_feature("inclusive_range_syntax"), - advanced_slice_patterns: has_feature("advanced_slice_patterns"), - slice_patterns: has_feature("slice_patterns"), - box_patterns: has_feature("box_patterns"), - associated_consts: has_feature("associated_consts"), - associated_type_defaults: has_feature("associated_type_defaults"), - }; - let mut cx = Context { features: features, span_handler: span_handler, From 11f1eb0c4e2ff7e43052b4b847fb4dffaeea46b7 Mon Sep 17 00:00:00 2001 From: Leo Testard Date: Mon, 4 Apr 2016 18:59:48 +0200 Subject: [PATCH 3/5] Fix tidy for the new syntax of feature declarations in libsyntax. --- src/tools/tidy/src/features.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 991cf201d44f0..0b989d92b3d1d 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -136,18 +136,18 @@ fn collect_lang_features(path: &Path) -> Vec { let mut features = Vec::new(); for line in contents.lines().map(|l| l.trim()) { - if !STATUSES.iter().any(|s| line.contains(s) && line.starts_with("(")) { + if !STATUSES.iter().any(|s| line.starts_with(&format!("({}", s))) { continue } let mut parts = line.split(","); - let name = parts.next().unwrap().replace("\"", "").replace("(", ""); - let since = parts.next().unwrap().trim().replace("\"", ""); - let status = match parts.skip(1).next().unwrap() { - s if s.contains("Active") => "unstable", - s if s.contains("Removed") => "unstable", - s if s.contains("Accepted") => "stable", + let status = match &parts.next().unwrap().trim().replace("(", "")[..] { + "active" => "unstable", + "removed" => "unstable", + "accepted" => "stable", s => panic!("unknown status: {}", s), }; + let name = parts.next().unwrap().trim().to_owned(); + let since = parts.next().unwrap().trim().replace("\"", ""); features.push(Feature { name: name, From 03ab057f97910769846f06ef904eb3eedc20134e Mon Sep 17 00:00:00 2001 From: Leo Testard Date: Thu, 7 Apr 2016 00:43:03 +0200 Subject: [PATCH 4/5] Remove the MacroVisitor pass. This pass was supposed to check use of gated features before `#[cfg]`-stripping but this was not the case since it in fact happens after. Checks that are actually important and must be done before macro expansion are now made where the features are actually used. Close #32648. Also ensure that attributes on macro-generated macro invocations are checked as well. Close #32782 and #32655. --- src/librustc_driver/driver.rs | 16 +-- src/librustc_plugin/load.rs | 39 +++--- src/libsyntax/ext/expand.rs | 43 ++++--- src/libsyntax/feature_gate.rs | 117 ++++-------------- src/libsyntax_ext/deriving/mod.rs | 94 +++++++++----- ...te-allow-internal-unstable-nested-macro.rs | 4 +- ...re-gate-allow-internal-unstable-struct.rs} | 15 +-- src/test/compile-fail/issue-32655.rs | 33 +++++ src/test/compile-fail/issue-32782.rs | 23 ++++ src/test/compile-fail/trace_macros-gate.rs | 2 +- src/test/compile-fail/trace_macros-gate3.rs | 20 --- 11 files changed, 207 insertions(+), 199 deletions(-) rename src/test/compile-fail/{trace_macros-gate2.rs => feature-gate-allow-internal-unstable-struct.rs} (54%) create mode 100644 src/test/compile-fail/issue-32655.rs create mode 100644 src/test/compile-fail/issue-32782.rs delete mode 100644 src/test/compile-fail/trace_macros-gate3.rs diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index de1a740e0bba4..bda905f3555f5 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -512,19 +512,13 @@ pub fn phase_2_configure_and_expand(sess: &Session, middle::recursion_limit::update_recursion_limit(sess, &krate); }); - time(time_passes, "gated macro checking", || { - sess.track_errors(|| { - let features = - syntax::feature_gate::check_crate_macros(sess.codemap(), - &sess.parse_sess.span_diagnostic, - &krate); - - // these need to be set "early" so that expansion sees `quote` if enabled. - *sess.features.borrow_mut() = features; - }) + // these need to be set "early" so that expansion sees `quote` if enabled. + sess.track_errors(|| { + *sess.features.borrow_mut() = + syntax::feature_gate::get_features(&sess.parse_sess.span_diagnostic, + &krate); })?; - krate = time(time_passes, "crate injection", || { syntax::std_inject::maybe_inject_crates_ref(krate, sess.opts.alt_std_name.clone()) }); diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs index ac40215bbb1d0..036e46c380398 100644 --- a/src/librustc_plugin/load.rs +++ b/src/librustc_plugin/load.rs @@ -51,27 +51,32 @@ pub fn load_plugins(sess: &Session, addl_plugins: Option>) -> Vec { let mut loader = PluginLoader::new(sess, cstore, crate_name); - for attr in &krate.attrs { - if !attr.check_name("plugin") { - continue; - } - - let plugins = match attr.meta_item_list() { - Some(xs) => xs, - None => { - call_malformed_plugin_attribute(sess, attr.span); + // do not report any error now. since crate attributes are + // not touched by expansion, every use of plugin without + // the feature enabled will result in an error later... + if sess.features.borrow().plugin { + for attr in &krate.attrs { + if !attr.check_name("plugin") { continue; } - }; - for plugin in plugins { - if plugin.value_str().is_some() { - call_malformed_plugin_attribute(sess, attr.span); - continue; + let plugins = match attr.meta_item_list() { + Some(xs) => xs, + None => { + call_malformed_plugin_attribute(sess, attr.span); + continue; + } + }; + + for plugin in plugins { + if plugin.value_str().is_some() { + call_malformed_plugin_attribute(sess, attr.span); + continue; + } + + let args = plugin.meta_item_list().map(ToOwned::to_owned).unwrap_or_default(); + loader.load_plugin(plugin.span, &plugin.name(), args); } - - let args = plugin.meta_item_list().map(ToOwned::to_owned).unwrap_or_default(); - loader.load_plugin(plugin.span, &plugin.name(), args); } } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index bc8d5cd770346..16b465ba36eb6 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -35,6 +35,16 @@ use std_inject; use std::collections::HashSet; use std::env; +// this function is called to detect use of feature-gated or invalid attributes +// on macro invoations since they will not be detected after macro expansion +fn check_attributes(attrs: &[ast::Attribute], fld: &MacroExpander) { + for attr in attrs.iter() { + feature_gate::check_attribute(&attr, &fld.cx.parse_sess.span_diagnostic, + &fld.cx.parse_sess.codemap(), + &fld.cx.ecfg.features.unwrap()); + } +} + pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { let expr_span = e.span; return e.and_then(|ast::Expr {id, node, span, attrs}| match node { @@ -42,6 +52,9 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { // expr_mac should really be expr_ext or something; it's the // entry-point for all syntax extensions. ast::ExprKind::Mac(mac) => { + if let Some(ref attrs) = attrs { + check_attributes(attrs, fld); + } // Assert that we drop any macro attributes on the floor here drop(attrs); @@ -367,6 +380,8 @@ pub fn expand_item_mac(it: P, _ => fld.cx.span_bug(it.span, "invalid item macro invocation") }); + check_attributes(&attrs, fld); + let fm = fresh_mark(); let items = { let expanded = match fld.cx.syntax_env.find(extname) { @@ -441,18 +456,6 @@ pub fn expand_item_mac(it: P, let allow_internal_unstable = attr::contains_name(&attrs, "allow_internal_unstable"); - // ensure any #[allow_internal_unstable]s are - // detected (including nested macro definitions - // etc.) - if allow_internal_unstable && !fld.cx.ecfg.enable_allow_internal_unstable() { - feature_gate::emit_feature_err( - &fld.cx.parse_sess.span_diagnostic, - "allow_internal_unstable", - span, - feature_gate::GateIssue::Language, - feature_gate::EXPLAIN_ALLOW_INTERNAL_UNSTABLE) - } - let export = attr::contains_name(&attrs, "macro_export"); let def = ast::MacroDef { ident: ident, @@ -516,6 +519,10 @@ fn expand_stmt(stmt: Stmt, fld: &mut MacroExpander) -> SmallVector { _ => return expand_non_macro_stmt(stmt, fld) }; + if let Some(ref attrs) = attrs { + check_attributes(attrs, fld); + } + // Assert that we drop any macro attributes on the floor here drop(attrs); @@ -1063,7 +1070,7 @@ fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander) attrs: ii.attrs, vis: ii.vis, defaultness: ii.defaultness, - node: match ii.node { + node: match ii.node { ast::ImplItemKind::Method(sig, body) => { let (sig, body) = expand_and_rename_method(sig, body, fld); ast::ImplItemKind::Method(sig, body) @@ -1072,13 +1079,11 @@ fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander) }, span: fld.new_span(ii.span) }), - ast::ImplItemKind::Macro(_) => { - let (span, mac) = match ii.node { - ast::ImplItemKind::Macro(mac) => (ii.span, mac), - _ => unreachable!() - }; + ast::ImplItemKind::Macro(mac) => { + check_attributes(&ii.attrs, fld); + let maybe_new_items = - expand_mac_invoc(mac, span, + expand_mac_invoc(mac, ii.span, |r| r.make_impl_items(), |meths, mark| meths.move_map(|m| mark_impl_item(m, mark)), fld); diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index e281e30dbc28f..63fc33e48727d 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -688,7 +688,7 @@ pub fn check_for_pushpop_syntax(f: Option<&Features>, diag: &Handler, span: Span } struct Context<'a> { - features: Features, + features: &'a Features, span_handler: &'a Handler, cm: &'a CodeMap, plugin_attributes: &'a [(String, AttributeType)], @@ -739,9 +739,7 @@ impl<'a> Context<'a> { with the prefix `rustc_` \ are reserved for internal compiler diagnostics"); } else if name.starts_with("derive_") { - gate_feature!(self, custom_derive, attr.span, - "attributes of the form `#[derive_*]` are reserved \ - for the compiler"); + gate_feature!(self, custom_derive, attr.span, EXPLAIN_DERIVE_UNDERSCORE); } else { // Only run the custom attribute lint during regular // feature gate checking. Macro gating runs @@ -759,6 +757,15 @@ impl<'a> Context<'a> { } } +pub fn check_attribute(attr: &ast::Attribute, handler: &Handler, + cm: &CodeMap, features: &Features) { + let cx = Context { + features: features, span_handler: handler, + cm: cm, plugin_attributes: &[] + }; + cx.check_attribute(attr, true); +} + fn find_lang_feature_issue(feature: &str) -> Option { if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) { let issue = info.2; @@ -819,64 +826,8 @@ pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str = pub const EXPLAIN_CUSTOM_DERIVE: &'static str = "`#[derive]` for custom traits is not stable enough for use and is subject to change"; -struct MacroVisitor<'a> { - context: &'a Context<'a> -} - -impl<'a, 'v> Visitor<'v> for MacroVisitor<'a> { - fn visit_mac(&mut self, mac: &ast::Mac) { - let path = &mac.node.path; - let name = path.segments.last().unwrap().identifier.name.as_str(); - - // 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 name == "asm" { - gate_feature!(self.context, asm, path.span, EXPLAIN_ASM); - } - - else if name == "log_syntax" { - gate_feature!(self.context, log_syntax, path.span, EXPLAIN_LOG_SYNTAX); - } - - else if name == "trace_macros" { - gate_feature!(self.context, trace_macros, path.span, EXPLAIN_TRACE_MACROS); - } - - else if name == "concat_idents" { - gate_feature!(self.context, concat_idents, path.span, EXPLAIN_CONCAT_IDENTS); - } - } - - fn visit_attribute(&mut self, attr: &'v ast::Attribute) { - self.context.check_attribute(attr, true); - } - - fn visit_expr(&mut self, e: &ast::Expr) { - // Issue 22181: overloaded-`box` and placement-`in` are - // implemented via a desugaring expansion, so their feature - // gates go into MacroVisitor since that works pre-expansion. - // - // Issue 22234: we also check during expansion as well. - // But we keep these checks as a pre-expansion check to catch - // uses in e.g. conditionalized code. - - if let ast::ExprKind::Box(_) = e.node { - gate_feature!(self.context, box_syntax, e.span, EXPLAIN_BOX_SYNTAX); - } - - if let ast::ExprKind::InPlace(..) = e.node { - gate_feature!(self.context, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN); - } - - visit::walk_expr(self, e); - } -} +pub const EXPLAIN_DERIVE_UNDERSCORE: &'static str = + "attributes of the form `#[derive_*]` are reserved for the compiler"; struct PostExpansionVisitor<'a> { context: &'a Context<'a>, @@ -1177,13 +1128,7 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { } } -fn check_crate_inner(cm: &CodeMap, span_handler: &Handler, - krate: &ast::Crate, - plugin_attributes: &[(String, AttributeType)], - check: F) - -> Features - where F: FnOnce(&mut Context, &ast::Crate) -{ +pub fn get_features(span_handler: &Handler, krate: &ast::Crate) -> Features { let mut features = Features::new(); for attr in &krate.attrs { @@ -1226,32 +1171,24 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &Handler, } } - let mut cx = Context { - features: features, - span_handler: span_handler, - cm: cm, - plugin_attributes: plugin_attributes, - }; - - check(&mut cx, krate); - cx.features -} - -pub fn check_crate_macros(cm: &CodeMap, span_handler: &Handler, krate: &ast::Crate) --> Features { - check_crate_inner(cm, span_handler, krate, &[] as &'static [_], - |ctx, krate| visit::walk_crate(&mut MacroVisitor { context: ctx }, krate)) + features } pub fn check_crate(cm: &CodeMap, span_handler: &Handler, krate: &ast::Crate, plugin_attributes: &[(String, AttributeType)], - unstable: UnstableFeatures) -> Features -{ + unstable: UnstableFeatures) -> Features { maybe_stage_features(span_handler, krate, unstable); - - check_crate_inner(cm, span_handler, krate, plugin_attributes, - |ctx, krate| visit::walk_crate(&mut PostExpansionVisitor { context: ctx }, - krate)) + 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 } #[derive(Clone, Copy)] diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index 92a141fb4ec86..4ca3196b9c5ec 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -96,6 +96,36 @@ fn expand_derive(cx: &mut ExtCtxt, let mut found_partial_eq = false; let mut found_eq = false; + // This span is **very** sensitive and crucial to + // getting the stability behavior we want. What we are + // doing is marking the generated `#[derive_*]` with the + // span of the `#[deriving(...)]` attribute (the + // entire attribute, not just the `PartialEq` or `Eq` + // part), but with the current backtrace. The current + // backtrace will contain a topmost entry that IS this + // `#[deriving(...)]` attribute and with the + // "allow-unstable" flag set to true. + // + // Note that we do NOT use the span of the `Eq` + // text itself. You might think this is + // equivalent, because the `Eq` appears within the + // `#[deriving(Eq)]` attribute, and hence we would + // inherit the "allows unstable" from the + // backtrace. But in fact this is not always the + // case. The actual source text that led to + // deriving can be `#[$attr]`, for example, where + // `$attr == deriving(Eq)`. In that case, the + // "#[derive_*]" would be considered to + // originate not from the deriving call but from + // text outside the deriving call, and hence would + // be forbidden from using unstable + // content. + // + // See tests src/run-pass/rfc1445 for + // examples. --nmatsakis + let span = Span { expn_id: cx.backtrace(), .. span }; + assert!(cx.parse_sess.codemap().span_allows_unstable(span)); + for titem in traits.iter().rev() { let tname = match titem.node { MetaItemKind::Word(ref tname) => tname, @@ -121,42 +151,13 @@ fn expand_derive(cx: &mut ExtCtxt, } // #[derive(Foo, Bar)] expands to #[derive_Foo] #[derive_Bar] - item.attrs.push(cx.attribute(titem.span, cx.meta_word(titem.span, + item.attrs.push(cx.attribute(span, cx.meta_word(titem.span, intern_and_get_ident(&format!("derive_{}", tname))))); } // RFC #1445. `#[derive(PartialEq, Eq)]` adds a (trusted) // `#[structural_match]` attribute. if found_partial_eq && found_eq { - // This span is **very** sensitive and crucial to - // getting the stability behavior we want. What we are - // doing is marking `#[structural_match]` with the - // span of the `#[deriving(...)]` attribute (the - // entire attribute, not just the `PartialEq` or `Eq` - // part), but with the current backtrace. The current - // backtrace will contain a topmost entry that IS this - // `#[deriving(...)]` attribute and with the - // "allow-unstable" flag set to true. - // - // Note that we do NOT use the span of the `Eq` - // text itself. You might think this is - // equivalent, because the `Eq` appears within the - // `#[deriving(Eq)]` attribute, and hence we would - // inherit the "allows unstable" from the - // backtrace. But in fact this is not always the - // case. The actual source text that led to - // deriving can be `#[$attr]`, for example, where - // `$attr == deriving(Eq)`. In that case, the - // "#[structural_match]" would be considered to - // originate not from the deriving call but from - // text outside the deriving call, and hence would - // be forbidden from using unstable - // content. - // - // See tests src/run-pass/rfc1445 for - // examples. --nmatsakis - let span = Span { expn_id: cx.backtrace(), .. span }; - assert!(cx.parse_sess.codemap().span_allows_unstable(span)); debug!("inserting structural_match with span {:?}", span); let structural_match = intern_and_get_ident("structural_match"); item.attrs.push(cx.attribute(span, @@ -188,6 +189,39 @@ macro_rules! derive_traits { mitem: &MetaItem, annotatable: &Annotatable, push: &mut FnMut(Annotatable)) { + if !ecx.parse_sess.codemap().span_allows_unstable(sp) + && !ecx.ecfg.features.unwrap().custom_derive { + // FIXME: + // https://github.com/rust-lang/rust/pull/32671#issuecomment-206245303 + // This is just to avoid breakage with syntex. + // Remove that to spawn an error instead. + let cm = ecx.parse_sess.codemap(); + let parent = cm.with_expn_info(ecx.backtrace(), + |info| info.unwrap().call_site.expn_id); + cm.with_expn_info(parent, |info| { + if info.is_some() { + let mut w = ecx.parse_sess.span_diagnostic.struct_span_warn( + sp, feature_gate::EXPLAIN_DERIVE_UNDERSCORE, + ); + if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_none() { + w.fileline_help( + sp, &format!("add #![feature(custom_derive)] to \ + the crate attributes to enable") + ); + } + w.emit(); + } else { + feature_gate::emit_feature_err( + &ecx.parse_sess.span_diagnostic, + "custom_derive", sp, feature_gate::GateIssue::Language, + feature_gate::EXPLAIN_DERIVE_UNDERSCORE + ); + + return; + } + }) + } + warn_if_deprecated(ecx, sp, $name); $func(ecx, sp, mitem, annotatable, push); } diff --git a/src/test/compile-fail/feature-gate-allow-internal-unstable-nested-macro.rs b/src/test/compile-fail/feature-gate-allow-internal-unstable-nested-macro.rs index c9251c925cc40..9ebf8a9b74a6c 100644 --- a/src/test/compile-fail/feature-gate-allow-internal-unstable-nested-macro.rs +++ b/src/test/compile-fail/feature-gate-allow-internal-unstable-nested-macro.rs @@ -11,8 +11,8 @@ macro_rules! bar { () => { // more layers don't help: - #[allow_internal_unstable] - macro_rules! baz { //~ ERROR allow_internal_unstable side-steps + #[allow_internal_unstable] //~ ERROR allow_internal_unstable side-steps + macro_rules! baz { () => {} } } diff --git a/src/test/compile-fail/trace_macros-gate2.rs b/src/test/compile-fail/feature-gate-allow-internal-unstable-struct.rs similarity index 54% rename from src/test/compile-fail/trace_macros-gate2.rs rename to src/test/compile-fail/feature-gate-allow-internal-unstable-struct.rs index 71cc45e132d33..b186278ef8b7b 100644 --- a/src/test/compile-fail/trace_macros-gate2.rs +++ b/src/test/compile-fail/feature-gate-allow-internal-unstable-struct.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,13 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test that the trace_macros feature gate is on. +// checks that this attribute is caught on non-macro items. +// this needs a different test since this is done after expansion -fn main() { - // (Infrastructure does not attempt to detect uses in macro definitions.) - macro_rules! expando { - ($x: ident) => { trace_macros!($x) } - } +#[allow_internal_unstable] //~ ERROR allow_internal_unstable side-steps +struct S; - expando!(true); //~ ERROR `trace_macros` is not stable -} +fn main() {} diff --git a/src/test/compile-fail/issue-32655.rs b/src/test/compile-fail/issue-32655.rs new file mode 100644 index 0000000000000..edd7fe4a1e588 --- /dev/null +++ b/src/test/compile-fail/issue-32655.rs @@ -0,0 +1,33 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(dead_code)] +#![feature(rustc_attrs)] + +macro_rules! foo ( + () => ( + #[derive_Clone] //~ WARN attributes of the form + struct T; + ); +); + +macro_rules! bar ( + ($e:item) => ($e) +); + +foo!(); + +bar!( + #[derive_Clone] //~ WARN attributes of the form + struct S; +); + +#[rustc_error] +fn main() {} //~ ERROR compilation successful diff --git a/src/test/compile-fail/issue-32782.rs b/src/test/compile-fail/issue-32782.rs new file mode 100644 index 0000000000000..696ea0ef5473b --- /dev/null +++ b/src/test/compile-fail/issue-32782.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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +macro_rules! bar ( + () => () +); + +macro_rules! foo ( + () => ( + #[allow_internal_unstable] //~ ERROR allow_internal_unstable side-steps + bar!(); + ); +); + +foo!(); +fn main() {} diff --git a/src/test/compile-fail/trace_macros-gate.rs b/src/test/compile-fail/trace_macros-gate.rs index 6473bcece91b6..d627de24d6794 100644 --- a/src/test/compile-fail/trace_macros-gate.rs +++ b/src/test/compile-fail/trace_macros-gate.rs @@ -26,5 +26,5 @@ fn main() { ($x: ident) => { trace_macros!($x) } } - expando!(true); + expando!(true); //~ ERROR `trace_macros` is not stable } diff --git a/src/test/compile-fail/trace_macros-gate3.rs b/src/test/compile-fail/trace_macros-gate3.rs deleted file mode 100644 index 66d03cf9d8046..0000000000000 --- a/src/test/compile-fail/trace_macros-gate3.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Test that the trace_macros feature gate is on. - -pub fn main() { - println!("arg: {}", trace_macros!()); //~ ERROR `trace_macros` is not stable - println!("arg: {}", trace_macros!(1)); //~ ERROR `trace_macros` is not stable - println!("arg: {}", trace_macros!(ident)); //~ ERROR `trace_macros` is not stable - println!("arg: {}", trace_macros!(for)); //~ ERROR `trace_macros` is not stable - println!("arg: {}", trace_macros!(true,)); //~ ERROR `trace_macros` is not stable - println!("arg: {}", trace_macros!(false 1)); //~ ERROR `trace_macros` is not stable -} From fa23d108638b7117e84c99a8d36a9dbab7b56812 Mon Sep 17 00:00:00 2001 From: Leo Testard Date: Sat, 9 Apr 2016 18:01:14 +0200 Subject: [PATCH 5/5] Remove some useless code. --- src/libsyntax/ext/expand.rs | 10 +++++---- src/libsyntax/feature_gate.rs | 42 ++++++++--------------------------- 2 files changed, 15 insertions(+), 37 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 16b465ba36eb6..3424696fa7fe7 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -83,10 +83,12 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { ast::ExprKind::InPlace(placer, value_expr) => { // Ensure feature-gate is enabled - feature_gate::check_for_placement_in( - fld.cx.ecfg.features, - &fld.cx.parse_sess.span_diagnostic, - expr_span); + if !fld.cx.ecfg.features.unwrap().placement_in_syntax { + feature_gate::emit_feature_err( + &fld.cx.parse_sess.span_diagnostic, "placement_in_syntax", expr_span, + feature_gate::GateIssue::Language, feature_gate::EXPLAIN_PLACEMENT_IN + ); + } let placer = fld.fold_expr(placer); let value_expr = fld.fold_expr(value_expr); diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 63fc33e48727d..c6b398507d453 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -654,39 +654,6 @@ impl GatedCfg { } } -const EXPLAIN_BOX_SYNTAX: &'static str = - "box expression syntax is experimental; you can call `Box::new` instead."; - -const EXPLAIN_PLACEMENT_IN: &'static str = - "placement-in expression syntax is experimental and subject to change."; - -const EXPLAIN_PUSHPOP_UNSAFE: &'static str = - "push/pop_unsafe macros are experimental and subject to change."; - -const EXPLAIN_STMT_ATTR_SYNTAX: &'static str = - "attributes on non-item statements and expressions are experimental."; - -pub fn check_for_box_syntax(f: Option<&Features>, diag: &Handler, span: Span) { - if let Some(&Features { box_syntax: true, .. }) = f { - return; - } - emit_feature_err(diag, "box_syntax", span, GateIssue::Language, EXPLAIN_BOX_SYNTAX); -} - -pub fn check_for_placement_in(f: Option<&Features>, diag: &Handler, span: Span) { - if let Some(&Features { placement_in_syntax: true, .. }) = f { - return; - } - emit_feature_err(diag, "placement_in_syntax", span, GateIssue::Language, EXPLAIN_PLACEMENT_IN); -} - -pub fn check_for_pushpop_syntax(f: Option<&Features>, diag: &Handler, span: Span) { - if let Some(&Features { pushpop_unsafe: true, .. }) = f { - return; - } - emit_feature_err(diag, "pushpop_unsafe", span, GateIssue::Language, EXPLAIN_PUSHPOP_UNSAFE); -} - struct Context<'a> { features: &'a Features, span_handler: &'a Handler, @@ -809,6 +776,12 @@ pub fn emit_feature_err(diag: &Handler, feature: &str, span: Span, issue: GateIs err.emit(); } +const EXPLAIN_BOX_SYNTAX: &'static str = + "box expression syntax is experimental; you can call `Box::new` instead."; + +const EXPLAIN_STMT_ATTR_SYNTAX: &'static str = + "attributes on non-item statements and expressions are experimental."; + pub const EXPLAIN_ASM: &'static str = "inline assembly is not stable enough for use and is subject to change"; @@ -829,6 +802,9 @@ pub const EXPLAIN_CUSTOM_DERIVE: &'static str = pub const EXPLAIN_DERIVE_UNDERSCORE: &'static str = "attributes of the form `#[derive_*]` are reserved for the compiler"; +pub const EXPLAIN_PLACEMENT_IN: &'static str = + "placement-in expression syntax is experimental and subject to change."; + struct PostExpansionVisitor<'a> { context: &'a Context<'a>, }