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-01-12 20:40:19 -06:00
|
|
|
use session::Session;
|
2015-01-16 12:25:16 -06:00
|
|
|
use lint;
|
2015-02-09 18:33:19 -06:00
|
|
|
use middle::def;
|
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};
|
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
|
|
|
use syntax::{attr, visit};
|
2014-07-10 13:17:40 -05:00
|
|
|
use syntax::ast;
|
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
|
|
|
use syntax::ast::{Attribute, Block, Crate, DefId, FnDecl, NodeId, Variant};
|
2015-03-10 05:28:44 -05:00
|
|
|
use syntax::ast::{Item, Generics, StructField};
|
2015-05-25 16:41:27 -05:00
|
|
|
use syntax::ast_util::{is_local, local_def};
|
2015-01-12 20:40:19 -06:00
|
|
|
use syntax::attr::{Stability, AttrMetaMethods};
|
2015-03-10 05:28:44 -05:00
|
|
|
use syntax::visit::{FnKind, Visitor};
|
2015-03-05 20:33:58 -06:00
|
|
|
use syntax::feature_gate::emit_feature_err;
|
2015-05-25 16:41:27 -05:00
|
|
|
use util::nodemap::{DefIdMap, FnvHashSet, FnvHashMap};
|
2015-01-01 20:41:44 -06:00
|
|
|
use util::ppaux::Repr;
|
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
|
|
|
use std::mem::replace;
|
|
|
|
|
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-05-25 16:41:27 -05:00
|
|
|
if self.index.staged_api[&ast::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-04-13 20:42:24 -05:00
|
|
|
Some(stab) => {
|
|
|
|
debug!("annotate: found {:?}", stab);
|
2015-05-25 16:41:27 -05:00
|
|
|
let stab = self.tcx.intern_stability(stab);
|
|
|
|
self.index.map.insert(local_def(id), Some(stab));
|
2015-04-13 20:42:24 -05:00
|
|
|
|
|
|
|
// Don't inherit #[stable(feature = "rust1", since = "1.0.0")]
|
|
|
|
if stab.level != attr::Stable {
|
|
|
|
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 {
|
|
|
|
self.index.map.insert(local_def(id), Some(stab));
|
|
|
|
} else if self.index.staged_api[&ast::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 {
|
2014-12-28 16:33:18 -06:00
|
|
|
ast::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 {
|
|
|
|
ast::ItemUse(_) => i.vis != ast::Public,
|
|
|
|
_ => 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
|
|
|
|
2014-11-29 15:41:21 -06:00
|
|
|
if let ast::ItemStruct(ref sd, _) = i.node {
|
|
|
|
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-03-10 05:28:44 -05:00
|
|
|
fn visit_trait_item(&mut self, ti: &ast::TraitItem) {
|
|
|
|
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-03-10 05:28:44 -05:00
|
|
|
fn visit_impl_item(&mut self, ii: &ast::ImplItem) {
|
|
|
|
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
|
|
|
|
|
|
|
fn visit_foreign_item(&mut self, i: &ast::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 {
|
|
|
|
ast::MetaWord(_) => {
|
|
|
|
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();
|
|
|
|
staged_api.insert(ast::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)
|
|
|
|
-> FnvHashMap<InternedString, attr::StabilityLevel> {
|
|
|
|
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-02-02 22:25:42 -06:00
|
|
|
used_features: FnvHashMap()
|
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-02-02 22:25:42 -06:00
|
|
|
used_features: FnvHashMap<InternedString, attr::StabilityLevel>
|
2015-01-14 17:20:14 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, 'tcx> Checker<'a, 'tcx> {
|
2015-05-25 16:41:27 -05:00
|
|
|
fn check(&mut self, id: ast::DefId, span: Span, stab: &Option<&Stability>) {
|
2015-01-14 17:20:14 -06:00
|
|
|
// Only the cross-crate scenario matters when checking unstable APIs
|
|
|
|
let cross_crate = !is_local(id);
|
|
|
|
if !cross_crate { return }
|
|
|
|
|
|
|
|
match *stab {
|
2015-05-25 16:41:27 -05:00
|
|
|
Some(&Stability { level: attr::Unstable, ref feature, ref reason, .. }) => {
|
2015-02-02 22:25:42 -06:00
|
|
|
self.used_features.insert(feature.clone(), attr::Unstable);
|
2015-01-14 17:20:14 -06:00
|
|
|
|
|
|
|
if !self.active_features.contains(feature) {
|
|
|
|
let msg = match *reason {
|
|
|
|
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-02-04 14:48:12 -06:00
|
|
|
&feature, span, &msg);
|
2015-01-14 17:20:14 -06:00
|
|
|
}
|
|
|
|
}
|
2015-05-25 16:41:27 -05:00
|
|
|
Some(&Stability { level, ref feature, .. }) => {
|
2015-02-02 22:25:42 -06:00
|
|
|
self.used_features.insert(feature.clone(), level);
|
|
|
|
|
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> {
|
|
|
|
fn visit_item(&mut self, item: &ast::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`
|
|
|
|
if item.span == DUMMY_SP && item.ident.as_str() == "__test" { return }
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_expr(&mut self, ex: &ast::Expr) {
|
|
|
|
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
|
|
|
|
|
|
|
fn visit_path(&mut self, path: &ast::Path, id: ast::NodeId) {
|
|
|
|
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
|
|
|
|
|
|
|
fn visit_pat(&mut self, pat: &ast::Pat) {
|
|
|
|
check_pat(self.tcx, pat,
|
|
|
|
&mut |id, sp, stab| self.check(id, sp, stab));
|
|
|
|
visit::walk_pat(self, pat)
|
|
|
|
}
|
2015-01-14 17:20:14 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Helper for discovering nodes to check for stability
|
2015-02-17 15:56:06 -06:00
|
|
|
pub fn check_item(tcx: &ty::ctxt, item: &ast::Item, warn_about_defns: bool,
|
2015-05-25 16:41:27 -05:00
|
|
|
cb: &mut FnMut(ast::DefId, Span, &Option<&Stability>)) {
|
2015-01-24 11:15:42 -06:00
|
|
|
match item.node {
|
|
|
|
ast::ItemExternCrate(_) => {
|
|
|
|
// 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,
|
|
|
|
};
|
|
|
|
let id = ast::DefId { krate: cnum, node: ast::CRATE_NODE_ID };
|
|
|
|
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.
|
|
|
|
ast::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-02-17 15:56:06 -06:00
|
|
|
let trait_items = ty::trait_items(tcx, trait_did);
|
|
|
|
|
|
|
|
for impl_item in impl_items {
|
|
|
|
let item = trait_items.iter().find(|item| {
|
2015-03-10 05:28:44 -05:00
|
|
|
item.name() == impl_item.ident.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
|
|
|
|
pub fn check_expr(tcx: &ty::ctxt, e: &ast::Expr,
|
2015-05-25 16:41:27 -05:00
|
|
|
cb: &mut FnMut(ast::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 {
|
|
|
|
ast::ExprMethodCall(i, _, _) => {
|
|
|
|
span = i.span;
|
|
|
|
let method_call = ty::MethodCall::expr(e.id);
|
|
|
|
match tcx.method_map.borrow().get(&method_call) {
|
|
|
|
Some(method) => {
|
|
|
|
match method.origin {
|
|
|
|
ty::MethodStatic(def_id) => {
|
|
|
|
def_id
|
|
|
|
}
|
2015-01-26 16:02:23 -06:00
|
|
|
ty::MethodStaticClosure(def_id) => {
|
2015-01-14 17:20:14 -06:00
|
|
|
def_id
|
|
|
|
}
|
|
|
|
ty::MethodTypeParam(ty::MethodParam {
|
|
|
|
ref trait_ref,
|
|
|
|
method_num: index,
|
|
|
|
..
|
|
|
|
}) |
|
|
|
|
ty::MethodTraitObject(ty::MethodObject {
|
|
|
|
ref trait_ref,
|
|
|
|
method_num: index,
|
|
|
|
..
|
|
|
|
}) => {
|
|
|
|
ty::trait_item(tcx, trait_ref.def_id, index).def_id()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => return
|
|
|
|
}
|
|
|
|
}
|
2015-02-25 05:34:21 -06:00
|
|
|
ast::ExprField(ref base_e, ref field) => {
|
|
|
|
span = field.span;
|
|
|
|
match ty::expr_ty_adjusted(tcx, base_e).sty {
|
|
|
|
ty::ty_struct(did, _) => {
|
|
|
|
ty::lookup_struct_fields(tcx, did)
|
|
|
|
.iter()
|
|
|
|
.find(|f| f.name == field.node.name)
|
|
|
|
.unwrap_or_else(|| {
|
|
|
|
tcx.sess.span_bug(field.span,
|
|
|
|
"stability::check_expr: unknown named field access")
|
|
|
|
})
|
|
|
|
.id
|
|
|
|
}
|
|
|
|
_ => tcx.sess.span_bug(e.span,
|
|
|
|
"stability::check_expr: named field access on non-struct")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast::ExprTupField(ref base_e, ref field) => {
|
|
|
|
span = field.span;
|
|
|
|
match ty::expr_ty_adjusted(tcx, base_e).sty {
|
|
|
|
ty::ty_struct(did, _) => {
|
|
|
|
ty::lookup_struct_fields(tcx, did)
|
|
|
|
.get(field.node)
|
|
|
|
.unwrap_or_else(|| {
|
|
|
|
tcx.sess.span_bug(field.span,
|
|
|
|
"stability::check_expr: unknown unnamed field access")
|
|
|
|
})
|
|
|
|
.id
|
|
|
|
}
|
|
|
|
ty::ty_tup(..) => return,
|
|
|
|
_ => tcx.sess.span_bug(e.span,
|
|
|
|
"stability::check_expr: unnamed field access on \
|
|
|
|
something other than a tuple or struct")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast::ExprStruct(_, ref expr_fields, _) => {
|
|
|
|
let type_ = ty::expr_ty(tcx, e);
|
|
|
|
match type_.sty {
|
|
|
|
ty::ty_struct(did, _) => {
|
|
|
|
let struct_fields = ty::lookup_struct_fields(tcx, did);
|
|
|
|
// check the stability of each field that appears
|
|
|
|
// in the construction expression.
|
|
|
|
for field in expr_fields {
|
|
|
|
let did = struct_fields
|
|
|
|
.iter()
|
|
|
|
.find(|f| f.name == field.ident.node.name)
|
|
|
|
.unwrap_or_else(|| {
|
|
|
|
tcx.sess.span_bug(field.span,
|
|
|
|
"stability::check_expr: unknown named \
|
|
|
|
field access")
|
|
|
|
})
|
|
|
|
.id;
|
|
|
|
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.
|
|
|
|
ty::ty_enum(..) => return,
|
|
|
|
_ => {
|
|
|
|
tcx.sess.span_bug(e.span,
|
|
|
|
&format!("stability::check_expr: struct construction \
|
|
|
|
of non-struct, type {:?}",
|
|
|
|
type_.repr(tcx)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-01-14 17:20:14 -06:00
|
|
|
_ => return
|
|
|
|
};
|
|
|
|
|
|
|
|
maybe_do_stability_check(tcx, id, span, cb);
|
|
|
|
}
|
|
|
|
|
2015-02-09 18:33:19 -06:00
|
|
|
pub fn check_path(tcx: &ty::ctxt, path: &ast::Path, id: ast::NodeId,
|
2015-05-25 16:41:27 -05:00
|
|
|
cb: &mut FnMut(ast::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(..)) => {}
|
|
|
|
Some(def) => {
|
|
|
|
maybe_do_stability_check(tcx, def.def_id(), path.span, cb);
|
|
|
|
}
|
|
|
|
None => {}
|
|
|
|
}
|
|
|
|
|
2015-02-09 18:33:19 -06:00
|
|
|
}
|
|
|
|
|
2015-02-25 05:34:21 -06:00
|
|
|
pub fn check_pat(tcx: &ty::ctxt, pat: &ast::Pat,
|
2015-05-25 16:41:27 -05:00
|
|
|
cb: &mut FnMut(ast::DefId, Span, &Option<&Stability>)) {
|
2015-02-25 05:34:21 -06:00
|
|
|
debug!("check_pat(pat = {:?})", pat);
|
|
|
|
if is_internal(tcx, pat.span) { return; }
|
|
|
|
|
|
|
|
let did = match ty::pat_ty_opt(tcx, pat) {
|
|
|
|
Some(&ty::TyS { sty: ty::ty_struct(did, _), .. }) => did,
|
|
|
|
Some(_) | None => return,
|
|
|
|
};
|
|
|
|
let struct_fields = ty::lookup_struct_fields(tcx, did);
|
|
|
|
match pat.node {
|
|
|
|
// Foo(a, b, c)
|
|
|
|
ast::PatEnum(_, Some(ref pat_fields)) => {
|
|
|
|
for (field, struct_field) in pat_fields.iter().zip(struct_fields.iter()) {
|
|
|
|
// a .. pattern is fine, but anything positional is
|
|
|
|
// not.
|
|
|
|
if let ast::PatWild(ast::PatWildMulti) = field.node {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
maybe_do_stability_check(tcx, struct_field.id, field.span, cb)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Foo { a, b, c }
|
|
|
|
ast::PatStruct(_, ref pat_fields, _) => {
|
|
|
|
for field in pat_fields {
|
|
|
|
let did = struct_fields
|
|
|
|
.iter()
|
|
|
|
.find(|f| f.name == field.node.ident.name)
|
|
|
|
.unwrap_or_else(|| {
|
|
|
|
tcx.sess.span_bug(field.span,
|
|
|
|
"stability::check_pat: unknown named field access")
|
|
|
|
})
|
|
|
|
.id;
|
|
|
|
maybe_do_stability_check(tcx, did, field.span, cb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// everything else is fine.
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-14 17:20:14 -06:00
|
|
|
fn maybe_do_stability_check(tcx: &ty::ctxt, id: ast::DefId, span: Span,
|
2015-05-25 16:41:27 -05:00
|
|
|
cb: &mut FnMut(ast::DefId, Span, &Option<&Stability>)) {
|
2015-01-14 17:20:14 -06:00
|
|
|
if !is_staged_api(tcx, id) { return }
|
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
|
|
|
if is_internal(tcx, span) { return }
|
2015-01-14 17:20:14 -06:00
|
|
|
let ref stability = lookup(tcx, id);
|
|
|
|
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 {
|
|
|
|
match ty::trait_item_of_item(tcx, id) {
|
|
|
|
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> {
|
|
|
|
debug!("lookup(id={})", id.repr(tcx));
|
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?
|
2014-08-04 15:56:56 -05:00
|
|
|
match ty::trait_item_of_item(tcx, 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
|
|
|
|
|
|
|
let item_stab = if is_local(id) {
|
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-05-25 16:41:27 -05:00
|
|
|
if ty::is_impl(tcx, id) {
|
|
|
|
if let Some(trait_id) = ty::trait_id_of_impl(tcx, id) {
|
|
|
|
// 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,
|
|
|
|
attr::StabilityLevel>) {
|
|
|
|
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";
|
|
|
|
|
|
|
|
for &span in sess.features.borrow().declared_stable_lang_features.iter() {
|
|
|
|
sess.add_lint(lint::builtin::STABLE_FEATURES,
|
|
|
|
ast::CRATE_NODE_ID,
|
|
|
|
span,
|
|
|
|
stable_msg.to_string());
|
|
|
|
}
|
|
|
|
|
|
|
|
for (used_lib_feature, level) in lib_features_used.iter() {
|
|
|
|
match remaining_lib_features.remove(used_lib_feature) {
|
|
|
|
Some(span) => {
|
|
|
|
if *level == attr::Stable {
|
|
|
|
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-02-02 22:25:42 -06:00
|
|
|
for (_, &span) in remaining_lib_features.iter() {
|
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
|
|
|
}
|