From 359de344e4c386e767421f9cbf7dda7da92f2b90 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 30 Nov 2019 08:24:29 +0100 Subject: [PATCH] de-macro-ize feature gate checking --- src/librustc/hir/lowering.rs | 8 +- src/librustc/hir/lowering/item.rs | 8 +- .../infer/error_reporting/need_type_info.rs | 6 +- src/librustc/infer/opaque_types/mod.rs | 4 +- src/librustc/lint/levels.rs | 16 +- src/librustc/middle/stability.rs | 6 +- src/librustc/traits/error_reporting.rs | 4 +- src/librustc/traits/select.rs | 2 +- src/librustc/traits/specialize/mod.rs | 4 +- src/librustc/ty/constness.rs | 6 +- src/librustc/ty/context.rs | 4 +- src/librustc/ty/mod.rs | 2 +- src/librustc/ty/wf.rs | 4 +- .../symbol_names_test.rs | 2 +- src/librustc_feature/active.rs | 69 +-- src/librustc_feature/builtin_attrs.rs | 49 +- src/librustc_feature/lib.rs | 4 +- src/librustc_incremental/assert_dep_graph.rs | 4 +- .../persist/dirty_clean.rs | 2 +- src/librustc_lint/builtin.rs | 15 +- src/librustc_metadata/native_libs.rs | 40 +- .../borrow_check/nll/type_check/mod.rs | 10 +- src/librustc_mir/build/matches/simplify.rs | 3 +- src/librustc_mir/hair/cx/expr.rs | 6 +- src/librustc_mir/hair/pattern/_match.rs | 10 +- src/librustc_mir/hair/pattern/check_match.rs | 4 +- .../transform/check_consts/ops.rs | 46 +- .../transform/check_consts/validation.rs | 2 +- src/librustc_mir/transform/check_unsafety.rs | 4 +- src/librustc_mir/transform/promote_consts.rs | 7 +- .../transform/qualify_min_const_fn.rs | 8 +- src/librustc_parse/config.rs | 2 +- src/librustc_passes/ast_validation.rs | 6 +- src/librustc_passes/check_const.rs | 2 +- src/librustc_passes/layout_test.rs | 2 +- src/librustc_resolve/macros.rs | 2 +- src/librustc_traits/lowering/mod.rs | 2 +- src/librustc_typeck/astconv.rs | 2 +- src/librustc_typeck/check/cast.rs | 4 +- src/librustc_typeck/check/coercion.rs | 10 +- src/librustc_typeck/check/expr.rs | 2 +- src/librustc_typeck/check/method/probe.rs | 6 +- src/librustc_typeck/check/mod.rs | 56 +-- src/librustc_typeck/check/wfcheck.rs | 4 +- src/librustc_typeck/coherence/mod.rs | 3 +- src/librustc_typeck/collect.rs | 61 ++- src/librustc_typeck/lib.rs | 6 +- src/librustc_typeck/outlives/utils.rs | 4 +- src/libsyntax/attr/builtin.rs | 4 +- src/libsyntax/feature_gate/check.rs | 464 ++++++++---------- src/libsyntax/lib.rs | 1 + src/libsyntax_expand/expand.rs | 4 +- 52 files changed, 478 insertions(+), 528 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index e13f6cabb5296..5232193417af9 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -834,7 +834,7 @@ impl<'a> LoweringContext<'a> { return; } - if !self.sess.features_untracked().in_band_lifetimes { + if !self.sess.features_untracked().on(sym::in_band_lifetimes) { return; } @@ -1394,7 +1394,7 @@ impl<'a> LoweringContext<'a> { } ImplTraitContext::Disallowed(pos) => { let allowed_in = if self.sess.features_untracked() - .impl_trait_in_bindings { + .on(sym::impl_trait_in_bindings) { "bindings or function and inherent method return types" } else { "function and inherent method return types" @@ -2118,7 +2118,7 @@ impl<'a> LoweringContext<'a> { fn lower_local(&mut self, l: &Local) -> (hir::Local, SmallVec<[NodeId; 1]>) { let mut ids = SmallVec::<[NodeId; 1]>::new(); - if self.sess.features_untracked().impl_trait_in_bindings { + if self.sess.features_untracked().on(sym::impl_trait_in_bindings) { if let Some(ref ty) = l.ty { let mut visitor = ImplTraitTypeIdVisitor { ids: &mut ids }; visitor.visit_ty(ty); @@ -2130,7 +2130,7 @@ impl<'a> LoweringContext<'a> { ty: l.ty .as_ref() .map(|t| self.lower_ty(t, - if self.sess.features_untracked().impl_trait_in_bindings { + if self.sess.features_untracked().on(sym::impl_trait_in_bindings) { ImplTraitContext::OpaqueTy(Some(parent_def_id)) } else { ImplTraitContext::Disallowed(ImplTraitPosition::Binding) diff --git a/src/librustc/hir/lowering/item.rs b/src/librustc/hir/lowering/item.rs index ff9d8c85df8b9..d5918ccee2aaa 100644 --- a/src/librustc/hir/lowering/item.rs +++ b/src/librustc/hir/lowering/item.rs @@ -181,7 +181,7 @@ impl LoweringContext<'_> { ItemKind::Impl(.., None, _, _) => smallvec![i.id], ItemKind::Static(ref ty, ..) => { let mut ids = smallvec![i.id]; - if self.sess.features_untracked().impl_trait_in_bindings { + if self.sess.features_untracked().on(sym::impl_trait_in_bindings) { let mut visitor = ImplTraitTypeIdVisitor { ids: &mut ids }; visitor.visit_ty(ty); } @@ -189,7 +189,7 @@ impl LoweringContext<'_> { }, ItemKind::Const(ref ty, ..) => { let mut ids = smallvec![i.id]; - if self.sess.features_untracked().impl_trait_in_bindings { + if self.sess.features_untracked().on(sym::impl_trait_in_bindings) { let mut visitor = ImplTraitTypeIdVisitor { ids: &mut ids }; visitor.visit_ty(ty); } @@ -285,7 +285,7 @@ impl LoweringContext<'_> { hir::ItemKind::Static( self.lower_ty( t, - if self.sess.features_untracked().impl_trait_in_bindings { + if self.sess.features_untracked().on(sym::impl_trait_in_bindings) { ImplTraitContext::OpaqueTy(None) } else { ImplTraitContext::Disallowed(ImplTraitPosition::Binding) @@ -299,7 +299,7 @@ impl LoweringContext<'_> { hir::ItemKind::Const( self.lower_ty( t, - if self.sess.features_untracked().impl_trait_in_bindings { + if self.sess.features_untracked().on(sym::impl_trait_in_bindings) { ImplTraitContext::OpaqueTy(None) } else { ImplTraitContext::Disallowed(ImplTraitPosition::Binding) diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs index 32eecdf01a31f..a55280d0ca8c3 100644 --- a/src/librustc/infer/error_reporting/need_type_info.rs +++ b/src/librustc/infer/error_reporting/need_type_info.rs @@ -5,8 +5,8 @@ use crate::infer::InferCtxt; use crate::infer::type_variable::TypeVariableOriginKind; use crate::ty::{self, Ty, Infer, TyVar}; use crate::ty::print::Print; -use syntax::source_map::DesugaringKind; -use syntax_pos::Span; +use syntax_pos::source_map::DesugaringKind; +use syntax_pos::{Span, symbol::sym}; use errors::{Applicability, DiagnosticBuilder}; use rustc_error_codes::*; @@ -217,7 +217,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let is_named_and_not_impl_trait = |ty: Ty<'_>| { &ty.to_string() != "_" && // FIXME: Remove this check after `impl_trait_in_bindings` is stabilized. #63527 - (!ty.is_impl_trait() || self.tcx.features().impl_trait_in_bindings) + (!ty.is_impl_trait() || self.tcx.features().on(sym::impl_trait_in_bindings)) }; let ty_msg = match local_visitor.found_ty { diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index 9b197c1ecb140..c2e77a20fd138 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -13,7 +13,7 @@ use errors::DiagnosticBuilder; use rustc::session::config::nightly_options; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; -use syntax_pos::Span; +use syntax_pos::{Span, symbol::sym}; use rustc_error_codes::*; @@ -488,7 +488,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { conflict2: ty::Region<'tcx>, ) -> bool { // If we have `#![feature(member_constraints)]`, no problems. - if self.tcx.features().member_constraints { + if self.tcx.features().on(sym::member_constraints) { return false; } diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs index 619ca724214c8..fcd26a9866adb 100644 --- a/src/librustc/lint/levels.rs +++ b/src/librustc/lint/levels.rs @@ -231,15 +231,13 @@ impl<'a> LintLevelsBuilder<'a> { // FIXME (#55112): issue unused-attributes lint if we thereby // don't have any lint names (`#[level(reason = "foo")]`) if let ast::LitKind::Str(rationale, _) = name_value.kind { - if !self.sess.features_untracked().lint_reasons { - feature_gate::feature_err( - &self.sess.parse_sess, - sym::lint_reasons, - item.span, - "lint reasons are experimental" - ) - .emit(); - } + feature_gate::gate_feature( + &self.sess.parse_sess, + self.sess.features_untracked(), + item.span, + sym::lint_reasons, + "lint reasons are experimental" + ); reason = Some(rationale); } else { bad_attr(name_value.span) diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 54aafe2114dac..d81f175b75890 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -116,7 +116,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { item_sp: Span, kind: AnnotationKind, visit_children: F) where F: FnOnce(&mut Self) { - if self.tcx.features().staged_api { + if self.tcx.features().on(sym::staged_api) { // This crate explicitly wants staged API. debug!("annotate(id = {:?}, attrs = {:?})", hir_id, attrs); if let Some(..) = attr::find_deprecation(&self.tcx.sess.parse_sess, attrs, item_sp) { @@ -393,7 +393,7 @@ impl<'tcx> Index<'tcx> { pub fn new(tcx: TyCtxt<'tcx>) -> Index<'tcx> { let is_staged_api = tcx.sess.opts.debugging_opts.force_unstable_if_unmarked || - tcx.features().staged_api; + tcx.features().on(sym::staged_api); let mut staged_api = FxHashMap::default(); staged_api.insert(LOCAL_CRATE, is_staged_api); let mut index = Index { @@ -836,7 +836,7 @@ impl Visitor<'tcx> for Checker<'tcx> { // There's no good place to insert stability check for non-Copy unions, // so semi-randomly perform it here in stability.rs - hir::ItemKind::Union(..) if !self.tcx.features().untagged_unions => { + hir::ItemKind::Union(..) if !self.tcx.features().on(sym::untagged_unions) => { let def_id = self.tcx.hir().local_def_id(item.hir_id); let adt_def = self.tcx.adt_def(def_id); let ty = self.tcx.type_of(def_id); diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index ba44c6c3b9a1f..caf2ec54e2f02 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -2353,13 +2353,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } ObligationCauseCode::VariableType(_) => { err.note("all local variables must have a statically known size"); - if !self.tcx.features().unsized_locals { + if !self.tcx.features().on(sym::unsized_locals) { err.help("unsized locals are gated as an unstable feature"); } } ObligationCauseCode::SizedArgumentType => { err.note("all function arguments must have a statically known size"); - if !self.tcx.features().unsized_locals { + if !self.tcx.features().on(sym::unsized_locals) { err.help("unsized locals are gated as an unstable feature"); } } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 5f324527a2725..cd55571c1e6ce 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -2215,7 +2215,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } if let Some(principal) = data.principal() { - if !self.infcx.tcx.features().object_safe_for_dispatch { + if !self.infcx.tcx.features().on(sym::object_safe_for_dispatch) { principal.with_self_ty(self.tcx(), self_ty) } else if self.tcx().is_object_safe(principal.def_id()) { principal.with_self_ty(self.tcx(), self_ty) diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 88a2db3dc6223..61ad499dfcdc5 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -16,7 +16,7 @@ use crate::infer::{InferCtxt, InferOk}; use crate::lint; use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause, TraitEngine}; use rustc_data_structures::fx::FxHashSet; -use syntax_pos::DUMMY_SP; +use syntax_pos::{DUMMY_SP, symbol::sym}; use crate::traits::select::IntercrateAmbiguityCause; use crate::ty::{self, TyCtxt, TypeFoldable}; use crate::ty::subst::{Subst, InternalSubsts, SubstsRef}; @@ -155,7 +155,7 @@ pub(super) fn specializes( // The feature gate should prevent introducing new specializations, but not // taking advantage of upstream ones. - if !tcx.features().specialization && + if !tcx.features().on(sym::specialization) && (impl1_def_id.is_local() || impl2_def_id.is_local()) { return false; } diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs index 676916f530a4d..78cee19c446ae 100644 --- a/src/librustc/ty/constness.rs +++ b/src/librustc/ty/constness.rs @@ -2,7 +2,7 @@ use crate::ty::query::Providers; use crate::hir::def_id::DefId; use crate::hir; use crate::ty::TyCtxt; -use syntax_pos::symbol::Symbol; +use syntax_pos::symbol::{sym, Symbol}; use crate::hir::map::blocks::FnLikeNode; use syntax::attr; @@ -42,7 +42,7 @@ impl<'tcx> TyCtxt<'tcx> { return false; } - if self.features().staged_api { + if self.features().on(sym::staged_api) { // in order for a libstd function to be considered min_const_fn // it needs to be stable and have no `rustc_const_unstable` attribute match self.lookup_stability(def_id) { @@ -56,7 +56,7 @@ impl<'tcx> TyCtxt<'tcx> { } } else { // users enabling the `const_fn` feature gate can do what they want - !self.features().const_fn + !self.features().on(sym::const_fn) } } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 6a0002cd80fd0..a8564fcc2771d 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1473,7 +1473,7 @@ impl<'tcx> TyCtxt<'tcx> { // // * Otherwise, use the behavior requested via `-Z borrowck=...` - if self.features().nll { return BorrowckMode::Mir; } + if self.features().on(sym::nll) { return BorrowckMode::Mir; } self.sess.opts.borrowck_mode } @@ -2437,7 +2437,7 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn mk_diverging_default(self) -> Ty<'tcx> { - if self.features().never_type_fallback { + if self.features().on(sym::never_type_fallback) { self.types.never } else { self.types.unit diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index c9a934e9ebd84..93e9ad5badbb0 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2898,7 +2898,7 @@ impl<'tcx> TyCtxt<'tcx> { (ImplPolarity::Negative, ImplPolarity::Negative) => {} }; - let is_marker_overlap = if self.features().overlapping_marker_traits { + let is_marker_overlap = if self.features().on(sym::overlapping_marker_traits) { let trait1_is_empty = self.impl_trait_ref(def_id1) .map_or(false, |trait_ref| { self.associated_item_def_ids(trait_ref.def_id).is_empty() diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 276fc8c1dec0f..d0798184e96f4 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -5,7 +5,7 @@ use crate::ty::subst::SubstsRef; use crate::traits::{self, AssocTypeBoundData}; use crate::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable}; use std::iter::once; -use syntax::symbol::{kw, Ident}; +use syntax::symbol::{kw, sym, Ident}; use syntax_pos::Span; use crate::middle::lang_items; @@ -538,7 +538,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // checking those let defer_to_coercion = - self.infcx.tcx.features().object_safe_for_dispatch; + self.infcx.tcx.features().on(sym::object_safe_for_dispatch); if !defer_to_coercion { let cause = self.cause(traits::MiscObligation); diff --git a/src/librustc_codegen_utils/symbol_names_test.rs b/src/librustc_codegen_utils/symbol_names_test.rs index 51269be4e9f40..c76051c91321a 100644 --- a/src/librustc_codegen_utils/symbol_names_test.rs +++ b/src/librustc_codegen_utils/symbol_names_test.rs @@ -15,7 +15,7 @@ pub fn report_symbol_names(tcx: TyCtxt<'_>) { // if the `rustc_attrs` feature is not enabled, then the // attributes we are interested in cannot be present anyway, so // skip the walk. - if !tcx.features().rustc_attrs { + if !tcx.features().on(sym::rustc_attrs) { return; } diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index 16d8ada9f24c0..82d4bd942a246 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -6,34 +6,22 @@ use syntax_pos::edition::Edition; use syntax_pos::Span; use syntax_pos::symbol::{Symbol, sym}; -macro_rules! set { - ($field: ident) => {{ - fn f(features: &mut Features, _: Span) { - features.$field = true; - } - f as fn(&mut Features, Span) - }} -} - macro_rules! declare_features { ($( $(#[doc = $doc:tt])* (active, $feature:ident, $ver:expr, $issue:expr, $edition:expr), )+) => { /// Represents active features that are currently being implemented or /// currently being considered for addition/removal. - pub const ACTIVE_FEATURES: - &[Feature] = - &[$( - // (sym::$feature, $ver, $issue, $edition, set!($feature)) - Feature { - state: State::Active { set: set!($feature) }, - name: sym::$feature, - since: $ver, - issue: $issue, - edition: $edition, - description: concat!($($doc,)*), - } - ),+]; + pub const ACTIVE_FEATURES: &[Feature] = &[$( + Feature { + state: State::Active, + name: sym::$feature, + since: $ver, + issue: $issue, + edition: $edition, + description: concat!($($doc,)*), + } + ),+]; /// A set of features to be used by later passes. #[derive(Clone, Default)] @@ -44,11 +32,36 @@ macro_rules! declare_features { pub declared_lib_features: Vec<(Symbol, Span)>, $( $(#[doc = $doc])* - pub $feature: bool + $feature: bool ),+ } impl Features { + /// Is the given feature enabled? + /// + /// Panics if the symbol doesn't correspond to a declared feature. + pub fn on(&self, name: Symbol) -> bool { + match name { + $(sym::$feature => self.$feature,)+ + _ => panic!("unknown feature `{}`", name), + } + } + + /// Enable the given `feature`. + /// + /// Panics if called on a non-active feature + /// or a symbol not corresponding to a declared feature. + pub fn enable(&mut self, feature: &Feature, _: Span) { + let Feature { name, .. } = feature; + match feature.state { + State::Active => match *name { + $(sym::$feature => self.$feature = true,)+ + _ => panic!("unknown feature `{}`", name), + }, + _ => panic!("called `set` on feature `{}` which is not `active`", name), + } + } + pub fn walk_feature_fields(&self, mut f: impl FnMut(&str, bool)) { $(f(stringify!($feature), self.$feature);)+ } @@ -56,16 +69,6 @@ macro_rules! declare_features { }; } -impl Feature { - /// Sets this feature in `Features`. Panics if called on a non-active feature. - pub fn set(&self, features: &mut Features, span: Span) { - match self.state { - State::Active { set } => set(features, span), - _ => panic!("called `set` on feature `{}` which is not `active`", self.name) - } - } -} - // If you change this, please modify `src/doc/unstable-book` as well. // // Don't ever remove anything from this list; move them to `removed.rs`. diff --git a/src/librustc_feature/builtin_attrs.rs b/src/librustc_feature/builtin_attrs.rs index 4fa0198d8716d..da470afd9538a 100644 --- a/src/librustc_feature/builtin_attrs.rs +++ b/src/librustc_feature/builtin_attrs.rs @@ -3,29 +3,21 @@ use AttributeType::*; use AttributeGate::*; -use crate::{Features, Stability}; +use crate::Stability; use rustc_data_structures::fx::FxHashMap; use syntax_pos::symbol::{Symbol, sym}; use lazy_static::lazy_static; -type GateFn = fn(&Features) -> bool; - -macro_rules! cfg_fn { - ($field: ident) => { - (|features| { features.$field }) as GateFn - } -} - -pub type GatedCfg = (Symbol, Symbol, GateFn); +pub type GatedCfg = (Symbol, Symbol); /// `cfg(...)`'s that are feature gated. const GATED_CFGS: &[GatedCfg] = &[ - // (name in cfg, feature, function to check if the feature is enabled) - (sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)), - (sym::target_has_atomic, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), - (sym::target_has_atomic_load_store, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), - (sym::sanitize, sym::cfg_sanitize, cfg_fn!(cfg_sanitize)), + // (name in cfg, feature) + (sym::target_thread_local, sym::cfg_target_thread_local), + (sym::target_has_atomic, sym::cfg_target_has_atomic), + (sym::target_has_atomic_load_store, sym::cfg_target_has_atomic), + (sym::sanitize, sym::cfg_sanitize), ]; /// Find a gated cfg determined by the `pred`icate which is given the cfg's name. @@ -52,27 +44,15 @@ pub enum AttributeType { CrateLevel, } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub enum AttributeGate { /// Is gated by a given feature gate, reason - /// and function to check if enabled - Gated(Stability, Symbol, &'static str, fn(&Features) -> bool), + Gated(Stability, Symbol, &'static str), /// 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 { - Self::Gated(ref stab, name, expl, _) => - write!(fmt, "Gated({:?}, {}, {})", stab, name, expl), - Self::Ungated => write!(fmt, "Ungated") - } - } -} - impl AttributeGate { fn is_deprecated(&self) -> bool { match *self { @@ -125,10 +105,10 @@ macro_rules! ungated { macro_rules! gated { ($attr:ident, $typ:expr, $tpl:expr, $gate:ident, $msg:expr $(,)?) => { - (sym::$attr, $typ, $tpl, Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate))) + (sym::$attr, $typ, $tpl, Gated(Stability::Unstable, sym::$gate, $msg)) }; ($attr:ident, $typ:expr, $tpl:expr, $msg:expr $(,)?) => { - (sym::$attr, $typ, $tpl, Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr))) + (sym::$attr, $typ, $tpl, Gated(Stability::Unstable, sym::$attr, $msg)) }; } @@ -142,8 +122,7 @@ macro_rules! rustc_attr { ) }; ($attr:ident, $typ:expr, $tpl:expr, $msg:expr $(,)?) => { - (sym::$attr, $typ, $tpl, - Gated(Stability::Unstable, sym::rustc_attrs, $msg, cfg_fn!(rustc_attrs))) + (sym::$attr, $typ, $tpl, Gated(Stability::Unstable, sym::rustc_attrs, $msg)) }; } @@ -280,7 +259,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), sym::plugin_registrar, "compiler plugins are deprecated", - cfg_fn!(plugin_registrar) ) ), ( @@ -292,7 +270,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), sym::plugin, "compiler plugins are deprecated", - cfg_fn!(plugin) ) ), @@ -489,7 +466,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ Stability::Unstable, sym::rustc_attrs, "diagnostic items compiler internal support for linting", - cfg_fn!(rustc_attrs), ), ), ( @@ -499,7 +475,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ sym::no_debug, "the `#[no_debug]` attribute was an experimental feature that has been \ deprecated due to lack of demand", - cfg_fn!(no_debug) ) ), gated!( diff --git a/src/librustc_feature/lib.rs b/src/librustc_feature/lib.rs index c38bb3740af3a..e18cfc28b64ec 100644 --- a/src/librustc_feature/lib.rs +++ b/src/librustc_feature/lib.rs @@ -17,12 +17,12 @@ mod builtin_attrs; use std::fmt; use std::num::NonZeroU32; -use syntax_pos::{Span, edition::Edition, symbol::Symbol}; +use syntax_pos::{edition::Edition, symbol::Symbol}; #[derive(Clone, Copy)] pub enum State { Accepted, - Active { set: fn(&mut Features, Span) }, + Active, Removed { reason: Option<&'static str> }, Stabilized { reason: Option<&'static str> }, } diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index 07d426af6ee95..2e2b181029a5e 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -49,7 +49,7 @@ use std::env; use std::fs::{self, File}; use std::io::Write; use syntax::ast; -use syntax_pos::Span; +use syntax_pos::{Span, symbol::sym}; pub fn assert_dep_graph(tcx: TyCtxt<'_>) { tcx.dep_graph.with_ignore(|| { @@ -60,7 +60,7 @@ pub fn assert_dep_graph(tcx: TyCtxt<'_>) { // if the `rustc_attrs` feature is not enabled, then the // attributes we are interested in cannot be present anyway, so // skip the walk. - if !tcx.features().rustc_attrs { + if !tcx.features().on(sym::rustc_attrs) { return; } diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index ea156a94ea17b..43050d322aaae 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -210,7 +210,7 @@ impl Assertion { pub fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) { // can't add `#[rustc_dirty]` etc without opting in to this feature - if !tcx.features().rustc_attrs { + if !tcx.features().on(sym::rustc_attrs) { return; } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 0fd7145f425d3..fa30f28a22a54 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -694,13 +694,12 @@ impl EarlyLintPass for DeprecatedAttr { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) { for &&(n, _, _, ref g) in &self.depr_attrs { if attr.ident().map(|ident| ident.name) == Some(n) { - if let &AttributeGate::Gated(Stability::Deprecated(link, suggestion), - ref name, - ref reason, - _) = g { + if let AttributeGate::Gated(Stability::Deprecated(link, suggestion), name, reason) + = g + { let msg = format!("use of deprecated attribute `{}`: {}. See {}", name, reason, link); - lint_deprecated_attr(cx, attr, &msg, suggestion); + lint_deprecated_attr(cx, attr, &msg, *suggestion); } return; } @@ -969,7 +968,7 @@ impl UnreachablePub { let def_span = cx.tcx.sess.source_map().def_span(span); let mut err = cx.struct_span_lint(UNREACHABLE_PUB, def_span, &format!("unreachable `pub` {}", what)); - let replacement = if cx.tcx.features().crate_visibility_modifier { + let replacement = if cx.tcx.features().on(sym::crate_visibility_modifier) { "crate" } else { "pub(crate)" @@ -1184,7 +1183,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints { use rustc::ty::fold::TypeFoldable; use rustc::ty::Predicate::*; - if cx.tcx.features().trivial_bounds { + if cx.tcx.features().on(sym::trivial_bounds) { let def_id = cx.tcx.hir().local_def_id(item.hir_id); let predicates = cx.tcx.predicates_of(def_id); for &(predicate, span) in predicates.predicates { @@ -1627,7 +1626,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExplicitOutlivesRequirements { fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) { use rustc::middle::resolve_lifetime::Region; - let infer_static = cx.tcx.features().infer_static_outlives_requirements; + let infer_static = cx.tcx.features().on(sym::infer_static_outlives_requirements); let def_id = cx.tcx.hir().local_def_id(item.hir_id); if let hir::ItemKind::Struct(_, ref hir_generics) | hir::ItemKind::Enum(_, ref hir_generics) diff --git a/src/librustc_metadata/native_libs.rs b/src/librustc_metadata/native_libs.rs index 425e5d1d821bf..3076c8f434d8f 100644 --- a/src/librustc_metadata/native_libs.rs +++ b/src/librustc_metadata/native_libs.rs @@ -7,7 +7,7 @@ use rustc::util::nodemap::FxHashSet; use rustc_target::spec::abi::Abi; use syntax::attr; use syntax::source_map::Span; -use syntax::feature_gate::feature_err; +use syntax::feature_gate::gate_feature; use syntax::symbol::{kw, sym, Symbol}; use syntax::{span_err, struct_span_err}; @@ -157,30 +157,32 @@ impl Collector<'tcx> { None => self.tcx.sess.err(msg), } } - if lib.cfg.is_some() && !self.tcx.features().link_cfg { - feature_err(&self.tcx.sess.parse_sess, sym::link_cfg, span.unwrap(), "is unstable") - .emit(); + if lib.cfg.is_some() { + gate_feature( + &self.tcx.sess.parse_sess, + self.tcx.features(), + span.unwrap(), + sym::link_cfg, + "is unstable", + ); } - if lib.kind == cstore::NativeStaticNobundle && - !self.tcx.features().static_nobundle - { - feature_err( + if lib.kind == cstore::NativeStaticNobundle { + gate_feature( &self.tcx.sess.parse_sess, - sym::static_nobundle, + self.tcx.features(), span.unwrap_or_else(|| syntax_pos::DUMMY_SP), - "kind=\"static-nobundle\" is unstable" - ) - .emit(); + sym::static_nobundle, + "kind=\"static-nobundle\" is unstable", + ); } - if lib.kind == cstore::NativeRawDylib && - !self.tcx.features().raw_dylib { - feature_err( + if lib.kind == cstore::NativeRawDylib { + gate_feature( &self.tcx.sess.parse_sess, - sym::raw_dylib, + self.tcx.features(), span.unwrap_or_else(|| syntax_pos::DUMMY_SP), - "kind=\"raw-dylib\" is unstable" - ) - .emit(); + sym::raw_dylib, + "kind=\"raw-dylib\" is unstable", + ); } self.libs.push(lib); } diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index a554867389e12..d5494a37ff5ab 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -32,7 +32,7 @@ use rustc::ty::subst::{GenericArgKind, Subst, SubstsRef, UserSubsts}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_error_codes::*; use rustc_index::vec::{Idx, IndexVec}; -use syntax_pos::{DUMMY_SP, Span}; +use syntax_pos::{DUMMY_SP, Span, symbol::sym}; use crate::borrow_check::borrow_set::BorrowSet; use crate::borrow_check::location::LocationTable; @@ -1451,7 +1451,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } self.check_rvalue(body, rv, location); - if !self.tcx().features().unsized_locals { + if !self.tcx().features().on(sym::unsized_locals) { let trait_ref = ty::TraitRef { def_id: tcx.lang_items().sized_trait().unwrap(), substs: tcx.mk_substs_trait(place_ty, &[]), @@ -1736,7 +1736,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // When `#![feature(unsized_locals)]` is not enabled, // this check is done at `check_local`. - if self.tcx().features().unsized_locals { + if self.tcx().features().on(sym::unsized_locals) { let span = term.source_info.span; self.ensure_place_sized(dest_ty, span); } @@ -1907,7 +1907,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // When `#![feature(unsized_locals)]` is enabled, only function calls // and nullary ops are checked in `check_call_dest`. - if !self.tcx().features().unsized_locals { + if !self.tcx().features().on(sym::unsized_locals) { let span = local_decl.source_info.span; let ty = local_decl.ty; self.ensure_place_sized(ty, span); @@ -2044,7 +2044,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Rvalue::NullaryOp(_, ty) => { // Even with unsized locals cannot box an unsized value. - if self.tcx().features().unsized_locals { + if self.tcx().features().on(sym::unsized_locals) { let span = body.source_info(location).span; self.ensure_place_sized(ty, span); } diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs index 3e71b871801d1..6d92e4c1a71e8 100644 --- a/src/librustc_mir/build/matches/simplify.rs +++ b/src/librustc_mir/build/matches/simplify.rs @@ -20,6 +20,7 @@ use rustc::ty::layout::{Integer, IntegerExt, Size}; use syntax::attr::{SignedInt, UnsignedInt}; use rustc::hir::RangeEnd; use rustc::mir::interpret::truncate; +use syntax_pos::symbol::sym; use std::mem; @@ -161,7 +162,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { PatKind::Variant { adt_def, substs, variant_index, ref subpatterns } => { let irrefutable = adt_def.variants.iter_enumerated().all(|(i, v)| { i == variant_index || { - self.hir.tcx().features().exhaustive_patterns && + self.hir.tcx().features().on(sym::exhaustive_patterns) && !v.uninhabited_from(self.hir.tcx(), substs, adt_def.adt_kind()).is_empty() } }) && (adt_def.did.is_local() || !adt_def.is_variant_list_non_exhaustive()); diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 8c852854be1f9..8e687f859d3e0 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -12,7 +12,7 @@ use rustc::ty::subst::{InternalSubsts, SubstsRef}; use rustc::hir; use rustc::hir::def_id::LocalDefId; use rustc::mir::BorrowKind; -use syntax_pos::Span; +use syntax_pos::{Span, symbol::sym}; impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { type Output = Expr<'tcx>; @@ -309,7 +309,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( match (op.node, cx.constness) { // Destroy control flow if `#![feature(const_if_match)]` is not enabled. (hir::BinOpKind::And, hir::Constness::Const) - if !cx.tcx.features().const_if_match => + if !cx.tcx.features().on(sym::const_if_match) => { cx.control_flow_destroyed.push(( op.span, @@ -322,7 +322,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( } } (hir::BinOpKind::Or, hir::Constness::Const) - if !cx.tcx.features().const_if_match => + if !cx.tcx.features().on(sym::const_if_match) => { cx.control_flow_destroyed.push(( op.span, diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 37a9381271a8c..3624a61725306 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -247,7 +247,7 @@ use rustc::util::captures::Captures; use rustc::util::common::ErrorReported; use syntax::attr::{SignedInt, UnsignedInt}; -use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::{Span, DUMMY_SP, symbol::sym}; use arena::TypedArena; @@ -589,7 +589,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { } fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool { - if self.tcx.features().exhaustive_patterns { + if self.tcx.features().on(sym::exhaustive_patterns) { self.tcx.is_ty_uninhabited_from(self.module, ty) } else { false @@ -1239,7 +1239,7 @@ fn all_constructors<'a, 'tcx>( .variants .iter() .filter(|v| { - !cx.tcx.features().exhaustive_patterns + !cx.tcx.features().on(sym::exhaustive_patterns) || !v .uninhabited_from(cx.tcx, substs, def.adt_kind()) .contains(cx.tcx, cx.module) @@ -1286,7 +1286,7 @@ fn all_constructors<'a, 'tcx>( } ty::Int(_) | ty::Uint(_) if pcx.ty.is_ptr_sized_integral() - && !cx.tcx.features().precise_pointer_size_matching => + && !cx.tcx.features().on(sym::precise_pointer_size_matching) => { // `usize`/`isize` are not allowed to be matched exhaustively unless the // `precise_pointer_size_matching` feature is enabled. So we treat those types like @@ -1351,7 +1351,7 @@ impl<'tcx> IntRange<'tcx> { /// Don't treat `usize`/`isize` exhaustively unless the `precise_pointer_size_matching` feature /// is enabled. fn treat_exhaustively(&self, tcx: TyCtxt<'tcx>) -> bool { - !self.ty.is_ptr_sized_integral() || tcx.features().precise_pointer_size_matching + !self.ty.is_ptr_sized_integral() || tcx.features().on(sym::precise_pointer_size_matching) } #[inline] diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index 737af3e1358f4..fbb60c4aa0906 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -18,7 +18,7 @@ use rustc::hir::{self, Pat}; use std::slice; -use syntax_pos::{MultiSpan, Span}; +use syntax_pos::{MultiSpan, Span, symbol::sym}; use rustc_error_codes::*; @@ -173,7 +173,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { let mut def_span = None; let mut missing_variants = vec![]; if inlined_arms.is_empty() { - let scrutinee_is_uninhabited = if self.tcx.features().exhaustive_patterns { + let scrutinee_is_uninhabited = if self.tcx.features().on(sym::exhaustive_patterns) { self.tcx.is_ty_uninhabited_from(module, pat_ty) } else { match pat_ty.kind { diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs index a4f12a4e54fa7..eeb592e0b6410 100644 --- a/src/librustc_mir/transform/check_consts/ops.rs +++ b/src/librustc_mir/transform/check_consts/ops.rs @@ -3,7 +3,6 @@ use rustc::hir::def_id::DefId; use rustc::mir::BorrowKind; use rustc::session::config::nightly_options; -use rustc::ty::TyCtxt; use syntax::feature_gate::feature_err; use syntax::symbol::sym; use syntax_pos::{Span, Symbol}; @@ -17,9 +16,9 @@ pub trait NonConstOp: std::fmt::Debug { /// Whether this operation can be evaluated by miri. const IS_SUPPORTED_IN_MIRI: bool = true; - /// Returns a boolean indicating whether the feature gate that would allow this operation is - /// enabled, or `None` if such a feature gate does not exist. - fn feature_gate(_tcx: TyCtxt<'tcx>) -> Option { + /// Returns the symbol for a feature gate that would allow this operation, + /// or `None` if no such a feature gate exists. + fn feature_gate() -> Option { None } @@ -28,7 +27,9 @@ pub trait NonConstOp: std::fmt::Debug { /// This check should assume that we are not in a non-const `fn`, where all operations are /// legal. fn is_allowed_in_item(&self, item: &Item<'_, '_>) -> bool { - Self::feature_gate(item.tcx).unwrap_or(false) + Self::feature_gate() + .map(|feature| item.tcx.features().on(feature)) + .unwrap_or(false) } fn emit_error(&self, item: &Item<'_, '_>, span: Span) { @@ -53,8 +54,8 @@ pub trait NonConstOp: std::fmt::Debug { #[derive(Debug)] pub struct Downcast; impl NonConstOp for Downcast { - fn feature_gate(tcx: TyCtxt<'_>) -> Option { - Some(tcx.features().const_if_match) + fn feature_gate() -> Option { + Some(sym::const_if_match) } } @@ -143,8 +144,8 @@ impl NonConstOp for HeapAllocation { #[derive(Debug)] pub struct IfOrMatch; impl NonConstOp for IfOrMatch { - fn feature_gate(tcx: TyCtxt<'_>) -> Option { - Some(tcx.features().const_if_match) + fn feature_gate() -> Option { + Some(sym::const_if_match) } fn emit_error(&self, item: &Item<'_, '_>, span: Span) { @@ -217,8 +218,8 @@ impl NonConstOp for MutDeref {} #[derive(Debug)] pub struct Panic; impl NonConstOp for Panic { - fn feature_gate(tcx: TyCtxt<'_>) -> Option { - Some(tcx.features().const_panic) + fn feature_gate() -> Option { + Some(sym::const_panic) } fn emit_error(&self, item: &Item<'_, '_>, span: Span) { @@ -235,8 +236,8 @@ impl NonConstOp for Panic { #[derive(Debug)] pub struct RawPtrComparison; impl NonConstOp for RawPtrComparison { - fn feature_gate(tcx: TyCtxt<'_>) -> Option { - Some(tcx.features().const_compare_raw_pointers) + fn feature_gate() -> Option { + Some(sym::const_compare_raw_pointers) } fn emit_error(&self, item: &Item<'_, '_>, span: Span) { @@ -253,8 +254,8 @@ impl NonConstOp for RawPtrComparison { #[derive(Debug)] pub struct RawPtrDeref; impl NonConstOp for RawPtrDeref { - fn feature_gate(tcx: TyCtxt<'_>) -> Option { - Some(tcx.features().const_raw_ptr_deref) + fn feature_gate() -> Option { + Some(sym::const_raw_ptr_deref) } fn emit_error(&self, item: &Item<'_, '_>, span: Span) { @@ -272,8 +273,8 @@ impl NonConstOp for RawPtrDeref { #[derive(Debug)] pub struct RawPtrToIntCast; impl NonConstOp for RawPtrToIntCast { - fn feature_gate(tcx: TyCtxt<'_>) -> Option { - Some(tcx.features().const_raw_ptr_to_usize_cast) + fn feature_gate() -> Option { + Some(sym::const_raw_ptr_to_usize_cast) } fn emit_error(&self, item: &Item<'_, '_>, span: Span) { @@ -329,8 +330,8 @@ impl NonConstOp for ThreadLocalAccess { #[derive(Debug)] pub struct Transmute; impl NonConstOp for Transmute { - fn feature_gate(tcx: TyCtxt<'_>) -> Option { - Some(tcx.features().const_transmute) + fn feature_gate() -> Option { + Some(sym::const_transmute) } fn emit_error(&self, item: &Item<'_, '_>, span: Span) { @@ -347,11 +348,12 @@ pub struct UnionAccess; impl NonConstOp for UnionAccess { fn is_allowed_in_item(&self, item: &Item<'_, '_>) -> bool { // Union accesses are stable in all contexts except `const fn`. - item.const_kind() != ConstKind::ConstFn || Self::feature_gate(item.tcx).unwrap() + item.const_kind() != ConstKind::ConstFn + || item.tcx.features().on(Self::feature_gate().unwrap()) } - fn feature_gate(tcx: TyCtxt<'_>) -> Option { - Some(tcx.features().const_fn_union) + fn feature_gate() -> Option { + Some(sym::const_fn_union) } fn emit_error(&self, item: &Item<'_, '_>, span: Span) { diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs index 9d477bfbae81f..1407b6b8117dd 100644 --- a/src/librustc_mir/transform/check_consts/validation.rs +++ b/src/librustc_mir/transform/check_consts/validation.rs @@ -253,7 +253,7 @@ impl Validator<'a, 'mir, 'tcx> { // If an operation is supported in miri (and is not already controlled by a feature gate) it // can be turned on with `-Zunleash-the-miri-inside-of-you`. let is_unleashable = O::IS_SUPPORTED_IN_MIRI - && O::feature_gate(self.tcx).is_none(); + && O::feature_gate().is_none(); if is_unleashable && self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you { self.tcx.sess.span_warn(span, "skipping const checks"); diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 2c45dcfbe2665..494fa90c9720f 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -155,7 +155,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { // possibly know what the result of various operations like `address / 2` would be // pointers during const evaluation have no integral address, only an abstract one Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) - if self.const_context && self.tcx.features().const_raw_ptr_to_usize_cast => { + if self.const_context && self.tcx.features().on(sym::const_raw_ptr_to_usize_cast) => { let operand_ty = operand.ty(self.body, self.tcx); let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast"); let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); @@ -177,7 +177,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { // or the linker will place various statics in memory. Without this information the // result of a comparison of addresses would differ between runtime and compile-time. Rvalue::BinaryOp(_, ref lhs, _) - if self.const_context && self.tcx.features().const_compare_raw_pointers => { + if self.const_context && self.tcx.features().on(sym::const_compare_raw_pointers) => { if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind { self.register_violations(&[UnsafetyViolation { source_info: self.source_info, diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index c99824bd35647..88e8b0791450a 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -214,7 +214,8 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { Rvalue::Ref(..) => { self.candidates.push(Candidate::Ref(location)); } - Rvalue::Repeat(..) if self.tcx.features().const_in_array_repeat_expressions => { + Rvalue::Repeat(..) + if self.tcx.features().on(sym::const_in_array_repeat_expressions) => { // FIXME(#49147) only promote the element when it isn't `Copy` // (so that code that can copy it at runtime is unaffected). self.candidates.push(Candidate::Repeat(location)); @@ -407,7 +408,7 @@ impl<'tcx> Validator<'_, 'tcx> { let statement = &self.body[loc.block].statements[loc.statement_index]; match &statement.kind { StatementKind::Assign(box(_, Rvalue::Repeat(ref operand, _))) => { - if !self.tcx.features().const_in_array_repeat_expressions { + if !self.tcx.features().on(sym::const_in_array_repeat_expressions) { return Err(Unpromotable); } @@ -1162,7 +1163,7 @@ crate fn should_suggest_const_in_array_repeat_expressions_attribute<'tcx>( }; let should_promote = validator.validate_operand(operand).is_ok(); - let feature_flag = tcx.features().const_in_array_repeat_expressions; + let feature_flag = tcx.features().on(sym::const_in_array_repeat_expressions); debug!("should_suggest_const_in_array_repeat_expressions_flag: mir_def_id={:?} \ should_promote={:?} feature_flag={:?}", mir_def_id, should_promote, feature_flag); should_promote && !feature_flag diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index e40d6a5952edb..be02f8ddd2cb4 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -217,7 +217,7 @@ fn check_statement( } | StatementKind::FakeRead(FakeReadCause::ForMatchedPlace, _) - if !tcx.features().const_if_match + if !tcx.features().on(sym::const_if_match) => { Err((span, "loops and conditional expressions are not stable in const fn".into())) } @@ -269,7 +269,7 @@ fn check_place( while let &[ref proj_base @ .., elem] = cursor { cursor = proj_base; match elem { - ProjectionElem::Downcast(..) if !tcx.features().const_if_match + ProjectionElem::Downcast(..) if !tcx.features().on(sym::const_if_match) => return Err((span, "`match` or `if let` in `const fn` is unstable".into())), ProjectionElem::Downcast(_symbol, _variant_index) => {} @@ -326,7 +326,7 @@ fn check_terminator( | TerminatorKind::FalseEdges { .. } | TerminatorKind::SwitchInt { .. } - if !tcx.features().const_if_match + if !tcx.features().on(sym::const_if_match) => Err(( span, "loops and conditional expressions are not stable in const fn".into(), @@ -338,7 +338,7 @@ fn check_terminator( } // FIXME(ecstaticmorse): We probably want to allow `Unreachable` unconditionally. - TerminatorKind::Unreachable if tcx.features().const_if_match => Ok(()), + TerminatorKind::Unreachable if tcx.features().on(sym::const_if_match) => Ok(()), | TerminatorKind::Abort | TerminatorKind::Unreachable => { Err((span, "const fn with unreachable code is not stable".into())) diff --git a/src/librustc_parse/config.rs b/src/librustc_parse/config.rs index 1bf6e9ecbc060..d8d72bb1f58a7 100644 --- a/src/librustc_parse/config.rs +++ b/src/librustc_parse/config.rs @@ -208,7 +208,7 @@ impl<'a> StripUnconfigured<'a> { /// If attributes are not allowed on expressions, emit an error for `attr` pub fn maybe_emit_expr_attr_err(&self, attr: &ast::Attribute) { - if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) { + if !self.features.map(|features| features.on(sym::stmt_expr_attributes)).unwrap_or(true) { let mut err = feature_err(self.sess, sym::stmt_expr_attributes, attr.span, diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 29cfee8408f30..d7458af2cdabf 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -356,7 +356,11 @@ fn validate_generics_order<'a>( &format!( "reorder the {}s: lifetimes, then types{}", pos_str, - if sess.features_untracked().const_generics { ", then consts" } else { "" }, + if sess.features_untracked().on(sym::const_generics) { + ", then consts" + } else { + "" + }, ), ordered_params.clone(), Applicability::MachineApplicable, diff --git a/src/librustc_passes/check_const.rs b/src/librustc_passes/check_const.rs index 63c6e60de7954..7cb43964fd661 100644 --- a/src/librustc_passes/check_const.rs +++ b/src/librustc_passes/check_const.rs @@ -45,7 +45,7 @@ impl NonConstExpr { | Self::Match(Normal) | Self::Match(IfDesugar { .. }) | Self::Match(IfLetDesugar { .. }) - => Some(features.const_if_match), + => Some(features.on(sym::const_if_match)), _ => None, } diff --git a/src/librustc_passes/layout_test.rs b/src/librustc_passes/layout_test.rs index 06683c16e4a9b..7e31a70e6be44 100644 --- a/src/librustc_passes/layout_test.rs +++ b/src/librustc_passes/layout_test.rs @@ -15,7 +15,7 @@ use syntax::ast::Attribute; use syntax::symbol::sym; pub fn test_layout(tcx: TyCtxt<'_>) { - if tcx.features().rustc_attrs { + if tcx.features().on(sym::rustc_attrs) { // if the `rustc_attrs` feature is not enabled, don't bother testing layout tcx.hir() .krate() diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 9e7098da49f32..e71d32423cd70 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -342,7 +342,7 @@ impl<'a> Resolver<'a> { if let Some(args) = &segment.args { self.session.span_err(args.span(), "generic arguments in macro path"); } - if kind == MacroKind::Attr && !features.rustc_attrs && + if kind == MacroKind::Attr && !features.on(sym::rustc_attrs) && segment.ident.as_str().starts_with("rustc") { let msg = "attributes starting with `rustc` are reserved for use by the `rustc` compiler"; diff --git a/src/librustc_traits/lowering/mod.rs b/src/librustc_traits/lowering/mod.rs index 0df367fcca83c..d565b384ba684 100644 --- a/src/librustc_traits/lowering/mod.rs +++ b/src/librustc_traits/lowering/mod.rs @@ -612,7 +612,7 @@ pub fn program_clauses_for_associated_type_value( } pub fn dump_program_clauses(tcx: TyCtxt<'_>) { - if !tcx.features().rustc_attrs { + if !tcx.features().on(sym::rustc_attrs) { return; } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index af978d5095eaa..61cd9806175ac 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -904,7 +904,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let trait_def = self.tcx().trait_def(trait_def_id); - if !self.tcx().features().unboxed_closures && + if !self.tcx().features().on(sym::unboxed_closures) && trait_segment.generic_args().parenthesized != trait_def.paren_sugar { // For now, require that parenthetical notation be used only with `Fn()` etc. diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 035ece238104f..ec53035254064 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -43,7 +43,7 @@ use rustc::ty::cast::{CastKind, CastTy}; use rustc::ty::error::TypeError; use rustc::middle::lang_items; use syntax::ast; -use syntax_pos::Span; +use syntax_pos::{Span, symbol::sym}; use crate::util::common::ErrorReported; use rustc_error_codes::*; @@ -391,7 +391,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { fn trivial_cast_lint(&self, fcx: &FnCtxt<'a, 'tcx>) { let t_cast = self.cast_ty; let t_expr = self.expr_ty; - let type_asc_or = if fcx.tcx.features().type_ascription { + let type_asc_or = if fcx.tcx.features().on(sym::type_ascription) { "type ascription or " } else { "" diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 901a2192e20dd..cc7a181b185dd 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -643,14 +643,14 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } } - if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion { - feature_gate::feature_err( + if has_unsized_tuple_coercion { + feature_gate::gate_feature( &self.tcx.sess.parse_sess, - sym::unsized_tuple_coercion, + self.tcx.features(), self.cause.span, + sym::unsized_tuple_coercion, "unsized tuple coercion is not stable enough for use and is subject to change", - ) - .emit(); + ); } Ok(coercion) diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 4766360c04897..2ddf669d63297 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -526,7 +526,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let ty::FnDef(..) = ty.kind { let fn_sig = ty.fn_sig(tcx); - if !tcx.features().unsized_locals { + if !tcx.features().on(sym::unsized_locals) { // We want to remove some Sized bounds from std functions, // but don't want to expose the removal to stable Rust. // i.e., we don't want to allow diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 9717190045afb..d49327c57489d 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -29,7 +29,7 @@ use rustc::infer::canonical::{OriginalQueryValues}; use rustc::middle::stability; use syntax::ast; use syntax::util::lev_distance::{lev_distance, find_best_match_for_name}; -use syntax_pos::{DUMMY_SP, Span, symbol::Symbol}; +use syntax_pos::{DUMMY_SP, Span, symbol::{sym, Symbol}}; use std::iter; use std::mem; use std::ops::Deref; @@ -338,7 +338,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if is_suggestion.0 { // Ambiguity was encountered during a suggestion. Just keep going. debug!("ProbeContext: encountered ambiguity in suggestion"); - } else if bad_ty.reached_raw_pointer && !self.tcx.features().arbitrary_self_types { + } else if bad_ty.reached_raw_pointer + && !self.tcx.features().on(sym::arbitrary_self_types) + { // this case used to be allowed by the compiler, // so we do a future-compat lint here for the 2015 edition // (see https://github.com/rust-lang/rust/issues/46906) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c7a0190a1d1b4..44785abd1a7a2 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -125,7 +125,7 @@ use syntax_pos::{self, BytePos, Span, MultiSpan}; use syntax_pos::hygiene::DesugaringKind; use syntax::ast; use syntax::attr; -use syntax::feature_gate::feature_err; +use syntax::feature_gate::gate_feature; use syntax::source_map::{DUMMY_SP, original_sp}; use syntax::symbol::{kw, sym, Ident}; use syntax::util::parser::ExprPrecedence; @@ -1029,7 +1029,7 @@ fn typeck_tables_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::TypeckTables<'_> { let expected_type = fcx.normalize_associated_types_in(body.value.span, &expected_type); fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized); - let revealed_ty = if tcx.features().impl_trait_in_bindings { + let revealed_ty = if tcx.features().on(sym::impl_trait_in_bindings) { fcx.instantiate_opaque_types_from_value( id, &expected_type, @@ -1173,7 +1173,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { Some(ref ty) => { let o_ty = self.fcx.to_ty(&ty); - let revealed_ty = if self.fcx.tcx.features().impl_trait_in_bindings { + let revealed_ty = if self.fcx.tcx.features().on(sym::impl_trait_in_bindings) { self.fcx.instantiate_opaque_types_from_value( self.parent_id, &o_ty, @@ -1208,7 +1208,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { if let PatKind::Binding(_, _, ident, _) = p.kind { let var_ty = self.assign(p.span, p.hir_id, None); - if !self.fcx.tcx.features().unsized_locals { + if !self.fcx.tcx.features().on(sym::unsized_locals) { self.fcx.require_type_is_sized(var_ty, p.span, traits::VariableType(p.hir_id)); } @@ -1335,7 +1335,7 @@ fn check_fn<'a, 'tcx>( // The check for a non-trivial pattern is a hack to avoid duplicate warnings // for simple cases like `fn foo(x: Trait)`, // where we would error once on the parameter as a whole, and once on the binding `x`. - if param.pat.simple_ident().is_none() && !fcx.tcx.features().unsized_locals { + if param.pat.simple_ident().is_none() && !fcx.tcx.features().on(sym::unsized_locals) { fcx.require_type_is_sized(param_ty, decl.output.span(), traits::SizedArgumentType); } @@ -2372,15 +2372,13 @@ fn check_transparent(tcx: TyCtxt<'_>, sp: Span, def_id: DefId) { let sp = tcx.sess.source_map().def_span(sp); if adt.is_enum() { - if !tcx.features().transparent_enums { - feature_err( - &tcx.sess.parse_sess, - sym::transparent_enums, - sp, - "transparent enums are unstable", - ) - .emit(); - } + gate_feature( + &tcx.sess.parse_sess, + tcx.features(), + sp, + sym::transparent_enums, + "transparent enums are unstable", + ); if adt.variants.len() != 1 { bad_variant_count(tcx, adt, sp, def_id); if adt.variants.is_empty() { @@ -2390,14 +2388,14 @@ fn check_transparent(tcx: TyCtxt<'_>, sp: Span, def_id: DefId) { } } - if adt.is_union() && !tcx.features().transparent_unions { - feature_err( + if adt.is_union() { + gate_feature( &tcx.sess.parse_sess, - sym::transparent_unions, + tcx.features(), sp, + sym::transparent_unions, "transparent unions are unstable", - ) - .emit(); + ); } // For each field, figure out if it's known to be a ZST and align(1) @@ -2453,15 +2451,13 @@ pub fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, vs: &'tcx [hir::Variant], i let repr_type_ty = def.repr.discr_type().to_ty(tcx); if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 { - if !tcx.features().repr128 { - feature_err( - &tcx.sess.parse_sess, - sym::repr128, - sp, - "repr with 128-bit type is unstable", - ) - .emit(); - } + gate_feature( + &tcx.sess.parse_sess, + tcx.features(), + sp, + sym::repr128, + "repr with 128-bit type is unstable", + ); } for v in vs { @@ -2470,7 +2466,9 @@ pub fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, vs: &'tcx [hir::Variant], i } } - if tcx.adt_def(def_id).repr.int.is_none() && tcx.features().arbitrary_enum_discriminant { + if tcx.adt_def(def_id).repr.int.is_none() + && tcx.features().on(sym::arbitrary_enum_discriminant) + { let is_unit = |var: &hir::Variant| match var.data { hir::VariantData::Unit(..) => true, diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 20b6b01de57b2..33c4c3de9e990 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -43,7 +43,7 @@ impl<'tcx> CheckWfFcxBuilder<'tcx> { let param_env = self.param_env; self.inherited.enter(|inh| { let fcx = FnCtxt::new(&inh, param_env, id); - if !inh.tcx.features().trivial_bounds { + if !inh.tcx.features().on(sym::trivial_bounds) { // As predicates are cached rather than obligations, this // needsto be called first so that they are checked with an // empty `param_env`. @@ -817,7 +817,7 @@ fn check_method_receiver<'fcx, 'tcx>( &ty::Binder::bind(receiver_ty) ); - if fcx.tcx.features().arbitrary_self_types { + if fcx.tcx.features().on(sym::arbitrary_self_types) { if !receiver_is_valid(fcx, span, receiver_ty, self_ty, true) { // Report error; `arbitrary_self_types` was enabled. e0307(fcx, span, receiver_ty); diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index eac8958bc3be0..5565856f4cd5d 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -11,6 +11,7 @@ use rustc::traits; use rustc::ty::{self, TyCtxt, TypeFoldable}; use rustc::ty::query::Providers; use rustc::util::common::time; +use syntax_pos::symbol::sym; use rustc_error_codes::*; @@ -68,7 +69,7 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt<'_>, impl_def_id: DefId, tra return; } - if tcx.features().unboxed_closures { + if tcx.features().on(sym::unboxed_closures) { // the feature gate allows all Fn traits return; } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 6d6e7685fa053..46cac725acdbc 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -769,7 +769,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::TraitDef { }; let paren_sugar = tcx.has_attr(def_id, sym::rustc_paren_sugar); - if paren_sugar && !tcx.features().unboxed_closures { + if paren_sugar && !tcx.features().on(sym::unboxed_closures) { let mut err = tcx.sess.struct_span_err( item.span, "the `#[rustc_paren_sugar]` attribute is a temporary means of controlling \ @@ -914,7 +914,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics { // HACK(eddyb) this provides the correct generics when // `feature(const_generics)` is enabled, so that const expressions // used with const generics, e.g. `Foo<{N+1}>`, can work at all. - if tcx.features().const_generics { + if tcx.features().on(sym::const_generics) { let parent_id = tcx.hir().get_parent_item(hir_id); Some(tcx.hir().local_def_id(parent_id)) } else { @@ -1036,7 +1036,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics { .. } => { if !allow_defaults && default.is_some() { - if !tcx.features().default_type_parameter_fallback { + if !tcx.features().on(sym::default_type_parameter_fallback) { tcx.lint_hir( lint::builtin::INVALID_TYPE_PARAM_DEFAULT, param.hir_id, @@ -1485,7 +1485,7 @@ fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { hir::GenericParamKind::Type { default: Some(ref ty), .. } => icx.to_ty(ty), hir::GenericParamKind::Const { ty: ref hir_ty, .. } => { let ty = icx.to_ty(hir_ty); - if !tcx.features().const_compare_raw_pointers { + if !tcx.features().on(sym::const_compare_raw_pointers) { let err = match ty.peel_refs().kind { ty::FnPtr(_) => Some("function pointers"), ty::RawPtr(_) => Some("raw pointers"), @@ -2389,7 +2389,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( // ABIs are handled at all correctly. -huonw if abi != abi::Abi::RustIntrinsic && abi != abi::Abi::PlatformIntrinsic - && !tcx.features().simd_ffi + && !tcx.features().on(sym::simd_ffi) { let check = |ast_ty: &hir::Ty, ty: Ty<'_>| { if ty.is_simd() { @@ -2500,33 +2500,32 @@ fn from_target_feature( }; // Only allow features whose feature gates have been enabled. - let allowed = match feature_gate.as_ref().map(|s| *s) { - Some(sym::arm_target_feature) => rust_features.arm_target_feature, - Some(sym::aarch64_target_feature) => rust_features.aarch64_target_feature, - Some(sym::hexagon_target_feature) => rust_features.hexagon_target_feature, - Some(sym::powerpc_target_feature) => rust_features.powerpc_target_feature, - Some(sym::mips_target_feature) => rust_features.mips_target_feature, - Some(sym::avx512_target_feature) => rust_features.avx512_target_feature, - Some(sym::mmx_target_feature) => rust_features.mmx_target_feature, - Some(sym::sse4a_target_feature) => rust_features.sse4a_target_feature, - Some(sym::tbm_target_feature) => rust_features.tbm_target_feature, - Some(sym::wasm_target_feature) => rust_features.wasm_target_feature, - Some(sym::cmpxchg16b_target_feature) => rust_features.cmpxchg16b_target_feature, - Some(sym::adx_target_feature) => rust_features.adx_target_feature, - Some(sym::movbe_target_feature) => rust_features.movbe_target_feature, - Some(sym::rtm_target_feature) => rust_features.rtm_target_feature, - Some(sym::f16c_target_feature) => rust_features.f16c_target_feature, + match feature_gate.as_ref().copied() { + Some(f @ sym::arm_target_feature) | + Some(f @ sym::aarch64_target_feature) | + Some(f @ sym::hexagon_target_feature) | + Some(f @ sym::powerpc_target_feature) | + Some(f @ sym::mips_target_feature) | + Some(f @ sym::avx512_target_feature) | + Some(f @ sym::mmx_target_feature) | + Some(f @ sym::sse4a_target_feature) | + Some(f @ sym::tbm_target_feature) | + Some(f @ sym::wasm_target_feature) | + Some(f @ sym::cmpxchg16b_target_feature) | + Some(f @ sym::adx_target_feature) | + Some(f @ sym::movbe_target_feature) | + Some(f @ sym::rtm_target_feature) | + Some(f @ sym::f16c_target_feature) => if id.is_local() { + feature_gate::gate_feature( + &tcx.sess.parse_sess, + rust_features, + item.span(), + f, + &format!("the target feature `{}` is currently unstable", feature), + ); + } Some(name) => bug!("unknown target feature gate {}", name), - None => true, - }; - if !allowed && id.is_local() { - feature_gate::feature_err( - &tcx.sess.parse_sess, - feature_gate.unwrap(), - item.span(), - &format!("the target feature `{}` is currently unstable", feature), - ) - .emit(); + None => {}, } Some(Symbol::intern(feature)) })); diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index c606feab08727..62eb490c73308 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -105,7 +105,7 @@ use rustc::ty::subst::SubstsRef; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::query::Providers; use rustc::util; -use syntax_pos::{DUMMY_SP, Span}; +use syntax_pos::{DUMMY_SP, Span, symbol::sym}; use util::common::time; use rustc_error_codes::*; @@ -308,7 +308,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorReported> { }); })?; - if tcx.features().rustc_attrs { + if tcx.features().on(sym::rustc_attrs) { tcx.sess.track_errors(|| { time(tcx.sess, "outlives testing", || outlives::test::test_inferred_outlives(tcx)); @@ -325,7 +325,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorReported> { coherence::check_coherence(tcx)); })?; - if tcx.features().rustc_attrs { + if tcx.features().on(sym::rustc_attrs) { tcx.sess.track_errors(|| { time(tcx.sess, "variance testing", || variance::test::test_variance(tcx)); diff --git a/src/librustc_typeck/outlives/utils.rs b/src/librustc_typeck/outlives/utils.rs index 361116e96d0bf..5612e3aaab861 100644 --- a/src/librustc_typeck/outlives/utils.rs +++ b/src/librustc_typeck/outlives/utils.rs @@ -3,7 +3,7 @@ use rustc::ty::subst::{GenericArg, GenericArgKind}; use rustc::ty::{self, Region, RegionKind, Ty, TyCtxt}; use smallvec::smallvec; use std::collections::BTreeMap; -use syntax_pos::Span; +use syntax_pos::{Span, symbol::sym}; /// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred /// must be added to the struct header. @@ -154,7 +154,7 @@ fn is_free_region(tcx: TyCtxt<'_>, region: Region<'_>) -> bool { RegionKind::ReStatic => { tcx.sess .features_untracked() - .infer_static_outlives_requirements + .on(sym::infer_static_outlives_requirements) } // Late-bound regions can appear in `fn` types: diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs index 3c10f27b60ae9..1df4becef1105 100644 --- a/src/libsyntax/attr/builtin.rs +++ b/src/libsyntax/attr/builtin.rs @@ -566,8 +566,8 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat } fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &ParseSess, features: &Features) { - let (cfg, feature, has_feature) = gated_cfg; - if !has_feature(features) && !cfg_span.allows_unstable(*feature) { + let (cfg, feature) = gated_cfg; + if !features.on(*feature) && !cfg_span.allows_unstable(*feature) { let explain = format!("`cfg({})` is experimental and subject to change", cfg); feature_err(sess, *feature, cfg_span, &explain).emit() } diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index 3d2c3b1d4f901..a3cd7b94d8cda 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -6,43 +6,19 @@ use rustc_feature::{find_feature_issue, GateIssue}; use crate::ast::{self, AssocTyConstraint, AssocTyConstraintKind, NodeId}; use crate::ast::{GenericParam, GenericParamKind, PatKind, RangeEnd, VariantData}; use crate::attr; -use crate::source_map::Spanned; -use crate::edition::{ALL_EDITIONS, Edition}; use crate::visit::{self, FnKind, Visitor}; use crate::sess::ParseSess; -use crate::symbol::{Symbol, sym}; use errors::{Applicability, DiagnosticBuilder, Handler}; use rustc_data_structures::fx::FxHashMap; use syntax_pos::{Span, DUMMY_SP, MultiSpan}; +use syntax_pos::edition::{ALL_EDITIONS, Edition}; +use syntax_pos::source_map::Spanned; +use syntax_pos::symbol::{Symbol, sym}; use log::debug; use rustc_error_codes::*; -macro_rules! gate_feature_fn { - ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $level: expr) => {{ - let (cx, has_feature, span, - name, explain, level) = (&*$cx, $has_feature, $span, $name, $explain, $level); - let has_feature: bool = has_feature(&$cx.features); - debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature); - if !has_feature && !span.allows_unstable($name) { - leveled_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain, level) - .emit(); - } - }} -} - -macro_rules! gate_feature { - ($cx: expr, $feature: ident, $span: expr, $explain: expr) => { - gate_feature_fn!($cx, |x:&Features| x.$feature, $span, - sym::$feature, $explain, GateStrength::Hard) - }; - ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => { - gate_feature_fn!($cx, |x:&Features| x.$feature, $span, - sym::$feature, $explain, $level) - }; -} - pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) { PostExpansionVisitor { parse_sess, features }.visit_attribute(attr) } @@ -114,31 +90,36 @@ fn leveled_feature_err<'a>( } +pub fn gate_feature( + parse_sess: &ParseSess, + features: &Features, + span: Span, + feature: Symbol, + explain: &str, +) { + PostExpansionVisitor { parse_sess, features }.gate(span, feature, explain) +} + struct PostExpansionVisitor<'a> { parse_sess: &'a ParseSess, features: &'a Features, } -macro_rules! gate_feature_post { - ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{ - let (cx, span) = ($cx, $span); - if !span.allows_unstable(sym::$feature) { - gate_feature!(cx, $feature, span, $explain) - } - }}; - ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {{ - let (cx, span) = ($cx, $span); - if !span.allows_unstable(sym::$feature) { - gate_feature!(cx, $feature, span, $explain, $level) +impl<'a> PostExpansionVisitor<'a> { + fn gate(&self, span: Span, feature: Symbol, explain: &str) { + if !span.allows_unstable(feature) { + let has: bool = self.features.on(feature); + debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", feature, span, has); + if !has && !span.allows_unstable(feature) { + feature_err(self.parse_sess, feature, span, explain).emit(); + } } - }} -} + } -impl<'a> PostExpansionVisitor<'a> { fn check_abi(&self, abi: ast::StrLit) { let ast::StrLit { symbol_unescaped, span, .. } = abi; - match &*symbol_unescaped.as_str() { + let (feature, explain) = match &*symbol_unescaped.as_str() { // Stable "Rust" | "C" | @@ -148,58 +129,60 @@ impl<'a> PostExpansionVisitor<'a> { "aapcs" | "win64" | "sysv64" | - "system" => {} - "rust-intrinsic" => { - gate_feature_post!(&self, intrinsics, span, - "intrinsics are subject to change"); - }, - "platform-intrinsic" => { - gate_feature_post!(&self, platform_intrinsics, span, - "platform intrinsics are experimental and possibly buggy"); - }, - "vectorcall" => { - gate_feature_post!(&self, abi_vectorcall, span, - "vectorcall is experimental and subject to change"); - }, - "thiscall" => { - gate_feature_post!(&self, abi_thiscall, span, - "thiscall is experimental and subject to change"); - }, - "rust-call" => { - gate_feature_post!(&self, unboxed_closures, span, - "rust-call ABI is subject to change"); - }, - "ptx-kernel" => { - gate_feature_post!(&self, abi_ptx, span, - "PTX ABIs are experimental and subject to change"); - }, - "unadjusted" => { - gate_feature_post!(&self, abi_unadjusted, span, - "unadjusted ABI is an implementation detail and perma-unstable"); - }, - "msp430-interrupt" => { - gate_feature_post!(&self, abi_msp430_interrupt, span, - "msp430-interrupt ABI is experimental and subject to change"); - }, - "x86-interrupt" => { - gate_feature_post!(&self, abi_x86_interrupt, span, - "x86-interrupt ABI is experimental and subject to change"); - }, - "amdgpu-kernel" => { - gate_feature_post!(&self, abi_amdgpu_kernel, span, - "amdgpu-kernel ABI is experimental and subject to change"); - }, - "efiapi" => { - gate_feature_post!(&self, abi_efiapi, span, - "efiapi ABI is experimental and subject to change"); - }, + "system" => return, + "rust-intrinsic" => ( + sym::intrinsics, + "intrinsics are subject to change", + ), + "platform-intrinsic" => ( + sym::platform_intrinsics, + "platform intrinsics are experimental and possibly buggy", + ), + "vectorcall" => ( + sym::abi_vectorcall, + "vectorcall is experimental and subject to change", + ), + "thiscall" => ( + sym::abi_thiscall, + "thiscall is experimental and subject to change", + ), + "rust-call" => ( + sym::unboxed_closures, + "rust-call ABI is subject to change", + ), + "ptx-kernel" => ( + sym::abi_ptx, + "PTX ABIs are experimental and subject to change", + ), + "unadjusted" => ( + sym::abi_unadjusted, + "unadjusted ABI is an implementation detail and perma-unstable", + ), + "msp430-interrupt" => ( + sym::abi_msp430_interrupt, + "msp430-interrupt ABI is experimental and subject to change", + ), + "x86-interrupt" => ( + sym::abi_x86_interrupt, + "x86-interrupt ABI is experimental and subject to change", + ), + "amdgpu-kernel" => ( + sym::abi_amdgpu_kernel, + "amdgpu-kernel ABI is experimental and subject to change", + ), + "efiapi" => ( + sym::abi_efiapi, + "efiapi ABI is experimental and subject to change", + ), abi => { self.parse_sess.span_diagnostic.delay_span_bug( span, &format!("unrecognized ABI not caught in lowering: {}", abi), - ) + ); + return; } - } + }; + self.gate(span, feature, explain); } fn check_extern(&self, ext: ast::Extern) { @@ -254,19 +237,12 @@ impl<'a> PostExpansionVisitor<'a> { fn check_gat(&self, generics: &ast::Generics, span: Span) { if !generics.params.is_empty() { - gate_feature_post!( - &self, - generic_associated_types, - span, - "generic associated types are unstable" - ); + self.gate(span, sym::generic_associated_types, "generic associated types are unstable"); } if !generics.where_clause.predicates.is_empty() { - gate_feature_post!( - &self, - generic_associated_types, - span, - "where clauses on associated types are unstable" + self.gate( + span, sym::generic_associated_types, + "where clauses on associated types are unstable", ); } } @@ -279,11 +255,9 @@ impl<'a> PostExpansionVisitor<'a> { impl Visitor<'_> for ImplTraitVisitor<'_> { fn visit_ty(&mut self, ty: &ast::Ty) { if let ast::TyKind::ImplTrait(..) = ty.kind { - gate_feature_post!( - &self.vis, - type_alias_impl_trait, - ty.span, - "`impl Trait` in type aliases is unstable" + self.vis.gate( + ty.span, sym::type_alias_impl_trait, + "`impl Trait` in type aliases is unstable", ); } visit::walk_ty(self, ty); @@ -291,6 +265,12 @@ impl<'a> PostExpansionVisitor<'a> { } ImplTraitVisitor { vis: self }.visit_ty(ty); } + + fn check_c_variadic(&self, span: Span, decl: &ast::FnDecl) { + if decl.c_variadic() { + self.gate(span, sym::c_variadic, "C-variadic functions are unstable"); + } + } } impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { @@ -298,38 +278,34 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).map(|a| **a); // Check feature gates for built-in attributes. - if let Some((.., AttributeGate::Gated(_, name, descr, has_feature))) = attr_info { - gate_feature_fn!(self, has_feature, attr.span, name, descr, GateStrength::Hard); + if let Some((.., AttributeGate::Gated(_, feature, descr))) = attr_info { + self.gate(attr.span, feature, descr); } // Check unstable flavors of the `#[doc]` attribute. if attr.check_name(sym::doc) { for nested_meta in attr.meta_item_list().unwrap_or_default() { - macro_rules! gate_doc { ($($name:ident => $feature:ident)*) => { - $(if nested_meta.check_name(sym::$name) { - let msg = concat!("`#[doc(", stringify!($name), ")]` is experimental"); - gate_feature!(self, $feature, attr.span, msg); - })* - }} - - gate_doc!( - include => external_doc - cfg => doc_cfg - masked => doc_masked - spotlight => doc_spotlight - alias => doc_alias - keyword => doc_keyword - ); + const GATED_DOC_FEATURES: &[(Symbol, Symbol, &str)] = &[ + (sym::include, sym::external_doc, "`#[doc(include)]` is experimental"), + (sym::cfg, sym::doc_cfg, "`#[doc(cfg)]` is experimental"), + (sym::masked, sym::doc_masked, "`#[doc(masked)]` is experimental"), + (sym::spotlight, sym::doc_spotlight, "`#[doc(spotlight)]` is experimental"), + (sym::alias, sym::doc_alias, "`#[doc(alias)]` is experimental"), + (sym::keyword, sym::doc_keyword, "`#[doc(keyword)]` is experimental"), + ]; + for (name, feature, explain) in GATED_DOC_FEATURES { + if nested_meta.check_name(*name) { + self.gate(attr.span, *feature, explain); + } + } } } } fn visit_name(&mut self, sp: Span, name: ast::Name) { if !name.as_str().is_ascii() { - gate_feature_post!( - &self, - non_ascii_idents, - self.parse_sess.source_map().def_span(sp), - "non-ascii idents are not fully supported" + self.gate( + self.parse_sess.source_map().def_span(sp), sym::non_ascii_idents, + "non-ascii idents are not fully supported", ); } } @@ -344,20 +320,24 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ast::ItemKind::Fn(..) => { if attr::contains_name(&i.attrs[..], sym::plugin_registrar) { - gate_feature_post!(&self, plugin_registrar, i.span, - "compiler plugins are experimental and possibly buggy"); + self.gate( + i.span, sym::plugin_registrar, + "compiler plugins are experimental and possibly buggy", + ); } if attr::contains_name(&i.attrs[..], sym::start) { - gate_feature_post!(&self, start, i.span, - "a `#[start]` function is an experimental \ - feature whose signature may change \ - over time"); + self.gate( + i.span, sym::start, + "a `#[start]` function is an experimental \ + feature whose signature may change over time", + ); } if attr::contains_name(&i.attrs[..], sym::main) { - gate_feature_post!(&self, main, i.span, - "declaration of a non-standard `#[main]` \ - function may change over time, for now \ - a top-level `fn main()` is required"); + self.gate( + i.span, sym::main, + "declaration of a non-standard `#[main]` function may change over time, \ + for now a top-level `fn main()` is required", + ); } } @@ -365,8 +345,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { for attr in attr::filter_by_name(&i.attrs[..], sym::repr) { for item in attr.meta_item_list().unwrap_or_else(Vec::new) { if item.check_name(sym::simd) { - gate_feature_post!(&self, repr_simd, attr.span, - "SIMD types are experimental and possibly buggy"); + self.gate( + attr.span, sym::repr_simd, + "SIMD types are experimental and possibly buggy", + ); } } } @@ -376,17 +358,15 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { for variant in variants { match (&variant.data, &variant.disr_expr) { (ast::VariantData::Unit(..), _) => {}, - (_, Some(disr_expr)) => - gate_feature_post!( - &self, - arbitrary_enum_discriminant, - disr_expr.value.span, - "discriminants on non-unit variants are experimental"), + (_, Some(disr_expr)) => self.gate( + disr_expr.value.span, sym::arbitrary_enum_discriminant, + "discriminants on non-unit variants are experimental", + ), _ => {}, } } - let has_feature = self.features.arbitrary_enum_discriminant; + let has_feature = self.features.on(sym::arbitrary_enum_discriminant); if !has_feature && !i.span.allows_unstable(sym::arbitrary_enum_discriminant) { self.maybe_report_invalid_custom_discriminants(&variants); } @@ -394,37 +374,31 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ast::ItemKind::Impl(_, polarity, defaultness, ..) => { if polarity == ast::ImplPolarity::Negative { - gate_feature_post!(&self, optin_builtin_traits, - i.span, - "negative trait bounds are not yet fully implemented; \ - use marker types for now"); + self.gate( + i.span, sym::optin_builtin_traits, + "negative trait bounds are not yet fully implemented; \ + use marker types for now", + ); } if let ast::Defaultness::Default = defaultness { - gate_feature_post!(&self, specialization, - i.span, - "specialization is unstable"); + self.gate(i.span, sym::specialization, "specialization is unstable"); } } ast::ItemKind::Trait(ast::IsAuto::Yes, ..) => { - gate_feature_post!(&self, optin_builtin_traits, - i.span, - "auto traits are experimental and possibly buggy"); + self.gate( + i.span, sym::optin_builtin_traits, + "auto traits are experimental and possibly buggy", + ); } ast::ItemKind::TraitAlias(..) => { - gate_feature_post!( - &self, - trait_alias, - i.span, - "trait aliases are experimental" - ); + self.gate(i.span, sym::trait_alias, "trait aliases are experimental"); } ast::ItemKind::MacroDef(ast::MacroDef { legacy: false, .. }) => { - let msg = "`macro` is experimental"; - gate_feature_post!(&self, decl_macro, i.span, msg); + self.gate(i.span, sym::decl_macro, "`macro` is experimental"); } ast::ItemKind::TyAlias(ref ty, ..) => self.check_impl_trait(&ty), @@ -445,13 +419,14 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { _ => false }; if links_to_llvm { - gate_feature_post!(&self, link_llvm_intrinsics, i.span, - "linking to LLVM intrinsics is experimental"); + self.gate( + i.span, sym::link_llvm_intrinsics, + "linking to LLVM intrinsics is experimental", + ); } } ast::ForeignItemKind::Ty => { - gate_feature_post!(&self, extern_types, i.span, - "extern types are experimental"); + self.gate(i.span, sym::extern_types, "extern types are experimental"); } ast::ForeignItemKind::Macro(..) => {} } @@ -472,26 +447,27 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_expr(&mut self, e: &'a ast::Expr) { match e.kind { ast::ExprKind::Box(_) => { - gate_feature_post!( - &self, box_syntax, e.span, - "box expression syntax is experimental; you can call `Box::new` instead" + self.gate( + e.span, sym::box_syntax, + "box expression syntax is experimental; you can call `Box::new` instead", ); } ast::ExprKind::Type(..) => { // To avoid noise about type ascription in common syntax errors, only emit if it // is the *only* error. if self.parse_sess.span_diagnostic.err_count() == 0 { - gate_feature_post!(&self, type_ascription, e.span, - "type ascription is experimental"); + self.gate(e.span, sym::type_ascription, "type ascription is experimental"); } } ast::ExprKind::TryBlock(_) => { - gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental"); + self.gate(e.span, sym::try_blocks, "`try` expression is experimental"); } ast::ExprKind::Block(_, opt_label) => { if let Some(label) = opt_label { - gate_feature_post!(&self, label_break_value, label.ident.span, - "labels on blocks are unstable"); + self.gate( + label.ident.span, sym::label_break_value, + "labels on blocks are unstable", + ); } } _ => {} @@ -509,23 +485,18 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { _ => pat, }; if inner_pat.is_rest() { - gate_feature_post!( - &self, - slice_patterns, - span, - "subslice patterns are unstable" - ); + self.gate(span, sym::slice_patterns, "subslice patterns are unstable"); } } } PatKind::Box(..) => { - gate_feature_post!(&self, box_patterns, - pattern.span, - "box pattern syntax is experimental"); + self.gate(pattern.span, sym::box_patterns, "box pattern syntax is experimental"); } PatKind::Range(_, _, Spanned { node: RangeEnd::Excluded, .. }) => { - gate_feature_post!(&self, exclusive_range_pattern, pattern.span, - "exclusive range pattern syntax is experimental"); + self.gate( + pattern.span, sym::exclusive_range_pattern, + "exclusive range pattern syntax is experimental", + ); } _ => {} } @@ -544,18 +515,16 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { self.check_extern(header.ext); } - if fn_decl.c_variadic() { - gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable"); - } + self.check_c_variadic(span, fn_decl); visit::walk_fn(self, fn_kind, fn_decl, span) } fn visit_generic_param(&mut self, param: &'a GenericParam) { match param.kind { - GenericParamKind::Const { .. } => - gate_feature_post!(&self, const_generics, param.ident.span, - "const generics are unstable"), + GenericParamKind::Const { .. } => { + self.gate(param.ident.span, sym::const_generics, "const generics are unstable"); + } _ => {} } visit::walk_generic_param(self, param) @@ -563,9 +532,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) { match constraint.kind { - AssocTyConstraintKind::Bound { .. } => - gate_feature_post!(&self, associated_type_bounds, constraint.span, - "associated type bounds are unstable"), + AssocTyConstraintKind::Bound { .. } => { + self.gate( + constraint.span, sym::associated_type_bounds, + "associated type bounds are unstable", + ); + } _ => {} } visit::walk_assoc_ty_constraint(self, constraint) @@ -577,19 +549,18 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { if block.is_none() { self.check_extern(sig.header.ext); } - if sig.decl.c_variadic() { - gate_feature_post!(&self, c_variadic, ti.span, - "C-variadic functions are unstable"); - } + self.check_c_variadic(ti.span, &sig.decl); if sig.header.constness.node == ast::Constness::Const { - gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable"); + self.gate(ti.span, sym::const_fn, "const fn is unstable"); } } ast::TraitItemKind::Type(_, ref default) => { if let Some(ty) = default { self.check_impl_trait(ty); - gate_feature_post!(&self, associated_type_defaults, ti.span, - "associated type defaults are unstable"); + self.gate( + ti.span, sym::associated_type_defaults, + "associated type defaults are unstable", + ); } self.check_gat(&ti.generics, ti.span); } @@ -600,18 +571,13 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_impl_item(&mut self, ii: &'a ast::ImplItem) { if ii.defaultness == ast::Defaultness::Default { - gate_feature_post!(&self, specialization, - ii.span, - "specialization is unstable"); + self.gate(ii.span, sym::specialization, "specialization is unstable"); } match ii.kind { ast::ImplItemKind::Method(ref sig, _) => { - if sig.decl.c_variadic() { - gate_feature_post!(&self, c_variadic, ii.span, - "C-variadic functions are unstable"); - } - } + self.check_c_variadic(ii.span, &sig.decl); + }, ast::ImplItemKind::TyAlias(ref ty) => { self.check_impl_trait(ty); self.check_gat(&ii.generics, ii.span); @@ -623,8 +589,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_vis(&mut self, vis: &'a ast::Visibility) { if let ast::VisibilityKind::Crate(ast::CrateSugar::JustCrate) = vis.node { - gate_feature_post!(&self, crate_visibility_modifier, vis.span, - "`crate` visibility modifier is experimental"); + self.gate( + vis.span, sym::crate_visibility_modifier, + "`crate` visibility modifier is experimental", + ); } visit::walk_vis(self, vis) } @@ -653,7 +621,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], } for feature in active_features_up_to(crate_edition) { - feature.set(&mut features, DUMMY_SP); + features.enable(feature, DUMMY_SP); edition_enabled_features.insert(feature.name, crate_edition); } @@ -685,7 +653,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], for feature in active_features_up_to(edition) { // FIXME(Manishearth) there is currently no way to set // lib features by edition - feature.set(&mut features, DUMMY_SP); + features.enable(feature, DUMMY_SP); edition_enabled_features.insert(feature.name, edition); } } @@ -768,7 +736,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], } if let Some(f) = ACTIVE_FEATURES.iter().find(|f| name == f.name) { - f.set(&mut features, mi.span()); + features.enable(f, mi.span()); features.declared_lang_features.push((name, mi.span(), None)); continue; } @@ -799,48 +767,44 @@ pub fn check_crate(krate: &ast::Crate, let mut visitor = PostExpansionVisitor { parse_sess, features }; let spans = parse_sess.gated_spans.spans.borrow(); - macro_rules! gate_all { - ($gate:ident, $msg:literal) => { - for span in spans.get(&sym::$gate).unwrap_or(&vec![]) { - gate_feature!(&visitor, $gate, *span, $msg); - } + let gate_all = |gate, msg| { + for span in spans.get(&gate).unwrap_or(&vec![]) { + visitor.gate(*span, gate, msg); } - } - gate_all!(let_chains, "`let` expressions in this position are experimental"); - gate_all!(async_closure, "async closures are unstable"); - gate_all!(generators, "yield syntax is experimental"); - gate_all!(or_patterns, "or-patterns syntax is experimental"); - gate_all!(const_extern_fn, "`const extern fn` definitions are unstable"); - gate_all!(raw_ref_op, "raw address of syntax is experimental"); + }; + + gate_all(sym::let_chains, "`let` expressions in this position are experimental"); + gate_all(sym::async_closure, "async closures are unstable"); + gate_all(sym::generators, "yield syntax is experimental"); + gate_all(sym::or_patterns, "or-patterns syntax is experimental"); + gate_all(sym::const_extern_fn, "`const extern fn` definitions are unstable"); + gate_all(sym::raw_ref_op, "raw address of syntax is experimental"); // All uses of `gate_all!` below this point were added in #65742, // and subsequently disabled (with the non-early gating readded). - macro_rules! gate_all { - ($gate:ident, $msg:literal) => { - // FIXME(eddyb) do something more useful than always - // disabling these uses of early feature-gatings. - if false { - for span in spans.get(&sym::$gate).unwrap_or(&vec![]) { - gate_feature!(&visitor, $gate, *span, $msg); - } - } - } - } + let gate_all = |gate, msg| { + // FIXME(eddyb) do something more useful than always + // disabling these uses of early feature-gatings. + if false { gate_all(gate, msg); } + }; - gate_all!(trait_alias, "trait aliases are experimental"); - gate_all!(associated_type_bounds, "associated type bounds are unstable"); - gate_all!(crate_visibility_modifier, "`crate` visibility modifier is experimental"); - gate_all!(const_generics, "const generics are unstable"); - gate_all!(decl_macro, "`macro` is experimental"); - gate_all!(box_patterns, "box pattern syntax is experimental"); - gate_all!(exclusive_range_pattern, "exclusive range pattern syntax is experimental"); - gate_all!(try_blocks, "`try` blocks are unstable"); - gate_all!(label_break_value, "labels on blocks are unstable"); - gate_all!(box_syntax, "box expression syntax is experimental; you can call `Box::new` instead"); + gate_all(sym::trait_alias, "trait aliases are experimental"); + gate_all(sym::associated_type_bounds, "associated type bounds are unstable"); + gate_all(sym::crate_visibility_modifier, "`crate` visibility modifier is experimental"); + gate_all(sym::const_generics, "const generics are unstable"); + gate_all(sym::decl_macro, "`macro` is experimental"); + gate_all(sym::box_patterns, "box pattern syntax is experimental"); + gate_all(sym::exclusive_range_pattern, "exclusive range pattern syntax is experimental"); + gate_all(sym::try_blocks, "`try` blocks are unstable"); + gate_all(sym::label_break_value, "labels on blocks are unstable"); + gate_all( + sym::box_syntax, + "box expression syntax is experimental; you can call `Box::new` instead", + ); // To avoid noise about type ascription in common syntax errors, // only emit if it is the *only* error. (Also check it last.) if parse_sess.span_diagnostic.err_count() == 0 { - gate_all!(type_ascription, "type ascription is experimental"); + gate_all(sym::type_ascription, "type ascription is experimental"); } visit::walk_crate(&mut visitor, krate); diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 3dcdd4db6377a..e993e99280be5 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -96,6 +96,7 @@ pub mod entry; pub mod feature_gate { mod check; pub use check::{check_crate, check_attribute, get_features, feature_err, feature_err_issue}; + pub use check::gate_feature; } pub mod mut_visit; pub mod ptr; diff --git a/src/libsyntax_expand/expand.rs b/src/libsyntax_expand/expand.rs index 9bfedb3b6174e..3b08cc7e64c73 100644 --- a/src/libsyntax_expand/expand.rs +++ b/src/libsyntax_expand/expand.rs @@ -1594,9 +1594,9 @@ impl<'feat> ExpansionConfig<'feat> { } fn proc_macro_hygiene(&self) -> bool { - self.features.map_or(false, |features| features.proc_macro_hygiene) + self.features.map_or(false, |features| features.on(sym::proc_macro_hygiene)) } fn custom_inner_attributes(&self) -> bool { - self.features.map_or(false, |features| features.custom_inner_attributes) + self.features.map_or(false, |features| features.on(sym::custom_inner_attributes)) } }