]> git.proxmox.com Git - rustc.git/blame - src/librustc/middle/stability.rs
Imported Upstream version 1.9.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
b039eaaf
SL
14pub use self::StabilityLevel::*;
15
9cc50fc6 16use dep_graph::DepNode;
54a0048b 17use hir::map as hir_map;
85aaf69f
SL
18use session::Session;
19use lint;
92a42be0 20use middle::cstore::{CrateStore, LOCAL_CRATE};
54a0048b
SL
21use hir::def::Def;
22use hir::def_id::{CRATE_DEF_INDEX, DefId};
23use ty::{self, TyCtxt};
92a42be0 24use middle::privacy::AccessLevels;
85aaf69f
SL
25use syntax::parse::token::InternedString;
26use syntax::codemap::{Span, DUMMY_SP};
1a4d82fc 27use syntax::ast;
b039eaaf 28use syntax::ast::{NodeId, Attribute};
e9174d1e 29use syntax::feature_gate::{GateIssue, emit_feature_err};
9cc50fc6 30use syntax::attr::{self, Stability, Deprecation, AttrMetaMethods};
62682a34 31use util::nodemap::{DefIdMap, FnvHashSet, FnvHashMap};
1a4d82fc 32
54a0048b
SL
33use hir;
34use hir::{Item, Generics, StructField, Variant, PatKind};
35use hir::intravisit::{self, Visitor};
e9174d1e 36
1a4d82fc 37use std::mem::replace;
c1a9b12d 38use std::cmp::Ordering;
1a4d82fc 39
b039eaaf
SL
40#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Copy, Debug, Eq, Hash)]
41pub enum StabilityLevel {
42 Unstable,
43 Stable,
44}
45
46impl StabilityLevel {
47 pub fn from_attr_level(level: &attr::StabilityLevel) -> Self {
48 if level.is_stable() { Stable } else { Unstable }
49 }
50}
51
92a42be0
SL
52#[derive(PartialEq)]
53enum AnnotationKind {
54 // Annotation is required if not inherited from unstable parents
55 Required,
56 // Annotation is useless, reject it
57 Prohibited,
58 // Annotation itself is useless, but it can be propagated to children
59 Container,
60}
61
1a4d82fc 62/// A stability index, giving the stability level for items and methods.
62682a34
SL
63pub struct Index<'tcx> {
64 /// This is mostly a cache, except the stabilities of local items
65 /// are filled by the annotator.
9cc50fc6
SL
66 stab_map: DefIdMap<Option<&'tcx Stability>>,
67 depr_map: DefIdMap<Option<Deprecation>>,
62682a34
SL
68
69 /// Maps for each crate whether it is part of the staged API.
70 staged_api: FnvHashMap<ast::CrateNum, bool>
1a4d82fc
JJ
71}
72
73// A private tree-walker for producing an Index.
62682a34 74struct Annotator<'a, 'tcx: 'a> {
54a0048b 75 tcx: &'a TyCtxt<'tcx>,
62682a34 76 index: &'a mut Index<'tcx>,
9cc50fc6
SL
77 parent_stab: Option<&'tcx Stability>,
78 parent_depr: Option<Deprecation>,
92a42be0
SL
79 access_levels: &'a AccessLevels,
80 in_trait_impl: bool,
1a4d82fc
JJ
81}
82
62682a34 83impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
1a4d82fc
JJ
84 // Determine the stability for a node based on its attributes and inherited
85 // stability. The stability is recorded in the index and used as the parent.
9cc50fc6 86 fn annotate<F>(&mut self, id: NodeId, attrs: &[Attribute],
92a42be0
SL
87 item_sp: Span, kind: AnnotationKind, visit_children: F)
88 where F: FnOnce(&mut Annotator)
1a4d82fc 89 {
92a42be0 90 if self.index.staged_api[&LOCAL_CRATE] && self.tcx.sess.features.borrow().staged_api {
9346a6ac 91 debug!("annotate(id = {:?}, attrs = {:?})", id, attrs);
9cc50fc6
SL
92 if let Some(..) = attr::find_deprecation(self.tcx.sess.diagnostic(), attrs, item_sp) {
93 self.tcx.sess.span_err(item_sp, "`#[deprecated]` cannot be used in staged api, \
94 use `#[rustc_deprecated]` instead");
95 }
92a42be0
SL
96 if let Some(mut stab) = attr::find_stability(self.tcx.sess.diagnostic(),
97 attrs, item_sp) {
98 // Error if prohibited, or can't inherit anything from a container
99 if kind == AnnotationKind::Prohibited ||
100 (kind == AnnotationKind::Container &&
101 stab.level.is_stable() &&
9cc50fc6 102 stab.rustc_depr.is_none()) {
92a42be0
SL
103 self.tcx.sess.span_err(item_sp, "This stability annotation is useless");
104 }
105
106 debug!("annotate: found {:?}", stab);
107 // If parent is deprecated and we're not, inherit this by merging
108 // deprecated_since and its reason.
9cc50fc6
SL
109 if let Some(parent_stab) = self.parent_stab {
110 if parent_stab.rustc_depr.is_some() && stab.rustc_depr.is_none() {
111 stab.rustc_depr = parent_stab.rustc_depr.clone()
c1a9b12d 112 }
92a42be0 113 }
c1a9b12d 114
92a42be0
SL
115 let stab = self.tcx.intern_stability(stab);
116
117 // Check if deprecated_since < stable_since. If it is,
118 // this is *almost surely* an accident.
9cc50fc6
SL
119 if let (&Some(attr::RustcDeprecation {since: ref dep_since, ..}),
120 &attr::Stable {since: ref stab_since}) = (&stab.rustc_depr, &stab.level) {
92a42be0
SL
121 // Explicit version of iter::order::lt to handle parse errors properly
122 for (dep_v, stab_v) in dep_since.split(".").zip(stab_since.split(".")) {
123 if let (Ok(dep_v), Ok(stab_v)) = (dep_v.parse::<u64>(), stab_v.parse()) {
124 match dep_v.cmp(&stab_v) {
125 Ordering::Less => {
126 self.tcx.sess.span_err(item_sp, "An API can't be stabilized \
127 after it is deprecated");
128 break
c1a9b12d 129 }
92a42be0
SL
130 Ordering::Equal => continue,
131 Ordering::Greater => break,
c1a9b12d 132 }
92a42be0
SL
133 } else {
134 // Act like it isn't less because the question is now nonsensical,
135 // and this makes us not do anything else interesting.
136 self.tcx.sess.span_err(item_sp, "Invalid stability or deprecation \
137 version found");
138 break
139 }
c1a9b12d 140 }
92a42be0 141 }
c1a9b12d 142
92a42be0 143 let def_id = self.tcx.map.local_def_id(id);
9cc50fc6 144 self.index.stab_map.insert(def_id, Some(stab));
92a42be0 145
9cc50fc6 146 let orig_parent_stab = replace(&mut self.parent_stab, Some(stab));
92a42be0 147 visit_children(self);
9cc50fc6 148 self.parent_stab = orig_parent_stab;
92a42be0 149 } else {
9cc50fc6 150 debug!("annotate: not found, parent = {:?}", self.parent_stab);
92a42be0
SL
151 let mut is_error = kind == AnnotationKind::Required &&
152 self.access_levels.is_reachable(id) &&
153 !self.tcx.sess.opts.test;
9cc50fc6 154 if let Some(stab) = self.parent_stab {
92a42be0
SL
155 if stab.level.is_unstable() {
156 let def_id = self.tcx.map.local_def_id(id);
9cc50fc6 157 self.index.stab_map.insert(def_id, Some(stab));
92a42be0 158 is_error = false;
9346a6ac
AL
159 }
160 }
92a42be0
SL
161 if is_error {
162 self.tcx.sess.span_err(item_sp, "This node does not have \
163 a stability attribute");
1a4d82fc 164 }
92a42be0 165 visit_children(self);
1a4d82fc 166 }
9346a6ac 167 } else {
92a42be0 168 // Emit errors for non-staged-api crates.
9346a6ac
AL
169 for attr in attrs {
170 let tag = attr.name();
92a42be0 171 if tag == "unstable" || tag == "stable" || tag == "rustc_deprecated" {
9346a6ac 172 attr::mark_used(attr);
92a42be0
SL
173 self.tcx.sess.span_err(attr.span(), "stability attributes may not be used \
174 outside of the standard library");
1a4d82fc 175 }
1a4d82fc 176 }
9cc50fc6
SL
177
178 if let Some(depr) = attr::find_deprecation(self.tcx.sess.diagnostic(), attrs, item_sp) {
179 if kind == AnnotationKind::Prohibited {
180 self.tcx.sess.span_err(item_sp, "This deprecation annotation is useless");
181 }
182
183 // `Deprecation` is just two pointers, no need to intern it
184 let def_id = self.tcx.map.local_def_id(id);
185 self.index.depr_map.insert(def_id, Some(depr.clone()));
186
187 let orig_parent_depr = replace(&mut self.parent_depr, Some(depr));
188 visit_children(self);
189 self.parent_depr = orig_parent_depr;
190 } else if let Some(depr) = self.parent_depr.clone() {
191 let def_id = self.tcx.map.local_def_id(id);
192 self.index.depr_map.insert(def_id, Some(depr));
193 visit_children(self);
194 } else {
195 visit_children(self);
196 }
1a4d82fc
JJ
197 }
198 }
199}
200
62682a34 201impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> {
92a42be0
SL
202 /// Because stability levels are scoped lexically, we want to walk
203 /// nested items in the context of the outer item, so enable
204 /// deep-walking.
205 fn visit_nested_item(&mut self, item: hir::ItemId) {
206 self.visit_item(self.tcx.map.expect_item(item.id))
207 }
1a4d82fc 208
92a42be0
SL
209 fn visit_item(&mut self, i: &Item) {
210 let orig_in_trait_impl = self.in_trait_impl;
92a42be0
SL
211 let mut kind = AnnotationKind::Required;
212 match i.node {
213 // Inherent impls and foreign modules serve only as containers for other items,
214 // they don't have their own stability. They still can be annotated as unstable
215 // and propagate this unstability to children, but this annotation is completely
216 // optional. They inherit stability from their parents when unannotated.
217 hir::ItemImpl(_, _, _, None, _, _) | hir::ItemForeignMod(..) => {
218 self.in_trait_impl = false;
219 kind = AnnotationKind::Container;
b039eaaf 220 }
92a42be0
SL
221 hir::ItemImpl(_, _, _, Some(_), _, _) => {
222 self.in_trait_impl = true;
223 }
224 hir::ItemStruct(ref sd, _) => {
92a42be0
SL
225 if !sd.is_struct() {
226 self.annotate(sd.id(), &i.attrs, i.span, AnnotationKind::Required, |_| {})
227 }
228 }
92a42be0 229 _ => {}
1a4d82fc 230 }
1a4d82fc 231
92a42be0
SL
232 self.annotate(i.id, &i.attrs, i.span, kind, |v| {
233 intravisit::walk_item(v, i)
234 });
235 self.in_trait_impl = orig_in_trait_impl;
1a4d82fc
JJ
236 }
237
e9174d1e 238 fn visit_trait_item(&mut self, ti: &hir::TraitItem) {
92a42be0
SL
239 self.annotate(ti.id, &ti.attrs, ti.span, AnnotationKind::Required, |v| {
240 intravisit::walk_trait_item(v, ti);
241 });
c34b1796 242 }
1a4d82fc 243
e9174d1e 244 fn visit_impl_item(&mut self, ii: &hir::ImplItem) {
92a42be0
SL
245 let kind = if self.in_trait_impl {
246 AnnotationKind::Prohibited
247 } else {
248 AnnotationKind::Required
249 };
250 self.annotate(ii.id, &ii.attrs, ii.span, kind, |v| {
251 intravisit::walk_impl_item(v, ii);
252 });
1a4d82fc
JJ
253 }
254
b039eaaf 255 fn visit_variant(&mut self, var: &Variant, g: &'v Generics, item_id: NodeId) {
92a42be0
SL
256 self.annotate(var.node.data.id(), &var.node.attrs, var.span, AnnotationKind::Required, |v| {
257 intravisit::walk_variant(v, var, g, item_id);
258 })
1a4d82fc
JJ
259 }
260
261 fn visit_struct_field(&mut self, s: &StructField) {
54a0048b 262 self.annotate(s.id, &s.attrs, s.span, AnnotationKind::Required, |v| {
92a42be0
SL
263 intravisit::walk_struct_field(v, s);
264 });
1a4d82fc
JJ
265 }
266
e9174d1e 267 fn visit_foreign_item(&mut self, i: &hir::ForeignItem) {
92a42be0
SL
268 self.annotate(i.id, &i.attrs, i.span, AnnotationKind::Required, |v| {
269 intravisit::walk_foreign_item(v, i);
270 });
271 }
272
273 fn visit_macro_def(&mut self, md: &'v hir::MacroDef) {
274 if md.imported_from.is_none() {
275 self.annotate(md.id, &md.attrs, md.span, AnnotationKind::Required, |_| {});
276 }
1a4d82fc
JJ
277 }
278}
279
62682a34 280impl<'tcx> Index<'tcx> {
1a4d82fc 281 /// Construct the stability index for a crate being compiled.
54a0048b 282 pub fn build(&mut self, tcx: &TyCtxt<'tcx>, access_levels: &AccessLevels) {
7453a54e
SL
283 let _task = tcx.dep_graph.in_task(DepNode::StabilityIndex);
284 let krate = tcx.map.krate();
1a4d82fc 285 let mut annotator = Annotator {
62682a34 286 tcx: tcx,
85aaf69f 287 index: self,
9cc50fc6
SL
288 parent_stab: None,
289 parent_depr: None,
92a42be0
SL
290 access_levels: access_levels,
291 in_trait_impl: false,
1a4d82fc 292 };
92a42be0
SL
293 annotator.annotate(ast::CRATE_NODE_ID, &krate.attrs, krate.span, AnnotationKind::Required,
294 |v| intravisit::walk_crate(v, krate));
85aaf69f
SL
295 }
296
7453a54e
SL
297 pub fn new(hir_map: &hir_map::Map) -> Index<'tcx> {
298 let _task = hir_map.dep_graph.in_task(DepNode::StabilityIndex);
299 let krate = hir_map.krate();
300
62682a34 301 let mut is_staged_api = false;
85aaf69f 302 for attr in &krate.attrs {
92a42be0
SL
303 if attr.name() == "stable" || attr.name() == "unstable" {
304 is_staged_api = true;
305 break
85aaf69f
SL
306 }
307 }
92a42be0 308
62682a34 309 let mut staged_api = FnvHashMap();
e9174d1e 310 staged_api.insert(LOCAL_CRATE, is_staged_api);
85aaf69f
SL
311 Index {
312 staged_api: staged_api,
9cc50fc6
SL
313 stab_map: DefIdMap(),
314 depr_map: DefIdMap(),
85aaf69f
SL
315 }
316 }
317}
318
319/// Cross-references the feature names of unstable APIs with enabled
320/// features and possibly prints errors. Returns a list of all
321/// features used.
54a0048b 322pub fn check_unstable_api_usage(tcx: &TyCtxt)
b039eaaf 323 -> FnvHashMap<InternedString, StabilityLevel> {
9cc50fc6 324 let _task = tcx.dep_graph.in_task(DepNode::StabilityCheck);
85aaf69f
SL
325 let ref active_lib_features = tcx.sess.features.borrow().declared_lib_features;
326
327 // Put the active features into a map for quick lookup
328 let active_features = active_lib_features.iter().map(|&(ref s, _)| s.clone()).collect();
329
330 let mut checker = Checker {
331 tcx: tcx,
332 active_features: active_features,
b039eaaf
SL
333 used_features: FnvHashMap(),
334 in_skip_block: 0,
85aaf69f 335 };
92a42be0 336 intravisit::walk_crate(&mut checker, tcx.map.krate());
85aaf69f 337
9cc50fc6 338 checker.used_features
85aaf69f
SL
339}
340
341struct Checker<'a, 'tcx: 'a> {
54a0048b 342 tcx: &'a TyCtxt<'tcx>,
85aaf69f 343 active_features: FnvHashSet<InternedString>,
b039eaaf
SL
344 used_features: FnvHashMap<InternedString, StabilityLevel>,
345 // Within a block where feature gate checking can be skipped.
346 in_skip_block: u32,
85aaf69f
SL
347}
348
349impl<'a, 'tcx> Checker<'a, 'tcx> {
9cc50fc6
SL
350 fn check(&mut self, id: DefId, span: Span,
351 stab: &Option<&Stability>, _depr: &Option<Deprecation>) {
352 if !is_staged_api(self.tcx, id) {
353 return;
354 }
85aaf69f 355 // Only the cross-crate scenario matters when checking unstable APIs
e9174d1e 356 let cross_crate = !id.is_local();
b039eaaf
SL
357 if !cross_crate {
358 return
359 }
360
361 // We don't need to check for stability - presumably compiler generated code.
362 if self.in_skip_block > 0 {
363 return;
364 }
85aaf69f
SL
365
366 match *stab {
b039eaaf
SL
367 Some(&Stability { level: attr::Unstable {ref reason, issue}, ref feature, .. }) => {
368 self.used_features.insert(feature.clone(), Unstable);
85aaf69f
SL
369
370 if !self.active_features.contains(feature) {
e9174d1e 371 let msg = match *reason {
85aaf69f
SL
372 Some(ref r) => format!("use of unstable library feature '{}': {}",
373 &feature, &r),
374 None => format!("use of unstable library feature '{}'", &feature)
375 };
c34b1796 376 emit_feature_err(&self.tcx.sess.parse_sess.span_diagnostic,
b039eaaf 377 &feature, span, GateIssue::Library(Some(issue)), &msg);
85aaf69f
SL
378 }
379 }
b039eaaf
SL
380 Some(&Stability { ref level, ref feature, .. }) => {
381 self.used_features.insert(feature.clone(), StabilityLevel::from_attr_level(level));
85aaf69f
SL
382
383 // Stable APIs are always ok to call and deprecated APIs are
384 // handled by a lint.
385 }
386 None => {
387 // This is an 'unmarked' API, which should not exist
388 // in the standard library.
389 if self.tcx.sess.features.borrow().unmarked_api {
9cc50fc6
SL
390 self.tcx.sess.struct_span_warn(span, "use of unmarked library feature")
391 .span_note(span, "this is either a bug in the library you are \
85aaf69f 392 using or a bug in the compiler - please \
9cc50fc6
SL
393 report it in both places")
394 .emit()
85aaf69f 395 } else {
9cc50fc6
SL
396 self.tcx.sess.struct_span_err(span, "use of unmarked library feature")
397 .span_note(span, "this is either a bug in the library you are \
85aaf69f 398 using or a bug in the compiler - please \
9cc50fc6
SL
399 report it in both places")
400 .span_note(span, "use #![feature(unmarked_api)] in the \
401 crate attributes to override this")
402 .emit()
85aaf69f
SL
403 }
404 }
405 }
406 }
407}
408
409impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> {
92a42be0
SL
410 /// Because stability levels are scoped lexically, we want to walk
411 /// nested items in the context of the outer item, so enable
412 /// deep-walking.
413 fn visit_nested_item(&mut self, item: hir::ItemId) {
414 self.visit_item(self.tcx.map.expect_item(item.id))
415 }
416
e9174d1e 417 fn visit_item(&mut self, item: &hir::Item) {
85aaf69f
SL
418 // When compiling with --test we don't enforce stability on the
419 // compiler-generated test module, demarcated with `DUMMY_SP` plus the
420 // name `__test`
b039eaaf 421 if item.span == DUMMY_SP && item.name.as_str() == "__test" { return }
85aaf69f
SL
422
423 check_item(self.tcx, item, true,
9cc50fc6 424 &mut |id, sp, stab, depr| self.check(id, sp, stab, depr));
92a42be0 425 intravisit::walk_item(self, item);
85aaf69f
SL
426 }
427
e9174d1e 428 fn visit_expr(&mut self, ex: &hir::Expr) {
85aaf69f 429 check_expr(self.tcx, ex,
9cc50fc6 430 &mut |id, sp, stab, depr| self.check(id, sp, stab, depr));
92a42be0 431 intravisit::walk_expr(self, ex);
85aaf69f
SL
432 }
433
e9174d1e 434 fn visit_path(&mut self, path: &hir::Path, id: ast::NodeId) {
85aaf69f 435 check_path(self.tcx, path, id,
9cc50fc6 436 &mut |id, sp, stab, depr| self.check(id, sp, stab, depr));
92a42be0 437 intravisit::walk_path(self, path)
85aaf69f 438 }
c34b1796 439
b039eaaf
SL
440 fn visit_path_list_item(&mut self, prefix: &hir::Path, item: &hir::PathListItem) {
441 check_path_list_item(self.tcx, item,
9cc50fc6 442 &mut |id, sp, stab, depr| self.check(id, sp, stab, depr));
92a42be0 443 intravisit::walk_path_list_item(self, prefix, item)
b039eaaf
SL
444 }
445
e9174d1e 446 fn visit_pat(&mut self, pat: &hir::Pat) {
c34b1796 447 check_pat(self.tcx, pat,
9cc50fc6 448 &mut |id, sp, stab, depr| self.check(id, sp, stab, depr));
92a42be0 449 intravisit::walk_pat(self, pat)
c34b1796 450 }
b039eaaf
SL
451
452 fn visit_block(&mut self, b: &hir::Block) {
453 let old_skip_count = self.in_skip_block;
454 match b.rules {
455 hir::BlockCheckMode::PushUnstableBlock => {
456 self.in_skip_block += 1;
457 }
458 hir::BlockCheckMode::PopUnstableBlock => {
459 self.in_skip_block = self.in_skip_block.checked_sub(1).unwrap();
460 }
461 _ => {}
462 }
92a42be0 463 intravisit::walk_block(self, b);
b039eaaf
SL
464 self.in_skip_block = old_skip_count;
465 }
85aaf69f
SL
466}
467
468/// Helper for discovering nodes to check for stability
54a0048b 469pub fn check_item(tcx: &TyCtxt, item: &hir::Item, warn_about_defns: bool,
9cc50fc6 470 cb: &mut FnMut(DefId, Span, &Option<&Stability>, &Option<Deprecation>)) {
85aaf69f 471 match item.node {
e9174d1e 472 hir::ItemExternCrate(_) => {
85aaf69f
SL
473 // compiler-generated `extern crate` items have a dummy span.
474 if item.span == DUMMY_SP { return }
475
92a42be0 476 let cnum = match tcx.sess.cstore.extern_mod_stmt_cnum(item.id) {
85aaf69f
SL
477 Some(cnum) => cnum,
478 None => return,
479 };
b039eaaf 480 let id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
85aaf69f
SL
481 maybe_do_stability_check(tcx, id, item.span, cb);
482 }
483
484 // For implementations of traits, check the stability of each item
485 // individually as it's possible to have a stable trait with unstable
486 // items.
e9174d1e 487 hir::ItemImpl(_, _, _, Some(ref t), _, ref impl_items) => {
c34b1796 488 let trait_did = tcx.def_map.borrow().get(&t.ref_id).unwrap().def_id();
c1a9b12d 489 let trait_items = tcx.trait_items(trait_did);
85aaf69f
SL
490
491 for impl_item in impl_items {
85aaf69f 492 let item = trait_items.iter().find(|item| {
b039eaaf 493 item.name() == impl_item.name
85aaf69f
SL
494 }).unwrap();
495 if warn_about_defns {
c34b1796 496 maybe_do_stability_check(tcx, item.def_id(), impl_item.span, cb);
85aaf69f
SL
497 }
498 }
499 }
500
501 _ => (/* pass */)
502 }
503}
504
505/// Helper for discovering nodes to check for stability
54a0048b 506pub fn check_expr(tcx: &TyCtxt, e: &hir::Expr,
9cc50fc6 507 cb: &mut FnMut(DefId, Span, &Option<&Stability>, &Option<Deprecation>)) {
85aaf69f
SL
508 let span;
509 let id = match e.node {
e9174d1e 510 hir::ExprMethodCall(i, _, _) => {
85aaf69f
SL
511 span = i.span;
512 let method_call = ty::MethodCall::expr(e.id);
c1a9b12d 513 tcx.tables.borrow().method_map[&method_call].def_id
85aaf69f 514 }
e9174d1e 515 hir::ExprField(ref base_e, ref field) => {
c34b1796 516 span = field.span;
c1a9b12d 517 match tcx.expr_ty_adjusted(base_e).sty {
b039eaaf 518 ty::TyStruct(def, _) => def.struct_variant().field_named(field.node).did,
54a0048b
SL
519 _ => span_bug!(e.span,
520 "stability::check_expr: named field access on non-struct")
c34b1796
AL
521 }
522 }
e9174d1e 523 hir::ExprTupField(ref base_e, ref field) => {
c34b1796 524 span = field.span;
c1a9b12d 525 match tcx.expr_ty_adjusted(base_e).sty {
e9174d1e 526 ty::TyStruct(def, _) => def.struct_variant().fields[field.node].did,
62682a34 527 ty::TyTuple(..) => return,
54a0048b
SL
528 _ => span_bug!(e.span,
529 "stability::check_expr: unnamed field access on \
530 something other than a tuple or struct")
c34b1796
AL
531 }
532 }
e9174d1e 533 hir::ExprStruct(_, ref expr_fields, _) => {
c1a9b12d 534 let type_ = tcx.expr_ty(e);
c34b1796 535 match type_.sty {
e9174d1e 536 ty::TyStruct(def, _) => {
c34b1796
AL
537 // check the stability of each field that appears
538 // in the construction expression.
539 for field in expr_fields {
e9174d1e 540 let did = def.struct_variant()
b039eaaf 541 .field_named(field.name.node)
e9174d1e 542 .did;
c34b1796
AL
543 maybe_do_stability_check(tcx, did, field.span, cb);
544 }
545
546 // we're done.
547 return
548 }
549 // we don't look at stability attributes on
550 // struct-like enums (yet...), but it's definitely not
551 // a bug to have construct one.
62682a34 552 ty::TyEnum(..) => return,
c34b1796 553 _ => {
54a0048b
SL
554 span_bug!(e.span,
555 "stability::check_expr: struct construction \
556 of non-struct, type {:?}",
557 type_);
c34b1796
AL
558 }
559 }
560 }
85aaf69f
SL
561 _ => return
562 };
563
564 maybe_do_stability_check(tcx, id, span, cb);
565}
566
54a0048b 567pub fn check_path(tcx: &TyCtxt, path: &hir::Path, id: ast::NodeId,
9cc50fc6 568 cb: &mut FnMut(DefId, Span, &Option<&Stability>, &Option<Deprecation>)) {
c34b1796 569 match tcx.def_map.borrow().get(&id).map(|d| d.full_def()) {
7453a54e
SL
570 Some(Def::PrimTy(..)) => {}
571 Some(Def::SelfTy(..)) => {}
c34b1796
AL
572 Some(def) => {
573 maybe_do_stability_check(tcx, def.def_id(), path.span, cb);
574 }
575 None => {}
576 }
b039eaaf 577}
c34b1796 578
54a0048b 579pub fn check_path_list_item(tcx: &TyCtxt, item: &hir::PathListItem,
9cc50fc6 580 cb: &mut FnMut(DefId, Span, &Option<&Stability>, &Option<Deprecation>)) {
b039eaaf 581 match tcx.def_map.borrow().get(&item.node.id()).map(|d| d.full_def()) {
7453a54e 582 Some(Def::PrimTy(..)) => {}
b039eaaf
SL
583 Some(def) => {
584 maybe_do_stability_check(tcx, def.def_id(), item.span, cb);
585 }
586 None => {}
587 }
c34b1796
AL
588}
589
54a0048b 590pub fn check_pat(tcx: &TyCtxt, pat: &hir::Pat,
9cc50fc6 591 cb: &mut FnMut(DefId, Span, &Option<&Stability>, &Option<Deprecation>)) {
c34b1796
AL
592 debug!("check_pat(pat = {:?})", pat);
593 if is_internal(tcx, pat.span) { return; }
594
e9174d1e
SL
595 let v = match tcx.pat_ty_opt(pat) {
596 Some(&ty::TyS { sty: ty::TyStruct(def, _), .. }) => def.struct_variant(),
c34b1796 597 Some(_) | None => return,
85aaf69f 598 };
c34b1796
AL
599 match pat.node {
600 // Foo(a, b, c)
7453a54e
SL
601 // A Variant(..) pattern `PatKind::TupleStruct(_, None)` doesn't have to be recursed into.
602 PatKind::TupleStruct(_, Some(ref pat_fields)) => {
e9174d1e 603 for (field, struct_field) in pat_fields.iter().zip(&v.fields) {
e9174d1e 604 maybe_do_stability_check(tcx, struct_field.did, field.span, cb)
c34b1796
AL
605 }
606 }
607 // Foo { a, b, c }
7453a54e 608 PatKind::Struct(_, ref pat_fields, _) => {
c34b1796 609 for field in pat_fields {
b039eaaf 610 let did = v.field_named(field.node.name).did;
c34b1796
AL
611 maybe_do_stability_check(tcx, did, field.span, cb);
612 }
613 }
614 // everything else is fine.
615 _ => {}
616 }
85aaf69f
SL
617}
618
54a0048b 619fn maybe_do_stability_check(tcx: &TyCtxt, id: DefId, span: Span,
9cc50fc6
SL
620 cb: &mut FnMut(DefId, Span,
621 &Option<&Stability>, &Option<Deprecation>)) {
c1a9b12d
SL
622 if is_internal(tcx, span) {
623 debug!("maybe_do_stability_check: \
624 skipping span={:?} since it is internal", span);
625 return;
626 }
9cc50fc6
SL
627 let (stability, deprecation) = if is_staged_api(tcx, id) {
628 (lookup_stability(tcx, id), None)
629 } else {
630 (None, lookup_deprecation(tcx, id))
631 };
c1a9b12d
SL
632 debug!("maybe_do_stability_check: \
633 inspecting id={:?} span={:?} of stability={:?}", id, span, stability);
9cc50fc6 634 cb(id, span, &stability, &deprecation);
85aaf69f
SL
635}
636
54a0048b 637fn is_internal(tcx: &TyCtxt, span: Span) -> bool {
c34b1796 638 tcx.sess.codemap().span_allows_unstable(span)
85aaf69f
SL
639}
640
54a0048b 641fn is_staged_api(tcx: &TyCtxt, id: DefId) -> bool {
c1a9b12d 642 match tcx.trait_item_of_item(id) {
85aaf69f
SL
643 Some(ty::MethodTraitItemId(trait_method_id))
644 if trait_method_id != id => {
645 is_staged_api(tcx, trait_method_id)
646 }
85aaf69f 647 _ => {
62682a34 648 *tcx.stability.borrow_mut().staged_api.entry(id.krate).or_insert_with(
92a42be0 649 || tcx.sess.cstore.is_staged_api(id.krate))
85aaf69f 650 }
1a4d82fc
JJ
651 }
652}
653
654/// Lookup the stability for a node, loading external crate
655/// metadata as necessary.
54a0048b 656pub fn lookup_stability<'tcx>(tcx: &TyCtxt<'tcx>, id: DefId) -> Option<&'tcx Stability> {
9cc50fc6 657 if let Some(st) = tcx.stability.borrow().stab_map.get(&id) {
62682a34
SL
658 return *st;
659 }
660
9cc50fc6
SL
661 let st = lookup_stability_uncached(tcx, id);
662 tcx.stability.borrow_mut().stab_map.insert(id, st);
62682a34
SL
663 st
664}
665
54a0048b 666pub fn lookup_deprecation<'tcx>(tcx: &TyCtxt<'tcx>, id: DefId) -> Option<Deprecation> {
9cc50fc6
SL
667 if let Some(depr) = tcx.stability.borrow().depr_map.get(&id) {
668 return depr.clone();
1a4d82fc
JJ
669 }
670
9cc50fc6
SL
671 let depr = lookup_deprecation_uncached(tcx, id);
672 tcx.stability.borrow_mut().depr_map.insert(id, depr.clone());
673 depr
674}
675
54a0048b 676fn lookup_stability_uncached<'tcx>(tcx: &TyCtxt<'tcx>, id: DefId) -> Option<&'tcx Stability> {
9cc50fc6
SL
677 debug!("lookup(id={:?})", id);
678 if id.is_local() {
62682a34 679 None // The stability cache is filled partially lazily
1a4d82fc 680 } else {
92a42be0 681 tcx.sess.cstore.stability(id).map(|st| tcx.intern_stability(st))
9cc50fc6
SL
682 }
683}
62682a34 684
54a0048b 685fn lookup_deprecation_uncached<'tcx>(tcx: &TyCtxt<'tcx>, id: DefId) -> Option<Deprecation> {
9cc50fc6
SL
686 debug!("lookup(id={:?})", id);
687 if id.is_local() {
688 None // The stability cache is filled partially lazily
689 } else {
690 tcx.sess.cstore.deprecation(id)
691 }
1a4d82fc
JJ
692}
693
85aaf69f
SL
694/// Given the list of enabled features that were not language features (i.e. that
695/// were expected to be library features), and the list of features used from
696/// libraries, identify activated features that don't exist and error about them.
697pub fn check_unused_or_stable_features(sess: &Session,
698 lib_features_used: &FnvHashMap<InternedString,
b039eaaf 699 StabilityLevel>) {
85aaf69f
SL
700 let ref declared_lib_features = sess.features.borrow().declared_lib_features;
701 let mut remaining_lib_features: FnvHashMap<InternedString, Span>
702 = declared_lib_features.clone().into_iter().collect();
703
704 let stable_msg = "this feature is stable. attribute no longer needed";
705
62682a34 706 for &span in &sess.features.borrow().declared_stable_lang_features {
85aaf69f
SL
707 sess.add_lint(lint::builtin::STABLE_FEATURES,
708 ast::CRATE_NODE_ID,
709 span,
710 stable_msg.to_string());
711 }
712
62682a34 713 for (used_lib_feature, level) in lib_features_used {
85aaf69f
SL
714 match remaining_lib_features.remove(used_lib_feature) {
715 Some(span) => {
b039eaaf 716 if *level == Stable {
85aaf69f
SL
717 sess.add_lint(lint::builtin::STABLE_FEATURES,
718 ast::CRATE_NODE_ID,
719 span,
720 stable_msg.to_string());
721 }
1a4d82fc 722 }
85aaf69f 723 None => ( /* used but undeclared, handled during the previous ast visit */ )
1a4d82fc
JJ
724 }
725 }
85aaf69f 726
62682a34 727 for &span in remaining_lib_features.values() {
85aaf69f
SL
728 sess.add_lint(lint::builtin::UNUSED_FEATURES,
729 ast::CRATE_NODE_ID,
730 span,
731 "unused or unknown feature".to_string());
732 }
1a4d82fc 733}