]> git.proxmox.com Git - rustc.git/blame - src/librustc/middle/stability.rs
Imported Upstream version 1.3.0+dfsg1
[rustc.git] / src / librustc / middle / stability.rs
CommitLineData
1a4d82fc
JJ
1// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11//! A pass that annotates every item and method with its stability level,
12//! propagating default levels lexically from parent to children ast nodes.
13
85aaf69f
SL
14use session::Session;
15use lint;
16use middle::def;
1a4d82fc 17use middle::ty;
85aaf69f 18use middle::privacy::PublicItems;
1a4d82fc 19use metadata::csearch;
85aaf69f
SL
20use syntax::parse::token::InternedString;
21use syntax::codemap::{Span, DUMMY_SP};
1a4d82fc
JJ
22use syntax::{attr, visit};
23use syntax::ast;
24use syntax::ast::{Attribute, Block, Crate, DefId, FnDecl, NodeId, Variant};
c34b1796 25use syntax::ast::{Item, Generics, StructField};
62682a34 26use syntax::ast_util::{is_local, local_def};
85aaf69f 27use syntax::attr::{Stability, AttrMetaMethods};
c34b1796
AL
28use syntax::visit::{FnKind, Visitor};
29use syntax::feature_gate::emit_feature_err;
62682a34 30use util::nodemap::{DefIdMap, FnvHashSet, FnvHashMap};
1a4d82fc
JJ
31
32use std::mem::replace;
c1a9b12d 33use std::cmp::Ordering;
1a4d82fc
JJ
34
35/// A stability index, giving the stability level for items and methods.
62682a34
SL
36pub struct Index<'tcx> {
37 /// This is mostly a cache, except the stabilities of local items
38 /// are filled by the annotator.
39 map: DefIdMap<Option<&'tcx Stability>>,
40
41 /// Maps for each crate whether it is part of the staged API.
42 staged_api: FnvHashMap<ast::CrateNum, bool>
1a4d82fc
JJ
43}
44
45// A private tree-walker for producing an Index.
62682a34
SL
46struct Annotator<'a, 'tcx: 'a> {
47 tcx: &'a ty::ctxt<'tcx>,
48 index: &'a mut Index<'tcx>,
49 parent: Option<&'tcx Stability>,
85aaf69f 50 export_map: &'a PublicItems,
1a4d82fc
JJ
51}
52
62682a34 53impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
1a4d82fc
JJ
54 // Determine the stability for a node based on its attributes and inherited
55 // stability. The stability is recorded in the index and used as the parent.
56 fn annotate<F>(&mut self, id: NodeId, use_parent: bool,
85aaf69f 57 attrs: &Vec<Attribute>, item_sp: Span, f: F, required: bool) where
1a4d82fc
JJ
58 F: FnOnce(&mut Annotator),
59 {
62682a34 60 if self.index.staged_api[&ast::LOCAL_CRATE] {
9346a6ac 61 debug!("annotate(id = {:?}, attrs = {:?})", id, attrs);
62682a34 62 match attr::find_stability(self.tcx.sess.diagnostic(), attrs, item_sp) {
c1a9b12d 63 Some(mut stab) => {
9346a6ac 64 debug!("annotate: found {:?}", stab);
c1a9b12d
SL
65 // if parent is deprecated and we're not, inherit this by merging
66 // deprecated_since and its reason.
67 if let Some(parent_stab) = self.parent {
68 if parent_stab.deprecated_since.is_some()
69 && stab.deprecated_since.is_none() {
70 stab.deprecated_since = parent_stab.deprecated_since.clone();
71 stab.reason = parent_stab.reason.clone();
72 }
73 }
74
62682a34 75 let stab = self.tcx.intern_stability(stab);
c1a9b12d
SL
76
77 // Check if deprecated_since < stable_since. If it is,
78 // this is *almost surely* an accident.
79 let deprecated_predates_stable = match (stab.deprecated_since.as_ref(),
80 stab.since.as_ref()) {
81 (Some(dep_since), Some(stab_since)) => {
82 // explicit version of iter::order::lt to handle parse errors properly
83 let mut is_less = false;
84 for (dep_v, stab_v) in dep_since.split(".").zip(stab_since.split(".")) {
85 match (dep_v.parse::<u64>(), stab_v.parse::<u64>()) {
86 (Ok(dep_v), Ok(stab_v)) => match dep_v.cmp(&stab_v) {
87 Ordering::Less => {
88 is_less = true;
89 break;
90 }
91 Ordering::Equal => { continue; }
92 Ordering::Greater => { break; }
93 },
94 _ => {
95 self.tcx.sess.span_err(item_sp,
96 "Invalid stability or deprecation version found");
97 // act like it isn't less because the question is now
98 // nonsensical, and this makes us not do anything else
99 // interesting.
100 break;
101 }
102 }
103 }
104 is_less
105 },
106 _ => false,
107 };
108
109 if deprecated_predates_stable {
110 self.tcx.sess.span_err(item_sp,
111 "An API can't be stabilized after it is deprecated");
112 }
113
62682a34 114 self.index.map.insert(local_def(id), Some(stab));
9346a6ac
AL
115
116 // Don't inherit #[stable(feature = "rust1", since = "1.0.0")]
117 if stab.level != attr::Stable {
118 let parent = replace(&mut self.parent, Some(stab));
119 f(self);
120 self.parent = parent;
121 } else {
122 f(self);
123 }
124 }
125 None => {
126 debug!("annotate: not found, use_parent = {:?}, parent = {:?}",
127 use_parent, self.parent);
128 if use_parent {
62682a34
SL
129 if let Some(stab) = self.parent {
130 self.index.map.insert(local_def(id), Some(stab));
131 } else if self.index.staged_api[&ast::LOCAL_CRATE] && required
9346a6ac 132 && self.export_map.contains(&id)
62682a34
SL
133 && !self.tcx.sess.opts.test {
134 self.tcx.sess.span_err(item_sp,
135 "This node does not \
136 have a stability attribute");
9346a6ac
AL
137 }
138 }
1a4d82fc
JJ
139 f(self);
140 }
141 }
9346a6ac
AL
142 } else {
143 // Emit warnings for non-staged-api crates. These should be errors.
144 for attr in attrs {
145 let tag = attr.name();
146 if tag == "unstable" || tag == "stable" || tag == "deprecated" {
147 attr::mark_used(attr);
62682a34 148 self.tcx.sess.span_err(attr.span(),
9346a6ac
AL
149 "stability attributes may not be used outside \
150 of the standard library");
1a4d82fc 151 }
1a4d82fc 152 }
9346a6ac 153 f(self);
1a4d82fc
JJ
154 }
155 }
156}
157
62682a34 158impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> {
1a4d82fc
JJ
159 fn visit_item(&mut self, i: &Item) {
160 // FIXME (#18969): the following is a hack around the fact
161 // that we cannot currently annotate the stability of
162 // `deriving`. Basically, we do *not* allow stability
163 // inheritance on trait implementations, so that derived
164 // implementations appear to be unannotated. This then allows
165 // derived implementations to be automatically tagged with the
166 // stability of the trait. This is WRONG, but expedient to get
167 // libstd stabilized for the 1.0 release.
168 let use_parent = match i.node {
169 ast::ItemImpl(_, _, _, Some(_), _, _) => false,
170 _ => true,
171 };
172
85aaf69f
SL
173 // In case of a `pub use <mod>;`, we should not error since the stability
174 // is inherited from the module itself
175 let required = match i.node {
176 ast::ItemUse(_) => i.vis != ast::Public,
177 _ => true
178 };
179
180 self.annotate(i.id, use_parent, &i.attrs, i.span,
181 |v| visit::walk_item(v, i), required);
1a4d82fc
JJ
182
183 if let ast::ItemStruct(ref sd, _) = i.node {
184 sd.ctor_id.map(|id| {
85aaf69f 185 self.annotate(id, true, &i.attrs, i.span, |_| {}, true)
1a4d82fc
JJ
186 });
187 }
188 }
189
c34b1796
AL
190 fn visit_fn(&mut self, _: FnKind<'v>, _: &'v FnDecl,
191 _: &'v Block, _: Span, _: NodeId) {
1a4d82fc
JJ
192 // Items defined in a function body have no reason to have
193 // a stability attribute, so we don't recurse.
194 }
195
c34b1796
AL
196 fn visit_trait_item(&mut self, ti: &ast::TraitItem) {
197 self.annotate(ti.id, true, &ti.attrs, ti.span,
198 |v| visit::walk_trait_item(v, ti), true);
199 }
1a4d82fc 200
c34b1796
AL
201 fn visit_impl_item(&mut self, ii: &ast::ImplItem) {
202 self.annotate(ii.id, true, &ii.attrs, ii.span,
203 |v| visit::walk_impl_item(v, ii), true);
1a4d82fc
JJ
204 }
205
206 fn visit_variant(&mut self, var: &Variant, g: &'v Generics) {
85aaf69f
SL
207 self.annotate(var.node.id, true, &var.node.attrs, var.span,
208 |v| visit::walk_variant(v, var, g), true)
1a4d82fc
JJ
209 }
210
211 fn visit_struct_field(&mut self, s: &StructField) {
85aaf69f
SL
212 self.annotate(s.node.id, true, &s.node.attrs, s.span,
213 |v| visit::walk_struct_field(v, s), true);
1a4d82fc
JJ
214 }
215
216 fn visit_foreign_item(&mut self, i: &ast::ForeignItem) {
85aaf69f 217 self.annotate(i.id, true, &i.attrs, i.span, |_| {}, true);
1a4d82fc
JJ
218 }
219}
220
62682a34 221impl<'tcx> Index<'tcx> {
1a4d82fc 222 /// Construct the stability index for a crate being compiled.
62682a34 223 pub fn build(&mut self, tcx: &ty::ctxt<'tcx>, krate: &Crate, export_map: &PublicItems) {
1a4d82fc 224 let mut annotator = Annotator {
62682a34 225 tcx: tcx,
85aaf69f
SL
226 index: self,
227 parent: None,
228 export_map: export_map,
1a4d82fc 229 };
85aaf69f
SL
230 annotator.annotate(ast::CRATE_NODE_ID, true, &krate.attrs, krate.span,
231 |v| visit::walk_crate(v, krate), true);
232 }
233
234 pub fn new(krate: &Crate) -> Index {
62682a34 235 let mut is_staged_api = false;
85aaf69f 236 for attr in &krate.attrs {
c34b1796 237 if &attr.name()[..] == "staged_api" {
85aaf69f
SL
238 match attr.node.value.node {
239 ast::MetaWord(_) => {
240 attr::mark_used(attr);
62682a34 241 is_staged_api = true;
85aaf69f
SL
242 }
243 _ => (/*pass*/)
244 }
245 }
246 }
62682a34
SL
247 let mut staged_api = FnvHashMap();
248 staged_api.insert(ast::LOCAL_CRATE, is_staged_api);
85aaf69f
SL
249 Index {
250 staged_api: staged_api,
62682a34 251 map: DefIdMap(),
85aaf69f
SL
252 }
253 }
254}
255
256/// Cross-references the feature names of unstable APIs with enabled
257/// features and possibly prints errors. Returns a list of all
258/// features used.
259pub fn check_unstable_api_usage(tcx: &ty::ctxt)
260 -> FnvHashMap<InternedString, attr::StabilityLevel> {
261 let ref active_lib_features = tcx.sess.features.borrow().declared_lib_features;
262
263 // Put the active features into a map for quick lookup
264 let active_features = active_lib_features.iter().map(|&(ref s, _)| s.clone()).collect();
265
266 let mut checker = Checker {
267 tcx: tcx,
268 active_features: active_features,
269 used_features: FnvHashMap()
270 };
271
272 let krate = tcx.map.krate();
273 visit::walk_crate(&mut checker, krate);
274
275 let used_features = checker.used_features;
276 return used_features;
277}
278
279struct Checker<'a, 'tcx: 'a> {
280 tcx: &'a ty::ctxt<'tcx>,
281 active_features: FnvHashSet<InternedString>,
282 used_features: FnvHashMap<InternedString, attr::StabilityLevel>
283}
284
285impl<'a, 'tcx> Checker<'a, 'tcx> {
62682a34 286 fn check(&mut self, id: ast::DefId, span: Span, stab: &Option<&Stability>) {
85aaf69f
SL
287 // Only the cross-crate scenario matters when checking unstable APIs
288 let cross_crate = !is_local(id);
289 if !cross_crate { return }
290
291 match *stab {
c1a9b12d 292 Some(&Stability { level: attr::Unstable, ref feature, ref reason, issue, .. }) => {
85aaf69f
SL
293 self.used_features.insert(feature.clone(), attr::Unstable);
294
295 if !self.active_features.contains(feature) {
c1a9b12d 296 let mut msg = match *reason {
85aaf69f
SL
297 Some(ref r) => format!("use of unstable library feature '{}': {}",
298 &feature, &r),
299 None => format!("use of unstable library feature '{}'", &feature)
300 };
c1a9b12d
SL
301 if let Some(n) = issue {
302 use std::fmt::Write;
303 write!(&mut msg, " (see issue #{})", n).unwrap();
304 }
85aaf69f 305
c34b1796 306 emit_feature_err(&self.tcx.sess.parse_sess.span_diagnostic,
85aaf69f
SL
307 &feature, span, &msg);
308 }
309 }
62682a34 310 Some(&Stability { level, ref feature, .. }) => {
85aaf69f
SL
311 self.used_features.insert(feature.clone(), level);
312
313 // Stable APIs are always ok to call and deprecated APIs are
314 // handled by a lint.
315 }
316 None => {
317 // This is an 'unmarked' API, which should not exist
318 // in the standard library.
319 if self.tcx.sess.features.borrow().unmarked_api {
320 self.tcx.sess.span_warn(span, "use of unmarked library feature");
321 self.tcx.sess.span_note(span, "this is either a bug in the library you are \
322 using or a bug in the compiler - please \
323 report it in both places");
324 } else {
325 self.tcx.sess.span_err(span, "use of unmarked library feature");
326 self.tcx.sess.span_note(span, "this is either a bug in the library you are \
327 using or a bug in the compiler - please \
328 report it in both places");
329 self.tcx.sess.span_note(span, "use #![feature(unmarked_api)] in the \
330 crate attributes to override this");
331 }
332 }
333 }
334 }
335}
336
337impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> {
338 fn visit_item(&mut self, item: &ast::Item) {
339 // When compiling with --test we don't enforce stability on the
340 // compiler-generated test module, demarcated with `DUMMY_SP` plus the
341 // name `__test`
c1a9b12d 342 if item.span == DUMMY_SP && item.ident.name == "__test" { return }
85aaf69f
SL
343
344 check_item(self.tcx, item, true,
345 &mut |id, sp, stab| self.check(id, sp, stab));
346 visit::walk_item(self, item);
347 }
348
349 fn visit_expr(&mut self, ex: &ast::Expr) {
350 check_expr(self.tcx, ex,
351 &mut |id, sp, stab| self.check(id, sp, stab));
352 visit::walk_expr(self, ex);
353 }
354
355 fn visit_path(&mut self, path: &ast::Path, id: ast::NodeId) {
356 check_path(self.tcx, path, id,
357 &mut |id, sp, stab| self.check(id, sp, stab));
358 visit::walk_path(self, path)
359 }
c34b1796
AL
360
361 fn visit_pat(&mut self, pat: &ast::Pat) {
362 check_pat(self.tcx, pat,
363 &mut |id, sp, stab| self.check(id, sp, stab));
364 visit::walk_pat(self, pat)
365 }
85aaf69f
SL
366}
367
368/// Helper for discovering nodes to check for stability
369pub fn check_item(tcx: &ty::ctxt, item: &ast::Item, warn_about_defns: bool,
62682a34 370 cb: &mut FnMut(ast::DefId, Span, &Option<&Stability>)) {
85aaf69f
SL
371 match item.node {
372 ast::ItemExternCrate(_) => {
373 // compiler-generated `extern crate` items have a dummy span.
374 if item.span == DUMMY_SP { return }
375
376 let cnum = match tcx.sess.cstore.find_extern_mod_stmt_cnum(item.id) {
377 Some(cnum) => cnum,
378 None => return,
379 };
380 let id = ast::DefId { krate: cnum, node: ast::CRATE_NODE_ID };
381 maybe_do_stability_check(tcx, id, item.span, cb);
382 }
383
384 // For implementations of traits, check the stability of each item
385 // individually as it's possible to have a stable trait with unstable
386 // items.
387 ast::ItemImpl(_, _, _, Some(ref t), _, ref impl_items) => {
c34b1796 388 let trait_did = tcx.def_map.borrow().get(&t.ref_id).unwrap().def_id();
c1a9b12d 389 let trait_items = tcx.trait_items(trait_did);
85aaf69f
SL
390
391 for impl_item in impl_items {
85aaf69f 392 let item = trait_items.iter().find(|item| {
c34b1796 393 item.name() == impl_item.ident.name
85aaf69f
SL
394 }).unwrap();
395 if warn_about_defns {
c34b1796 396 maybe_do_stability_check(tcx, item.def_id(), impl_item.span, cb);
85aaf69f
SL
397 }
398 }
399 }
400
401 _ => (/* pass */)
402 }
403}
404
405/// Helper for discovering nodes to check for stability
406pub fn check_expr(tcx: &ty::ctxt, e: &ast::Expr,
62682a34 407 cb: &mut FnMut(ast::DefId, Span, &Option<&Stability>)) {
85aaf69f
SL
408 let span;
409 let id = match e.node {
410 ast::ExprMethodCall(i, _, _) => {
411 span = i.span;
412 let method_call = ty::MethodCall::expr(e.id);
c1a9b12d 413 tcx.tables.borrow().method_map[&method_call].def_id
85aaf69f 414 }
c34b1796
AL
415 ast::ExprField(ref base_e, ref field) => {
416 span = field.span;
c1a9b12d 417 match tcx.expr_ty_adjusted(base_e).sty {
62682a34 418 ty::TyStruct(did, _) => {
c1a9b12d 419 tcx.lookup_struct_fields(did)
c34b1796
AL
420 .iter()
421 .find(|f| f.name == field.node.name)
422 .unwrap_or_else(|| {
423 tcx.sess.span_bug(field.span,
424 "stability::check_expr: unknown named field access")
425 })
426 .id
427 }
428 _ => tcx.sess.span_bug(e.span,
429 "stability::check_expr: named field access on non-struct")
430 }
431 }
432 ast::ExprTupField(ref base_e, ref field) => {
433 span = field.span;
c1a9b12d 434 match tcx.expr_ty_adjusted(base_e).sty {
62682a34 435 ty::TyStruct(did, _) => {
c1a9b12d 436 tcx.lookup_struct_fields(did)
c34b1796
AL
437 .get(field.node)
438 .unwrap_or_else(|| {
439 tcx.sess.span_bug(field.span,
440 "stability::check_expr: unknown unnamed field access")
441 })
442 .id
443 }
62682a34 444 ty::TyTuple(..) => return,
c34b1796
AL
445 _ => tcx.sess.span_bug(e.span,
446 "stability::check_expr: unnamed field access on \
447 something other than a tuple or struct")
448 }
449 }
450 ast::ExprStruct(_, ref expr_fields, _) => {
c1a9b12d 451 let type_ = tcx.expr_ty(e);
c34b1796 452 match type_.sty {
62682a34 453 ty::TyStruct(did, _) => {
c1a9b12d 454 let struct_fields = tcx.lookup_struct_fields(did);
c34b1796
AL
455 // check the stability of each field that appears
456 // in the construction expression.
457 for field in expr_fields {
458 let did = struct_fields
459 .iter()
460 .find(|f| f.name == field.ident.node.name)
461 .unwrap_or_else(|| {
462 tcx.sess.span_bug(field.span,
463 "stability::check_expr: unknown named \
464 field access")
465 })
466 .id;
467 maybe_do_stability_check(tcx, did, field.span, cb);
468 }
469
470 // we're done.
471 return
472 }
473 // we don't look at stability attributes on
474 // struct-like enums (yet...), but it's definitely not
475 // a bug to have construct one.
62682a34 476 ty::TyEnum(..) => return,
c34b1796
AL
477 _ => {
478 tcx.sess.span_bug(e.span,
479 &format!("stability::check_expr: struct construction \
480 of non-struct, type {:?}",
62682a34 481 type_));
c34b1796
AL
482 }
483 }
484 }
85aaf69f
SL
485 _ => return
486 };
487
488 maybe_do_stability_check(tcx, id, span, cb);
489}
490
491pub fn check_path(tcx: &ty::ctxt, path: &ast::Path, id: ast::NodeId,
62682a34 492 cb: &mut FnMut(ast::DefId, Span, &Option<&Stability>)) {
c34b1796
AL
493 match tcx.def_map.borrow().get(&id).map(|d| d.full_def()) {
494 Some(def::DefPrimTy(..)) => {}
495 Some(def) => {
496 maybe_do_stability_check(tcx, def.def_id(), path.span, cb);
497 }
498 None => {}
499 }
500
501}
502
503pub fn check_pat(tcx: &ty::ctxt, pat: &ast::Pat,
62682a34 504 cb: &mut FnMut(ast::DefId, Span, &Option<&Stability>)) {
c34b1796
AL
505 debug!("check_pat(pat = {:?})", pat);
506 if is_internal(tcx, pat.span) { return; }
507
c1a9b12d 508 let did = match tcx.pat_ty_opt(pat) {
62682a34 509 Some(&ty::TyS { sty: ty::TyStruct(did, _), .. }) => did,
c34b1796 510 Some(_) | None => return,
85aaf69f 511 };
c1a9b12d 512 let struct_fields = tcx.lookup_struct_fields(did);
c34b1796
AL
513 match pat.node {
514 // Foo(a, b, c)
515 ast::PatEnum(_, Some(ref pat_fields)) => {
62682a34 516 for (field, struct_field) in pat_fields.iter().zip(&struct_fields) {
c34b1796
AL
517 // a .. pattern is fine, but anything positional is
518 // not.
519 if let ast::PatWild(ast::PatWildMulti) = field.node {
520 continue
521 }
522 maybe_do_stability_check(tcx, struct_field.id, field.span, cb)
523 }
524 }
525 // Foo { a, b, c }
526 ast::PatStruct(_, ref pat_fields, _) => {
527 for field in pat_fields {
528 let did = struct_fields
529 .iter()
530 .find(|f| f.name == field.node.ident.name)
531 .unwrap_or_else(|| {
532 tcx.sess.span_bug(field.span,
533 "stability::check_pat: unknown named field access")
534 })
535 .id;
536 maybe_do_stability_check(tcx, did, field.span, cb);
537 }
538 }
539 // everything else is fine.
540 _ => {}
541 }
85aaf69f
SL
542}
543
544fn maybe_do_stability_check(tcx: &ty::ctxt, id: ast::DefId, span: Span,
62682a34 545 cb: &mut FnMut(ast::DefId, Span, &Option<&Stability>)) {
c1a9b12d
SL
546 if !is_staged_api(tcx, id) {
547 debug!("maybe_do_stability_check: \
548 skipping id={:?} since it is not staged_api", id);
549 return;
550 }
551 if is_internal(tcx, span) {
552 debug!("maybe_do_stability_check: \
553 skipping span={:?} since it is internal", span);
554 return;
555 }
85aaf69f 556 let ref stability = lookup(tcx, id);
c1a9b12d
SL
557 debug!("maybe_do_stability_check: \
558 inspecting id={:?} span={:?} of stability={:?}", id, span, stability);
85aaf69f
SL
559 cb(id, span, stability);
560}
561
562fn is_internal(tcx: &ty::ctxt, span: Span) -> bool {
c34b1796 563 tcx.sess.codemap().span_allows_unstable(span)
85aaf69f
SL
564}
565
566fn is_staged_api(tcx: &ty::ctxt, id: DefId) -> bool {
c1a9b12d 567 match tcx.trait_item_of_item(id) {
85aaf69f
SL
568 Some(ty::MethodTraitItemId(trait_method_id))
569 if trait_method_id != id => {
570 is_staged_api(tcx, trait_method_id)
571 }
85aaf69f 572 _ => {
62682a34
SL
573 *tcx.stability.borrow_mut().staged_api.entry(id.krate).or_insert_with(
574 || csearch::is_staged_api(&tcx.sess.cstore, id.krate))
85aaf69f 575 }
1a4d82fc
JJ
576 }
577}
578
579/// Lookup the stability for a node, loading external crate
580/// metadata as necessary.
62682a34
SL
581pub fn lookup<'tcx>(tcx: &ty::ctxt<'tcx>, id: DefId) -> Option<&'tcx Stability> {
582 if let Some(st) = tcx.stability.borrow().map.get(&id) {
583 return *st;
584 }
585
586 let st = lookup_uncached(tcx, id);
587 tcx.stability.borrow_mut().map.insert(id, st);
588 st
589}
590
591fn lookup_uncached<'tcx>(tcx: &ty::ctxt<'tcx>, id: DefId) -> Option<&'tcx Stability> {
592 debug!("lookup(id={:?})", id);
1a4d82fc
JJ
593
594 // is this definition the implementation of a trait method?
c1a9b12d 595 match tcx.trait_item_of_item(id) {
1a4d82fc
JJ
596 Some(ty::MethodTraitItemId(trait_method_id)) if trait_method_id != id => {
597 debug!("lookup: trait_method_id={:?}", trait_method_id);
598 return lookup(tcx, trait_method_id)
599 }
600 _ => {}
601 }
602
603 let item_stab = if is_local(id) {
62682a34 604 None // The stability cache is filled partially lazily
1a4d82fc 605 } else {
62682a34 606 csearch::get_stability(&tcx.sess.cstore, id).map(|st| tcx.intern_stability(st))
1a4d82fc
JJ
607 };
608
609 item_stab.or_else(|| {
c1a9b12d
SL
610 if tcx.is_impl(id) {
611 if let Some(trait_id) = tcx.trait_id_of_impl(id) {
62682a34
SL
612 // FIXME (#18969): for the time being, simply use the
613 // stability of the trait to determine the stability of any
614 // unmarked impls for it. See FIXME above for more details.
615
616 debug!("lookup: trait_id={:?}", trait_id);
617 return lookup(tcx, trait_id);
618 }
1a4d82fc 619 }
62682a34 620 None
1a4d82fc
JJ
621 })
622}
623
85aaf69f
SL
624/// Given the list of enabled features that were not language features (i.e. that
625/// were expected to be library features), and the list of features used from
626/// libraries, identify activated features that don't exist and error about them.
627pub fn check_unused_or_stable_features(sess: &Session,
628 lib_features_used: &FnvHashMap<InternedString,
629 attr::StabilityLevel>) {
630 let ref declared_lib_features = sess.features.borrow().declared_lib_features;
631 let mut remaining_lib_features: FnvHashMap<InternedString, Span>
632 = declared_lib_features.clone().into_iter().collect();
633
634 let stable_msg = "this feature is stable. attribute no longer needed";
635
62682a34 636 for &span in &sess.features.borrow().declared_stable_lang_features {
85aaf69f
SL
637 sess.add_lint(lint::builtin::STABLE_FEATURES,
638 ast::CRATE_NODE_ID,
639 span,
640 stable_msg.to_string());
641 }
642
62682a34 643 for (used_lib_feature, level) in lib_features_used {
85aaf69f
SL
644 match remaining_lib_features.remove(used_lib_feature) {
645 Some(span) => {
646 if *level == attr::Stable {
647 sess.add_lint(lint::builtin::STABLE_FEATURES,
648 ast::CRATE_NODE_ID,
649 span,
650 stable_msg.to_string());
651 }
1a4d82fc 652 }
85aaf69f 653 None => ( /* used but undeclared, handled during the previous ast visit */ )
1a4d82fc
JJ
654 }
655 }
85aaf69f 656
62682a34 657 for &span in remaining_lib_features.values() {
85aaf69f
SL
658 sess.add_lint(lint::builtin::UNUSED_FEATURES,
659 ast::CRATE_NODE_ID,
660 span,
661 "unused or unknown feature".to_string());
662 }
1a4d82fc 663}