Add stability inheritance
This commit makes several changes to the stability index infrastructure:
* Stability levels are now inherited lexically, i.e., each item's
stability level becomes the default for any nested items.
* The computed stability level for an item is stored as part of the
metadata. When using an item from an external crate, this data is
looked up and cached.
* The stability lint works from the computed stability level, rather
than manual stability attribute annotations. However, the lint still
checks only a limited set of item uses (e.g., it does not check every
component of a path on import). This will be addressed in a later PR,
as part of issue #8962.
* The stability lint only applies to items originating from external
crates, since the stability index is intended as a promise to
downstream crates.
* The "experimental" lint is now _allow_ by default. This is because
almost all existing crates have been marked "experimental", pending
library stabilization. With inheritance in place, this would generate
a massive explosion of warnings for every Rust program.
The lint should be changed back to deny-by-default after library
stabilization is complete.
* The "deprecated" lint still warns by default.
The net result: we can begin tracking stability index for the standard
libraries as we stabilize, without impacting most clients.
Closes #13540.
2014-06-11 19:23:11 -05:00
|
|
|
// Copyright 2014 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 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
|
|
|
//! A pass that annotates every item and method with its stability level,
|
|
|
|
//! propagating default levels lexically from parent to children ast nodes.
|
|
|
|
|
2015-10-12 22:01:31 -05:00
|
|
|
pub use self::StabilityLevel::*;
|
|
|
|
|
2015-01-12 20:40:19 -06:00
|
|
|
use session::Session;
|
2015-01-16 12:25:16 -06:00
|
|
|
use lint;
|
2015-09-01 11:35:05 -05:00
|
|
|
use metadata::cstore::LOCAL_CRATE;
|
2015-02-09 18:33:19 -06:00
|
|
|
use middle::def;
|
2015-09-17 13:29:59 -05:00
|
|
|
use middle::def_id::{CRATE_DEF_INDEX, DefId};
|
2015-01-01 20:41:44 -06:00
|
|
|
use middle::ty;
|
2015-02-03 10:34:13 -06:00
|
|
|
use middle::privacy::PublicItems;
|
2015-01-01 20:41:44 -06:00
|
|
|
use metadata::csearch;
|
2015-01-14 17:20:14 -06:00
|
|
|
use syntax::parse::token::InternedString;
|
|
|
|
use syntax::codemap::{Span, DUMMY_SP};
|
2014-07-10 13:17:40 -05:00
|
|
|
use syntax::ast;
|
2015-09-14 04:58:20 -05:00
|
|
|
use syntax::ast::{NodeId, Attribute};
|
2015-09-04 18:37:22 -05:00
|
|
|
use syntax::feature_gate::{GateIssue, emit_feature_err};
|
2015-09-14 04:58:20 -05:00
|
|
|
use syntax::attr::{self, Stability, AttrMetaMethods};
|
2015-05-25 16:41:27 -05:00
|
|
|
use util::nodemap::{DefIdMap, FnvHashSet, FnvHashMap};
|
Add stability inheritance
This commit makes several changes to the stability index infrastructure:
* Stability levels are now inherited lexically, i.e., each item's
stability level becomes the default for any nested items.
* The computed stability level for an item is stored as part of the
metadata. When using an item from an external crate, this data is
looked up and cached.
* The stability lint works from the computed stability level, rather
than manual stability attribute annotations. However, the lint still
checks only a limited set of item uses (e.g., it does not check every
component of a path on import). This will be addressed in a later PR,
as part of issue #8962.
* The stability lint only applies to items originating from external
crates, since the stability index is intended as a promise to
downstream crates.
* The "experimental" lint is now _allow_ by default. This is because
almost all existing crates have been marked "experimental", pending
library stabilization. With inheritance in place, this would generate
a massive explosion of warnings for every Rust program.
The lint should be changed back to deny-by-default after library
stabilization is complete.
* The "deprecated" lint still warns by default.
The net result: we can begin tracking stability index for the standard
libraries as we stabilize, without impacting most clients.
Closes #13540.
2014-06-11 19:23:11 -05:00
|
|
|
|
2015-07-31 02:04:06 -05:00
|
|
|
use rustc_front::hir;
|
2015-09-14 04:58:20 -05:00
|
|
|
use rustc_front::hir::{FnDecl, Block, Crate, Item, Generics, StructField, Variant};
|
2015-07-31 02:04:06 -05:00
|
|
|
use rustc_front::visit::{self, FnKind, Visitor};
|
|
|
|
|
2014-09-12 05:10:30 -05:00
|
|
|
use std::mem::replace;
|
2015-06-11 19:18:46 -05:00
|
|
|
use std::cmp::Ordering;
|
2014-09-12 05:10:30 -05:00
|
|
|
|
2015-10-12 22:01:31 -05:00
|
|
|
#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Copy, Debug, Eq, Hash)]
|
|
|
|
pub enum StabilityLevel {
|
|
|
|
Unstable,
|
|
|
|
Stable,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl StabilityLevel {
|
|
|
|
pub fn from_attr_level(level: &attr::StabilityLevel) -> Self {
|
|
|
|
if level.is_stable() { Stable } else { Unstable }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Add stability inheritance
This commit makes several changes to the stability index infrastructure:
* Stability levels are now inherited lexically, i.e., each item's
stability level becomes the default for any nested items.
* The computed stability level for an item is stored as part of the
metadata. When using an item from an external crate, this data is
looked up and cached.
* The stability lint works from the computed stability level, rather
than manual stability attribute annotations. However, the lint still
checks only a limited set of item uses (e.g., it does not check every
component of a path on import). This will be addressed in a later PR,
as part of issue #8962.
* The stability lint only applies to items originating from external
crates, since the stability index is intended as a promise to
downstream crates.
* The "experimental" lint is now _allow_ by default. This is because
almost all existing crates have been marked "experimental", pending
library stabilization. With inheritance in place, this would generate
a massive explosion of warnings for every Rust program.
The lint should be changed back to deny-by-default after library
stabilization is complete.
* The "deprecated" lint still warns by default.
The net result: we can begin tracking stability index for the standard
libraries as we stabilize, without impacting most clients.
Closes #13540.
2014-06-11 19:23:11 -05:00
|
|
|
/// A stability index, giving the stability level for items and methods.
|
2015-05-25 16:41:27 -05:00
|
|
|
pub struct Index<'tcx> {
|
|
|
|
/// This is mostly a cache, except the stabilities of local items
|
|
|
|
/// are filled by the annotator.
|
|
|
|
map: DefIdMap<Option<&'tcx Stability>>,
|
|
|
|
|
|
|
|
/// Maps for each crate whether it is part of the staged API.
|
|
|
|
staged_api: FnvHashMap<ast::CrateNum, bool>
|
Add stability inheritance
This commit makes several changes to the stability index infrastructure:
* Stability levels are now inherited lexically, i.e., each item's
stability level becomes the default for any nested items.
* The computed stability level for an item is stored as part of the
metadata. When using an item from an external crate, this data is
looked up and cached.
* The stability lint works from the computed stability level, rather
than manual stability attribute annotations. However, the lint still
checks only a limited set of item uses (e.g., it does not check every
component of a path on import). This will be addressed in a later PR,
as part of issue #8962.
* The stability lint only applies to items originating from external
crates, since the stability index is intended as a promise to
downstream crates.
* The "experimental" lint is now _allow_ by default. This is because
almost all existing crates have been marked "experimental", pending
library stabilization. With inheritance in place, this would generate
a massive explosion of warnings for every Rust program.
The lint should be changed back to deny-by-default after library
stabilization is complete.
* The "deprecated" lint still warns by default.
The net result: we can begin tracking stability index for the standard
libraries as we stabilize, without impacting most clients.
Closes #13540.
2014-06-11 19:23:11 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// A private tree-walker for producing an Index.
|
2015-05-25 16:41:27 -05:00
|
|
|
struct Annotator<'a, 'tcx: 'a> {
|
|
|
|
tcx: &'a ty::ctxt<'tcx>,
|
|
|
|
index: &'a mut Index<'tcx>,
|
|
|
|
parent: Option<&'tcx Stability>,
|
2015-02-03 10:34:13 -06:00
|
|
|
export_map: &'a PublicItems,
|
Add stability inheritance
This commit makes several changes to the stability index infrastructure:
* Stability levels are now inherited lexically, i.e., each item's
stability level becomes the default for any nested items.
* The computed stability level for an item is stored as part of the
metadata. When using an item from an external crate, this data is
looked up and cached.
* The stability lint works from the computed stability level, rather
than manual stability attribute annotations. However, the lint still
checks only a limited set of item uses (e.g., it does not check every
component of a path on import). This will be addressed in a later PR,
as part of issue #8962.
* The stability lint only applies to items originating from external
crates, since the stability index is intended as a promise to
downstream crates.
* The "experimental" lint is now _allow_ by default. This is because
almost all existing crates have been marked "experimental", pending
library stabilization. With inheritance in place, this would generate
a massive explosion of warnings for every Rust program.
The lint should be changed back to deny-by-default after library
stabilization is complete.
* The "deprecated" lint still warns by default.
The net result: we can begin tracking stability index for the standard
libraries as we stabilize, without impacting most clients.
Closes #13540.
2014-06-11 19:23:11 -05:00
|
|
|
}
|
|
|
|
|
2015-05-25 16:41:27 -05:00
|
|
|
impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
|
Add stability inheritance
This commit makes several changes to the stability index infrastructure:
* Stability levels are now inherited lexically, i.e., each item's
stability level becomes the default for any nested items.
* The computed stability level for an item is stored as part of the
metadata. When using an item from an external crate, this data is
looked up and cached.
* The stability lint works from the computed stability level, rather
than manual stability attribute annotations. However, the lint still
checks only a limited set of item uses (e.g., it does not check every
component of a path on import). This will be addressed in a later PR,
as part of issue #8962.
* The stability lint only applies to items originating from external
crates, since the stability index is intended as a promise to
downstream crates.
* The "experimental" lint is now _allow_ by default. This is because
almost all existing crates have been marked "experimental", pending
library stabilization. With inheritance in place, this would generate
a massive explosion of warnings for every Rust program.
The lint should be changed back to deny-by-default after library
stabilization is complete.
* The "deprecated" lint still warns by default.
The net result: we can begin tracking stability index for the standard
libraries as we stabilize, without impacting most clients.
Closes #13540.
2014-06-11 19:23:11 -05:00
|
|
|
// Determine the stability for a node based on its attributes and inherited
|
2014-09-12 05:10:30 -05:00
|
|
|
// stability. The stability is recorded in the index and used as the parent.
|
2014-12-17 22:12:41 -06:00
|
|
|
fn annotate<F>(&mut self, id: NodeId, use_parent: bool,
|
2015-02-03 10:34:13 -06:00
|
|
|
attrs: &Vec<Attribute>, item_sp: Span, f: F, required: bool) where
|
2014-12-08 19:26:43 -06:00
|
|
|
F: FnOnce(&mut Annotator),
|
|
|
|
{
|
2015-08-16 05:32:28 -05:00
|
|
|
if self.index.staged_api[&LOCAL_CRATE] {
|
2015-04-13 20:42:24 -05:00
|
|
|
debug!("annotate(id = {:?}, attrs = {:?})", id, attrs);
|
2015-05-25 16:41:27 -05:00
|
|
|
match attr::find_stability(self.tcx.sess.diagnostic(), attrs, item_sp) {
|
2015-06-06 17:52:28 -05:00
|
|
|
Some(mut stab) => {
|
2015-04-13 20:42:24 -05:00
|
|
|
debug!("annotate: found {:?}", stab);
|
2015-06-06 17:52:28 -05:00
|
|
|
// if parent is deprecated and we're not, inherit this by merging
|
|
|
|
// deprecated_since and its reason.
|
|
|
|
if let Some(parent_stab) = self.parent {
|
2015-10-12 22:01:31 -05:00
|
|
|
if parent_stab.depr.is_some()
|
|
|
|
&& stab.depr.is_none() {
|
|
|
|
stab.depr = parent_stab.depr.clone()
|
2015-06-06 17:52:28 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-25 16:41:27 -05:00
|
|
|
let stab = self.tcx.intern_stability(stab);
|
2015-06-11 19:18:46 -05:00
|
|
|
|
|
|
|
// Check if deprecated_since < stable_since. If it is,
|
|
|
|
// this is *almost surely* an accident.
|
2015-10-12 22:01:31 -05:00
|
|
|
let deprecated_predates_stable = match (&stab.depr, &stab.level) {
|
|
|
|
(&Some(attr::Deprecation {since: ref dep_since, ..}),
|
|
|
|
&attr::Stable {since: ref stab_since}) => {
|
2015-06-11 19:18:46 -05:00
|
|
|
// explicit version of iter::order::lt to handle parse errors properly
|
|
|
|
let mut is_less = false;
|
|
|
|
for (dep_v, stab_v) in dep_since.split(".").zip(stab_since.split(".")) {
|
|
|
|
match (dep_v.parse::<u64>(), stab_v.parse::<u64>()) {
|
|
|
|
(Ok(dep_v), Ok(stab_v)) => match dep_v.cmp(&stab_v) {
|
|
|
|
Ordering::Less => {
|
|
|
|
is_less = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Ordering::Equal => { continue; }
|
|
|
|
Ordering::Greater => { break; }
|
|
|
|
},
|
|
|
|
_ => {
|
|
|
|
self.tcx.sess.span_err(item_sp,
|
|
|
|
"Invalid stability or deprecation version found");
|
|
|
|
// act like it isn't less because the question is now
|
|
|
|
// nonsensical, and this makes us not do anything else
|
|
|
|
// interesting.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
is_less
|
|
|
|
},
|
|
|
|
_ => false,
|
|
|
|
};
|
|
|
|
|
|
|
|
if deprecated_predates_stable {
|
|
|
|
self.tcx.sess.span_err(item_sp,
|
|
|
|
"An API can't be stabilized after it is deprecated");
|
|
|
|
}
|
|
|
|
|
2015-09-02 15:11:32 -05:00
|
|
|
let def_id = self.tcx.map.local_def_id(id);
|
|
|
|
self.index.map.insert(def_id, Some(stab));
|
2015-04-13 20:42:24 -05:00
|
|
|
|
|
|
|
// Don't inherit #[stable(feature = "rust1", since = "1.0.0")]
|
2015-10-12 22:01:31 -05:00
|
|
|
if !stab.level.is_stable() {
|
2015-04-13 20:42:24 -05:00
|
|
|
let parent = replace(&mut self.parent, Some(stab));
|
|
|
|
f(self);
|
|
|
|
self.parent = parent;
|
|
|
|
} else {
|
|
|
|
f(self);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
debug!("annotate: not found, use_parent = {:?}, parent = {:?}",
|
|
|
|
use_parent, self.parent);
|
|
|
|
if use_parent {
|
2015-05-25 16:41:27 -05:00
|
|
|
if let Some(stab) = self.parent {
|
2015-09-02 15:11:32 -05:00
|
|
|
let def_id = self.tcx.map.local_def_id(id);
|
|
|
|
self.index.map.insert(def_id, Some(stab));
|
2015-08-16 05:32:28 -05:00
|
|
|
} else if self.index.staged_api[&LOCAL_CRATE] && required
|
2015-04-13 20:42:24 -05:00
|
|
|
&& self.export_map.contains(&id)
|
2015-05-25 16:41:27 -05:00
|
|
|
&& !self.tcx.sess.opts.test {
|
|
|
|
self.tcx.sess.span_err(item_sp,
|
|
|
|
"This node does not \
|
|
|
|
have a stability attribute");
|
2015-04-13 20:42:24 -05:00
|
|
|
}
|
|
|
|
}
|
2014-11-11 14:46:47 -06:00
|
|
|
f(self);
|
|
|
|
}
|
2014-09-12 05:10:30 -05:00
|
|
|
}
|
2015-04-13 20:42:24 -05:00
|
|
|
} else {
|
|
|
|
// Emit warnings for non-staged-api crates. These should be errors.
|
|
|
|
for attr in attrs {
|
|
|
|
let tag = attr.name();
|
|
|
|
if tag == "unstable" || tag == "stable" || tag == "deprecated" {
|
|
|
|
attr::mark_used(attr);
|
2015-05-25 16:41:27 -05:00
|
|
|
self.tcx.sess.span_err(attr.span(),
|
2015-04-20 19:00:35 -05:00
|
|
|
"stability attributes may not be used outside \
|
|
|
|
of the standard library");
|
2014-12-17 22:12:41 -06:00
|
|
|
}
|
Add stability inheritance
This commit makes several changes to the stability index infrastructure:
* Stability levels are now inherited lexically, i.e., each item's
stability level becomes the default for any nested items.
* The computed stability level for an item is stored as part of the
metadata. When using an item from an external crate, this data is
looked up and cached.
* The stability lint works from the computed stability level, rather
than manual stability attribute annotations. However, the lint still
checks only a limited set of item uses (e.g., it does not check every
component of a path on import). This will be addressed in a later PR,
as part of issue #8962.
* The stability lint only applies to items originating from external
crates, since the stability index is intended as a promise to
downstream crates.
* The "experimental" lint is now _allow_ by default. This is because
almost all existing crates have been marked "experimental", pending
library stabilization. With inheritance in place, this would generate
a massive explosion of warnings for every Rust program.
The lint should be changed back to deny-by-default after library
stabilization is complete.
* The "deprecated" lint still warns by default.
The net result: we can begin tracking stability index for the standard
libraries as we stabilize, without impacting most clients.
Closes #13540.
2014-06-11 19:23:11 -05:00
|
|
|
}
|
2015-04-13 20:42:24 -05:00
|
|
|
f(self);
|
Add stability inheritance
This commit makes several changes to the stability index infrastructure:
* Stability levels are now inherited lexically, i.e., each item's
stability level becomes the default for any nested items.
* The computed stability level for an item is stored as part of the
metadata. When using an item from an external crate, this data is
looked up and cached.
* The stability lint works from the computed stability level, rather
than manual stability attribute annotations. However, the lint still
checks only a limited set of item uses (e.g., it does not check every
component of a path on import). This will be addressed in a later PR,
as part of issue #8962.
* The stability lint only applies to items originating from external
crates, since the stability index is intended as a promise to
downstream crates.
* The "experimental" lint is now _allow_ by default. This is because
almost all existing crates have been marked "experimental", pending
library stabilization. With inheritance in place, this would generate
a massive explosion of warnings for every Rust program.
The lint should be changed back to deny-by-default after library
stabilization is complete.
* The "deprecated" lint still warns by default.
The net result: we can begin tracking stability index for the standard
libraries as we stabilize, without impacting most clients.
Closes #13540.
2014-06-11 19:23:11 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-25 16:41:27 -05:00
|
|
|
impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> {
|
2014-09-12 05:10:30 -05:00
|
|
|
fn visit_item(&mut self, i: &Item) {
|
2014-12-17 22:12:41 -06:00
|
|
|
// FIXME (#18969): the following is a hack around the fact
|
|
|
|
// that we cannot currently annotate the stability of
|
|
|
|
// `deriving`. Basically, we do *not* allow stability
|
|
|
|
// inheritance on trait implementations, so that derived
|
|
|
|
// implementations appear to be unannotated. This then allows
|
|
|
|
// derived implementations to be automatically tagged with the
|
|
|
|
// stability of the trait. This is WRONG, but expedient to get
|
|
|
|
// libstd stabilized for the 1.0 release.
|
|
|
|
let use_parent = match i.node {
|
2015-07-31 02:04:06 -05:00
|
|
|
hir::ItemImpl(_, _, _, Some(_), _, _) => false,
|
2014-12-17 22:12:41 -06:00
|
|
|
_ => true,
|
|
|
|
};
|
|
|
|
|
2015-02-03 10:34:13 -06:00
|
|
|
// In case of a `pub use <mod>;`, we should not error since the stability
|
|
|
|
// is inherited from the module itself
|
|
|
|
let required = match i.node {
|
2015-07-31 02:04:06 -05:00
|
|
|
hir::ItemUse(_) => i.vis != hir::Public,
|
2015-02-03 10:34:13 -06:00
|
|
|
_ => true
|
|
|
|
};
|
|
|
|
|
|
|
|
self.annotate(i.id, use_parent, &i.attrs, i.span,
|
|
|
|
|v| visit::walk_item(v, i), required);
|
2014-11-11 14:46:47 -06:00
|
|
|
|
2015-07-31 02:04:06 -05:00
|
|
|
if let hir::ItemStruct(ref sd, _) = i.node {
|
2014-11-29 15:41:21 -06:00
|
|
|
sd.ctor_id.map(|id| {
|
2015-02-03 10:34:13 -06:00
|
|
|
self.annotate(id, true, &i.attrs, i.span, |_| {}, true)
|
2014-11-29 15:41:21 -06:00
|
|
|
});
|
2014-11-11 14:46:47 -06:00
|
|
|
}
|
Add stability inheritance
This commit makes several changes to the stability index infrastructure:
* Stability levels are now inherited lexically, i.e., each item's
stability level becomes the default for any nested items.
* The computed stability level for an item is stored as part of the
metadata. When using an item from an external crate, this data is
looked up and cached.
* The stability lint works from the computed stability level, rather
than manual stability attribute annotations. However, the lint still
checks only a limited set of item uses (e.g., it does not check every
component of a path on import). This will be addressed in a later PR,
as part of issue #8962.
* The stability lint only applies to items originating from external
crates, since the stability index is intended as a promise to
downstream crates.
* The "experimental" lint is now _allow_ by default. This is because
almost all existing crates have been marked "experimental", pending
library stabilization. With inheritance in place, this would generate
a massive explosion of warnings for every Rust program.
The lint should be changed back to deny-by-default after library
stabilization is complete.
* The "deprecated" lint still warns by default.
The net result: we can begin tracking stability index for the standard
libraries as we stabilize, without impacting most clients.
Closes #13540.
2014-06-11 19:23:11 -05:00
|
|
|
}
|
|
|
|
|
2015-03-10 05:28:44 -05:00
|
|
|
fn visit_fn(&mut self, _: FnKind<'v>, _: &'v FnDecl,
|
|
|
|
_: &'v Block, _: Span, _: NodeId) {
|
2014-11-17 04:37:07 -06:00
|
|
|
// Items defined in a function body have no reason to have
|
|
|
|
// a stability attribute, so we don't recurse.
|
Add stability inheritance
This commit makes several changes to the stability index infrastructure:
* Stability levels are now inherited lexically, i.e., each item's
stability level becomes the default for any nested items.
* The computed stability level for an item is stored as part of the
metadata. When using an item from an external crate, this data is
looked up and cached.
* The stability lint works from the computed stability level, rather
than manual stability attribute annotations. However, the lint still
checks only a limited set of item uses (e.g., it does not check every
component of a path on import). This will be addressed in a later PR,
as part of issue #8962.
* The stability lint only applies to items originating from external
crates, since the stability index is intended as a promise to
downstream crates.
* The "experimental" lint is now _allow_ by default. This is because
almost all existing crates have been marked "experimental", pending
library stabilization. With inheritance in place, this would generate
a massive explosion of warnings for every Rust program.
The lint should be changed back to deny-by-default after library
stabilization is complete.
* The "deprecated" lint still warns by default.
The net result: we can begin tracking stability index for the standard
libraries as we stabilize, without impacting most clients.
Closes #13540.
2014-06-11 19:23:11 -05:00
|
|
|
}
|
|
|
|
|
2015-07-31 02:04:06 -05:00
|
|
|
fn visit_trait_item(&mut self, ti: &hir::TraitItem) {
|
2015-03-10 05:28:44 -05:00
|
|
|
self.annotate(ti.id, true, &ti.attrs, ti.span,
|
|
|
|
|v| visit::walk_trait_item(v, ti), true);
|
|
|
|
}
|
2014-08-05 21:44:21 -05:00
|
|
|
|
2015-07-31 02:04:06 -05:00
|
|
|
fn visit_impl_item(&mut self, ii: &hir::ImplItem) {
|
2015-03-10 05:28:44 -05:00
|
|
|
self.annotate(ii.id, true, &ii.attrs, ii.span,
|
|
|
|
|v| visit::walk_impl_item(v, ii), true);
|
Add stability inheritance
This commit makes several changes to the stability index infrastructure:
* Stability levels are now inherited lexically, i.e., each item's
stability level becomes the default for any nested items.
* The computed stability level for an item is stored as part of the
metadata. When using an item from an external crate, this data is
looked up and cached.
* The stability lint works from the computed stability level, rather
than manual stability attribute annotations. However, the lint still
checks only a limited set of item uses (e.g., it does not check every
component of a path on import). This will be addressed in a later PR,
as part of issue #8962.
* The stability lint only applies to items originating from external
crates, since the stability index is intended as a promise to
downstream crates.
* The "experimental" lint is now _allow_ by default. This is because
almost all existing crates have been marked "experimental", pending
library stabilization. With inheritance in place, this would generate
a massive explosion of warnings for every Rust program.
The lint should be changed back to deny-by-default after library
stabilization is complete.
* The "deprecated" lint still warns by default.
The net result: we can begin tracking stability index for the standard
libraries as we stabilize, without impacting most clients.
Closes #13540.
2014-06-11 19:23:11 -05:00
|
|
|
}
|
|
|
|
|
2014-09-09 17:54:36 -05:00
|
|
|
fn visit_variant(&mut self, var: &Variant, g: &'v Generics) {
|
2015-01-22 14:33:46 -06:00
|
|
|
self.annotate(var.node.id, true, &var.node.attrs, var.span,
|
2015-02-03 10:34:13 -06:00
|
|
|
|v| visit::walk_variant(v, var, g), true)
|
Add stability inheritance
This commit makes several changes to the stability index infrastructure:
* Stability levels are now inherited lexically, i.e., each item's
stability level becomes the default for any nested items.
* The computed stability level for an item is stored as part of the
metadata. When using an item from an external crate, this data is
looked up and cached.
* The stability lint works from the computed stability level, rather
than manual stability attribute annotations. However, the lint still
checks only a limited set of item uses (e.g., it does not check every
component of a path on import). This will be addressed in a later PR,
as part of issue #8962.
* The stability lint only applies to items originating from external
crates, since the stability index is intended as a promise to
downstream crates.
* The "experimental" lint is now _allow_ by default. This is because
almost all existing crates have been marked "experimental", pending
library stabilization. With inheritance in place, this would generate
a massive explosion of warnings for every Rust program.
The lint should be changed back to deny-by-default after library
stabilization is complete.
* The "deprecated" lint still warns by default.
The net result: we can begin tracking stability index for the standard
libraries as we stabilize, without impacting most clients.
Closes #13540.
2014-06-11 19:23:11 -05:00
|
|
|
}
|
|
|
|
|
2014-09-12 05:10:30 -05:00
|
|
|
fn visit_struct_field(&mut self, s: &StructField) {
|
2015-01-22 14:33:46 -06:00
|
|
|
self.annotate(s.node.id, true, &s.node.attrs, s.span,
|
2015-02-03 10:34:13 -06:00
|
|
|
|v| visit::walk_struct_field(v, s), true);
|
2014-07-10 13:17:40 -05:00
|
|
|
}
|
2014-12-20 12:08:16 -06:00
|
|
|
|
2015-07-31 02:04:06 -05:00
|
|
|
fn visit_foreign_item(&mut self, i: &hir::ForeignItem) {
|
2015-02-03 10:34:13 -06:00
|
|
|
self.annotate(i.id, true, &i.attrs, i.span, |_| {}, true);
|
2014-12-20 12:08:16 -06:00
|
|
|
}
|
Add stability inheritance
This commit makes several changes to the stability index infrastructure:
* Stability levels are now inherited lexically, i.e., each item's
stability level becomes the default for any nested items.
* The computed stability level for an item is stored as part of the
metadata. When using an item from an external crate, this data is
looked up and cached.
* The stability lint works from the computed stability level, rather
than manual stability attribute annotations. However, the lint still
checks only a limited set of item uses (e.g., it does not check every
component of a path on import). This will be addressed in a later PR,
as part of issue #8962.
* The stability lint only applies to items originating from external
crates, since the stability index is intended as a promise to
downstream crates.
* The "experimental" lint is now _allow_ by default. This is because
almost all existing crates have been marked "experimental", pending
library stabilization. With inheritance in place, this would generate
a massive explosion of warnings for every Rust program.
The lint should be changed back to deny-by-default after library
stabilization is complete.
* The "deprecated" lint still warns by default.
The net result: we can begin tracking stability index for the standard
libraries as we stabilize, without impacting most clients.
Closes #13540.
2014-06-11 19:23:11 -05:00
|
|
|
}
|
|
|
|
|
2015-05-25 16:41:27 -05:00
|
|
|
impl<'tcx> Index<'tcx> {
|
Add stability inheritance
This commit makes several changes to the stability index infrastructure:
* Stability levels are now inherited lexically, i.e., each item's
stability level becomes the default for any nested items.
* The computed stability level for an item is stored as part of the
metadata. When using an item from an external crate, this data is
looked up and cached.
* The stability lint works from the computed stability level, rather
than manual stability attribute annotations. However, the lint still
checks only a limited set of item uses (e.g., it does not check every
component of a path on import). This will be addressed in a later PR,
as part of issue #8962.
* The stability lint only applies to items originating from external
crates, since the stability index is intended as a promise to
downstream crates.
* The "experimental" lint is now _allow_ by default. This is because
almost all existing crates have been marked "experimental", pending
library stabilization. With inheritance in place, this would generate
a massive explosion of warnings for every Rust program.
The lint should be changed back to deny-by-default after library
stabilization is complete.
* The "deprecated" lint still warns by default.
The net result: we can begin tracking stability index for the standard
libraries as we stabilize, without impacting most clients.
Closes #13540.
2014-06-11 19:23:11 -05:00
|
|
|
/// Construct the stability index for a crate being compiled.
|
2015-05-25 16:41:27 -05:00
|
|
|
pub fn build(&mut self, tcx: &ty::ctxt<'tcx>, krate: &Crate, export_map: &PublicItems) {
|
2015-02-03 09:46:08 -06:00
|
|
|
let mut annotator = Annotator {
|
2015-05-25 16:41:27 -05:00
|
|
|
tcx: tcx,
|
2015-02-03 09:46:08 -06:00
|
|
|
index: self,
|
2015-02-03 10:34:13 -06:00
|
|
|
parent: None,
|
|
|
|
export_map: export_map,
|
2015-02-03 09:46:08 -06:00
|
|
|
};
|
|
|
|
annotator.annotate(ast::CRATE_NODE_ID, true, &krate.attrs, krate.span,
|
2015-02-03 10:34:13 -06:00
|
|
|
|v| visit::walk_crate(v, krate), true);
|
2015-02-03 09:46:08 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn new(krate: &Crate) -> Index {
|
2015-05-25 16:41:27 -05:00
|
|
|
let mut is_staged_api = false;
|
2015-01-31 11:20:46 -06:00
|
|
|
for attr in &krate.attrs {
|
2015-02-20 13:08:14 -06:00
|
|
|
if &attr.name()[..] == "staged_api" {
|
2015-01-12 20:40:19 -06:00
|
|
|
match attr.node.value.node {
|
2015-09-14 04:58:20 -05:00
|
|
|
ast::MetaWord(_) => {
|
2015-01-12 20:40:19 -06:00
|
|
|
attr::mark_used(attr);
|
2015-05-25 16:41:27 -05:00
|
|
|
is_staged_api = true;
|
2015-01-12 20:40:19 -06:00
|
|
|
}
|
|
|
|
_ => (/*pass*/)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-05-25 16:41:27 -05:00
|
|
|
let mut staged_api = FnvHashMap();
|
2015-08-16 05:32:28 -05:00
|
|
|
staged_api.insert(LOCAL_CRATE, is_staged_api);
|
2015-02-03 09:46:08 -06:00
|
|
|
Index {
|
2015-01-12 20:40:19 -06:00
|
|
|
staged_api: staged_api,
|
2015-05-25 16:41:27 -05:00
|
|
|
map: DefIdMap(),
|
2015-01-12 20:40:19 -06:00
|
|
|
}
|
Add stability inheritance
This commit makes several changes to the stability index infrastructure:
* Stability levels are now inherited lexically, i.e., each item's
stability level becomes the default for any nested items.
* The computed stability level for an item is stored as part of the
metadata. When using an item from an external crate, this data is
looked up and cached.
* The stability lint works from the computed stability level, rather
than manual stability attribute annotations. However, the lint still
checks only a limited set of item uses (e.g., it does not check every
component of a path on import). This will be addressed in a later PR,
as part of issue #8962.
* The stability lint only applies to items originating from external
crates, since the stability index is intended as a promise to
downstream crates.
* The "experimental" lint is now _allow_ by default. This is because
almost all existing crates have been marked "experimental", pending
library stabilization. With inheritance in place, this would generate
a massive explosion of warnings for every Rust program.
The lint should be changed back to deny-by-default after library
stabilization is complete.
* The "deprecated" lint still warns by default.
The net result: we can begin tracking stability index for the standard
libraries as we stabilize, without impacting most clients.
Closes #13540.
2014-06-11 19:23:11 -05:00
|
|
|
}
|
2014-06-26 13:37:39 -05:00
|
|
|
}
|
Add stability inheritance
This commit makes several changes to the stability index infrastructure:
* Stability levels are now inherited lexically, i.e., each item's
stability level becomes the default for any nested items.
* The computed stability level for an item is stored as part of the
metadata. When using an item from an external crate, this data is
looked up and cached.
* The stability lint works from the computed stability level, rather
than manual stability attribute annotations. However, the lint still
checks only a limited set of item uses (e.g., it does not check every
component of a path on import). This will be addressed in a later PR,
as part of issue #8962.
* The stability lint only applies to items originating from external
crates, since the stability index is intended as a promise to
downstream crates.
* The "experimental" lint is now _allow_ by default. This is because
almost all existing crates have been marked "experimental", pending
library stabilization. With inheritance in place, this would generate
a massive explosion of warnings for every Rust program.
The lint should be changed back to deny-by-default after library
stabilization is complete.
* The "deprecated" lint still warns by default.
The net result: we can begin tracking stability index for the standard
libraries as we stabilize, without impacting most clients.
Closes #13540.
2014-06-11 19:23:11 -05:00
|
|
|
|
2015-01-14 17:20:14 -06:00
|
|
|
/// Cross-references the feature names of unstable APIs with enabled
|
|
|
|
/// features and possibly prints errors. Returns a list of all
|
|
|
|
/// features used.
|
2015-02-02 22:25:42 -06:00
|
|
|
pub fn check_unstable_api_usage(tcx: &ty::ctxt)
|
2015-10-12 22:01:31 -05:00
|
|
|
-> FnvHashMap<InternedString, StabilityLevel> {
|
2015-02-02 22:25:42 -06:00
|
|
|
let ref active_lib_features = tcx.sess.features.borrow().declared_lib_features;
|
2015-01-14 17:20:14 -06:00
|
|
|
|
|
|
|
// 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,
|
2015-09-28 19:46:01 -05:00
|
|
|
used_features: FnvHashMap(),
|
|
|
|
in_skip_block: 0,
|
2015-01-14 17:20:14 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
let krate = tcx.map.krate();
|
|
|
|
visit::walk_crate(&mut checker, krate);
|
|
|
|
|
|
|
|
let used_features = checker.used_features;
|
|
|
|
return used_features;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Checker<'a, 'tcx: 'a> {
|
|
|
|
tcx: &'a ty::ctxt<'tcx>,
|
|
|
|
active_features: FnvHashSet<InternedString>,
|
2015-10-12 22:01:31 -05:00
|
|
|
used_features: FnvHashMap<InternedString, StabilityLevel>,
|
2015-09-28 19:46:01 -05:00
|
|
|
// Within a block where feature gate checking can be skipped.
|
|
|
|
in_skip_block: u32,
|
2015-01-14 17:20:14 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, 'tcx> Checker<'a, 'tcx> {
|
2015-08-16 05:32:28 -05:00
|
|
|
fn check(&mut self, id: DefId, span: Span, stab: &Option<&Stability>) {
|
2015-01-14 17:20:14 -06:00
|
|
|
// Only the cross-crate scenario matters when checking unstable APIs
|
2015-08-16 05:32:28 -05:00
|
|
|
let cross_crate = !id.is_local();
|
2015-09-28 19:46:01 -05:00
|
|
|
if !cross_crate {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// We don't need to check for stability - presumably compiler generated code.
|
|
|
|
if self.in_skip_block > 0 {
|
|
|
|
return;
|
|
|
|
}
|
2015-01-14 17:20:14 -06:00
|
|
|
|
|
|
|
match *stab {
|
2015-10-12 22:01:31 -05:00
|
|
|
Some(&Stability { level: attr::Unstable {ref reason, issue}, ref feature, .. }) => {
|
|
|
|
self.used_features.insert(feature.clone(), Unstable);
|
2015-01-14 17:20:14 -06:00
|
|
|
|
|
|
|
if !self.active_features.contains(feature) {
|
2015-09-04 18:37:22 -05:00
|
|
|
let msg = match *reason {
|
2015-01-14 17:20:14 -06:00
|
|
|
Some(ref r) => format!("use of unstable library feature '{}': {}",
|
2015-02-04 14:48:12 -06:00
|
|
|
&feature, &r),
|
|
|
|
None => format!("use of unstable library feature '{}'", &feature)
|
2015-01-14 17:20:14 -06:00
|
|
|
};
|
2015-03-05 20:33:58 -06:00
|
|
|
emit_feature_err(&self.tcx.sess.parse_sess.span_diagnostic,
|
2015-10-12 22:01:31 -05:00
|
|
|
&feature, span, GateIssue::Library(Some(issue)), &msg);
|
2015-01-14 17:20:14 -06:00
|
|
|
}
|
|
|
|
}
|
2015-10-12 22:01:31 -05:00
|
|
|
Some(&Stability { ref level, ref feature, .. }) => {
|
|
|
|
self.used_features.insert(feature.clone(), StabilityLevel::from_attr_level(level));
|
2015-02-02 22:25:42 -06:00
|
|
|
|
2015-01-14 17:20:14 -06:00
|
|
|
// Stable APIs are always ok to call and deprecated APIs are
|
|
|
|
// handled by a lint.
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
// This is an 'unmarked' API, which should not exist
|
|
|
|
// in the standard library.
|
2015-02-03 13:51:26 -06:00
|
|
|
if self.tcx.sess.features.borrow().unmarked_api {
|
|
|
|
self.tcx.sess.span_warn(span, "use of unmarked library feature");
|
|
|
|
self.tcx.sess.span_note(span, "this is either a bug in the library you are \
|
2015-02-17 12:42:31 -06:00
|
|
|
using or a bug in the compiler - please \
|
2015-02-03 13:51:26 -06:00
|
|
|
report it in both places");
|
|
|
|
} else {
|
|
|
|
self.tcx.sess.span_err(span, "use of unmarked library feature");
|
|
|
|
self.tcx.sess.span_note(span, "this is either a bug in the library you are \
|
2015-02-17 12:42:31 -06:00
|
|
|
using or a bug in the compiler - please \
|
2015-02-03 13:51:26 -06:00
|
|
|
report it in both places");
|
|
|
|
self.tcx.sess.span_note(span, "use #![feature(unmarked_api)] in the \
|
|
|
|
crate attributes to override this");
|
|
|
|
}
|
2015-01-14 17:20:14 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> {
|
2015-07-31 02:04:06 -05:00
|
|
|
fn visit_item(&mut self, item: &hir::Item) {
|
2015-02-09 18:33:19 -06:00
|
|
|
// When compiling with --test we don't enforce stability on the
|
|
|
|
// compiler-generated test module, demarcated with `DUMMY_SP` plus the
|
|
|
|
// name `__test`
|
2015-09-24 15:05:02 -05:00
|
|
|
if item.span == DUMMY_SP && item.name.as_str() == "__test" { return }
|
2015-02-09 18:33:19 -06:00
|
|
|
|
2015-02-17 15:56:06 -06:00
|
|
|
check_item(self.tcx, item, true,
|
2015-01-14 17:20:14 -06:00
|
|
|
&mut |id, sp, stab| self.check(id, sp, stab));
|
|
|
|
visit::walk_item(self, item);
|
|
|
|
}
|
|
|
|
|
2015-07-31 02:04:06 -05:00
|
|
|
fn visit_expr(&mut self, ex: &hir::Expr) {
|
2015-01-14 17:20:14 -06:00
|
|
|
check_expr(self.tcx, ex,
|
|
|
|
&mut |id, sp, stab| self.check(id, sp, stab));
|
|
|
|
visit::walk_expr(self, ex);
|
|
|
|
}
|
2015-02-09 18:33:19 -06:00
|
|
|
|
2015-07-31 02:04:06 -05:00
|
|
|
fn visit_path(&mut self, path: &hir::Path, id: ast::NodeId) {
|
2015-02-09 18:33:19 -06:00
|
|
|
check_path(self.tcx, path, id,
|
|
|
|
&mut |id, sp, stab| self.check(id, sp, stab));
|
|
|
|
visit::walk_path(self, path)
|
|
|
|
}
|
2015-02-25 05:34:21 -06:00
|
|
|
|
2015-09-12 08:10:12 -05:00
|
|
|
fn visit_path_list_item(&mut self, prefix: &hir::Path, item: &hir::PathListItem) {
|
|
|
|
check_path_list_item(self.tcx, item,
|
|
|
|
&mut |id, sp, stab| self.check(id, sp, stab));
|
|
|
|
visit::walk_path_list_item(self, prefix, item)
|
|
|
|
}
|
|
|
|
|
2015-07-31 02:04:06 -05:00
|
|
|
fn visit_pat(&mut self, pat: &hir::Pat) {
|
2015-02-25 05:34:21 -06:00
|
|
|
check_pat(self.tcx, pat,
|
|
|
|
&mut |id, sp, stab| self.check(id, sp, stab));
|
|
|
|
visit::walk_pat(self, pat)
|
|
|
|
}
|
2015-09-28 19:46:01 -05:00
|
|
|
|
|
|
|
fn visit_block(&mut self, b: &hir::Block) {
|
|
|
|
let old_skip_count = self.in_skip_block;
|
|
|
|
match b.rules {
|
|
|
|
hir::BlockCheckMode::PushUnstableBlock => {
|
|
|
|
self.in_skip_block += 1;
|
|
|
|
}
|
|
|
|
hir::BlockCheckMode::PopUnstableBlock => {
|
|
|
|
self.in_skip_block = self.in_skip_block.checked_sub(1).unwrap();
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
visit::walk_block(self, b);
|
|
|
|
self.in_skip_block = old_skip_count;
|
|
|
|
}
|
2015-01-14 17:20:14 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Helper for discovering nodes to check for stability
|
2015-07-31 02:04:06 -05:00
|
|
|
pub fn check_item(tcx: &ty::ctxt, item: &hir::Item, warn_about_defns: bool,
|
2015-08-16 05:32:28 -05:00
|
|
|
cb: &mut FnMut(DefId, Span, &Option<&Stability>)) {
|
2015-01-24 11:15:42 -06:00
|
|
|
match item.node {
|
2015-07-31 02:04:06 -05:00
|
|
|
hir::ItemExternCrate(_) => {
|
2015-01-24 11:15:42 -06:00
|
|
|
// compiler-generated `extern crate` items have a dummy span.
|
|
|
|
if item.span == DUMMY_SP { return }
|
|
|
|
|
|
|
|
let cnum = match tcx.sess.cstore.find_extern_mod_stmt_cnum(item.id) {
|
|
|
|
Some(cnum) => cnum,
|
|
|
|
None => return,
|
|
|
|
};
|
2015-09-17 13:29:59 -05:00
|
|
|
let id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
|
2015-01-24 11:15:42 -06:00
|
|
|
maybe_do_stability_check(tcx, id, item.span, cb);
|
|
|
|
}
|
2015-02-17 15:56:06 -06:00
|
|
|
|
|
|
|
// For implementations of traits, check the stability of each item
|
|
|
|
// individually as it's possible to have a stable trait with unstable
|
|
|
|
// items.
|
2015-07-31 02:04:06 -05:00
|
|
|
hir::ItemImpl(_, _, _, Some(ref t), _, ref impl_items) => {
|
2015-03-21 20:15:47 -05:00
|
|
|
let trait_did = tcx.def_map.borrow().get(&t.ref_id).unwrap().def_id();
|
2015-06-25 15:42:17 -05:00
|
|
|
let trait_items = tcx.trait_items(trait_did);
|
2015-02-17 15:56:06 -06:00
|
|
|
|
|
|
|
for impl_item in impl_items {
|
|
|
|
let item = trait_items.iter().find(|item| {
|
2015-09-19 20:50:30 -05:00
|
|
|
item.name() == impl_item.name
|
2015-02-17 15:56:06 -06:00
|
|
|
}).unwrap();
|
|
|
|
if warn_about_defns {
|
2015-03-10 05:28:44 -05:00
|
|
|
maybe_do_stability_check(tcx, item.def_id(), impl_item.span, cb);
|
2015-02-17 15:56:06 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-24 11:15:42 -06:00
|
|
|
_ => (/* pass */)
|
|
|
|
}
|
2015-01-14 17:20:14 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Helper for discovering nodes to check for stability
|
2015-07-31 02:04:06 -05:00
|
|
|
pub fn check_expr(tcx: &ty::ctxt, e: &hir::Expr,
|
2015-08-16 05:32:28 -05:00
|
|
|
cb: &mut FnMut(DefId, Span, &Option<&Stability>)) {
|
2015-02-09 18:33:19 -06:00
|
|
|
let span;
|
2015-01-14 17:20:14 -06:00
|
|
|
let id = match e.node {
|
2015-07-31 02:04:06 -05:00
|
|
|
hir::ExprMethodCall(i, _, _) => {
|
2015-01-14 17:20:14 -06:00
|
|
|
span = i.span;
|
|
|
|
let method_call = ty::MethodCall::expr(e.id);
|
2015-07-03 23:07:10 -05:00
|
|
|
tcx.tables.borrow().method_map[&method_call].def_id
|
2015-01-14 17:20:14 -06:00
|
|
|
}
|
2015-07-31 02:04:06 -05:00
|
|
|
hir::ExprField(ref base_e, ref field) => {
|
2015-02-25 05:34:21 -06:00
|
|
|
span = field.span;
|
2015-06-25 15:42:17 -05:00
|
|
|
match tcx.expr_ty_adjusted(base_e).sty {
|
2015-09-20 06:00:18 -05:00
|
|
|
ty::TyStruct(def, _) => def.struct_variant().field_named(field.node).did,
|
2015-02-25 05:34:21 -06:00
|
|
|
_ => tcx.sess.span_bug(e.span,
|
|
|
|
"stability::check_expr: named field access on non-struct")
|
|
|
|
}
|
|
|
|
}
|
2015-07-31 02:04:06 -05:00
|
|
|
hir::ExprTupField(ref base_e, ref field) => {
|
2015-02-25 05:34:21 -06:00
|
|
|
span = field.span;
|
2015-06-25 15:42:17 -05:00
|
|
|
match tcx.expr_ty_adjusted(base_e).sty {
|
2015-08-02 14:52:50 -05:00
|
|
|
ty::TyStruct(def, _) => def.struct_variant().fields[field.node].did,
|
2015-06-11 18:21:46 -05:00
|
|
|
ty::TyTuple(..) => return,
|
2015-02-25 05:34:21 -06:00
|
|
|
_ => tcx.sess.span_bug(e.span,
|
|
|
|
"stability::check_expr: unnamed field access on \
|
|
|
|
something other than a tuple or struct")
|
|
|
|
}
|
|
|
|
}
|
2015-07-31 02:04:06 -05:00
|
|
|
hir::ExprStruct(_, ref expr_fields, _) => {
|
2015-06-25 15:42:17 -05:00
|
|
|
let type_ = tcx.expr_ty(e);
|
2015-02-25 05:34:21 -06:00
|
|
|
match type_.sty {
|
2015-07-20 14:13:36 -05:00
|
|
|
ty::TyStruct(def, _) => {
|
2015-02-25 05:34:21 -06:00
|
|
|
// check the stability of each field that appears
|
|
|
|
// in the construction expression.
|
|
|
|
for field in expr_fields {
|
2015-08-02 14:52:50 -05:00
|
|
|
let did = def.struct_variant()
|
2015-09-20 06:00:18 -05:00
|
|
|
.field_named(field.name.node)
|
2015-08-02 14:52:50 -05:00
|
|
|
.did;
|
2015-02-25 05:34:21 -06:00
|
|
|
maybe_do_stability_check(tcx, did, field.span, cb);
|
|
|
|
}
|
|
|
|
|
|
|
|
// we're done.
|
|
|
|
return
|
|
|
|
}
|
|
|
|
// we don't look at stability attributes on
|
|
|
|
// struct-like enums (yet...), but it's definitely not
|
|
|
|
// a bug to have construct one.
|
2015-06-11 18:21:46 -05:00
|
|
|
ty::TyEnum(..) => return,
|
2015-02-25 05:34:21 -06:00
|
|
|
_ => {
|
|
|
|
tcx.sess.span_bug(e.span,
|
|
|
|
&format!("stability::check_expr: struct construction \
|
|
|
|
of non-struct, type {:?}",
|
2015-06-18 12:25:05 -05:00
|
|
|
type_));
|
2015-02-25 05:34:21 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-01-14 17:20:14 -06:00
|
|
|
_ => return
|
|
|
|
};
|
|
|
|
|
|
|
|
maybe_do_stability_check(tcx, id, span, cb);
|
|
|
|
}
|
|
|
|
|
2015-07-31 02:04:06 -05:00
|
|
|
pub fn check_path(tcx: &ty::ctxt, path: &hir::Path, id: ast::NodeId,
|
2015-08-16 05:32:28 -05:00
|
|
|
cb: &mut FnMut(DefId, Span, &Option<&Stability>)) {
|
2015-02-16 22:44:23 -06:00
|
|
|
match tcx.def_map.borrow().get(&id).map(|d| d.full_def()) {
|
|
|
|
Some(def::DefPrimTy(..)) => {}
|
2015-09-08 09:08:30 -05:00
|
|
|
Some(def::DefSelfTy(..)) => {}
|
2015-02-16 22:44:23 -06:00
|
|
|
Some(def) => {
|
|
|
|
maybe_do_stability_check(tcx, def.def_id(), path.span, cb);
|
|
|
|
}
|
|
|
|
None => {}
|
|
|
|
}
|
2015-09-12 08:10:12 -05:00
|
|
|
}
|
2015-02-16 22:44:23 -06:00
|
|
|
|
2015-09-12 08:10:12 -05:00
|
|
|
pub fn check_path_list_item(tcx: &ty::ctxt, item: &hir::PathListItem,
|
|
|
|
cb: &mut FnMut(DefId, Span, &Option<&Stability>)) {
|
|
|
|
match tcx.def_map.borrow().get(&item.node.id()).map(|d| d.full_def()) {
|
|
|
|
Some(def::DefPrimTy(..)) => {}
|
|
|
|
Some(def) => {
|
|
|
|
maybe_do_stability_check(tcx, def.def_id(), item.span, cb);
|
|
|
|
}
|
|
|
|
None => {}
|
|
|
|
}
|
2015-02-09 18:33:19 -06:00
|
|
|
}
|
|
|
|
|
2015-07-31 02:04:06 -05:00
|
|
|
pub fn check_pat(tcx: &ty::ctxt, pat: &hir::Pat,
|
2015-08-16 05:32:28 -05:00
|
|
|
cb: &mut FnMut(DefId, Span, &Option<&Stability>)) {
|
2015-02-25 05:34:21 -06:00
|
|
|
debug!("check_pat(pat = {:?})", pat);
|
|
|
|
if is_internal(tcx, pat.span) { return; }
|
|
|
|
|
2015-08-02 14:52:50 -05:00
|
|
|
let v = match tcx.pat_ty_opt(pat) {
|
|
|
|
Some(&ty::TyS { sty: ty::TyStruct(def, _), .. }) => def.struct_variant(),
|
2015-02-25 05:34:21 -06:00
|
|
|
Some(_) | None => return,
|
|
|
|
};
|
|
|
|
match pat.node {
|
|
|
|
// Foo(a, b, c)
|
2015-07-31 02:04:06 -05:00
|
|
|
hir::PatEnum(_, Some(ref pat_fields)) => {
|
2015-08-02 14:52:50 -05:00
|
|
|
for (field, struct_field) in pat_fields.iter().zip(&v.fields) {
|
2015-02-25 05:34:21 -06:00
|
|
|
// a .. pattern is fine, but anything positional is
|
|
|
|
// not.
|
2015-07-31 02:04:06 -05:00
|
|
|
if let hir::PatWild(hir::PatWildMulti) = field.node {
|
2015-02-25 05:34:21 -06:00
|
|
|
continue
|
|
|
|
}
|
2015-08-02 14:52:50 -05:00
|
|
|
maybe_do_stability_check(tcx, struct_field.did, field.span, cb)
|
2015-02-25 05:34:21 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Foo { a, b, c }
|
2015-07-31 02:04:06 -05:00
|
|
|
hir::PatStruct(_, ref pat_fields, _) => {
|
2015-02-25 05:34:21 -06:00
|
|
|
for field in pat_fields {
|
2015-09-20 08:47:24 -05:00
|
|
|
let did = v.field_named(field.node.name).did;
|
2015-02-25 05:34:21 -06:00
|
|
|
maybe_do_stability_check(tcx, did, field.span, cb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// everything else is fine.
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-16 05:32:28 -05:00
|
|
|
fn maybe_do_stability_check(tcx: &ty::ctxt, id: DefId, span: Span,
|
|
|
|
cb: &mut FnMut(DefId, Span, &Option<&Stability>)) {
|
2015-06-05 11:53:17 -05:00
|
|
|
if !is_staged_api(tcx, id) {
|
|
|
|
debug!("maybe_do_stability_check: \
|
|
|
|
skipping id={:?} since it is not staged_api", id);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if is_internal(tcx, span) {
|
|
|
|
debug!("maybe_do_stability_check: \
|
|
|
|
skipping span={:?} since it is internal", span);
|
|
|
|
return;
|
|
|
|
}
|
2015-01-14 17:20:14 -06:00
|
|
|
let ref stability = lookup(tcx, id);
|
2015-06-05 11:53:17 -05:00
|
|
|
debug!("maybe_do_stability_check: \
|
|
|
|
inspecting id={:?} span={:?} of stability={:?}", id, span, stability);
|
2015-01-14 17:20:14 -06:00
|
|
|
cb(id, span, stability);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_internal(tcx: &ty::ctxt, span: Span) -> bool {
|
Add #[allow_internal_unstable] to track stability for macros better.
Unstable items used in a macro expansion will now always trigger
stability warnings, *unless* the unstable items are directly inside a
macro marked with `#[allow_internal_unstable]`. IOW, the compiler warns
unless the span of the unstable item is a subspan of the definition of a
macro marked with that attribute.
E.g.
#[allow_internal_unstable]
macro_rules! foo {
($e: expr) => {{
$e;
unstable(); // no warning
only_called_by_foo!();
}}
}
macro_rules! only_called_by_foo {
() => { unstable() } // warning
}
foo!(unstable()) // warning
The unstable inside `foo` is fine, due to the attribute. But the
`unstable` inside `only_called_by_foo` is not, since that macro doesn't
have the attribute, and the `unstable` passed into `foo` is also not
fine since it isn't contained in the macro itself (that is, even though
it is only used directly in the macro).
In the process this makes the stability tracking much more precise,
e.g. previously `println!("{}", unstable())` got no warning, but now it
does. As such, this is a bug fix that may cause [breaking-change]s.
The attribute is definitely feature gated, since it explicitly allows
side-stepping the feature gating system.
2015-02-28 21:09:28 -06:00
|
|
|
tcx.sess.codemap().span_allows_unstable(span)
|
2015-01-14 17:20:14 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
fn is_staged_api(tcx: &ty::ctxt, id: DefId) -> bool {
|
2015-06-25 15:42:17 -05:00
|
|
|
match tcx.trait_item_of_item(id) {
|
2015-01-14 17:20:14 -06:00
|
|
|
Some(ty::MethodTraitItemId(trait_method_id))
|
|
|
|
if trait_method_id != id => {
|
|
|
|
is_staged_api(tcx, trait_method_id)
|
|
|
|
}
|
|
|
|
_ => {
|
2015-05-25 16:41:27 -05:00
|
|
|
*tcx.stability.borrow_mut().staged_api.entry(id.krate).or_insert_with(
|
|
|
|
|| csearch::is_staged_api(&tcx.sess.cstore, id.krate))
|
2015-01-14 17:20:14 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-26 13:37:39 -05:00
|
|
|
/// Lookup the stability for a node, loading external crate
|
|
|
|
/// metadata as necessary.
|
2015-05-25 16:41:27 -05:00
|
|
|
pub fn lookup<'tcx>(tcx: &ty::ctxt<'tcx>, id: DefId) -> Option<&'tcx Stability> {
|
|
|
|
if let Some(st) = tcx.stability.borrow().map.get(&id) {
|
|
|
|
return *st;
|
|
|
|
}
|
|
|
|
|
|
|
|
let st = lookup_uncached(tcx, id);
|
|
|
|
tcx.stability.borrow_mut().map.insert(id, st);
|
|
|
|
st
|
|
|
|
}
|
|
|
|
|
|
|
|
fn lookup_uncached<'tcx>(tcx: &ty::ctxt<'tcx>, id: DefId) -> Option<&'tcx Stability> {
|
2015-06-18 12:25:05 -05:00
|
|
|
debug!("lookup(id={:?})", id);
|
2015-01-01 20:41:44 -06:00
|
|
|
|
2014-06-26 13:37:39 -05:00
|
|
|
// is this definition the implementation of a trait method?
|
2015-06-25 15:42:17 -05:00
|
|
|
match tcx.trait_item_of_item(id) {
|
2015-01-01 20:41:44 -06:00
|
|
|
Some(ty::MethodTraitItemId(trait_method_id)) if trait_method_id != id => {
|
2014-12-20 02:09:35 -06:00
|
|
|
debug!("lookup: trait_method_id={:?}", trait_method_id);
|
2014-12-17 22:12:41 -06:00
|
|
|
return lookup(tcx, trait_method_id)
|
Add stability inheritance
This commit makes several changes to the stability index infrastructure:
* Stability levels are now inherited lexically, i.e., each item's
stability level becomes the default for any nested items.
* The computed stability level for an item is stored as part of the
metadata. When using an item from an external crate, this data is
looked up and cached.
* The stability lint works from the computed stability level, rather
than manual stability attribute annotations. However, the lint still
checks only a limited set of item uses (e.g., it does not check every
component of a path on import). This will be addressed in a later PR,
as part of issue #8962.
* The stability lint only applies to items originating from external
crates, since the stability index is intended as a promise to
downstream crates.
* The "experimental" lint is now _allow_ by default. This is because
almost all existing crates have been marked "experimental", pending
library stabilization. With inheritance in place, this would generate
a massive explosion of warnings for every Rust program.
The lint should be changed back to deny-by-default after library
stabilization is complete.
* The "deprecated" lint still warns by default.
The net result: we can begin tracking stability index for the standard
libraries as we stabilize, without impacting most clients.
Closes #13540.
2014-06-11 19:23:11 -05:00
|
|
|
}
|
2014-12-17 22:12:41 -06:00
|
|
|
_ => {}
|
Add stability inheritance
This commit makes several changes to the stability index infrastructure:
* Stability levels are now inherited lexically, i.e., each item's
stability level becomes the default for any nested items.
* The computed stability level for an item is stored as part of the
metadata. When using an item from an external crate, this data is
looked up and cached.
* The stability lint works from the computed stability level, rather
than manual stability attribute annotations. However, the lint still
checks only a limited set of item uses (e.g., it does not check every
component of a path on import). This will be addressed in a later PR,
as part of issue #8962.
* The stability lint only applies to items originating from external
crates, since the stability index is intended as a promise to
downstream crates.
* The "experimental" lint is now _allow_ by default. This is because
almost all existing crates have been marked "experimental", pending
library stabilization. With inheritance in place, this would generate
a massive explosion of warnings for every Rust program.
The lint should be changed back to deny-by-default after library
stabilization is complete.
* The "deprecated" lint still warns by default.
The net result: we can begin tracking stability index for the standard
libraries as we stabilize, without impacting most clients.
Closes #13540.
2014-06-11 19:23:11 -05:00
|
|
|
}
|
2014-12-17 22:12:41 -06:00
|
|
|
|
2015-08-16 05:32:28 -05:00
|
|
|
let item_stab = if id.is_local() {
|
2015-05-25 16:41:27 -05:00
|
|
|
None // The stability cache is filled partially lazily
|
2014-12-17 22:12:41 -06:00
|
|
|
} else {
|
2015-05-25 16:41:27 -05:00
|
|
|
csearch::get_stability(&tcx.sess.cstore, id).map(|st| tcx.intern_stability(st))
|
2014-12-17 22:12:41 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
item_stab.or_else(|| {
|
2015-06-25 15:42:17 -05:00
|
|
|
if tcx.is_impl(id) {
|
|
|
|
if let Some(trait_id) = tcx.trait_id_of_impl(id) {
|
2015-05-25 16:41:27 -05:00
|
|
|
// FIXME (#18969): for the time being, simply use the
|
|
|
|
// stability of the trait to determine the stability of any
|
|
|
|
// unmarked impls for it. See FIXME above for more details.
|
|
|
|
|
|
|
|
debug!("lookup: trait_id={:?}", trait_id);
|
|
|
|
return lookup(tcx, trait_id);
|
|
|
|
}
|
2014-12-17 22:12:41 -06:00
|
|
|
}
|
2015-05-25 16:41:27 -05:00
|
|
|
None
|
2014-12-17 22:12:41 -06:00
|
|
|
})
|
Add stability inheritance
This commit makes several changes to the stability index infrastructure:
* Stability levels are now inherited lexically, i.e., each item's
stability level becomes the default for any nested items.
* The computed stability level for an item is stored as part of the
metadata. When using an item from an external crate, this data is
looked up and cached.
* The stability lint works from the computed stability level, rather
than manual stability attribute annotations. However, the lint still
checks only a limited set of item uses (e.g., it does not check every
component of a path on import). This will be addressed in a later PR,
as part of issue #8962.
* The stability lint only applies to items originating from external
crates, since the stability index is intended as a promise to
downstream crates.
* The "experimental" lint is now _allow_ by default. This is because
almost all existing crates have been marked "experimental", pending
library stabilization. With inheritance in place, this would generate
a massive explosion of warnings for every Rust program.
The lint should be changed back to deny-by-default after library
stabilization is complete.
* The "deprecated" lint still warns by default.
The net result: we can begin tracking stability index for the standard
libraries as we stabilize, without impacting most clients.
Closes #13540.
2014-06-11 19:23:11 -05:00
|
|
|
}
|
Preliminary feature staging
This partially implements the feature staging described in the
[release channel RFC][rc]. It does not yet fully conform to the RFC as
written, but does accomplish its goals sufficiently for the 1.0 alpha
release.
It has three primary user-visible effects:
* On the nightly channel, use of unstable APIs generates a warning.
* On the beta channel, use of unstable APIs generates a warning.
* On the beta channel, use of feature gates generates a warning.
Code that does not trigger these warnings is considered 'stable',
modulo pre-1.0 bugs.
Disabling the warnings for unstable APIs continues to be done in the
existing (i.e. old) style, via `#[allow(...)]`, not that specified in
the RFC. I deem this marginally acceptable since any code that must do
this is not using the stable dialect of Rust.
Use of feature gates is itself gated with the new 'unstable_features'
lint, on nightly set to 'allow', and on beta 'warn'.
The attribute scheme used here corresponds to an older version of the
RFC, with the `#[staged_api]` crate attribute toggling the staging
behavior of the stability attributes, but the user impact is only
in-tree so I'm not concerned about having to make design changes later
(and I may ultimately prefer the scheme here after all, with the
`#[staged_api]` crate attribute).
Since the Rust codebase itself makes use of unstable features the
compiler and build system to a midly elaborate dance to allow it to
bootstrap while disobeying these lints (which would otherwise be
errors because Rust builds with `-D warnings`).
This patch includes one significant hack that causes a
regression. Because the `format_args!` macro emits calls to unstable
APIs it would trigger the lint. I added a hack to the lint to make it
not trigger, but this in turn causes arguments to `println!` not to be
checked for feature gates. I don't presently understand macro
expansion well enough to fix. This is bug #20661.
Closes #16678
[rc]: https://github.com/rust-lang/rfcs/blob/master/text/0507-release-channels.md
2015-01-06 08:26:08 -06:00
|
|
|
|
2015-01-14 17:20:14 -06:00
|
|
|
/// 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.
|
2015-02-02 22:25:42 -06:00
|
|
|
pub fn check_unused_or_stable_features(sess: &Session,
|
|
|
|
lib_features_used: &FnvHashMap<InternedString,
|
2015-10-12 22:01:31 -05:00
|
|
|
StabilityLevel>) {
|
2015-02-02 22:25:42 -06:00
|
|
|
let ref declared_lib_features = sess.features.borrow().declared_lib_features;
|
|
|
|
let mut remaining_lib_features: FnvHashMap<InternedString, Span>
|
|
|
|
= declared_lib_features.clone().into_iter().collect();
|
|
|
|
|
|
|
|
let stable_msg = "this feature is stable. attribute no longer needed";
|
|
|
|
|
2015-06-10 11:22:20 -05:00
|
|
|
for &span in &sess.features.borrow().declared_stable_lang_features {
|
2015-02-02 22:25:42 -06:00
|
|
|
sess.add_lint(lint::builtin::STABLE_FEATURES,
|
|
|
|
ast::CRATE_NODE_ID,
|
|
|
|
span,
|
|
|
|
stable_msg.to_string());
|
|
|
|
}
|
|
|
|
|
2015-06-10 11:22:20 -05:00
|
|
|
for (used_lib_feature, level) in lib_features_used {
|
2015-02-02 22:25:42 -06:00
|
|
|
match remaining_lib_features.remove(used_lib_feature) {
|
|
|
|
Some(span) => {
|
2015-10-12 22:01:31 -05:00
|
|
|
if *level == Stable {
|
2015-02-02 22:25:42 -06:00
|
|
|
sess.add_lint(lint::builtin::STABLE_FEATURES,
|
|
|
|
ast::CRATE_NODE_ID,
|
|
|
|
span,
|
|
|
|
stable_msg.to_string());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => ( /* used but undeclared, handled during the previous ast visit */ )
|
|
|
|
}
|
2015-01-16 12:25:16 -06:00
|
|
|
}
|
|
|
|
|
2015-06-10 11:22:20 -05:00
|
|
|
for &span in remaining_lib_features.values() {
|
2015-01-16 12:25:16 -06:00
|
|
|
sess.add_lint(lint::builtin::UNUSED_FEATURES,
|
|
|
|
ast::CRATE_NODE_ID,
|
|
|
|
span,
|
|
|
|
"unused or unknown feature".to_string());
|
|
|
|
}
|
Preliminary feature staging
This partially implements the feature staging described in the
[release channel RFC][rc]. It does not yet fully conform to the RFC as
written, but does accomplish its goals sufficiently for the 1.0 alpha
release.
It has three primary user-visible effects:
* On the nightly channel, use of unstable APIs generates a warning.
* On the beta channel, use of unstable APIs generates a warning.
* On the beta channel, use of feature gates generates a warning.
Code that does not trigger these warnings is considered 'stable',
modulo pre-1.0 bugs.
Disabling the warnings for unstable APIs continues to be done in the
existing (i.e. old) style, via `#[allow(...)]`, not that specified in
the RFC. I deem this marginally acceptable since any code that must do
this is not using the stable dialect of Rust.
Use of feature gates is itself gated with the new 'unstable_features'
lint, on nightly set to 'allow', and on beta 'warn'.
The attribute scheme used here corresponds to an older version of the
RFC, with the `#[staged_api]` crate attribute toggling the staging
behavior of the stability attributes, but the user impact is only
in-tree so I'm not concerned about having to make design changes later
(and I may ultimately prefer the scheme here after all, with the
`#[staged_api]` crate attribute).
Since the Rust codebase itself makes use of unstable features the
compiler and build system to a midly elaborate dance to allow it to
bootstrap while disobeying these lints (which would otherwise be
errors because Rust builds with `-D warnings`).
This patch includes one significant hack that causes a
regression. Because the `format_args!` macro emits calls to unstable
APIs it would trigger the lint. I added a hack to the lint to make it
not trigger, but this in turn causes arguments to `println!` not to be
checked for feature gates. I don't presently understand macro
expansion well enough to fix. This is bug #20661.
Closes #16678
[rc]: https://github.com/rust-lang/rfcs/blob/master/text/0507-release-channels.md
2015-01-06 08:26:08 -06:00
|
|
|
}
|