diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index aa678ba788a5b..5f6a7c452c4c4 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -436,6 +436,9 @@ impl DepKind { } define_dep_nodes!( <'tcx> + // We use this for most things when incr. comp. is turned off. + [] Null, + // Represents the `Krate` as a whole (the `hir::Krate` value) (as // distinct from the krate module). This is basically a hash of // the entire krate, so if you read from `Krate` (e.g., by calling @@ -605,8 +608,8 @@ define_dep_nodes!( <'tcx> [input] MissingExternCrateItem(CrateNum), [input] UsedCrateSource(CrateNum), [input] PostorderCnums, - [input] HasCloneClosures(CrateNum), - [input] HasCopyClosures(CrateNum), + [] HasCloneClosures(CrateNum), + [] HasCopyClosures(CrateNum), // This query is not expected to have inputs -- as a result, it's // not a good candidate for "replay" because it's essentially a @@ -630,8 +633,6 @@ define_dep_nodes!( <'tcx> [] CompileCodegenUnit(InternedString), [input] OutputFilenames, [anon] NormalizeTy, - // We use this for most things when incr. comp. is turned off. - [] Null, [] SubstituteNormalizeAndTestPredicates { key: (DefId, &'tcx Substs<'tcx>) }, @@ -642,6 +643,7 @@ define_dep_nodes!( <'tcx> [] GetSymbolExportLevel(DefId), + [input] Features, ); trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index fa745bf165577..877027a21a221 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -550,7 +550,7 @@ impl<'a> LoweringContext<'a> { { assert!(!self.is_collecting_in_band_lifetimes); assert!(self.lifetimes_to_define.is_empty()); - self.is_collecting_in_band_lifetimes = self.sess.features.borrow().in_band_lifetimes; + self.is_collecting_in_band_lifetimes = self.sess.features_untracked().in_band_lifetimes; assert!(self.in_band_ty_params.is_empty()); @@ -964,7 +964,7 @@ impl<'a> LoweringContext<'a> { let span = t.span; match itctx { ImplTraitContext::Existential => { - let has_feature = self.sess.features.borrow().conservative_impl_trait; + let has_feature = self.sess.features_untracked().conservative_impl_trait; if !t.span.allows_unstable() && !has_feature { emit_feature_err(&self.sess.parse_sess, "conservative_impl_trait", t.span, GateIssue::Language, @@ -988,7 +988,7 @@ impl<'a> LoweringContext<'a> { }, lifetimes) }, ImplTraitContext::Universal(def_id) => { - let has_feature = self.sess.features.borrow().universal_impl_trait; + let has_feature = self.sess.features_untracked().universal_impl_trait; if !t.span.allows_unstable() && !has_feature { emit_feature_err(&self.sess.parse_sess, "universal_impl_trait", t.span, GateIssue::Language, @@ -3713,7 +3713,7 @@ impl<'a> LoweringContext<'a> { } fn maybe_lint_bare_trait(&self, span: Span, id: NodeId, is_global: bool) { - if self.sess.features.borrow().dyn_trait { + if self.sess.features_untracked().dyn_trait { self.sess.buffer_lint_with_diagnostic( builtin::BARE_TRAIT_OBJECT, id, span, "trait objects without an explicit `dyn` are deprecated", diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index c31a5c9d86d77..f935cbfcde992 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -17,6 +17,7 @@ use std::hash as std_hash; use std::mem; use syntax::ast; +use syntax::feature_gate; use syntax::parse::token; use syntax::symbol::InternedString; use syntax::tokenstream; @@ -460,3 +461,21 @@ fn stable_non_narrow_char(swc: ::syntax_pos::NonNarrowChar, (pos.0 - filemap_start.0, width as u32) } + + + +impl<'gcx> HashStable> for feature_gate::Features { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'gcx>, + hasher: &mut StableHasher) { + // Unfortunately we cannot exhaustively list fields here, since the + // struct is macro generated. + self.declared_stable_lang_features.hash_stable(hcx, hasher); + self.declared_lib_features.hash_stable(hcx, hasher); + + self.walk_feature_fields(|feature_name, value| { + feature_name.hash_stable(hcx, hasher); + value.hash_stable(hcx, hasher); + }); + } +} diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 37a84361aea2d..559b2720076f4 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -289,11 +289,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ) { debug!("report_region_errors(): {} errors to start", errors.len()); - if will_later_be_reported_by_nll && self.tcx.sess.nll() { + if will_later_be_reported_by_nll && self.tcx.nll() { // With `#![feature(nll)]`, we want to present a nice user // experience, so don't even mention the errors from the // AST checker. - if self.tcx.sess.features.borrow().nll { + if self.tcx.features().nll { return; } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index e80ea16f565ab..16c33d6bd837d 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -131,7 +131,7 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> { item_sp: Span, kind: AnnotationKind, visit_children: F) where F: FnOnce(&mut Self) { - if self.tcx.sess.features.borrow().staged_api { + if self.tcx.features().staged_api { // This crate explicitly wants staged API. debug!("annotate(id = {:?}, attrs = {:?})", id, attrs); if let Some(..) = attr::find_deprecation(self.tcx.sess.diagnostic(), attrs, item_sp) { @@ -398,7 +398,7 @@ impl<'a, 'tcx> Index<'tcx> { pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Index<'tcx> { let is_staged_api = tcx.sess.opts.debugging_opts.force_unstable_if_unmarked || - tcx.sess.features.borrow().staged_api; + tcx.features().staged_api; let mut staged_api = FxHashMap(); staged_api.insert(LOCAL_CRATE, is_staged_api); let mut index = Index { @@ -408,7 +408,7 @@ impl<'a, 'tcx> Index<'tcx> { active_features: FxHashSet(), }; - let ref active_lib_features = tcx.sess.features.borrow().declared_lib_features; + let ref active_lib_features = tcx.features().declared_lib_features; // Put the active features into a map for quick lookup index.active_features = active_lib_features.iter().map(|&(ref s, _)| s.clone()).collect(); @@ -677,7 +677,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { // There's no good place to insert stability check for non-Copy unions, // so semi-randomly perform it here in stability.rs - hir::ItemUnion(..) if !self.tcx.sess.features.borrow().untagged_unions => { + hir::ItemUnion(..) if !self.tcx.features().untagged_unions => { let def_id = self.tcx.hir.local_def_id(item.id); let adt_def = self.tcx.adt_def(def_id); let ty = self.tcx.type_of(def_id); @@ -721,8 +721,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// were expected to be library features), and the list of features used from /// libraries, identify activated features that don't exist and error about them. pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let sess = &tcx.sess; - let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE); if tcx.stability().staged_api[&LOCAL_CRATE] { @@ -736,12 +734,12 @@ pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { krate.visit_all_item_likes(&mut missing.as_deep_visitor()); } - let ref declared_lib_features = sess.features.borrow().declared_lib_features; + let ref declared_lib_features = tcx.features().declared_lib_features; let mut remaining_lib_features: FxHashMap = declared_lib_features.clone().into_iter().collect(); remaining_lib_features.remove(&Symbol::intern("proc_macro")); - for &(ref stable_lang_feature, span) in &sess.features.borrow().declared_stable_lang_features { + for &(ref stable_lang_feature, span) in &tcx.features().declared_stable_lang_features { let version = find_lang_feature_accepted_version(&stable_lang_feature.as_str()) .expect("unexpectedly couldn't find version feature was stabilized"); tcx.lint_node(lint::builtin::STABLE_FEATURES, diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index bd87a8f918ab3..5e9eeb973007f 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -20,7 +20,7 @@ use lint::builtin::BuiltinLintDiagnostics; use middle::allocator::AllocatorKind; use middle::dependency_format; use session::search_paths::PathKind; -use session::config::{BorrowckMode, DebugInfoLevel, OutputType, Epoch}; +use session::config::{DebugInfoLevel, OutputType, Epoch}; use ty::tls; use util::nodemap::{FxHashMap, FxHashSet}; use util::common::{duration_to_secs_str, ErrorReported}; @@ -93,7 +93,8 @@ pub struct Session { /// multiple crates with the same name to coexist. See the /// trans::back::symbol_names module for more information. pub crate_disambiguator: RefCell>, - pub features: RefCell, + + features: RefCell>, /// The maximum recursion limit for potentially infinitely recursive /// operations such as auto-dereference and monomorphization. @@ -194,6 +195,7 @@ impl Session { None => bug!("accessing disambiguator before initialization"), } } + pub fn struct_span_warn<'a, S: Into>(&'a self, sp: S, msg: &str) @@ -456,16 +458,22 @@ impl Session { self.opts.debugging_opts.print_llvm_passes } - /// If true, we should use NLL-style region checking instead of - /// lexical style. - pub fn nll(&self) -> bool { - self.features.borrow().nll || self.opts.debugging_opts.nll + /// Get the features enabled for the current compilation session. + /// DO NOT USE THIS METHOD if there is a TyCtxt available, as it circumvents + /// dependency tracking. Use tcx.features() instead. + #[inline] + pub fn features_untracked(&self) -> cell::Ref { + let features = self.features.borrow(); + + if features.is_none() { + bug!("Access to Session::features before it is initialized"); + } + + cell::Ref::map(features, |r| r.as_ref().unwrap()) } - /// If true, we should use the MIR-based borrowck (we may *also* use - /// the AST-based borrowck). - pub fn use_mir(&self) -> bool { - self.borrowck_mode().use_mir() + pub fn init_features(&self, features: feature_gate::Features) { + *(self.features.borrow_mut()) = Some(features); } /// If true, we should gather causal information during NLL @@ -475,42 +483,6 @@ impl Session { self.opts.debugging_opts.nll_dump_cause } - /// If true, we should enable two-phase borrows checks. This is - /// done with either `-Ztwo-phase-borrows` or with - /// `#![feature(nll)]`. - pub fn two_phase_borrows(&self) -> bool { - self.features.borrow().nll || self.opts.debugging_opts.two_phase_borrows - } - - /// What mode(s) of borrowck should we run? AST? MIR? both? - /// (Also considers the `#![feature(nll)]` setting.) - pub fn borrowck_mode(&self) -> BorrowckMode { - match self.opts.borrowck_mode { - mode @ BorrowckMode::Mir | - mode @ BorrowckMode::Compare => mode, - - mode @ BorrowckMode::Ast => { - if self.nll() { - BorrowckMode::Mir - } else { - mode - } - } - - } - } - - /// Should we emit EndRegion MIR statements? These are consumed by - /// MIR borrowck, but not when NLL is used. They are also consumed - /// by the validation stuff. - pub fn emit_end_regions(&self) -> bool { - // FIXME(#46875) -- we should not emit end regions when NLL is enabled, - // but for now we can't stop doing so because it causes false positives - self.opts.debugging_opts.emit_end_regions || - self.opts.debugging_opts.mir_emit_validate > 0 || - self.use_mir() - } - /// Calculates the flavor of LTO to use for this compilation. pub fn lto(&self) -> config::Lto { // If our target has codegen requirements ignore the command line @@ -1029,7 +1001,7 @@ pub fn build_session_(sopts: config::Options, crate_types: RefCell::new(Vec::new()), dependency_formats: RefCell::new(FxHashMap()), crate_disambiguator: RefCell::new(None), - features: RefCell::new(feature_gate::Features::new()), + features: RefCell::new(None), recursion_limit: Cell::new(64), type_length_limit: Cell::new(1048576), next_node_id: Cell::new(NodeId::new(1)), diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 43940d7cea3ed..d11565618a687 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -164,7 +164,7 @@ pub(super) fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // The feature gate should prevent introducing new specializations, but not // taking advantage of upstream ones. - if !tcx.sess.features.borrow().specialization && + if !tcx.features().specialization && (impl1_def_id.is_local() || impl2_def_id.is_local()) { return false; } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index d04c477101731..a7f065d57aeed 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -14,7 +14,7 @@ use dep_graph::DepGraph; use dep_graph::{DepNode, DepConstructor}; use errors::DiagnosticBuilder; use session::Session; -use session::config::OutputFilenames; +use session::config::{BorrowckMode, OutputFilenames}; use middle; use hir::{TraitCandidate, HirId, ItemLocalId}; use hir::def::{Def, Export}; @@ -71,6 +71,7 @@ use syntax::abi; use syntax::ast::{self, Name, NodeId}; use syntax::attr; use syntax::codemap::MultiSpan; +use syntax::feature_gate; use syntax::symbol::{Symbol, keywords}; use syntax_pos::Span; @@ -1255,6 +1256,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.all_crate_nums(LOCAL_CRATE) } + pub fn features(self) -> Lrc { + self.features_query(LOCAL_CRATE) + } + pub fn def_key(self, id: DefId) -> hir_map::DefKey { if id.is_local() { self.hir.def_key(id) @@ -1362,6 +1367,53 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.on_disk_query_result_cache.serialize(self.global_tcx(), encoder) } + /// If true, we should use NLL-style region checking instead of + /// lexical style. + pub fn nll(self) -> bool { + self.features().nll || self.sess.opts.debugging_opts.nll + } + + /// If true, we should use the MIR-based borrowck (we may *also* use + /// the AST-based borrowck). + pub fn use_mir(self) -> bool { + self.borrowck_mode().use_mir() + } + + /// If true, we should enable two-phase borrows checks. This is + /// done with either `-Ztwo-phase-borrows` or with + /// `#![feature(nll)]`. + pub fn two_phase_borrows(self) -> bool { + self.features().nll || self.sess.opts.debugging_opts.two_phase_borrows + } + + /// What mode(s) of borrowck should we run? AST? MIR? both? + /// (Also considers the `#![feature(nll)]` setting.) + pub fn borrowck_mode(&self) -> BorrowckMode { + match self.sess.opts.borrowck_mode { + mode @ BorrowckMode::Mir | + mode @ BorrowckMode::Compare => mode, + + mode @ BorrowckMode::Ast => { + if self.nll() { + BorrowckMode::Mir + } else { + mode + } + } + + } + } + + /// Should we emit EndRegion MIR statements? These are consumed by + /// MIR borrowck, but not when NLL is used. They are also consumed + /// by the validation stuff. + pub fn emit_end_regions(self) -> bool { + // FIXME(#46875) -- we should not emit end regions when NLL is enabled, + // but for now we can't stop doing so because it causes false positives + self.sess.opts.debugging_opts.emit_end_regions || + self.sess.opts.debugging_opts.mir_emit_validate > 0 || + self.use_mir() + } } impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { @@ -2020,7 +2072,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn mk_diverging_default(self) -> Ty<'tcx> { - if self.sess.features.borrow().never_type { + if self.features().never_type { self.types.never } else { self.intern_tup(&[], true) @@ -2395,13 +2447,17 @@ pub fn provide(providers: &mut ty::maps::Providers) { }; providers.has_copy_closures = |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); - tcx.sess.features.borrow().copy_closures + tcx.features().copy_closures }; providers.has_clone_closures = |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); - tcx.sess.features.borrow().clone_closures + tcx.features().clone_closures }; providers.fully_normalize_monormophic_ty = |tcx, ty| { tcx.fully_normalize_associated_types_in(&ty) }; + providers.features_query = |tcx, cnum| { + assert_eq!(cnum, LOCAL_CRATE); + Lrc::new(tcx.sess.features_untracked().clone()) + }; } diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index eb07876b05f26..c91b30440e5e3 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -593,6 +593,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::fully_normalize_monormophic_ty<'t } } +impl<'tcx> QueryDescription<'tcx> for queries::features_query<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("looking up enabled feature gates") + } +} + impl<'tcx> QueryDescription<'tcx> for queries::typeck_tables_of<'tcx> { #[inline] fn cache_on_disk(def_id: Self::Key) -> bool { diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 6edb1d9be35db..c211713db6bc0 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -52,6 +52,7 @@ use syntax_pos::{Span, DUMMY_SP}; use syntax_pos::symbol::InternedString; use syntax::attr; use syntax::ast; +use syntax::feature_gate; use syntax::symbol::Symbol; #[macro_use] @@ -374,12 +375,19 @@ define_maps! { <'tcx> // Get an estimate of the size of an InstanceDef based on its MIR for CGU partitioning. [] fn instance_def_size_estimate: instance_def_size_estimate_dep_node(ty::InstanceDef<'tcx>) -> usize, + + [] fn features_query: features_node(CrateNum) -> Lrc, } ////////////////////////////////////////////////////////////////////// // These functions are little shims used to find the dep-node for a // given query when there is not a *direct* mapping: + +fn features_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::Features +} + fn erase_regions_ty<'tcx>(ty: Ty<'tcx>) -> DepConstructor<'tcx> { DepConstructor::EraseRegionsTy { ty } } diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index b654b6bc42a12..3443b9b61b215 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -936,6 +936,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::TargetFeaturesEnabled => { force!(target_features_enabled, def_id!()); } DepKind::GetSymbolExportLevel => { force!(symbol_export_level, def_id!()); } + DepKind::Features => { force!(features_query, LOCAL_CRATE); } } true diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 9ba33a57c2050..f6f4e1ceb1563 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2335,7 +2335,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Returns true if the impls are the same polarity and are implementing /// a trait which contains no items pub fn impls_are_allowed_to_overlap(self, def_id1: DefId, def_id2: DefId) -> bool { - if !self.sess.features.borrow().overlapping_marker_traits { + if !self.features().overlapping_marker_traits { return false; } let trait1_is_empty = self.impl_trait_ref(def_id1) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 4fe6ee45295a3..bb198adea4a6a 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -276,7 +276,7 @@ impl<'b, 'tcx: 'b> BorrowckErrors for BorrowckCtxt<'b, 'tcx> { o: Origin) -> DiagnosticBuilder<'a> { - if !o.should_emit_errors(self.tcx.sess.borrowck_mode()) { + if !o.should_emit_errors(self.tcx.borrowck_mode()) { self.tcx.sess.diagnostic().cancel(&mut diag); } diag diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs index 54e3418d4f017..8e3b99f2dbfee 100644 --- a/src/librustc_const_eval/_match.rs +++ b/src/librustc_const_eval/_match.rs @@ -201,7 +201,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { } fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool { - if self.tcx.sess.features.borrow().never_type { + if self.tcx.features().never_type { self.tcx.is_ty_uninhabited_from(self.module, ty) } else { false @@ -227,7 +227,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { substs: &'tcx ty::subst::Substs<'tcx>) -> bool { - if self.tcx.sess.features.borrow().never_type { + if self.tcx.features().never_type { self.tcx.is_enum_variant_uninhabited_from(self.module, variant, substs) } else { false diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index ae53ed0e1140d..6f7143c185cb3 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -212,7 +212,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { let pat_ty = self.tables.node_id_to_type(scrut.hir_id); let module = self.tcx.hir.get_module_parent(scrut.id); if inlined_arms.is_empty() { - let scrutinee_is_uninhabited = if self.tcx.sess.features.borrow().never_type { + let scrutinee_is_uninhabited = if self.tcx.features().never_type { self.tcx.is_ty_uninhabited_from(module, pat_ty) } else { self.conservative_is_uninhabited(pat_ty) diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 8e4ec93c14bae..2a571fa82643b 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -398,7 +398,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, }).collect::, _>>()?)))) } hir::ExprIndex(ref arr, ref idx) => { - if !tcx.sess.features.borrow().const_indexing { + if !tcx.features().const_indexing { signal!(e, IndexOpFeatureGated); } let arr = cx.eval(arr)?; diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 15afea1921386..571cc46bc6413 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -650,7 +650,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, let (mut krate, features) = syntax::config::features(krate, &sess.parse_sess, sess.opts.test); // these need to be set "early" so that expansion sees `quote` if enabled. - *sess.features.borrow_mut() = features; + sess.init_features(features); *sess.crate_types.borrow_mut() = collect_crate_types(sess, &krate.attrs); @@ -699,7 +699,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, let mut registry = registry.unwrap_or(Registry::new(sess, krate.span)); time(time_passes, "plugin registration", || { - if sess.features.borrow().rustc_diagnostic_macros { + if sess.features_untracked().rustc_diagnostic_macros { registry.register_macro("__diagnostic_used", diagnostics::plugin::expand_diagnostic_used); registry.register_macro("__register_diagnostic", @@ -749,7 +749,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, crate_loader, &resolver_arenas); resolver.whitelisted_legacy_custom_derives = whitelisted_legacy_custom_derives; - syntax_ext::register_builtins(&mut resolver, syntax_exts, sess.features.borrow().quote); + syntax_ext::register_builtins(&mut resolver, syntax_exts, sess.features_untracked().quote); krate = time(time_passes, "expansion", || { // Windows dlls do not have rpaths, so they don't know how to find their @@ -780,7 +780,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, .filter(|p| env::join_paths(iter::once(p)).is_ok())) .unwrap()); } - let features = sess.features.borrow(); + let features = sess.features_untracked(); let cfg = syntax::ext::expand::ExpansionConfig { features: Some(&features), recursion_limit: sess.recursion_limit.get(), @@ -819,7 +819,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, sess.opts.test, krate, sess.diagnostic(), - &sess.features.borrow()) + &sess.features_untracked()) }); // If we're actually rustdoc then there's no need to actually compile @@ -886,7 +886,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, sess.track_errors(|| { syntax::feature_gate::check_crate(&krate, &sess.parse_sess, - &sess.features.borrow(), + &sess.features_untracked(), &attributes, sess.opts.unstable_features); }) diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index 5976b80d90f87..17a6176b79e95 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -69,7 +69,7 @@ pub fn assert_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { // 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.sess.features.borrow().rustc_attrs { + if !tcx.features().rustc_attrs { return; } diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index c3e283535ec82..e114606a63115 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -219,7 +219,7 @@ impl Assertion { pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { // can't add `#[rustc_dirty]` etc without opting in to this feature - if !tcx.sess.features.borrow().rustc_attrs { + if !tcx.features().rustc_attrs { return; } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 66f34a72edf2d..62ac898337ca9 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1356,7 +1356,7 @@ impl UnreachablePub { // visibility is token at start of declaration (can be macro // variable rather than literal `pub`) let pub_span = cx.tcx.sess.codemap().span_until_char(def_span, ' '); - let replacement = if cx.tcx.sess.features.borrow().crate_visibility_modifier { + let replacement = if cx.tcx.features().crate_visibility_modifier { "crate" } else { "pub(crate)" diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 439533fae49d9..6ab3172c4fefa 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -72,7 +72,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { let mut fn_warned = false; let mut op_warned = false; - if cx.tcx.sess.features.borrow().fn_must_use { + if cx.tcx.features().fn_must_use { let maybe_def = match expr.node { hir::ExprCall(ref callee, _) => { match callee.node { diff --git a/src/librustc_metadata/native_libs.rs b/src/librustc_metadata/native_libs.rs index c0ce32cc97068..2504f8dc251f9 100644 --- a/src/librustc_metadata/native_libs.rs +++ b/src/librustc_metadata/native_libs.rs @@ -146,7 +146,7 @@ impl<'a, 'tcx> Collector<'a, 'tcx> { None => self.tcx.sess.err(msg), } } - if lib.cfg.is_some() && !self.tcx.sess.features.borrow().link_cfg { + if lib.cfg.is_some() && !self.tcx.features().link_cfg { feature_gate::emit_feature_err(&self.tcx.sess.parse_sess, "link_cfg", span.unwrap(), @@ -154,7 +154,7 @@ impl<'a, 'tcx> Collector<'a, 'tcx> { "is feature gated"); } if lib.kind == cstore::NativeStaticNobundle && - !self.tcx.sess.features.borrow().static_nobundle { + !self.tcx.features().static_nobundle { feature_gate::emit_feature_err(&self.tcx.sess.parse_sess, "static_nobundle", span.unwrap(), diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index c6635d59154e2..b77e7cf2ec8b5 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -535,7 +535,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { err.span_label(borrow_span, "borrowed value does not live long enough"); err.span_label(drop_span, "borrowed value only lives until here"); - if !self.tcx.sess.nll() { + if !self.tcx.nll() { self.tcx.note_and_explain_region( scope_tree, &mut err, @@ -572,7 +572,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { err.span_label(proper_span, "temporary value does not live long enough"); err.span_label(drop_span, "temporary value only lives until here"); - if !self.tcx.sess.nll() { + if !self.tcx.nll() { self.tcx.note_and_explain_region( scope_tree, &mut err, diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index c6ed971f767cf..1ff0ffaaa68b3 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -72,7 +72,7 @@ fn mir_borrowck<'a, 'tcx>( let input_mir = tcx.mir_validated(def_id); debug!("run query mir_borrowck: {}", tcx.item_path_str(def_id)); - if !tcx.has_attr(def_id, "rustc_mir_borrowck") && !tcx.sess.use_mir() { + if !tcx.has_attr(def_id, "rustc_mir_borrowck") && !tcx.use_mir() { return None; } @@ -101,7 +101,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( // contain non-lexical lifetimes. It will have a lifetime tied // to the inference context. let mut mir: Mir<'tcx> = input_mir.clone(); - let free_regions = if !tcx.sess.nll() { + let free_regions = if !tcx.nll() { None } else { let mir = &mut mir; @@ -204,7 +204,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( ); (Some(Rc::new(regioncx)), opt_closure_req) } else { - assert!(!tcx.sess.nll()); + assert!(!tcx.nll()); (None, None) }; let flow_inits = flow_inits; // remove mut @@ -719,7 +719,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { /// allowed to be split into separate Reservation and /// Activation phases. fn allow_two_phase_borrow(&self, kind: BorrowKind) -> bool { - self.tcx.sess.two_phase_borrows() && + self.tcx.two_phase_borrows() && (kind.allows_two_phase_borrow() || self.tcx.sess.opts.debugging_opts.two_phase_beyond_autoref) } @@ -1253,7 +1253,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { span: Span, flow_state: &Flows<'cx, 'gcx, 'tcx>, ) { - if !self.tcx.sess.two_phase_borrows() { + if !self.tcx.two_phase_borrows() { return; } 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 a06d39d225c45..3af10c5c25169 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -1587,7 +1587,7 @@ impl MirPass for TypeckMir { // When NLL is enabled, the borrow checker runs the typeck // itself, so we don't need this MIR pass anymore. - if tcx.sess.nll() { + if tcx.nll() { return; } diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs index 932aad0bb1d84..1ed8289d44184 100644 --- a/src/librustc_mir/build/cfg.rs +++ b/src/librustc_mir/build/cfg.rs @@ -50,7 +50,7 @@ impl<'tcx> CFG<'tcx> { block: BasicBlock, source_info: SourceInfo, region_scope: region::Scope) { - if tcx.sess.emit_end_regions() { + if tcx.emit_end_regions() { if let region::ScopeData::CallSite(_) = region_scope.data() { // The CallSite scope (aka the root scope) is sort of weird, in that it is // supposed to "separate" the "interior" and "exterior" of a closure. Being diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs index b16d7ed236509..abea55835466f 100644 --- a/src/librustc_mir/build/matches/simplify.rs +++ b/src/librustc_mir/build/matches/simplify.rs @@ -113,7 +113,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { PatternKind::Variant { adt_def, substs, variant_index, ref subpatterns } => { let irrefutable = adt_def.variants.iter().enumerate().all(|(i, v)| { i == variant_index || { - self.hir.tcx().sess.features.borrow().never_type && + self.hir.tcx().features().never_type && self.hir.tcx().is_variant_uninhabited_from_all_modules(v, substs) } }); diff --git a/src/librustc_mir/transform/clean_end_regions.rs b/src/librustc_mir/transform/clean_end_regions.rs index 7986313aa8134..6e8985d99d287 100644 --- a/src/librustc_mir/transform/clean_end_regions.rs +++ b/src/librustc_mir/transform/clean_end_regions.rs @@ -42,7 +42,7 @@ impl MirPass for CleanEndRegions { tcx: TyCtxt<'a, 'tcx, 'tcx>, _source: MirSource, mir: &mut Mir<'tcx>) { - if !tcx.sess.emit_end_regions() { return; } + if !tcx.emit_end_regions() { return; } let mut gather = GatherBorrowedRegions { seen_regions: FxHashSet() diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 0b0ce1fb4d48b..8f5831270d6e5 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -936,7 +936,7 @@ This does not pose a problem by itself because they can't be accessed directly." if self.mode != Mode::Fn && // feature-gate is not enabled, - !self.tcx.sess.features.borrow() + !self.tcx.features() .declared_lib_features .iter() .any(|&(ref sym, _)| sym == feature_name) && diff --git a/src/librustc_mir/util/borrowck_errors.rs b/src/librustc_mir/util/borrowck_errors.rs index 4a7ee397aec00..89242ca32bcbf 100644 --- a/src/librustc_mir/util/borrowck_errors.rs +++ b/src/librustc_mir/util/borrowck_errors.rs @@ -514,7 +514,7 @@ impl<'b, 'gcx, 'tcx> BorrowckErrors for TyCtxt<'b, 'gcx, 'tcx> { o: Origin) -> DiagnosticBuilder<'a> { - if !o.should_emit_errors(self.sess.borrowck_mode()) { + if !o.should_emit_errors(self.borrowck_mode()) { self.sess.diagnostic().cancel(&mut diag); } diag diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs index a46b85d93cbb8..bf59165a9c461 100644 --- a/src/librustc_plugin/load.rs +++ b/src/librustc_plugin/load.rs @@ -52,7 +52,7 @@ pub fn load_plugins(sess: &Session, // do not report any error now. since crate attributes are // not touched by expansion, every use of plugin without // the feature enabled will result in an error later... - if sess.features.borrow().plugin { + if sess.features_untracked().plugin { for attr in &krate.attrs { if !attr.check_name("plugin") { continue; diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index b9899f499148d..bf7b81c4d0e42 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -590,7 +590,7 @@ impl<'a> Resolver<'a> { }; let ext = Lrc::new(macro_rules::compile(&self.session.parse_sess, - &self.session.features, + &self.session.features_untracked(), ¯o_def)); self.macro_map.insert(def_id, ext.clone()); ext diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 317bd9217b591..fc1ff24818403 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1524,7 +1524,7 @@ impl<'a> Resolver<'a> { invocations.insert(Mark::root(), arenas.alloc_invocation_data(InvocationData::root(graph_root))); - let features = session.features.borrow(); + let features = session.features_untracked(); let mut macro_defs = FxHashMap(); macro_defs.insert(Mark::root(), root_def_id); @@ -2998,7 +2998,7 @@ impl<'a> Resolver<'a> { let prim = self.primitive_type_table.primitive_types[&path[0].node.name]; match prim { TyUint(UintTy::U128) | TyInt(IntTy::I128) => { - if !self.session.features.borrow().i128_type { + if !self.session.features_untracked().i128_type { emit_feature_err(&self.session.parse_sess, "i128_type", span, GateIssue::Language, "128-bit type is unstable"); @@ -3089,7 +3089,7 @@ impl<'a> Resolver<'a> { let prev_name = path[0].node.name; if prev_name == keywords::Extern.name() || prev_name == keywords::CrateRoot.name() && - self.session.features.borrow().extern_absolute_paths { + self.session.features_untracked().extern_absolute_paths { // `::extern_crate::a::b` let crate_id = self.crate_loader.resolve_crate_from_path(name, ident.span); let crate_root = diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 81cc5e59bbbf7..95fa0f3b52fef 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -744,7 +744,7 @@ impl<'a> Resolver<'a> { let def_id = self.definitions.local_def_id(item.id); let ext = Lrc::new(macro_rules::compile(&self.session.parse_sess, - &self.session.features, + &self.session.features_untracked(), item)); self.macro_map.insert(def_id, ext); @@ -838,7 +838,7 @@ impl<'a> Resolver<'a> { } fn gate_legacy_custom_derive(&mut self, name: Symbol, span: Span) { - if !self.session.features.borrow().custom_derive { + if !self.session.features_untracked().custom_derive { let sess = &self.session.parse_sess; let explain = feature_gate::EXPLAIN_CUSTOM_DERIVE; emit_feature_err(sess, "custom_derive", span, GateIssue::Language, explain); diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 438ab3a3513fc..01c1ded94578e 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -609,7 +609,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { if module_path.len() == 1 && (module_path[0].node.name == keywords::CrateRoot.name() || module_path[0].node.name == keywords::Extern.name()) { let is_extern = module_path[0].node.name == keywords::Extern.name() || - self.session.features.borrow().extern_absolute_paths; + self.session.features_untracked().extern_absolute_paths; match directive.subclass { GlobImport { .. } if is_extern => { return Some((directive.span, diff --git a/src/librustc_trans_utils/symbol_names_test.rs b/src/librustc_trans_utils/symbol_names_test.rs index 5d7d4f3055bad..267c8d2bd03c8 100644 --- a/src/librustc_trans_utils/symbol_names_test.rs +++ b/src/librustc_trans_utils/symbol_names_test.rs @@ -28,7 +28,7 @@ pub fn report_symbol_names<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { // 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.sess.features.borrow().rustc_attrs { + if !tcx.features().rustc_attrs { return; } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 6a6c49c904838..0df1225cf2624 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -415,7 +415,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let trait_def = self.tcx().trait_def(trait_def_id); - if !self.tcx().sess.features.borrow().unboxed_closures && + if !self.tcx().features().unboxed_closures && trait_segment.with_parameters(|p| p.parenthesized) != trait_def.paren_sugar { // For now, require that parenthetical notation be used only with `Fn()` etc. let msg = if trait_def.paren_sugar { diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index da66a2e52e81f..a261c12bcdd94 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -114,7 +114,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; if pat_adjustments.len() > 0 { - if tcx.sess.features.borrow().match_default_bindings { + if tcx.features().match_default_bindings { debug!("default binding mode is now {:?}", def_bm); self.inh.tables.borrow_mut() .pat_adjustments_mut() diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index e2d6817697e8f..abb0acd699cba 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -586,7 +586,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } } - if has_unsized_tuple_coercion && !self.tcx.sess.features.borrow().unsized_tuple_coercion { + if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion { feature_gate::emit_feature_err(&self.tcx.sess.parse_sess, "unsized_tuple_coercion", self.cause.span, diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index c95ead285594b..841559013a093 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -324,7 +324,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // possible that there will be multiple applicable methods. if !is_suggestion.0 { if reached_raw_pointer - && !self.tcx.sess.features.borrow().arbitrary_self_types { + && !self.tcx.features().arbitrary_self_types { // this case used to be allowed by the compiler, // so we do a future-compat lint here for the 2015 epoch // (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 db5a458bb8ce4..0f59973eab251 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1105,7 +1105,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, } fcx.demand_suptype(span, ret_ty, actual_return_ty); - if fcx.tcx.sess.features.borrow().termination_trait { + if fcx.tcx.features().termination_trait { // If the termination trait language item is activated, check that the main return type // implements the termination trait. if let Some(term_id) = fcx.tcx.lang_items().termination() { @@ -1616,7 +1616,7 @@ pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, 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.sess.features.borrow().repr128 { + if !tcx.features().repr128 { emit_feature_err(&tcx.sess.parse_sess, "repr128", sp, diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 39e757c52ff29..d10ee358e0728 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -536,7 +536,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { let is_self_ty = |ty| fcx.infcx.can_eq(fcx.param_env, self_ty, ty).is_ok(); let self_kind = ExplicitSelf::determine(self_arg_ty, is_self_ty); - if !fcx.tcx.sess.features.borrow().arbitrary_self_types { + if !fcx.tcx.features().arbitrary_self_types { match self_kind { ExplicitSelf::ByValue | ExplicitSelf::ByReference(_, _) | diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index f65d627781f0f..d3de31d630a97 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -74,7 +74,7 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, impl_def_id: DefId, trait_d return; } - if tcx.sess.features.borrow().unboxed_closures { + if tcx.features().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 1c8d22e4666a6..f7158593f0b6e 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -711,7 +711,7 @@ fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; let paren_sugar = tcx.has_attr(def_id, "rustc_paren_sugar"); - if paren_sugar && !tcx.sess.features.borrow().unboxed_closures { + if paren_sugar && !tcx.features().unboxed_closures { let mut err = tcx.sess.struct_span_err( item.span, "the `#[rustc_paren_sugar]` attribute is a temporary means of controlling \ @@ -953,7 +953,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } if !allow_defaults && p.default.is_some() { - if !tcx.sess.features.borrow().default_type_parameter_fallback { + if !tcx.features().default_type_parameter_fallback { tcx.lint_node( lint::builtin::INVALID_TYPE_PARAM_DEFAULT, p.id, @@ -1692,7 +1692,7 @@ fn compute_sig_of_foreign_fn_decl<'a, 'tcx>( // feature gate SIMD types in FFI, since I (huonw) am not sure the // ABIs are handled at all correctly. if abi != abi::Abi::RustIntrinsic && abi != abi::Abi::PlatformIntrinsic - && !tcx.sess.features.borrow().simd_ffi { + && !tcx.features().simd_ffi { let check = |ast_ty: &hir::Ty, ty: Ty| { if ty.is_simd() { tcx.sess.struct_span_err(ast_ty.span, diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index af32738d9d04b..d9bd96b0d769f 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -207,7 +207,7 @@ fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let actual = tcx.fn_sig(main_def_id); let expected_return_type = if tcx.lang_items().termination().is_some() - && tcx.sess.features.borrow().termination_trait { + && tcx.features().termination_trait { // we take the return type of the given main function, the real check is done // in `check_fn` actual.output().skip_binder() diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index f4c9d556c8abf..e4477bee5c0e9 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -629,7 +629,7 @@ impl<'a, 'hir> HirCollector<'a, 'hir> { nested: F) { let mut attrs = Attributes::from_ast(self.sess.diagnostic(), attrs); if let Some(ref cfg) = attrs.cfg { - if !cfg.matches(&self.sess.parse_sess, Some(&self.sess.features.borrow())) { + if !cfg.matches(&self.sess.parse_sess, Some(&self.sess.features_untracked())) { return; } } diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 728b3e4076d1b..9162a582599fc 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -26,7 +26,6 @@ use parse::token::Token::*; use symbol::Symbol; use tokenstream::{TokenStream, TokenTree}; -use std::cell::RefCell; use std::collections::HashMap; use std::collections::hash_map::Entry; @@ -184,7 +183,7 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt, // Holy self-referential! /// Converts a `macro_rules!` invocation into a syntax extension. -pub fn compile(sess: &ParseSess, features: &RefCell, def: &ast::Item) -> SyntaxExtension { +pub fn compile(sess: &ParseSess, features: &Features, def: &ast::Item) -> SyntaxExtension { let lhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("lhs")); let rhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("rhs")); @@ -296,7 +295,7 @@ pub fn compile(sess: &ParseSess, features: &RefCell, def: &ast::Item) } fn check_lhs_nt_follows(sess: &ParseSess, - features: &RefCell, + features: &Features, attrs: &[ast::Attribute], lhs: "ed::TokenTree) -> bool { // lhs is going to be like TokenTree::Delimited(...), where the @@ -353,7 +352,7 @@ fn check_rhs(sess: &ParseSess, rhs: "ed::TokenTree) -> bool { } fn check_matcher(sess: &ParseSess, - features: &RefCell, + features: &Features, attrs: &[ast::Attribute], matcher: &[quoted::TokenTree]) -> bool { let first_sets = FirstSets::new(matcher); @@ -601,7 +600,7 @@ impl TokenSet { // Requires that `first_sets` is pre-computed for `matcher`; // see `FirstSets::new`. fn check_matcher_core(sess: &ParseSess, - features: &RefCell, + features: &Features, attrs: &[ast::Attribute], first_sets: &FirstSets, matcher: &[quoted::TokenTree], @@ -869,7 +868,7 @@ fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> Result, + features: &Features, attrs: &[ast::Attribute], tok: "ed::TokenTree) -> Result<(), String> { debug!("has_legal_fragment_specifier({:?})", tok); @@ -884,7 +883,7 @@ fn has_legal_fragment_specifier(sess: &ParseSess, } fn is_legal_fragment_specifier(sess: &ParseSess, - features: &RefCell, + features: &Features, attrs: &[ast::Attribute], frag_name: &str, frag_span: Span) -> bool { @@ -892,7 +891,7 @@ fn is_legal_fragment_specifier(sess: &ParseSess, "item" | "block" | "stmt" | "expr" | "pat" | "path" | "ty" | "ident" | "meta" | "tt" | "" => true, "lifetime" => { - if !features.borrow().macro_lifetime_matcher && + if !features.macro_lifetime_matcher && !attr::contains_name(attrs, "allow_internal_unstable") { let explain = feature_gate::EXPLAIN_LIFETIME_MATCHER; emit_feature_err(sess, @@ -904,7 +903,7 @@ fn is_legal_fragment_specifier(sess: &ParseSess, true }, "vis" => { - if !features.borrow().macro_vis_matcher && + if !features.macro_vis_matcher && !attr::contains_name(attrs, "allow_internal_unstable") { let explain = feature_gate::EXPLAIN_VIS_MATCHER; emit_feature_err(sess, diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs index c9d7f78c2e303..122bb9ba024a4 100644 --- a/src/libsyntax/ext/tt/quoted.rs +++ b/src/libsyntax/ext/tt/quoted.rs @@ -17,7 +17,6 @@ use symbol::keywords; use syntax_pos::{BytePos, Span, DUMMY_SP}; use tokenstream; -use std::cell::RefCell; use std::iter::Peekable; use rustc_data_structures::sync::Lrc; @@ -183,7 +182,7 @@ pub fn parse( input: tokenstream::TokenStream, expect_matchers: bool, sess: &ParseSess, - features: &RefCell, + features: &Features, attrs: &[ast::Attribute], ) -> Vec { // Will contain the final collection of `self::TokenTree` @@ -251,7 +250,7 @@ fn parse_tree( trees: &mut Peekable, expect_matchers: bool, sess: &ParseSess, - features: &RefCell, + features: &Features, attrs: &[ast::Attribute], ) -> TokenTree where @@ -382,7 +381,7 @@ fn parse_sep_and_kleene_op( input: &mut Peekable, span: Span, sess: &ParseSess, - features: &RefCell, + features: &Features, attrs: &[ast::Attribute], ) -> (Option, KleeneOp) where @@ -415,7 +414,7 @@ where match parse_kleene_op(input, span) { // #2 is a KleeneOp (this is the only valid option) :) Ok(Ok(op)) if op == KleeneOp::ZeroOrOne => { - if !features.borrow().macro_at_most_once_rep + if !features.macro_at_most_once_rep && !attr::contains_name(attrs, "allow_internal_unstable") { let explain = feature_gate::EXPLAIN_MACRO_AT_MOST_ONCE_REP; @@ -438,7 +437,7 @@ where Err(span) => span, } } else { - if !features.borrow().macro_at_most_once_rep + if !features.macro_at_most_once_rep && !attr::contains_name(attrs, "allow_internal_unstable") { let explain = feature_gate::EXPLAIN_MACRO_AT_MOST_ONCE_REP; @@ -460,7 +459,7 @@ where Ok(Err((tok, span))) => match parse_kleene_op(input, span) { // #2 is a KleeneOp :D Ok(Ok(op)) if op == KleeneOp::ZeroOrOne => { - if !features.borrow().macro_at_most_once_rep + if !features.macro_at_most_once_rep && !attr::contains_name(attrs, "allow_internal_unstable") { let explain = feature_gate::EXPLAIN_MACRO_AT_MOST_ONCE_REP; @@ -487,7 +486,7 @@ where Err(span) => span, }; - if !features.borrow().macro_at_most_once_rep + if !features.macro_at_most_once_rep && !attr::contains_name(attrs, "allow_internal_unstable") { sess.span_diagnostic diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 058df1d516909..45d82bc7af38e 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -62,6 +62,7 @@ macro_rules! declare_features { &[$((stringify!($feature), $ver, $issue, set!($feature))),+]; /// A set of features to be used by later passes. + #[derive(Clone)] pub struct Features { /// `#![feature]` attrs for stable language features, for error reporting pub declared_stable_lang_features: Vec<(Symbol, Span)>, @@ -78,6 +79,12 @@ macro_rules! declare_features { $($feature: false),+ } } + + pub fn walk_feature_fields(&self, mut f: F) + where F: FnMut(&str, bool) + { + $(f(stringify!($feature), self.$feature);)+ + } } }; diff --git a/src/test/incremental/feature_gate.rs b/src/test/incremental/feature_gate.rs new file mode 100644 index 0000000000000..de2f9ab52f60b --- /dev/null +++ b/src/test/incremental/feature_gate.rs @@ -0,0 +1,23 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This test makes sure that we detect changed feature gates. + +// revisions:rpass1 cfail2 +// compile-flags: -Z query-dep-graph + +#![feature(rustc_attrs)] +#![cfg_attr(rpass1, feature(nll))] + +fn main() { + let mut v = vec![1]; + v.push(v[0]); + //[cfail2]~^ ERROR cannot borrow +} diff --git a/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs b/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs index 9ebc438ad5a00..fd8f7b9e384f3 100644 --- a/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs +++ b/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs @@ -41,7 +41,7 @@ fn expand_mbe_matches(cx: &mut ExtCtxt, _: Span, args: &[TokenTree]) let mbe_matcher = quoted::parse(mbe_matcher.into_iter().collect(), true, cx.parse_sess, - &RefCell::new(Features::new()), + &Features::new(), &[]); let map = match TokenTree::parse(cx, &mbe_matcher, args.iter().cloned().collect()) { Success(map) => map,