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.
This commit is contained in:
parent
f05cd6e04e
commit
6008f2c982
15 changed files with 385 additions and 109 deletions
|
@ -2300,28 +2300,43 @@ One can indicate the stability of an API using the following attributes:
|
|||
These levels are directly inspired by
|
||||
[Node.js' "stability index"](http://nodejs.org/api/documentation.html).
|
||||
|
||||
There are lints for disallowing items marked with certain levels:
|
||||
`deprecated`, `experimental` and `unstable`; the first two will warn
|
||||
by default. Items with not marked with a stability are considered to
|
||||
be unstable for the purposes of the lint. One can give an optional
|
||||
Stability levels are inherited, so an items's stability attribute is the
|
||||
default stability for everything nested underneath it.
|
||||
|
||||
There are lints for disallowing items marked with certain levels: `deprecated`,
|
||||
`experimental` and `unstable`. For now, only `deprecated` warns by default, but
|
||||
this will change once the standard library has been stabilized.
|
||||
Stability levels are meant to be promises at the crate
|
||||
level, so these lints only apply when referencing
|
||||
items from an _external_ crate, not to items defined within the
|
||||
current crate. Items with no stability level are considered
|
||||
to be unstable for the purposes of the lint. One can give an optional
|
||||
string that will be displayed when the lint flags the use of an item.
|
||||
|
||||
~~~~ {.ignore}
|
||||
#![warn(unstable)]
|
||||
For example, if we define one crate called `stability_levels`:
|
||||
|
||||
~~~~ {.ignore}
|
||||
#[deprecated="replaced by `best`"]
|
||||
fn bad() {
|
||||
pub fn bad() {
|
||||
// delete everything
|
||||
}
|
||||
|
||||
fn better() {
|
||||
pub fn better() {
|
||||
// delete fewer things
|
||||
}
|
||||
|
||||
#[stable]
|
||||
fn best() {
|
||||
pub fn best() {
|
||||
// delete nothing
|
||||
}
|
||||
~~~~
|
||||
|
||||
then the lints will work as follows for a client crate:
|
||||
|
||||
~~~~ {.ignore}
|
||||
#![warn(unstable)]
|
||||
extern crate stability_levels;
|
||||
use stability_levels::{bad, better, best};
|
||||
|
||||
fn main() {
|
||||
bad(); // "warning: use of deprecated item: replaced by `best`"
|
||||
|
|
|
@ -20,7 +20,7 @@ use metadata::common::LinkMeta;
|
|||
use metadata::creader;
|
||||
use middle::cfg;
|
||||
use middle::cfg::graphviz::LabelledCFG;
|
||||
use middle::{trans, freevars, kind, ty, typeck, lint, reachable};
|
||||
use middle::{trans, freevars, stability, kind, ty, typeck, lint, reachable};
|
||||
use middle::dependency_format;
|
||||
use middle;
|
||||
use plugin::load::Plugins;
|
||||
|
@ -312,8 +312,11 @@ pub fn phase_3_run_analysis_passes(sess: Session,
|
|||
time(time_passes, "loop checking", (), |_|
|
||||
middle::check_loop::check_crate(&sess, krate));
|
||||
|
||||
let stability_index = time(time_passes, "stability index", (), |_|
|
||||
stability::Index::build(krate));
|
||||
|
||||
let ty_cx = ty::mk_ctxt(sess, def_map, named_region_map, ast_map,
|
||||
freevars, region_map, lang_items);
|
||||
freevars, region_map, lang_items, stability_index);
|
||||
|
||||
// passes are timed inside typeck
|
||||
typeck::check_crate(&ty_cx, trait_map, krate);
|
||||
|
|
|
@ -80,6 +80,7 @@ pub mod middle {
|
|||
pub mod weak_lang_items;
|
||||
pub mod save;
|
||||
pub mod intrinsicck;
|
||||
pub mod stability;
|
||||
}
|
||||
|
||||
pub mod front {
|
||||
|
|
|
@ -210,6 +210,9 @@ pub static tag_method_argument_name: uint = 0x8f;
|
|||
pub static tag_reachable_extern_fns: uint = 0x90;
|
||||
pub static tag_reachable_extern_fn_id: uint = 0x91;
|
||||
|
||||
pub static tag_items_data_item_stability: uint = 0x92;
|
||||
|
||||
|
||||
#[deriving(Clone, Show)]
|
||||
pub struct LinkMeta {
|
||||
pub crateid: CrateId,
|
||||
|
|
|
@ -25,6 +25,7 @@ use serialize::ebml::reader;
|
|||
use std::rc::Rc;
|
||||
use syntax::ast;
|
||||
use syntax::ast_map;
|
||||
use syntax::attr;
|
||||
use syntax::diagnostic::expect;
|
||||
use syntax::parse::token;
|
||||
|
||||
|
@ -328,3 +329,10 @@ pub fn is_typedef(cstore: &cstore::CStore, did: ast::DefId) -> bool {
|
|||
let cdata = cstore.get_crate_data(did.krate);
|
||||
decoder::is_typedef(&*cdata, did.node)
|
||||
}
|
||||
|
||||
pub fn get_stability(cstore: &cstore::CStore,
|
||||
def: ast::DefId)
|
||||
-> Option<attr::Stability> {
|
||||
let cdata = cstore.get_crate_data(def.krate);
|
||||
decoder::get_stability(&*cdata, def.node)
|
||||
}
|
||||
|
|
|
@ -439,6 +439,14 @@ pub fn get_type(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt)
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_stability(cdata: Cmd, id: ast::NodeId) -> Option<attr::Stability> {
|
||||
let item = lookup_item(id, cdata.data());
|
||||
reader::maybe_get_doc(item, tag_items_data_item_stability).map(|doc| {
|
||||
let mut decoder = reader::Decoder::new(doc);
|
||||
Decodable::decode(&mut decoder).unwrap()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_impl_trait(cdata: Cmd,
|
||||
id: ast::NodeId,
|
||||
tcx: &ty::ctxt) -> Option<Rc<ty::TraitRef>>
|
||||
|
|
|
@ -327,6 +327,10 @@ fn encode_enum_variant_info(ecx: &EncodeContext,
|
|||
encode_parent_item(ebml_w, local_def(id));
|
||||
encode_visibility(ebml_w, variant.node.vis);
|
||||
encode_attributes(ebml_w, variant.node.attrs.as_slice());
|
||||
|
||||
let stab = ecx.tcx.stability.borrow().lookup_local(variant.node.id);
|
||||
encode_stability(ebml_w, stab);
|
||||
|
||||
match variant.node.kind {
|
||||
ast::TupleVariantKind(ref args)
|
||||
if args.len() > 0 && generics.ty_params.len() == 0 => {
|
||||
|
@ -588,6 +592,7 @@ fn encode_info_for_mod(ecx: &EncodeContext,
|
|||
|
||||
encode_path(ebml_w, path.clone());
|
||||
encode_visibility(ebml_w, vis);
|
||||
encode_stability(ebml_w, ecx.tcx.stability.borrow().lookup_local(id));
|
||||
|
||||
// Encode the reexports of this module, if this module is public.
|
||||
if vis == Public {
|
||||
|
@ -717,6 +722,8 @@ fn encode_info_for_struct_ctor(ecx: &EncodeContext,
|
|||
encode_symbol(ecx, ebml_w, ctor_id);
|
||||
}
|
||||
|
||||
encode_stability(ebml_w, ecx.tcx.stability.borrow().lookup_local(ctor_id));
|
||||
|
||||
// indicate that this is a tuple struct ctor, because downstream users will normally want
|
||||
// the tuple struct definition, but without this there is no way for them to tell that
|
||||
// they actually have a ctor rather than a normal function
|
||||
|
@ -761,6 +768,9 @@ fn encode_info_for_method(ecx: &EncodeContext,
|
|||
encode_method_ty_fields(ecx, ebml_w, m);
|
||||
encode_parent_item(ebml_w, local_def(parent_id));
|
||||
|
||||
let stab = ecx.tcx.stability.borrow().lookup_local(m.def_id.node);
|
||||
encode_stability(ebml_w, stab);
|
||||
|
||||
// The type for methods gets encoded twice, which is unfortunate.
|
||||
let tpt = lookup_item_type(ecx.tcx, m.def_id);
|
||||
encode_bounds_and_type(ebml_w, ecx, &tpt);
|
||||
|
@ -880,6 +890,14 @@ fn encode_sized(ebml_w: &mut Encoder, sized: Sized) {
|
|||
ebml_w.end_tag();
|
||||
}
|
||||
|
||||
fn encode_stability(ebml_w: &mut Encoder, stab_opt: Option<attr::Stability>) {
|
||||
stab_opt.map(|stab| {
|
||||
ebml_w.start_tag(tag_items_data_item_stability);
|
||||
stab.encode(ebml_w).unwrap();
|
||||
ebml_w.end_tag();
|
||||
});
|
||||
}
|
||||
|
||||
fn encode_info_for_item(ecx: &EncodeContext,
|
||||
ebml_w: &mut Encoder,
|
||||
item: &Item,
|
||||
|
@ -900,6 +918,8 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
|||
ecx.tcx.sess.codemap().span_to_str(item.span));
|
||||
|
||||
let def_id = local_def(item.id);
|
||||
let stab = tcx.stability.borrow().lookup_local(item.id);
|
||||
|
||||
match item.node {
|
||||
ItemStatic(_, m, _) => {
|
||||
add_to_index(item, ebml_w, index);
|
||||
|
@ -921,6 +941,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
|||
encode_inlined_item(ecx, ebml_w, IIItemRef(item));
|
||||
}
|
||||
encode_visibility(ebml_w, vis);
|
||||
encode_stability(ebml_w, stab);
|
||||
ebml_w.end_tag();
|
||||
}
|
||||
ItemFn(ref decl, fn_style, _, ref generics, _) => {
|
||||
|
@ -939,6 +960,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
|||
encode_symbol(ecx, ebml_w, item.id);
|
||||
}
|
||||
encode_visibility(ebml_w, vis);
|
||||
encode_stability(ebml_w, stab);
|
||||
encode_method_argument_names(ebml_w, &**decl);
|
||||
ebml_w.end_tag();
|
||||
}
|
||||
|
@ -968,6 +990,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
|||
ebml_w.end_tag();
|
||||
}
|
||||
encode_visibility(ebml_w, vis);
|
||||
encode_stability(ebml_w, stab);
|
||||
ebml_w.end_tag();
|
||||
}
|
||||
ItemTy(..) => {
|
||||
|
@ -979,6 +1002,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
|||
encode_name(ebml_w, item.ident.name);
|
||||
encode_path(ebml_w, path);
|
||||
encode_visibility(ebml_w, vis);
|
||||
encode_stability(ebml_w, stab);
|
||||
ebml_w.end_tag();
|
||||
}
|
||||
ItemEnum(ref enum_definition, ref generics) => {
|
||||
|
@ -1001,6 +1025,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
|||
encode_inherent_implementations(ecx, ebml_w, def_id);
|
||||
|
||||
encode_visibility(ebml_w, vis);
|
||||
encode_stability(ebml_w, stab);
|
||||
ebml_w.end_tag();
|
||||
|
||||
encode_enum_variant_info(ecx,
|
||||
|
@ -1035,6 +1060,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
|||
encode_name(ebml_w, item.ident.name);
|
||||
encode_attributes(ebml_w, item.attrs.as_slice());
|
||||
encode_path(ebml_w, path.clone());
|
||||
encode_stability(ebml_w, stab);
|
||||
encode_visibility(ebml_w, vis);
|
||||
|
||||
/* Encode def_ids for each field and method
|
||||
|
@ -1095,6 +1121,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
|||
encode_impl_vtables(ebml_w, ecx, &impl_vtables);
|
||||
}
|
||||
encode_path(ebml_w, path.clone());
|
||||
encode_stability(ebml_w, stab);
|
||||
ebml_w.end_tag();
|
||||
|
||||
// Iterate down the methods, emitting them. We rely on the
|
||||
|
@ -1138,6 +1165,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
|||
// should no longer need this ugly little hack either.
|
||||
encode_sized(ebml_w, sized);
|
||||
encode_visibility(ebml_w, vis);
|
||||
encode_stability(ebml_w, stab);
|
||||
for &method_def_id in ty::trait_method_def_ids(tcx, def_id).iter() {
|
||||
ebml_w.start_tag(tag_item_trait_method);
|
||||
encode_def_id(ebml_w, method_def_id);
|
||||
|
@ -1176,9 +1204,11 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
|||
ebml_w.start_tag(tag_items_data_item);
|
||||
|
||||
encode_method_ty_fields(ecx, ebml_w, &*method_ty);
|
||||
|
||||
encode_parent_item(ebml_w, def_id);
|
||||
|
||||
let stab = tcx.stability.borrow().lookup_local(method_def_id.node);
|
||||
encode_stability(ebml_w, stab);
|
||||
|
||||
let elem = ast_map::PathName(method_ty.ident.name);
|
||||
encode_path(ebml_w, path.clone().chain(Some(elem).move_iter()));
|
||||
|
||||
|
|
|
@ -372,7 +372,8 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[
|
|||
LintSpec {
|
||||
lint: Experimental,
|
||||
desc: "detects use of #[experimental] items",
|
||||
default: Warn
|
||||
// FIXME #6875: Change to Warn after std library stabilization is complete
|
||||
default: Allow
|
||||
}),
|
||||
|
||||
("unstable",
|
||||
|
@ -1661,6 +1662,8 @@ fn check_missing_doc_variant(cx: &Context, v: &ast::Variant) {
|
|||
/// Checks for use of items with #[deprecated], #[experimental] and
|
||||
/// #[unstable] (or none of them) attributes.
|
||||
fn check_stability(cx: &Context, e: &ast::Expr) {
|
||||
let tcx = cx.tcx;
|
||||
|
||||
let id = match e.node {
|
||||
ast::ExprPath(..) | ast::ExprStruct(..) => {
|
||||
match cx.tcx.def_map.borrow().find(&e.id) {
|
||||
|
@ -1670,7 +1673,7 @@ fn check_stability(cx: &Context, e: &ast::Expr) {
|
|||
}
|
||||
ast::ExprMethodCall(..) => {
|
||||
let method_call = typeck::MethodCall::expr(e.id);
|
||||
match cx.tcx.method_map.borrow().find(&method_call) {
|
||||
match tcx.method_map.borrow().find(&method_call) {
|
||||
Some(method) => {
|
||||
match method.origin {
|
||||
typeck::MethodStatic(def_id) => {
|
||||
|
@ -1678,8 +1681,8 @@ fn check_stability(cx: &Context, e: &ast::Expr) {
|
|||
// of the method inside trait definition.
|
||||
// Otherwise, use the current def_id (which refers
|
||||
// to the method inside impl).
|
||||
ty::trait_method_of_method(
|
||||
cx.tcx, def_id).unwrap_or(def_id)
|
||||
ty::trait_method_of_method(cx.tcx, def_id)
|
||||
.unwrap_or(def_id)
|
||||
}
|
||||
typeck::MethodParam(typeck::MethodParam {
|
||||
trait_id: trait_id,
|
||||
|
@ -1699,32 +1702,11 @@ fn check_stability(cx: &Context, e: &ast::Expr) {
|
|||
_ => return
|
||||
};
|
||||
|
||||
let stability = if ast_util::is_local(id) {
|
||||
// this crate
|
||||
let s = cx.tcx.map.with_attrs(id.node, |attrs| {
|
||||
attrs.map(|a| attr::find_stability(a.as_slice()))
|
||||
});
|
||||
match s {
|
||||
Some(s) => s,
|
||||
// stability attributes are promises made across crates; do not
|
||||
// check anything for crate-local usage.
|
||||
if ast_util::is_local(id) { return }
|
||||
|
||||
// no possibility of having attributes
|
||||
// (e.g. it's a local variable), so just
|
||||
// ignore it.
|
||||
None => return
|
||||
}
|
||||
} else {
|
||||
// cross-crate
|
||||
|
||||
let mut s = None;
|
||||
// run through all the attributes and take the first
|
||||
// stability one.
|
||||
csearch::get_item_attrs(&cx.tcx.sess.cstore, id, |attrs| {
|
||||
if s.is_none() {
|
||||
s = attr::find_stability(attrs.as_slice())
|
||||
}
|
||||
});
|
||||
s
|
||||
};
|
||||
let stability = tcx.stability.borrow_mut().lookup(&tcx.sess.cstore, id);
|
||||
|
||||
let (lint, label) = match stability {
|
||||
// no stability attributes == Unstable
|
||||
|
|
125
src/librustc/middle/stability.rs
Normal file
125
src/librustc/middle/stability.rs
Normal file
|
@ -0,0 +1,125 @@
|
|||
// 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.
|
||||
|
||||
use util::nodemap::{NodeMap, DefIdMap};
|
||||
use syntax::codemap::Span;
|
||||
use syntax::{attr, visit};
|
||||
use syntax::ast::{Attribute, Block, Crate, DefId, FnDecl, NodeId, Variant};
|
||||
use syntax::ast::{Item, Required, Provided, TraitMethod, TypeMethod, Method};
|
||||
use syntax::ast::{Generics, StructDef, Ident};
|
||||
use syntax::ast_util::is_local;
|
||||
use syntax::attr::Stability;
|
||||
use syntax::visit::{FnKind, FkMethod, Visitor};
|
||||
use metadata::{cstore, csearch};
|
||||
|
||||
/// A stability index, giving the stability level for items and methods.
|
||||
pub struct Index {
|
||||
// stability for crate-local items; unmarked stability == no entry
|
||||
local: NodeMap<Stability>,
|
||||
// cache for extern-crate items; unmarked stability == entry with None
|
||||
extern_cache: DefIdMap<Option<Stability>>
|
||||
}
|
||||
|
||||
// A private tree-walker for producing an Index.
|
||||
struct Annotator {
|
||||
index: Index
|
||||
}
|
||||
|
||||
impl Annotator {
|
||||
// Determine the stability for a node based on its attributes and inherited
|
||||
// stability. The stability is recorded in the index and returned.
|
||||
fn annotate(&mut self, id: NodeId, attrs: &[Attribute],
|
||||
parent: Option<Stability>) -> Option<Stability> {
|
||||
match attr::find_stability(attrs).or(parent) {
|
||||
Some(stab) => {
|
||||
self.index.local.insert(id, stab.clone());
|
||||
Some(stab)
|
||||
}
|
||||
None => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Visitor<Option<Stability>> for Annotator {
|
||||
fn visit_item(&mut self, i: &Item, parent: Option<Stability>) {
|
||||
let stab = self.annotate(i.id, i.attrs.as_slice(), parent);
|
||||
visit::walk_item(self, i, stab)
|
||||
}
|
||||
|
||||
fn visit_fn(&mut self, fk: &FnKind, fd: &FnDecl, b: &Block,
|
||||
s: Span, _: NodeId, parent: Option<Stability>) {
|
||||
let stab = match *fk {
|
||||
FkMethod(_, _, meth) =>
|
||||
self.annotate(meth.id, meth.attrs.as_slice(), parent),
|
||||
_ => parent
|
||||
};
|
||||
visit::walk_fn(self, fk, fd, b, s, stab)
|
||||
}
|
||||
|
||||
fn visit_trait_method(&mut self, t: &TraitMethod, parent: Option<Stability>) {
|
||||
let stab = match *t {
|
||||
Required(TypeMethod {attrs: ref attrs, id: id, ..}) =>
|
||||
self.annotate(id, attrs.as_slice(), parent),
|
||||
|
||||
// work around lack of pattern matching for @ types
|
||||
Provided(method) => match *method {
|
||||
Method {attrs: ref attrs, id: id, ..} =>
|
||||
self.annotate(id, attrs.as_slice(), parent)
|
||||
}
|
||||
};
|
||||
visit::walk_trait_method(self, t, stab)
|
||||
}
|
||||
|
||||
fn visit_variant(&mut self, v: &Variant, g: &Generics, parent: Option<Stability>) {
|
||||
let stab = self.annotate(v.node.id, v.node.attrs.as_slice(), parent);
|
||||
visit::walk_variant(self, v, g, stab)
|
||||
}
|
||||
|
||||
fn visit_struct_def(&mut self, s: &StructDef, _: Ident, _: &Generics,
|
||||
_: NodeId, parent: Option<Stability>) {
|
||||
s.ctor_id.map(|id| self.annotate(id, &[], parent.clone()));
|
||||
visit::walk_struct_def(self, s, parent)
|
||||
}
|
||||
}
|
||||
|
||||
impl Index {
|
||||
/// Construct the stability index for a crate being compiled.
|
||||
pub fn build(krate: &Crate) -> Index {
|
||||
let mut annotator = Annotator {
|
||||
index: Index {
|
||||
local: NodeMap::new(),
|
||||
extern_cache: DefIdMap::new()
|
||||
}
|
||||
};
|
||||
visit::walk_crate(&mut annotator, krate,
|
||||
attr::find_stability(krate.attrs.as_slice()));
|
||||
annotator.index
|
||||
}
|
||||
|
||||
/// Lookup the stability for a node, loading external crate
|
||||
/// metadata as necessary.
|
||||
pub fn lookup(&mut self, cstore: &cstore::CStore, id: DefId) -> Option<Stability> {
|
||||
if is_local(id) {
|
||||
self.lookup_local(id.node)
|
||||
} else {
|
||||
let stab = csearch::get_stability(cstore, id);
|
||||
self.extern_cache.insert(id, stab.clone());
|
||||
stab
|
||||
}
|
||||
}
|
||||
|
||||
/// Lookup the stability for a local node without loading any external crates
|
||||
pub fn lookup_local(&self, id: NodeId) -> Option<Stability> {
|
||||
self.local.find_copy(&id)
|
||||
}
|
||||
}
|
|
@ -25,6 +25,7 @@ use middle::resolve;
|
|||
use middle::resolve_lifetime;
|
||||
use middle::subst;
|
||||
use middle::subst::{Subst, Substs, VecPerParamSpace};
|
||||
use middle::stability;
|
||||
use middle::ty;
|
||||
use middle::typeck;
|
||||
use middle::typeck::MethodCall;
|
||||
|
@ -373,6 +374,9 @@ pub struct ctxt {
|
|||
/// to be valid. We gather up these restrictions in the intrinsicck pass
|
||||
/// and check them in trans.
|
||||
pub transmute_restrictions: RefCell<Vec<TransmuteRestriction>>,
|
||||
|
||||
/// Maps any item's def-id to its stability index.
|
||||
pub stability: RefCell<stability::Index>,
|
||||
}
|
||||
|
||||
pub enum tbox_flag {
|
||||
|
@ -1065,7 +1069,8 @@ pub fn mk_ctxt(s: Session,
|
|||
map: ast_map::Map,
|
||||
freevars: freevars::freevar_map,
|
||||
region_maps: middle::region::RegionMaps,
|
||||
lang_items: middle::lang_items::LanguageItems)
|
||||
lang_items: middle::lang_items::LanguageItems,
|
||||
stability: stability::Index)
|
||||
-> ctxt {
|
||||
ctxt {
|
||||
named_region_map: named_region_map,
|
||||
|
@ -1119,6 +1124,7 @@ pub fn mk_ctxt(s: Session,
|
|||
dependency_formats: RefCell::new(HashMap::new()),
|
||||
node_lint_levels: RefCell::new(HashMap::new()),
|
||||
transmute_restrictions: RefCell::new(Vec::new()),
|
||||
stability: RefCell::new(stability)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -361,13 +361,14 @@ pub fn test_cfg<AM: AttrMetaMethods, It: Iterator<AM>>
|
|||
}
|
||||
|
||||
/// Represents the #[deprecated="foo"] and friends attributes.
|
||||
#[deriving(Encodable,Decodable,Clone,Show)]
|
||||
pub struct Stability {
|
||||
pub level: StabilityLevel,
|
||||
pub text: Option<InternedString>
|
||||
}
|
||||
|
||||
/// The available stability levels.
|
||||
#[deriving(PartialEq,PartialOrd,Clone,Show)]
|
||||
#[deriving(Encodable,Decodable,PartialEq,PartialOrd,Clone,Show)]
|
||||
pub enum StabilityLevel {
|
||||
Deprecated,
|
||||
Experimental,
|
||||
|
|
51
src/test/auxiliary/inherited_stability.rs
Normal file
51
src/test/auxiliary/inherited_stability.rs
Normal file
|
@ -0,0 +1,51 @@
|
|||
// 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.
|
||||
#![crate_id="inherited_stability#0.1"]
|
||||
#![crate_type = "lib"]
|
||||
#![experimental]
|
||||
|
||||
pub fn experimental() {}
|
||||
|
||||
#[stable]
|
||||
pub fn stable() {}
|
||||
|
||||
#[stable]
|
||||
pub mod stable_mod {
|
||||
#[experimental]
|
||||
pub fn experimental() {}
|
||||
|
||||
pub fn stable() {}
|
||||
}
|
||||
|
||||
pub mod experimental_mod {
|
||||
pub fn experimental() {}
|
||||
|
||||
#[stable]
|
||||
pub fn stable() {}
|
||||
}
|
||||
|
||||
#[stable]
|
||||
pub trait Stable {
|
||||
#[experimental]
|
||||
fn experimental(&self);
|
||||
|
||||
fn stable(&self);
|
||||
}
|
||||
|
||||
impl Stable for uint {
|
||||
fn experimental(&self) {}
|
||||
fn stable(&self) {}
|
||||
}
|
||||
|
||||
pub enum Experimental {
|
||||
ExperimentalVariant,
|
||||
#[stable]
|
||||
StableVariant
|
||||
}
|
27
src/test/auxiliary/lint_output_format.rs
Executable file
27
src/test/auxiliary/lint_output_format.rs
Executable file
|
@ -0,0 +1,27 @@
|
|||
// 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.
|
||||
|
||||
#![crate_id="lint_output_format#0.1"]
|
||||
#![crate_type = "lib"]
|
||||
|
||||
#[deprecated]
|
||||
pub fn foo() -> uint {
|
||||
20
|
||||
}
|
||||
|
||||
#[experimental]
|
||||
pub fn bar() -> uint {
|
||||
40
|
||||
}
|
||||
|
||||
#[unstable]
|
||||
pub fn baz() -> uint {
|
||||
30
|
||||
}
|
|
@ -9,21 +9,10 @@
|
|||
// except according to those terms.
|
||||
|
||||
// compile-flags:-F experimental -D unstable
|
||||
// aux-build:lint_output_format.rs
|
||||
|
||||
#[deprecated]
|
||||
fn foo() -> uint {
|
||||
20
|
||||
}
|
||||
|
||||
#[experimental]
|
||||
fn bar() -> uint {
|
||||
40
|
||||
}
|
||||
|
||||
#[unstable]
|
||||
fn baz() -> uint {
|
||||
30
|
||||
}
|
||||
extern crate lint_output_format;
|
||||
use lint_output_format::{foo, bar, baz};
|
||||
|
||||
fn main() {
|
||||
let _x = foo(); //~ WARNING #[warn(deprecated)] on by default
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
// aux-build:lint_stability.rs
|
||||
// aux-build:inherited_stability.rs
|
||||
|
||||
#![feature(globs)]
|
||||
#![deny(unstable)]
|
||||
|
@ -21,7 +22,6 @@ mod cross_crate {
|
|||
use self::lint_stability::*;
|
||||
|
||||
fn test() {
|
||||
// FIXME: attributes on methods are not encoded cross crate.
|
||||
let foo = MethodTester;
|
||||
|
||||
deprecated(); //~ ERROR use of deprecated item
|
||||
|
@ -133,6 +133,29 @@ mod cross_crate {
|
|||
}
|
||||
}
|
||||
|
||||
mod inheritance {
|
||||
extern crate inherited_stability;
|
||||
use self::inherited_stability::*;
|
||||
|
||||
fn test_inheritance() {
|
||||
experimental(); //~ ERROR use of experimental item
|
||||
stable();
|
||||
|
||||
stable_mod::experimental(); //~ ERROR use of experimental item
|
||||
stable_mod::stable();
|
||||
|
||||
experimental_mod::experimental(); //~ ERROR use of experimental item
|
||||
experimental_mod::stable();
|
||||
|
||||
let _ = ExperimentalVariant; //~ ERROR use of experimental item
|
||||
let _ = StableVariant;
|
||||
|
||||
let x: uint = 0;
|
||||
x.experimental(); //~ ERROR use of experimental item
|
||||
x.stable();
|
||||
}
|
||||
}
|
||||
|
||||
mod this_crate {
|
||||
#[deprecated]
|
||||
pub fn deprecated() {}
|
||||
|
@ -299,35 +322,39 @@ mod this_crate {
|
|||
pub struct LockedTupleStruct(int);
|
||||
|
||||
fn test() {
|
||||
// None of the following should generate errors, because
|
||||
// stability attributes now have meaning only *across* crates,
|
||||
// not within a single crate.
|
||||
|
||||
let foo = MethodTester;
|
||||
|
||||
deprecated(); //~ ERROR use of deprecated item
|
||||
foo.method_deprecated(); //~ ERROR use of deprecated item
|
||||
foo.trait_deprecated(); //~ ERROR use of deprecated item
|
||||
deprecated();
|
||||
foo.method_deprecated();
|
||||
foo.trait_deprecated();
|
||||
|
||||
deprecated_text(); //~ ERROR use of deprecated item: text
|
||||
foo.method_deprecated_text(); //~ ERROR use of deprecated item: text
|
||||
foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
|
||||
deprecated_text();
|
||||
foo.method_deprecated_text();
|
||||
foo.trait_deprecated_text();
|
||||
|
||||
experimental(); //~ ERROR use of experimental item
|
||||
foo.method_experimental(); //~ ERROR use of experimental item
|
||||
foo.trait_experimental(); //~ ERROR use of experimental item
|
||||
experimental();
|
||||
foo.method_experimental();
|
||||
foo.trait_experimental();
|
||||
|
||||
experimental_text(); //~ ERROR use of experimental item: text
|
||||
foo.method_experimental_text(); //~ ERROR use of experimental item: text
|
||||
foo.trait_experimental_text(); //~ ERROR use of experimental item: text
|
||||
experimental_text();
|
||||
foo.method_experimental_text();
|
||||
foo.trait_experimental_text();
|
||||
|
||||
unstable(); //~ ERROR use of unstable item
|
||||
foo.method_unstable(); //~ ERROR use of unstable item
|
||||
foo.trait_unstable(); //~ ERROR use of unstable item
|
||||
unstable();
|
||||
foo.method_unstable();
|
||||
foo.trait_unstable();
|
||||
|
||||
unstable_text(); //~ ERROR use of unstable item: text
|
||||
foo.method_unstable_text(); //~ ERROR use of unstable item: text
|
||||
foo.trait_unstable_text(); //~ ERROR use of unstable item: text
|
||||
unstable_text();
|
||||
foo.method_unstable_text();
|
||||
foo.trait_unstable_text();
|
||||
|
||||
unmarked(); //~ ERROR use of unmarked item
|
||||
foo.method_unmarked(); //~ ERROR use of unmarked item
|
||||
foo.trait_unmarked(); //~ ERROR use of unmarked item
|
||||
unmarked();
|
||||
foo.method_unmarked();
|
||||
foo.trait_unmarked();
|
||||
|
||||
stable();
|
||||
foo.method_stable();
|
||||
|
@ -354,58 +381,58 @@ mod this_crate {
|
|||
foo.trait_locked_text();
|
||||
|
||||
|
||||
let _ = DeprecatedStruct { i: 0 }; //~ ERROR use of deprecated item
|
||||
let _ = ExperimentalStruct { i: 0 }; //~ ERROR use of experimental item
|
||||
let _ = UnstableStruct { i: 0 }; //~ ERROR use of unstable item
|
||||
let _ = UnmarkedStruct { i: 0 }; //~ ERROR use of unmarked item
|
||||
let _ = DeprecatedStruct { i: 0 };
|
||||
let _ = ExperimentalStruct { i: 0 };
|
||||
let _ = UnstableStruct { i: 0 };
|
||||
let _ = UnmarkedStruct { i: 0 };
|
||||
let _ = StableStruct { i: 0 };
|
||||
let _ = FrozenStruct { i: 0 };
|
||||
let _ = LockedStruct { i: 0 };
|
||||
|
||||
let _ = DeprecatedUnitStruct; //~ ERROR use of deprecated item
|
||||
let _ = ExperimentalUnitStruct; //~ ERROR use of experimental item
|
||||
let _ = UnstableUnitStruct; //~ ERROR use of unstable item
|
||||
let _ = UnmarkedUnitStruct; //~ ERROR use of unmarked item
|
||||
let _ = DeprecatedUnitStruct;
|
||||
let _ = ExperimentalUnitStruct;
|
||||
let _ = UnstableUnitStruct;
|
||||
let _ = UnmarkedUnitStruct;
|
||||
let _ = StableUnitStruct;
|
||||
let _ = FrozenUnitStruct;
|
||||
let _ = LockedUnitStruct;
|
||||
|
||||
let _ = DeprecatedVariant; //~ ERROR use of deprecated item
|
||||
let _ = ExperimentalVariant; //~ ERROR use of experimental item
|
||||
let _ = UnstableVariant; //~ ERROR use of unstable item
|
||||
let _ = UnmarkedVariant; //~ ERROR use of unmarked item
|
||||
let _ = DeprecatedVariant;
|
||||
let _ = ExperimentalVariant;
|
||||
let _ = UnstableVariant;
|
||||
let _ = UnmarkedVariant;
|
||||
let _ = StableVariant;
|
||||
let _ = FrozenVariant;
|
||||
let _ = LockedVariant;
|
||||
|
||||
let _ = DeprecatedTupleStruct (1); //~ ERROR use of deprecated item
|
||||
let _ = ExperimentalTupleStruct (1); //~ ERROR use of experimental item
|
||||
let _ = UnstableTupleStruct (1); //~ ERROR use of unstable item
|
||||
let _ = UnmarkedTupleStruct (1); //~ ERROR use of unmarked item
|
||||
let _ = DeprecatedTupleStruct (1);
|
||||
let _ = ExperimentalTupleStruct (1);
|
||||
let _ = UnstableTupleStruct (1);
|
||||
let _ = UnmarkedTupleStruct (1);
|
||||
let _ = StableTupleStruct (1);
|
||||
let _ = FrozenTupleStruct (1);
|
||||
let _ = LockedTupleStruct (1);
|
||||
}
|
||||
|
||||
fn test_method_param<F: Trait>(foo: F) {
|
||||
foo.trait_deprecated(); //~ ERROR use of deprecated item
|
||||
foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
|
||||
foo.trait_experimental(); //~ ERROR use of experimental item
|
||||
foo.trait_experimental_text(); //~ ERROR use of experimental item: text
|
||||
foo.trait_unstable(); //~ ERROR use of unstable item
|
||||
foo.trait_unstable_text(); //~ ERROR use of unstable item: text
|
||||
foo.trait_unmarked(); //~ ERROR use of unmarked item
|
||||
foo.trait_deprecated();
|
||||
foo.trait_deprecated_text();
|
||||
foo.trait_experimental();
|
||||
foo.trait_experimental_text();
|
||||
foo.trait_unstable();
|
||||
foo.trait_unstable_text();
|
||||
foo.trait_unmarked();
|
||||
foo.trait_stable();
|
||||
}
|
||||
|
||||
fn test_method_object(foo: &Trait) {
|
||||
foo.trait_deprecated(); //~ ERROR use of deprecated item
|
||||
foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
|
||||
foo.trait_experimental(); //~ ERROR use of experimental item
|
||||
foo.trait_experimental_text(); //~ ERROR use of experimental item: text
|
||||
foo.trait_unstable(); //~ ERROR use of unstable item
|
||||
foo.trait_unstable_text(); //~ ERROR use of unstable item: text
|
||||
foo.trait_unmarked(); //~ ERROR use of unmarked item
|
||||
foo.trait_deprecated();
|
||||
foo.trait_deprecated_text();
|
||||
foo.trait_experimental();
|
||||
foo.trait_experimental_text();
|
||||
foo.trait_unstable();
|
||||
foo.trait_unstable_text();
|
||||
foo.trait_unmarked();
|
||||
foo.trait_stable();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue