diff options
| author | Eduard Burtescu <edy.burt@gmail.com> | 2016-11-10 19:08:21 +0200 |
|---|---|---|
| committer | Eduard-Mihai Burtescu <edy.burt@gmail.com> | 2016-11-28 04:18:11 +0200 |
| commit | 9aaf26e7aa4068d7e5643b136fb70ecd689a746d (patch) | |
| tree | 60fdabfe4a91fa16c2b24d8d310bc3ff50ca28cc /src/librustc/middle | |
| parent | f97c132cac79ef6bdf9f950b415c67bb43af387a (diff) | |
| download | rust-9aaf26e7aa4068d7e5643b136fb70ecd689a746d.tar.gz rust-9aaf26e7aa4068d7e5643b136fb70ecd689a746d.zip | |
rustc: rework stability to be on-demand for type-directed lookup.
Diffstat (limited to 'src/librustc/middle')
| -rw-r--r-- | src/librustc/middle/stability.rs | 512 |
1 files changed, 215 insertions, 297 deletions
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index d01954ab95a..f5e18e13465 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -15,11 +15,10 @@ pub use self::StabilityLevel::*; use dep_graph::DepNode; use hir::map as hir_map; -use session::Session; use lint; use hir::def::Def; use hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, DefIndex, LOCAL_CRATE}; -use ty::{self, TyCtxt, AdtKind}; +use ty::TyCtxt; use middle::privacy::AccessLevels; use syntax::symbol::Symbol; use syntax_pos::{Span, DUMMY_SP}; @@ -30,9 +29,9 @@ use syntax::attr::{self, Stability, Deprecation}; use util::nodemap::{DefIdMap, FxHashSet, FxHashMap}; use hir; -use hir::{Item, Generics, StructField, Variant, PatKind}; +use hir::{Item, Generics, StructField, Variant}; use hir::intravisit::{self, Visitor}; -use hir::pat_util::EnumerateAndAdjustIterator; +use hir::itemlikevisit::DeepVisitor; use std::mem::replace; use std::cmp::Ordering; @@ -101,7 +100,13 @@ pub struct Index<'tcx> { depr_map: DefIdMap<Option<DeprecationEntry>>, /// Maps for each crate whether it is part of the staged API. - staged_api: FxHashMap<CrateNum, bool> + staged_api: FxHashMap<CrateNum, bool>, + + /// Features enabled for this crate. + active_features: FxHashSet<Symbol>, + + /// Features used by this crate. Updated before and during typeck. + used_features: FxHashMap<Symbol, attr::StabilityLevel> } // A private tree-walker for producing an Index. @@ -110,7 +115,6 @@ struct Annotator<'a, 'tcx: 'a> { index: &'a mut Index<'tcx>, parent_stab: Option<&'tcx Stability>, parent_depr: Option<DeprecationEntry>, - access_levels: &'a AccessLevels, in_trait_impl: bool, } @@ -183,20 +187,12 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> { self.parent_stab = orig_parent_stab; } else { debug!("annotate: not found, parent = {:?}", self.parent_stab); - let mut is_error = kind == AnnotationKind::Required && - self.access_levels.is_reachable(id) && - !self.tcx.sess.opts.test; if let Some(stab) = self.parent_stab { if stab.level.is_unstable() { let def_id = self.tcx.map.local_def_id(id); self.index.stab_map.insert(def_id, Some(stab)); - is_error = false; } } - if is_error { - self.tcx.sess.span_err(item_sp, "This node does not have \ - a stability attribute"); - } visit_children(self); } } else { @@ -313,9 +309,81 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { } } +struct MissingStabilityAnnotations<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + access_levels: &'a AccessLevels, +} + +impl<'a, 'tcx: 'a> MissingStabilityAnnotations<'a, 'tcx> { + fn check_missing_stability(&self, id: NodeId, span: Span) { + let def_id = self.tcx.map.local_def_id(id); + let is_error = !self.tcx.sess.opts.test && + !self.tcx.stability.borrow().stab_map.contains_key(&def_id) && + self.access_levels.is_reachable(id); + if is_error { + self.tcx.sess.span_err(span, "This node does not have a stability attribute"); + } + } +} + +impl<'a, 'tcx, 'v> Visitor<'v> for MissingStabilityAnnotations<'a, 'tcx> { + fn visit_item(&mut self, i: &Item) { + match i.node { + // Inherent impls and foreign modules serve only as containers for other items, + // they don't have their own stability. They still can be annotated as unstable + // and propagate this unstability to children, but this annotation is completely + // optional. They inherit stability from their parents when unannotated. + hir::ItemImpl(.., None, _, _) | hir::ItemForeignMod(..) => {} + + _ => self.check_missing_stability(i.id, i.span) + } + + intravisit::walk_item(self, i) + } + + fn visit_trait_item(&mut self, ti: &hir::TraitItem) { + self.check_missing_stability(ti.id, ti.span); + intravisit::walk_trait_item(self, ti); + } + + fn visit_impl_item(&mut self, ii: &hir::ImplItem) { + let impl_def_id = self.tcx.map.local_def_id(self.tcx.map.get_parent(ii.id)); + if self.tcx.impl_trait_ref(impl_def_id).is_none() { + self.check_missing_stability(ii.id, ii.span); + } + intravisit::walk_impl_item(self, ii); + } + + fn visit_variant(&mut self, var: &Variant, g: &Generics, item_id: NodeId) { + self.check_missing_stability(var.node.data.id(), var.span); + intravisit::walk_variant(self, var, g, item_id); + } + + fn visit_struct_field(&mut self, s: &StructField) { + self.check_missing_stability(s.id, s.span); + intravisit::walk_struct_field(self, s); + } + + fn visit_foreign_item(&mut self, i: &hir::ForeignItem) { + self.check_missing_stability(i.id, i.span); + intravisit::walk_foreign_item(self, i); + } + + fn visit_macro_def(&mut self, md: &hir::MacroDef) { + if md.imported_from.is_none() { + self.check_missing_stability(md.id, md.span); + } + } +} + impl<'a, 'tcx> Index<'tcx> { /// Construct the stability index for a crate being compiled. - pub fn build(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, access_levels: &AccessLevels) { + pub fn build(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>) { + let ref active_lib_features = tcx.sess.features.borrow().declared_lib_features; + + // Put the active features into a map for quick lookup + self.active_features = active_lib_features.iter().map(|&(ref s, _)| s.clone()).collect(); + let _task = tcx.dep_graph.in_task(DepNode::StabilityIndex); let krate = tcx.map.krate(); let mut annotator = Annotator { @@ -323,7 +391,6 @@ impl<'a, 'tcx> Index<'tcx> { index: self, parent_stab: None, parent_depr: None, - access_levels: access_levels, in_trait_impl: false, }; annotator.annotate(ast::CRATE_NODE_ID, &krate.attrs, krate.span, AnnotationKind::Required, @@ -348,87 +415,118 @@ impl<'a, 'tcx> Index<'tcx> { staged_api: staged_api, stab_map: DefIdMap(), depr_map: DefIdMap(), + active_features: FxHashSet(), + used_features: FxHashMap(), } } } /// Cross-references the feature names of unstable APIs with enabled -/// features and possibly prints errors. Returns a list of all -/// features used. -pub fn check_unstable_api_usage<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> FxHashMap<Symbol, attr::StabilityLevel> { - let _task = tcx.dep_graph.in_task(DepNode::StabilityCheck); - let ref active_lib_features = tcx.sess.features.borrow().declared_lib_features; - - // Put the active features into a map for quick lookup - let active_features = active_lib_features.iter().map(|&(ref s, _)| s.clone()).collect(); - - let mut checker = Checker { - tcx: tcx, - active_features: active_features, - used_features: FxHashMap(), - }; - intravisit::walk_crate(&mut checker, tcx.map.krate()); - - checker.used_features +/// features and possibly prints errors. +pub fn check_unstable_api_usage<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { + let mut checker = Checker { tcx: tcx }; + tcx.visit_all_item_likes_in_krate(DepNode::StabilityCheck, + &mut DeepVisitor::new(&mut checker)); } struct Checker<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - active_features: FxHashSet<Symbol>, - used_features: FxHashMap<Symbol, attr::StabilityLevel>, } -impl<'a, 'tcx> Checker<'a, 'tcx> { - fn check(&mut self, id: DefId, span: Span, - stab: &Option<&Stability>, _depr: &Option<DeprecationEntry>) { - if !is_staged_api(self.tcx, id) { +impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { + pub fn check_stability(self, def_id: DefId, id: NodeId, span: Span) { + if self.sess.codemap().span_allows_unstable(span) { + debug!("stability: \ + skipping span={:?} since it is internal", span); return; } + + let lint_deprecated = |note: Option<Symbol>| { + let msg = if let Some(note) = note { + format!("use of deprecated item: {}", note) + } else { + format!("use of deprecated item") + }; + + self.sess.add_lint(lint::builtin::DEPRECATED, id, span, msg); + }; + + // Deprecated attributes apply in-crate and cross-crate. + if let Some(depr_entry) = self.lookup_deprecation_entry(def_id) { + let skip = if id == ast::DUMMY_NODE_ID { + true + } else { + let parent_def_id = self.map.local_def_id(self.map.get_parent(id)); + self.lookup_deprecation_entry(parent_def_id).map_or(false, |parent_depr| { + parent_depr.same_origin(&depr_entry) + }) + }; + + if !skip { + lint_deprecated(depr_entry.attr.note); + } + } + + let is_staged_api = *self.stability.borrow_mut().staged_api.entry(def_id.krate) + .or_insert_with(|| self.sess.cstore.is_staged_api(def_id.krate)); + if !is_staged_api { + return; + } + + let stability = self.lookup_stability(def_id); + debug!("stability: \ + inspecting def_id={:?} span={:?} of stability={:?}", def_id, span, stability); + + if let Some(&Stability{rustc_depr: Some(attr::RustcDeprecation { reason, .. }), ..}) + = stability { + if id != ast::DUMMY_NODE_ID { + lint_deprecated(Some(reason)); + } + } + // Only the cross-crate scenario matters when checking unstable APIs - let cross_crate = !id.is_local(); + let cross_crate = !def_id.is_local(); if !cross_crate { return } - match *stab { - Some(&Stability { level: attr::Unstable {ref reason, issue}, ref feature, .. }) => { - self.used_features.insert(feature.clone(), - attr::Unstable { reason: reason.clone(), issue: issue }); + if let Some(&Stability { ref level, ref feature, .. }) = stability { + self.stability.borrow_mut().used_features.insert(feature.clone(), level.clone()); + } - if !self.active_features.contains(feature) { + match stability { + Some(&Stability { level: attr::Unstable {ref reason, issue}, ref feature, .. }) => { + if !self.stability.borrow().active_features.contains(feature) { let msg = match *reason { Some(ref r) => format!("use of unstable library feature '{}': {}", &feature.as_str(), &r), None => format!("use of unstable library feature '{}'", &feature) }; - emit_feature_err(&self.tcx.sess.parse_sess, &feature.as_str(), span, + emit_feature_err(&self.sess.parse_sess, &feature.as_str(), span, GateIssue::Library(Some(issue)), &msg); } } - Some(&Stability { ref level, ref feature, .. }) => { - self.used_features.insert(feature.clone(), level.clone()); - + Some(_) => { // Stable APIs are always ok to call and deprecated APIs are - // handled by a lint. + // handled by the lint emitting logic above. } None => { // This is an 'unmarked' API, which should not exist // in the standard library. - if self.tcx.sess.features.borrow().unmarked_api { - self.tcx.sess.struct_span_warn(span, "use of unmarked library feature") - .span_note(span, "this is either a bug in the library you are \ - using or a bug in the compiler - please \ - report it in both places") - .emit() + if self.sess.features.borrow().unmarked_api { + self.sess.struct_span_warn(span, "use of unmarked library feature") + .span_note(span, "this is either a bug in the library you are \ + using or a bug in the compiler - please \ + report it in both places") + .emit() } else { - self.tcx.sess.struct_span_err(span, "use of unmarked library feature") - .span_note(span, "this is either a bug in the library you are \ - using or a bug in the compiler - please \ - report it in both places") - .span_note(span, "use #![feature(unmarked_api)] in the \ - crate attributes to override this") - .emit() + self.sess.struct_span_err(span, "use of unmarked library feature") + .span_note(span, "this is either a bug in the library you are \ + using or a bug in the compiler - please \ + report it in both places") + .span_note(span, "use #![feature(unmarked_api)] in the \ + crate attributes to override this") + .emit() } } } @@ -436,249 +534,55 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { } impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { - /// Because stability levels are scoped lexically, we want to walk - /// nested items in the context of the outer item, so enable - /// deep-walking. - fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> { - Some(&self.tcx.map) - } - fn visit_item(&mut self, item: &'tcx hir::Item) { - // When compiling with --test we don't enforce stability on the - // compiler-generated test module, demarcated with `DUMMY_SP` plus the - // name `__test` - if item.span == DUMMY_SP && item.name == "__test" { return } - - check_item(self.tcx, item, true, - &mut |id, sp, stab, depr| self.check(id, sp, stab, depr)); - intravisit::walk_item(self, item); - } - - fn visit_expr(&mut self, ex: &'tcx hir::Expr) { - check_expr(self.tcx, ex, - &mut |id, sp, stab, depr| self.check(id, sp, stab, depr)); - intravisit::walk_expr(self, ex); - } - - fn visit_path(&mut self, path: &'tcx hir::Path, _: ast::NodeId) { - check_path(self.tcx, path, - &mut |id, sp, stab, depr| self.check(id, sp, stab, depr)); - intravisit::walk_path(self, path) - } - - fn visit_pat(&mut self, pat: &'tcx hir::Pat) { - check_pat(self.tcx, pat, - &mut |id, sp, stab, depr| self.check(id, sp, stab, depr)); - intravisit::walk_pat(self, pat) - } - - fn visit_ty(&mut self, ty: &'tcx hir::Ty) { - check_ty(self.tcx, ty, - &mut |id, sp, stab, depr| self.check(id, sp, stab, depr)); - intravisit::walk_ty(self, ty) - } -} - -/// Helper for discovering nodes to check for stability -pub fn check_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - item: &hir::Item, - warn_about_defns: bool, - cb: &mut FnMut(DefId, Span, - &Option<&Stability>, - &Option<DeprecationEntry>)) { - match item.node { - hir::ItemExternCrate(_) => { - // compiler-generated `extern crate` items have a dummy span. - if item.span == DUMMY_SP { return } - - let cnum = match tcx.sess.cstore.extern_mod_stmt_cnum(item.id) { - Some(cnum) => cnum, - None => return, - }; - let id = DefId { krate: cnum, index: CRATE_DEF_INDEX }; - maybe_do_stability_check(tcx, id, item.span, cb); - } - - // For implementations of traits, check the stability of each item - // individually as it's possible to have a stable trait with unstable - // items. - hir::ItemImpl(.., Some(ref t), _, ref impl_item_refs) => { - let trait_did = t.path.def.def_id(); - for impl_item_ref in impl_item_refs { - let impl_item = tcx.map.impl_item(impl_item_ref.id); - let item = tcx.associated_items(trait_did) - .find(|item| item.name == impl_item.name).unwrap(); - if warn_about_defns { - maybe_do_stability_check(tcx, item.def_id, impl_item.span, cb); - } + match item.node { + hir::ItemExternCrate(_) => { + // compiler-generated `extern crate` items have a dummy span. + if item.span == DUMMY_SP { return } + + let cnum = match self.tcx.sess.cstore.extern_mod_stmt_cnum(item.id) { + Some(cnum) => cnum, + None => return, + }; + let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX }; + self.tcx.check_stability(def_id, item.id, item.span); } - } - _ => (/* pass */) - } -} - -/// Helper for discovering nodes to check for stability -pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr, - cb: &mut FnMut(DefId, Span, - &Option<&Stability>, - &Option<DeprecationEntry>)) { - let span; - let id = match e.node { - hir::ExprMethodCall(i, ..) => { - span = i.span; - let method_call = ty::MethodCall::expr(e.id); - tcx.tables().method_map[&method_call].def_id - } - hir::ExprPath(ref qpath @ hir::QPath::TypeRelative(..)) => { - span = e.span; - tcx.tables().qpath_def(qpath, e.id).def_id() - } - hir::ExprField(ref base_e, ref field) => { - span = field.span; - match tcx.tables().expr_ty_adjusted(base_e).sty { - ty::TyAdt(def, _) => { - def.struct_variant().field_named(field.node).did - } - _ => span_bug!(e.span, - "stability::check_expr: named field access on non-ADT") - } - } - hir::ExprTupField(ref base_e, ref field) => { - span = field.span; - match tcx.tables().expr_ty_adjusted(base_e).sty { - ty::TyAdt(def, _) => { - def.struct_variant().fields[field.node].did - } - ty::TyTuple(..) => return, - _ => span_bug!(e.span, - "stability::check_expr: unnamed field access on \ - something other than a tuple or struct") - } - } - hir::ExprStruct(_, ref expr_fields, _) => { - match tcx.tables().expr_ty(e).sty { - ty::TyAdt(adt, ..) => match adt.adt_kind() { - AdtKind::Struct | AdtKind::Union => { - // check the stability of each field that appears - // in the construction expression. - for field in expr_fields { - let did = adt.struct_variant().field_named(field.name.node).did; - maybe_do_stability_check(tcx, did, field.span, cb); + // For implementations of traits, check the stability of each item + // individually as it's possible to have a stable trait with unstable + // items. + hir::ItemImpl(.., Some(ref t), _, ref impl_item_refs) => { + if let Def::Trait(trait_did) = t.path.def { + for impl_item_ref in impl_item_refs { + let impl_item = self.tcx.map.impl_item(impl_item_ref.id); + let trait_item_def_id = self.tcx.associated_items(trait_did) + .find(|item| item.name == impl_item.name).map(|item| item.def_id); + if let Some(def_id) = trait_item_def_id { + // Pass `DUMMY_NODE_ID` to skip deprecation warnings. + self.tcx.check_stability(def_id, ast::DUMMY_NODE_ID, impl_item.span); } - - // we're done. - return } - AdtKind::Enum => { - // we don't look at stability attributes on - // struct-like enums (yet...), but it's definitely not - // a bug to have construct one. - return - } - }, - ref ty => span_bug!(e.span, "stability::check_expr: struct \ - construction of non-ADT type: {:?}", ty) + } } - } - _ => return - }; - - maybe_do_stability_check(tcx, id, span, cb); -} -pub fn check_path<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - path: &hir::Path, - cb: &mut FnMut(DefId, Span, - &Option<&Stability>, - &Option<DeprecationEntry>)) { - match path.def { - Def::PrimTy(..) | Def::SelfTy(..) | Def::Err => {} - _ => maybe_do_stability_check(tcx, path.def.def_id(), path.span, cb) - } -} - -pub fn check_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &hir::Pat, - cb: &mut FnMut(DefId, Span, - &Option<&Stability>, - &Option<DeprecationEntry>)) { - debug!("check_pat(pat = {:?})", pat); - if is_internal(tcx, pat.span) { return; } - - if let PatKind::Path(ref qpath @ hir::QPath::TypeRelative(..)) = pat.node { - let def_id = tcx.tables().qpath_def(qpath, pat.id).def_id(); - maybe_do_stability_check(tcx, def_id, pat.span, cb) - } - - let v = match tcx.tables().pat_ty_opt(pat).map(|ty| &ty.sty) { - Some(&ty::TyAdt(adt, _)) if !adt.is_enum() => adt.struct_variant(), - _ => return, - }; - match pat.node { - // Foo(a, b, c) - PatKind::TupleStruct(_, ref pat_fields, ddpos) => { - for (i, field) in pat_fields.iter().enumerate_and_adjust(v.fields.len(), ddpos) { - maybe_do_stability_check(tcx, v.fields[i].did, field.span, cb) - } - } - // Foo { a, b, c } - PatKind::Struct(_, ref pat_fields, _) => { - for field in pat_fields { - let did = v.field_named(field.node.name).did; - maybe_do_stability_check(tcx, did, field.span, cb); - } + _ => (/* pass */) } - // everything else is fine. - _ => {} + intravisit::walk_item(self, item); } -} - -pub fn check_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: &hir::Ty, - cb: &mut FnMut(DefId, Span, - &Option<&Stability>, - &Option<DeprecationEntry>)) { - debug!("check_ty(ty = {:?})", ty); - if is_internal(tcx, ty.span) { return; } - if let hir::TyPath(hir::QPath::TypeRelative(..)) = ty.node { - let def_id = tcx.tables().type_relative_path_defs[&ty.id].def_id(); - maybe_do_stability_check(tcx, def_id, ty.span, cb); + fn visit_path(&mut self, path: &'tcx hir::Path, id: ast::NodeId) { + match path.def { + Def::PrimTy(..) | Def::SelfTy(..) | Def::Err => {} + _ => self.tcx.check_stability(path.def.def_id(), id, path.span) + } + intravisit::walk_path(self, path) } } -fn maybe_do_stability_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - id: DefId, span: Span, - cb: &mut FnMut(DefId, Span, - &Option<&Stability>, - &Option<DeprecationEntry>)) { - if is_internal(tcx, span) { - debug!("maybe_do_stability_check: \ - skipping span={:?} since it is internal", span); - return; - } - let (stability, deprecation) = if is_staged_api(tcx, id) { - (tcx.lookup_stability(id), None) - } else { - (None, tcx.lookup_deprecation_entry(id)) - }; - debug!("maybe_do_stability_check: \ - inspecting id={:?} span={:?} of stability={:?}", id, span, stability); - cb(id, span, &stability, &deprecation); -} - -fn is_internal<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: Span) -> bool { - tcx.sess.codemap().span_allows_unstable(span) -} - -fn is_staged_api<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> bool { - *tcx.stability.borrow_mut().staged_api.entry(id.krate).or_insert_with( - || tcx.sess.cstore.is_staged_api(id.krate)) -} - -impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { +impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Lookup the stability for a node, loading external crate /// metadata as necessary. - pub fn lookup_stability(self, id: DefId) -> Option<&'tcx Stability> { + pub fn lookup_stability(self, id: DefId) -> Option<&'gcx Stability> { if let Some(st) = self.stability.borrow().stab_map.get(&id) { return *st; } @@ -702,7 +606,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { depr } - fn lookup_stability_uncached(self, id: DefId) -> Option<&'tcx Stability> { + fn lookup_stability_uncached(self, id: DefId) -> Option<&'gcx Stability> { debug!("lookup(id={:?})", id); if id.is_local() { None // The stability cache is filled partially lazily @@ -724,9 +628,22 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { /// Given the list of enabled features that were not language features (i.e. that /// 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(sess: &Session, - lib_features_used: &FxHashMap<Symbol, - attr::StabilityLevel>) { +pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + access_levels: &AccessLevels) { + let sess = &tcx.sess; + + if tcx.stability.borrow().staged_api[&LOCAL_CRATE] && tcx.sess.features.borrow().staged_api { + let _task = tcx.dep_graph.in_task(DepNode::StabilityIndex); + let krate = tcx.map.krate(); + let mut missing = MissingStabilityAnnotations { + tcx: tcx, + access_levels: access_levels, + }; + missing.check_missing_stability(ast::CRATE_NODE_ID, krate.span); + intravisit::walk_crate(&mut missing, krate); + krate.visit_all_item_likes(&mut DeepVisitor::new(&mut missing)); + } + let ref declared_lib_features = sess.features.borrow().declared_lib_features; let mut remaining_lib_features: FxHashMap<Symbol, Span> = declared_lib_features.clone().into_iter().collect(); @@ -744,7 +661,8 @@ pub fn check_unused_or_stable_features(sess: &Session, format_stable_since_msg(version)); } - for (used_lib_feature, level) in lib_features_used { + let index = tcx.stability.borrow(); + for (used_lib_feature, level) in &index.used_features { match remaining_lib_features.remove(used_lib_feature) { Some(span) => { if let &attr::StabilityLevel::Stable { since: ref version } = level { |
