about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorLeo Testard <leo.testard@gmail.com>2016-04-04 17:08:41 +0200
committerLeo Testard <leo.testard@gmail.com>2016-04-21 14:00:14 +0200
commitef1de519ff286a21e220d5839a6a5d468d296773 (patch)
tree62c997499d591bb72af9ab20df9e629ffa70a584 /src/libsyntax
parent2f1dfe615d479f19fa1b989e014eb8d4d516a23a (diff)
downloadrust-ef1de519ff286a21e220d5839a6a5d468d296773.tar.gz
rust-ef1de519ff286a21e220d5839a6a5d468d296773.zip
Generate the features structure and arrays with new macros.
This is more readable, safer, and allows for a much more efficient parsing.
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ext/expand.rs14
-rw-r--r--src/libsyntax/feature_gate.rs603
2 files changed, 196 insertions, 421 deletions
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index cd7b0fcfb00..bc8d5cd7703 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 7b0a0f39b24..e281e30dbc2 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<u32>, 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<Span>,
+            /// #![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<u32>)] = &[
+            $((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<u32>)] = &[
+            $((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<u32>, 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<u32>, 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<Span>,
-    /// #![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<u32> {
-    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<F>(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<F>(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,