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-12-22 15:35:02 -06:00
|
|
|
use dep_graph::DepNode;
|
2016-03-29 00:50:44 -05:00
|
|
|
use hir::map as hir_map;
|
2015-01-12 20:40:19 -06:00
|
|
|
use session::Session;
|
2015-01-16 12:25:16 -06:00
|
|
|
use lint;
|
2016-04-12 08:58:55 -05:00
|
|
|
use middle::cstore::LOCAL_CRATE;
|
2016-03-29 04:54:26 -05:00
|
|
|
use hir::def::Def;
|
2016-08-04 08:18:36 -05:00
|
|
|
use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex};
|
2016-03-22 10:30:57 -05:00
|
|
|
use ty::{self, TyCtxt};
|
2015-11-19 05:16:35 -06:00
|
|
|
use middle::privacy::AccessLevels;
|
2015-01-14 17:20:14 -06:00
|
|
|
use syntax::parse::token::InternedString;
|
2016-06-21 17:08:13 -05:00
|
|
|
use syntax_pos::{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};
|
2016-05-30 15:55:12 -05:00
|
|
|
use syntax::feature_gate::{GateIssue, emit_feature_err, find_lang_feature_accepted_version};
|
2015-12-04 10:34:28 -06:00
|
|
|
use syntax::attr::{self, Stability, Deprecation, 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
|
|
|
|
2016-03-29 00:50:44 -05:00
|
|
|
use hir;
|
|
|
|
use hir::{Item, Generics, StructField, Variant, PatKind};
|
|
|
|
use hir::intravisit::{self, Visitor};
|
2016-03-06 06:54:44 -06:00
|
|
|
use hir::pat_util::EnumerateAndAdjustIterator;
|
2015-07-31 02:04:06 -05:00
|
|
|
|
2014-09-12 05:10:30 -05:00
|
|
|
use std::mem::replace;
|
2015-06-11 19:18:46 -05:00
|
|
|
use std::cmp::Ordering;
|
2016-05-30 15:55:12 -05:00
|
|
|
use std::ops::Deref;
|
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 }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-16 10:53:41 -06:00
|
|
|
#[derive(PartialEq)]
|
|
|
|
enum AnnotationKind {
|
|
|
|
// Annotation is required if not inherited from unstable parents
|
2015-11-16 12:01:06 -06:00
|
|
|
Required,
|
2015-11-16 10:53:41 -06:00
|
|
|
// Annotation is useless, reject it
|
2015-11-16 12:01:06 -06:00
|
|
|
Prohibited,
|
2015-11-16 10:53:41 -06:00
|
|
|
// Annotation itself is useless, but it can be propagated to children
|
2015-11-16 12:01:06 -06:00
|
|
|
Container,
|
2015-11-16 10:53:41 -06:00
|
|
|
}
|
|
|
|
|
2016-08-04 08:18:36 -05:00
|
|
|
/// An entry in the `depr_map`.
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct DeprecationEntry {
|
|
|
|
/// The metadata of the attribute associated with this entry.
|
|
|
|
pub attr: Deprecation,
|
|
|
|
/// The def id where the attr was originally attached. `None` for non-local
|
|
|
|
/// `DefId`'s.
|
|
|
|
origin: Option<DefIndex>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DeprecationEntry {
|
|
|
|
fn local(attr: Deprecation, id: DefId) -> DeprecationEntry {
|
|
|
|
assert!(id.is_local());
|
|
|
|
DeprecationEntry {
|
|
|
|
attr: attr,
|
|
|
|
origin: Some(id.index),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn external(attr: Deprecation) -> DeprecationEntry {
|
|
|
|
DeprecationEntry {
|
|
|
|
attr: attr,
|
|
|
|
origin: None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn same_origin(&self, other: &DeprecationEntry) -> bool {
|
|
|
|
match (self.origin, other.origin) {
|
|
|
|
(Some(o1), Some(o2)) => o1 == o2,
|
|
|
|
_ => false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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.
|
2015-12-04 10:34:28 -06:00
|
|
|
stab_map: DefIdMap<Option<&'tcx Stability>>,
|
2016-08-04 08:18:36 -05:00
|
|
|
depr_map: DefIdMap<Option<DeprecationEntry>>,
|
2015-05-25 16:41:27 -05:00
|
|
|
|
|
|
|
/// 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> {
|
2016-05-02 21:23:22 -05:00
|
|
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
2015-05-25 16:41:27 -05:00
|
|
|
index: &'a mut Index<'tcx>,
|
2015-12-04 10:34:28 -06:00
|
|
|
parent_stab: Option<&'tcx Stability>,
|
2016-08-04 08:18:36 -05:00
|
|
|
parent_depr: Option<DeprecationEntry>,
|
2015-11-19 05:16:35 -06:00
|
|
|
access_levels: &'a AccessLevels,
|
2015-11-16 10:53:41 -06:00
|
|
|
in_trait_impl: 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
|
|
|
}
|
|
|
|
|
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.
|
2015-12-17 11:41:28 -06:00
|
|
|
fn annotate<F>(&mut self, id: NodeId, attrs: &[Attribute],
|
2015-11-16 10:53:41 -06:00
|
|
|
item_sp: Span, kind: AnnotationKind, visit_children: F)
|
|
|
|
where F: FnOnce(&mut Annotator)
|
2014-12-08 19:26:43 -06:00
|
|
|
{
|
2015-11-25 15:15:46 -06:00
|
|
|
if self.index.staged_api[&LOCAL_CRATE] && self.tcx.sess.features.borrow().staged_api {
|
2015-04-13 20:42:24 -05:00
|
|
|
debug!("annotate(id = {:?}, attrs = {:?})", id, attrs);
|
2015-12-04 10:34:28 -06:00
|
|
|
if let Some(..) = attr::find_deprecation(self.tcx.sess.diagnostic(), attrs, item_sp) {
|
|
|
|
self.tcx.sess.span_err(item_sp, "`#[deprecated]` cannot be used in staged api, \
|
|
|
|
use `#[rustc_deprecated]` instead");
|
|
|
|
}
|
2015-11-16 10:53:41 -06:00
|
|
|
if let Some(mut stab) = attr::find_stability(self.tcx.sess.diagnostic(),
|
|
|
|
attrs, item_sp) {
|
|
|
|
// Error if prohibited, or can't inherit anything from a container
|
2015-11-16 12:01:06 -06:00
|
|
|
if kind == AnnotationKind::Prohibited ||
|
|
|
|
(kind == AnnotationKind::Container &&
|
|
|
|
stab.level.is_stable() &&
|
2015-12-04 10:34:28 -06:00
|
|
|
stab.rustc_depr.is_none()) {
|
2015-11-16 10:53:41 -06:00
|
|
|
self.tcx.sess.span_err(item_sp, "This stability annotation is useless");
|
|
|
|
}
|
2015-06-06 17:52:28 -05:00
|
|
|
|
2015-11-16 10:53:41 -06:00
|
|
|
debug!("annotate: found {:?}", stab);
|
|
|
|
// If parent is deprecated and we're not, inherit this by merging
|
|
|
|
// deprecated_since and its reason.
|
2015-12-04 10:34:28 -06:00
|
|
|
if let Some(parent_stab) = self.parent_stab {
|
|
|
|
if parent_stab.rustc_depr.is_some() && stab.rustc_depr.is_none() {
|
|
|
|
stab.rustc_depr = parent_stab.rustc_depr.clone()
|
2015-11-16 10:53:41 -06:00
|
|
|
}
|
|
|
|
}
|
2015-06-11 19:18:46 -05:00
|
|
|
|
2015-11-16 10:53:41 -06:00
|
|
|
let stab = self.tcx.intern_stability(stab);
|
|
|
|
|
|
|
|
// Check if deprecated_since < stable_since. If it is,
|
|
|
|
// this is *almost surely* an accident.
|
2015-12-04 10:34:28 -06:00
|
|
|
if let (&Some(attr::RustcDeprecation {since: ref dep_since, ..}),
|
|
|
|
&attr::Stable {since: ref stab_since}) = (&stab.rustc_depr, &stab.level) {
|
2015-11-16 10:53:41 -06:00
|
|
|
// Explicit version of iter::order::lt to handle parse errors properly
|
|
|
|
for (dep_v, stab_v) in dep_since.split(".").zip(stab_since.split(".")) {
|
|
|
|
if let (Ok(dep_v), Ok(stab_v)) = (dep_v.parse::<u64>(), stab_v.parse()) {
|
|
|
|
match dep_v.cmp(&stab_v) {
|
|
|
|
Ordering::Less => {
|
|
|
|
self.tcx.sess.span_err(item_sp, "An API can't be stabilized \
|
|
|
|
after it is deprecated");
|
|
|
|
break
|
2015-06-11 19:18:46 -05:00
|
|
|
}
|
2015-11-16 10:53:41 -06:00
|
|
|
Ordering::Equal => continue,
|
|
|
|
Ordering::Greater => break,
|
2015-06-11 19:18:46 -05:00
|
|
|
}
|
2015-11-16 10:53:41 -06:00
|
|
|
} else {
|
|
|
|
// Act like it isn't less because the question is now nonsensical,
|
|
|
|
// and this makes us not do anything else interesting.
|
|
|
|
self.tcx.sess.span_err(item_sp, "Invalid stability or deprecation \
|
|
|
|
version found");
|
|
|
|
break
|
|
|
|
}
|
2015-06-11 19:18:46 -05:00
|
|
|
}
|
2015-11-16 10:53:41 -06:00
|
|
|
}
|
2015-06-11 19:18:46 -05:00
|
|
|
|
2015-11-16 10:53:41 -06:00
|
|
|
let def_id = self.tcx.map.local_def_id(id);
|
2015-12-04 10:34:28 -06:00
|
|
|
self.index.stab_map.insert(def_id, Some(stab));
|
2015-11-16 10:53:41 -06:00
|
|
|
|
2015-12-04 10:34:28 -06:00
|
|
|
let orig_parent_stab = replace(&mut self.parent_stab, Some(stab));
|
2015-11-16 10:53:41 -06:00
|
|
|
visit_children(self);
|
2015-12-04 10:34:28 -06:00
|
|
|
self.parent_stab = orig_parent_stab;
|
2015-11-16 10:53:41 -06:00
|
|
|
} else {
|
2015-12-04 10:34:28 -06:00
|
|
|
debug!("annotate: not found, parent = {:?}", self.parent_stab);
|
2015-11-16 12:01:06 -06:00
|
|
|
let mut is_error = kind == AnnotationKind::Required &&
|
2015-11-19 05:16:35 -06:00
|
|
|
self.access_levels.is_reachable(id) &&
|
2015-11-16 10:53:41 -06:00
|
|
|
!self.tcx.sess.opts.test;
|
2015-12-04 10:34:28 -06:00
|
|
|
if let Some(stab) = self.parent_stab {
|
2015-11-16 10:53:41 -06:00
|
|
|
if stab.level.is_unstable() {
|
|
|
|
let def_id = self.tcx.map.local_def_id(id);
|
2015-12-04 10:34:28 -06:00
|
|
|
self.index.stab_map.insert(def_id, Some(stab));
|
2015-11-16 10:53:41 -06:00
|
|
|
is_error = false;
|
2015-04-13 20:42:24 -05:00
|
|
|
}
|
|
|
|
}
|
2015-11-16 10:53:41 -06:00
|
|
|
if is_error {
|
|
|
|
self.tcx.sess.span_err(item_sp, "This node does not have \
|
|
|
|
a stability attribute");
|
2014-11-11 14:46:47 -06:00
|
|
|
}
|
2015-11-16 10:53:41 -06:00
|
|
|
visit_children(self);
|
2014-09-12 05:10:30 -05:00
|
|
|
}
|
2015-04-13 20:42:24 -05:00
|
|
|
} else {
|
2015-11-16 10:53:41 -06:00
|
|
|
// Emit errors for non-staged-api crates.
|
2015-04-13 20:42:24 -05:00
|
|
|
for attr in attrs {
|
|
|
|
let tag = attr.name();
|
2015-11-20 07:11:20 -06:00
|
|
|
if tag == "unstable" || tag == "stable" || tag == "rustc_deprecated" {
|
2015-04-13 20:42:24 -05:00
|
|
|
attr::mark_used(attr);
|
2015-11-16 10:53:41 -06:00
|
|
|
self.tcx.sess.span_err(attr.span(), "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-12-04 10:34:28 -06:00
|
|
|
|
|
|
|
if let Some(depr) = attr::find_deprecation(self.tcx.sess.diagnostic(), attrs, item_sp) {
|
|
|
|
if kind == AnnotationKind::Prohibited {
|
|
|
|
self.tcx.sess.span_err(item_sp, "This deprecation annotation is useless");
|
|
|
|
}
|
|
|
|
|
|
|
|
// `Deprecation` is just two pointers, no need to intern it
|
|
|
|
let def_id = self.tcx.map.local_def_id(id);
|
2016-08-04 08:18:36 -05:00
|
|
|
let depr_entry = Some(DeprecationEntry::local(depr, def_id));
|
|
|
|
self.index.depr_map.insert(def_id, depr_entry.clone());
|
2015-12-04 10:34:28 -06:00
|
|
|
|
2016-08-04 08:18:36 -05:00
|
|
|
let orig_parent_depr = replace(&mut self.parent_depr, depr_entry);
|
2015-12-04 10:34:28 -06:00
|
|
|
visit_children(self);
|
|
|
|
self.parent_depr = orig_parent_depr;
|
2016-08-04 08:18:36 -05:00
|
|
|
} else if let parent_depr @ Some(_) = self.parent_depr.clone() {
|
2015-12-04 10:34:28 -06:00
|
|
|
let def_id = self.tcx.map.local_def_id(id);
|
2016-08-04 08:18:36 -05:00
|
|
|
self.index.depr_map.insert(def_id, parent_depr);
|
2015-12-04 10:34:28 -06:00
|
|
|
visit_children(self);
|
|
|
|
} else {
|
|
|
|
visit_children(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> {
|
2015-11-17 17:56:13 -06:00
|
|
|
/// Because stability levels are scoped lexically, we want to walk
|
|
|
|
/// nested items in the context of the outer item, so enable
|
|
|
|
/// deep-walking.
|
|
|
|
fn visit_nested_item(&mut self, item: hir::ItemId) {
|
2016-05-02 20:56:42 -05:00
|
|
|
let tcx = self.tcx;
|
|
|
|
self.visit_item(tcx.map.expect_item(item.id))
|
2015-11-17 17:56:13 -06:00
|
|
|
}
|
|
|
|
|
2014-09-12 05:10:30 -05:00
|
|
|
fn visit_item(&mut self, i: &Item) {
|
2015-11-16 10:53:41 -06:00
|
|
|
let orig_in_trait_impl = self.in_trait_impl;
|
2015-11-16 12:01:06 -06:00
|
|
|
let mut kind = AnnotationKind::Required;
|
2015-11-16 10:53:41 -06:00
|
|
|
match i.node {
|
|
|
|
// Inherent impls and foreign modules serve only as containers for other items,
|
|
|
|
// they don't have their own stability. They still can be annotated as unstable
|
|
|
|
// and propagate this unstability to children, but this annotation is completely
|
|
|
|
// optional. They inherit stability from their parents when unannotated.
|
|
|
|
hir::ItemImpl(_, _, _, None, _, _) | hir::ItemForeignMod(..) => {
|
|
|
|
self.in_trait_impl = false;
|
2015-11-16 12:01:06 -06:00
|
|
|
kind = AnnotationKind::Container;
|
2015-11-16 10:53:41 -06:00
|
|
|
}
|
|
|
|
hir::ItemImpl(_, _, _, Some(_), _, _) => {
|
|
|
|
self.in_trait_impl = true;
|
2015-10-01 19:53:28 -05:00
|
|
|
}
|
2015-11-16 10:53:41 -06:00
|
|
|
hir::ItemStruct(ref sd, _) => {
|
|
|
|
if !sd.is_struct() {
|
2015-11-16 12:01:06 -06:00
|
|
|
self.annotate(sd.id(), &i.attrs, i.span, AnnotationKind::Required, |_| {})
|
2015-11-16 10:53:41 -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-11-16 10:53:41 -06:00
|
|
|
self.annotate(i.id, &i.attrs, i.span, kind, |v| {
|
2015-11-17 17:56:13 -06:00
|
|
|
intravisit::walk_item(v, i)
|
2015-11-16 10:53:41 -06:00
|
|
|
});
|
|
|
|
self.in_trait_impl = orig_in_trait_impl;
|
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-11-16 12:01:06 -06:00
|
|
|
self.annotate(ti.id, &ti.attrs, ti.span, AnnotationKind::Required, |v| {
|
2015-11-17 17:56:13 -06:00
|
|
|
intravisit::walk_trait_item(v, ti);
|
2015-11-16 10:53:41 -06:00
|
|
|
});
|
2015-03-10 05:28:44 -05:00
|
|
|
}
|
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-11-16 12:01:06 -06:00
|
|
|
let kind = if self.in_trait_impl {
|
|
|
|
AnnotationKind::Prohibited
|
|
|
|
} else {
|
|
|
|
AnnotationKind::Required
|
|
|
|
};
|
2015-11-16 10:53:41 -06:00
|
|
|
self.annotate(ii.id, &ii.attrs, ii.span, kind, |v| {
|
2015-11-17 17:56:13 -06:00
|
|
|
intravisit::walk_impl_item(v, ii);
|
2015-11-16 10:53: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-10-02 08:14:20 -05:00
|
|
|
fn visit_variant(&mut self, var: &Variant, g: &'v Generics, item_id: NodeId) {
|
2015-11-16 12:01:06 -06:00
|
|
|
self.annotate(var.node.data.id(), &var.node.attrs, var.span, AnnotationKind::Required, |v| {
|
2015-11-17 17:56:13 -06:00
|
|
|
intravisit::walk_variant(v, var, g, item_id);
|
2015-11-16 10:53: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-09-12 05:10:30 -05:00
|
|
|
fn visit_struct_field(&mut self, s: &StructField) {
|
2016-02-27 02:34:29 -06:00
|
|
|
self.annotate(s.id, &s.attrs, s.span, AnnotationKind::Required, |v| {
|
2015-11-17 17:56:13 -06:00
|
|
|
intravisit::walk_struct_field(v, s);
|
2015-11-16 10:53:41 -06:00
|
|
|
});
|
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-11-16 12:01:06 -06:00
|
|
|
self.annotate(i.id, &i.attrs, i.span, AnnotationKind::Required, |v| {
|
2015-11-17 17:56:13 -06:00
|
|
|
intravisit::walk_foreign_item(v, i);
|
2015-11-16 10:53:41 -06:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_macro_def(&mut self, md: &'v hir::MacroDef) {
|
|
|
|
if md.imported_from.is_none() {
|
2015-11-16 12:01:06 -06:00
|
|
|
self.annotate(md.id, &md.attrs, md.span, AnnotationKind::Required, |_| {});
|
2015-11-16 10:53:41 -06:00
|
|
|
}
|
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
|
|
|
}
|
|
|
|
|
2016-05-02 20:56:42 -05:00
|
|
|
impl<'a, '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.
|
2016-05-02 21:23:22 -05:00
|
|
|
pub fn build(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, access_levels: &AccessLevels) {
|
2016-01-29 14:04:07 -06:00
|
|
|
let _task = tcx.dep_graph.in_task(DepNode::StabilityIndex);
|
|
|
|
let krate = tcx.map.krate();
|
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-12-04 10:34:28 -06:00
|
|
|
parent_stab: None,
|
|
|
|
parent_depr: None,
|
2015-11-19 05:16:35 -06:00
|
|
|
access_levels: access_levels,
|
2015-11-16 10:53:41 -06:00
|
|
|
in_trait_impl: false,
|
2015-02-03 09:46:08 -06:00
|
|
|
};
|
2015-11-16 12:01:06 -06:00
|
|
|
annotator.annotate(ast::CRATE_NODE_ID, &krate.attrs, krate.span, AnnotationKind::Required,
|
2015-11-17 17:56:13 -06:00
|
|
|
|v| intravisit::walk_crate(v, krate));
|
2015-02-03 09:46:08 -06:00
|
|
|
}
|
|
|
|
|
2016-01-29 14:04:07 -06:00
|
|
|
pub fn new(hir_map: &hir_map::Map) -> Index<'tcx> {
|
|
|
|
let _task = hir_map.dep_graph.in_task(DepNode::StabilityIndex);
|
|
|
|
let krate = hir_map.krate();
|
|
|
|
|
2015-11-25 15:15:46 -06:00
|
|
|
let mut is_staged_api = false;
|
|
|
|
for attr in &krate.attrs {
|
|
|
|
if attr.name() == "stable" || attr.name() == "unstable" {
|
|
|
|
is_staged_api = true;
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-25 16:41:27 -05:00
|
|
|
let mut staged_api = FnvHashMap();
|
2015-11-25 15:15:46 -06: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-12-04 10:34:28 -06:00
|
|
|
stab_map: DefIdMap(),
|
|
|
|
depr_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.
|
2016-05-02 21:23:22 -05:00
|
|
|
pub fn check_unstable_api_usage<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
|
2016-05-30 15:55:12 -05:00
|
|
|
-> FnvHashMap<InternedString, attr::StabilityLevel> {
|
2015-12-22 15:35:02 -06:00
|
|
|
let _task = tcx.dep_graph.in_task(DepNode::StabilityCheck);
|
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
|
|
|
};
|
2015-11-17 17:56:13 -06:00
|
|
|
intravisit::walk_crate(&mut checker, tcx.map.krate());
|
2015-01-14 17:20:14 -06:00
|
|
|
|
2015-12-22 15:35:02 -06:00
|
|
|
checker.used_features
|
2015-01-14 17:20:14 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
struct Checker<'a, 'tcx: 'a> {
|
2016-05-02 21:23:22 -05:00
|
|
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
2015-01-14 17:20:14 -06:00
|
|
|
active_features: FnvHashSet<InternedString>,
|
2016-05-30 15:55:12 -05:00
|
|
|
used_features: FnvHashMap<InternedString, attr::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-12-04 10:34:28 -06:00
|
|
|
fn check(&mut self, id: DefId, span: Span,
|
|
|
|
stab: &Option<&Stability>, _depr: &Option<Deprecation>) {
|
|
|
|
if !is_staged_api(self.tcx, id) {
|
|
|
|
return;
|
|
|
|
}
|
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, .. }) => {
|
2016-05-30 15:55:12 -05:00
|
|
|
self.used_features.insert(feature.clone(),
|
|
|
|
attr::Unstable { reason: reason.clone(), issue: issue });
|
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, .. }) => {
|
2016-05-30 15:55:12 -05:00
|
|
|
self.used_features.insert(feature.clone(), level.clone());
|
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 {
|
2015-12-20 15:00:43 -06:00
|
|
|
self.tcx.sess.struct_span_warn(span, "use of unmarked library feature")
|
|
|
|
.span_note(span, "this is either a bug in the library you are \
|
2015-02-17 12:42:31 -06:00
|
|
|
using or a bug in the compiler - please \
|
2015-12-20 15:00:43 -06:00
|
|
|
report it in both places")
|
|
|
|
.emit()
|
2015-02-03 13:51:26 -06:00
|
|
|
} else {
|
2015-12-20 15:00:43 -06:00
|
|
|
self.tcx.sess.struct_span_err(span, "use of unmarked library feature")
|
|
|
|
.span_note(span, "this is either a bug in the library you are \
|
2015-02-17 12:42:31 -06:00
|
|
|
using or a bug in the compiler - please \
|
2015-12-20 15:00:43 -06:00
|
|
|
report it in both places")
|
|
|
|
.span_note(span, "use #![feature(unmarked_api)] in the \
|
|
|
|
crate attributes to override this")
|
|
|
|
.emit()
|
2015-02-03 13:51:26 -06:00
|
|
|
}
|
2015-01-14 17:20:14 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> {
|
2015-11-17 17:56:13 -06:00
|
|
|
/// Because stability levels are scoped lexically, we want to walk
|
|
|
|
/// nested items in the context of the outer item, so enable
|
|
|
|
/// deep-walking.
|
|
|
|
fn visit_nested_item(&mut self, item: hir::ItemId) {
|
2016-05-02 20:56:42 -05:00
|
|
|
let tcx = self.tcx;
|
|
|
|
self.visit_item(tcx.map.expect_item(item.id))
|
2015-11-17 17:56:13 -06:00
|
|
|
}
|
|
|
|
|
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-12-04 10:34:28 -06:00
|
|
|
&mut |id, sp, stab, depr| self.check(id, sp, stab, depr));
|
2015-11-17 17:56:13 -06:00
|
|
|
intravisit::walk_item(self, item);
|
2015-01-14 17:20:14 -06:00
|
|
|
}
|
|
|
|
|
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,
|
2015-12-04 10:34:28 -06:00
|
|
|
&mut |id, sp, stab, depr| self.check(id, sp, stab, depr));
|
2015-11-17 17:56:13 -06:00
|
|
|
intravisit::walk_expr(self, ex);
|
2015-01-14 17:20:14 -06:00
|
|
|
}
|
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,
|
2015-12-04 10:34:28 -06:00
|
|
|
&mut |id, sp, stab, depr| self.check(id, sp, stab, depr));
|
2015-11-17 17:56:13 -06:00
|
|
|
intravisit::walk_path(self, path)
|
2015-02-09 18:33:19 -06:00
|
|
|
}
|
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,
|
2015-12-04 10:34:28 -06:00
|
|
|
&mut |id, sp, stab, depr| self.check(id, sp, stab, depr));
|
2015-11-17 17:56:13 -06:00
|
|
|
intravisit::walk_path_list_item(self, prefix, item)
|
2015-09-12 08:10:12 -05:00
|
|
|
}
|
|
|
|
|
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,
|
2015-12-04 10:34:28 -06:00
|
|
|
&mut |id, sp, stab, depr| self.check(id, sp, stab, depr));
|
2015-11-17 17:56:13 -06:00
|
|
|
intravisit::walk_pat(self, pat)
|
2015-02-25 05:34:21 -06:00
|
|
|
}
|
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();
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
2015-11-17 17:56:13 -06:00
|
|
|
intravisit::walk_block(self, b);
|
2015-09-28 19:46:01 -05:00
|
|
|
self.in_skip_block = old_skip_count;
|
|
|
|
}
|
2015-01-14 17:20:14 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Helper for discovering nodes to check for stability
|
2016-05-02 21:23:22 -05:00
|
|
|
pub fn check_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|
|
|
item: &hir::Item,
|
|
|
|
warn_about_defns: bool,
|
|
|
|
cb: &mut FnMut(DefId, Span,
|
|
|
|
&Option<&Stability>,
|
|
|
|
&Option<Deprecation>)) {
|
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 }
|
|
|
|
|
2015-11-21 13:39:05 -06:00
|
|
|
let cnum = match tcx.sess.cstore.extern_mod_stmt_cnum(item.id) {
|
2015-01-24 11:15:42 -06:00
|
|
|
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) => {
|
2016-06-03 15:15:00 -05:00
|
|
|
let trait_did = tcx.expect_def(t.ref_id).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
|
2016-05-02 21:23:22 -05:00
|
|
|
pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr,
|
|
|
|
cb: &mut FnMut(DefId, Span,
|
|
|
|
&Option<&Stability>,
|
|
|
|
&Option<Deprecation>)) {
|
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,
|
2016-03-25 12:31:27 -05:00
|
|
|
_ => span_bug!(e.span,
|
|
|
|
"stability::check_expr: named field access on non-struct")
|
2015-02-25 05:34:21 -06:00
|
|
|
}
|
|
|
|
}
|
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,
|
2016-03-25 12:31:27 -05:00
|
|
|
_ => span_bug!(e.span,
|
|
|
|
"stability::check_expr: unnamed field access on \
|
|
|
|
something other than a tuple or struct")
|
2015-02-25 05:34:21 -06:00
|
|
|
}
|
|
|
|
}
|
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
|
|
|
_ => {
|
2016-03-25 12:31:27 -05:00
|
|
|
span_bug!(e.span,
|
|
|
|
"stability::check_expr: struct construction \
|
|
|
|
of non-struct, type {:?}",
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2016-05-02 21:23:22 -05:00
|
|
|
pub fn check_path<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|
|
|
path: &hir::Path, id: ast::NodeId,
|
|
|
|
cb: &mut FnMut(DefId, Span,
|
|
|
|
&Option<&Stability>,
|
|
|
|
&Option<Deprecation>)) {
|
2016-06-03 15:15:00 -05:00
|
|
|
// Paths in import prefixes may have no resolution.
|
|
|
|
match tcx.expect_def_or_none(id) {
|
2016-01-20 13:31:10 -06:00
|
|
|
Some(Def::PrimTy(..)) => {}
|
|
|
|
Some(Def::SelfTy(..)) => {}
|
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
|
|
|
|
2016-05-02 21:23:22 -05:00
|
|
|
pub fn check_path_list_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|
|
|
item: &hir::PathListItem,
|
|
|
|
cb: &mut FnMut(DefId, Span,
|
|
|
|
&Option<&Stability>,
|
|
|
|
&Option<Deprecation>)) {
|
2016-06-03 15:15:00 -05:00
|
|
|
match tcx.expect_def(item.node.id()) {
|
|
|
|
Def::PrimTy(..) => {}
|
|
|
|
def => {
|
2015-09-12 08:10:12 -05:00
|
|
|
maybe_do_stability_check(tcx, def.def_id(), item.span, cb);
|
|
|
|
}
|
|
|
|
}
|
2015-02-09 18:33:19 -06:00
|
|
|
}
|
|
|
|
|
2016-05-02 21:23:22 -05:00
|
|
|
pub fn check_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &hir::Pat,
|
|
|
|
cb: &mut FnMut(DefId, Span,
|
|
|
|
&Option<&Stability>,
|
|
|
|
&Option<Deprecation>)) {
|
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)
|
2016-03-06 06:54:44 -06:00
|
|
|
PatKind::TupleStruct(_, ref pat_fields, ddpos) => {
|
2016-03-06 06:54:44 -06:00
|
|
|
for (i, field) in pat_fields.iter().enumerate_and_adjust(v.fields.len(), ddpos) {
|
|
|
|
maybe_do_stability_check(tcx, v.fields[i].did, field.span, cb)
|
2015-02-25 05:34:21 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Foo { a, b, c }
|
2016-02-14 06:25:12 -06:00
|
|
|
PatKind::Struct(_, 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.
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-02 21:23:22 -05:00
|
|
|
fn maybe_do_stability_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|
|
|
id: DefId, span: Span,
|
|
|
|
cb: &mut FnMut(DefId, Span,
|
|
|
|
&Option<&Stability>,
|
|
|
|
&Option<Deprecation>)) {
|
2015-06-05 11:53:17 -05:00
|
|
|
if is_internal(tcx, span) {
|
|
|
|
debug!("maybe_do_stability_check: \
|
|
|
|
skipping span={:?} since it is internal", span);
|
|
|
|
return;
|
|
|
|
}
|
2015-12-04 10:34:28 -06:00
|
|
|
let (stability, deprecation) = if is_staged_api(tcx, id) {
|
2016-03-16 17:15:31 -05:00
|
|
|
(tcx.lookup_stability(id), None)
|
2015-12-04 10:34:28 -06:00
|
|
|
} else {
|
2016-03-16 17:15:31 -05:00
|
|
|
(None, tcx.lookup_deprecation(id))
|
2015-12-04 10:34:28 -06:00
|
|
|
};
|
2015-06-05 11:53:17 -05:00
|
|
|
debug!("maybe_do_stability_check: \
|
|
|
|
inspecting id={:?} span={:?} of stability={:?}", id, span, stability);
|
2015-12-04 10:34:28 -06:00
|
|
|
cb(id, span, &stability, &deprecation);
|
2015-01-14 17:20:14 -06:00
|
|
|
}
|
|
|
|
|
2016-05-02 21:23:22 -05:00
|
|
|
fn is_internal<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, 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
|
|
|
}
|
|
|
|
|
2016-05-02 21:23:22 -05:00
|
|
|
fn is_staged_api<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, 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(
|
2015-11-20 06:51:18 -06:00
|
|
|
|| tcx.sess.cstore.is_staged_api(id.krate))
|
2015-01-14 17:20:14 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-02 21:23:22 -05:00
|
|
|
impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
|
2016-05-11 00:48:12 -05:00
|
|
|
/// Lookup the stability for a node, loading external crate
|
|
|
|
/// metadata as necessary.
|
|
|
|
pub fn lookup_stability(self, id: DefId) -> Option<&'tcx Stability> {
|
|
|
|
if let Some(st) = self.stability.borrow().stab_map.get(&id) {
|
|
|
|
return *st;
|
|
|
|
}
|
|
|
|
|
|
|
|
let st = self.lookup_stability_uncached(id);
|
|
|
|
self.stability.borrow_mut().stab_map.insert(id, st);
|
|
|
|
st
|
2015-05-25 16:41:27 -05:00
|
|
|
}
|
|
|
|
|
2016-05-11 00:48:12 -05:00
|
|
|
pub fn lookup_deprecation(self, id: DefId) -> Option<Deprecation> {
|
2016-08-04 08:18:36 -05:00
|
|
|
self.lookup_deprecation_entry(id).map(|depr| depr.attr)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn lookup_deprecation_entry(self, id: DefId) -> Option<DeprecationEntry> {
|
2016-05-11 00:48:12 -05:00
|
|
|
if let Some(depr) = self.stability.borrow().depr_map.get(&id) {
|
|
|
|
return depr.clone();
|
|
|
|
}
|
2015-05-25 16:41:27 -05:00
|
|
|
|
2016-05-11 00:48:12 -05:00
|
|
|
let depr = self.lookup_deprecation_uncached(id);
|
|
|
|
self.stability.borrow_mut().depr_map.insert(id, depr.clone());
|
|
|
|
depr
|
2015-12-04 10:34:28 -06:00
|
|
|
}
|
|
|
|
|
2016-05-11 00:48:12 -05:00
|
|
|
fn lookup_stability_uncached(self, id: DefId) -> Option<&'tcx Stability> {
|
|
|
|
debug!("lookup(id={:?})", id);
|
|
|
|
if id.is_local() {
|
|
|
|
None // The stability cache is filled partially lazily
|
|
|
|
} else {
|
|
|
|
self.sess.cstore.stability(id).map(|st| self.intern_stability(st))
|
|
|
|
}
|
2015-12-12 12:40:45 -06:00
|
|
|
}
|
2015-12-04 10:34:28 -06:00
|
|
|
|
2016-08-04 08:18:36 -05:00
|
|
|
fn lookup_deprecation_uncached(self, id: DefId) -> Option<DeprecationEntry> {
|
2016-05-11 00:48:12 -05:00
|
|
|
debug!("lookup(id={:?})", id);
|
|
|
|
if id.is_local() {
|
|
|
|
None // The stability cache is filled partially lazily
|
|
|
|
} else {
|
2016-08-04 08:18:36 -05:00
|
|
|
self.sess.cstore.deprecation(id).map(DeprecationEntry::external)
|
2016-05-11 00:48:12 -05:00
|
|
|
}
|
2015-12-12 12:40:45 -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,
|
2016-05-30 15:55:12 -05:00
|
|
|
attr::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();
|
|
|
|
|
2016-05-30 15:55:12 -05:00
|
|
|
fn format_stable_since_msg(version: &str) -> String {
|
|
|
|
format!("this feature has been stable since {}. Attribute no longer needed", version)
|
|
|
|
}
|
2015-02-02 22:25:42 -06:00
|
|
|
|
2016-05-30 15:55:12 -05:00
|
|
|
for &(ref stable_lang_feature, span) in &sess.features.borrow().declared_stable_lang_features {
|
|
|
|
let version = find_lang_feature_accepted_version(stable_lang_feature.deref())
|
|
|
|
.expect("unexpectedly couldn't find version feature was stabilized");
|
2015-02-02 22:25:42 -06:00
|
|
|
sess.add_lint(lint::builtin::STABLE_FEATURES,
|
|
|
|
ast::CRATE_NODE_ID,
|
|
|
|
span,
|
2016-05-30 15:55:12 -05:00
|
|
|
format_stable_since_msg(version));
|
2015-02-02 22:25:42 -06:00
|
|
|
}
|
|
|
|
|
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) => {
|
2016-05-30 15:55:12 -05:00
|
|
|
if let &attr::StabilityLevel::Stable { since: ref version } = level {
|
2015-02-02 22:25:42 -06:00
|
|
|
sess.add_lint(lint::builtin::STABLE_FEATURES,
|
|
|
|
ast::CRATE_NODE_ID,
|
|
|
|
span,
|
2016-05-30 15:55:12 -05:00
|
|
|
format_stable_since_msg(version.deref()));
|
2015-02-02 22:25:42 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
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
|
|
|
}
|