From 2e0fc86748832be1b2b0f4cbacaca53026229b22 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Wed, 11 Jun 2014 17:23:11 -0700 Subject: [PATCH] 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. --- src/doc/rust.md | 33 +++-- src/librustc/driver/driver.rs | 7 +- src/librustc/lib.rs | 1 + src/librustc/metadata/common.rs | 3 + src/librustc/metadata/csearch.rs | 8 ++ src/librustc/metadata/decoder.rs | 8 ++ src/librustc/metadata/encoder.rs | 32 ++++- src/librustc/middle/lint.rs | 40 ++---- src/librustc/middle/stability.rs | 125 +++++++++++++++++++ src/librustc/middle/ty.rs | 8 +- src/libsyntax/attr.rs | 3 +- src/test/auxiliary/inherited_stability.rs | 51 ++++++++ src/test/auxiliary/lint_output_format.rs | 27 ++++ src/test/compile-fail/lint-output-format.rs | 17 +-- src/test/compile-fail/lint-stability.rs | 131 ++++++++++++-------- 15 files changed, 385 insertions(+), 109 deletions(-) create mode 100644 src/librustc/middle/stability.rs create mode 100644 src/test/auxiliary/inherited_stability.rs create mode 100755 src/test/auxiliary/lint_output_format.rs diff --git a/src/doc/rust.md b/src/doc/rust.md index ca5ecc191cc9a..6049ffab2bf73 100644 --- a/src/doc/rust.md +++ b/src/doc/rust.md @@ -2301,28 +2301,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`" diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index e767a7c84f686..ac6558aef651f 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -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); diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index fff0ae9e40c0d..e311d1e9b15bb 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -81,6 +81,7 @@ pub mod middle { pub mod weak_lang_items; pub mod save; pub mod intrinsicck; + pub mod stability; } pub mod front { diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 5a974aecabcb2..9e1d272f5da2e 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -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, diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 43c895a201fa6..32b7df23d520a 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -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 { + let cdata = cstore.get_crate_data(def.krate); + decoder::get_stability(&*cdata, def.node) +} diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 68aa2bacd08e2..548a8c50501dd 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -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 { + 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> diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 98d9b45738fd0..a94ea0b98eb6a 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -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) { + 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())); diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index bf42f76f1a276..c2a19bb43c833 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -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 diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs new file mode 100644 index 0000000000000..fc76648ec5524 --- /dev/null +++ b/src/librustc/middle/stability.rs @@ -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 or the MIT license +// , 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, + // cache for extern-crate items; unmarked stability == entry with None + extern_cache: DefIdMap> +} + +// 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) -> Option { + match attr::find_stability(attrs).or(parent) { + Some(stab) => { + self.index.local.insert(id, stab.clone()); + Some(stab) + } + None => None + } + } +} + +impl Visitor> for Annotator { + fn visit_item(&mut self, i: &Item, parent: Option) { + 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) { + 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) { + 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) { + 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) { + 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 { + 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 { + self.local.find_copy(&id) + } +} diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index c4e48bea85e0a..c5e84b8e0c8f0 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -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>, + + /// Maps any item's def-id to its stability index. + pub stability: RefCell, } 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) } } diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 18a91fe465ec5..a037c0ac07e0e 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -361,13 +361,14 @@ pub fn test_cfg> } /// Represents the #[deprecated="foo"] and friends attributes. +#[deriving(Encodable,Decodable,Clone,Show)] pub struct Stability { pub level: StabilityLevel, pub text: Option } /// The available stability levels. -#[deriving(PartialEq,PartialOrd,Clone,Show)] +#[deriving(Encodable,Decodable,PartialEq,PartialOrd,Clone,Show)] pub enum StabilityLevel { Deprecated, Experimental, diff --git a/src/test/auxiliary/inherited_stability.rs b/src/test/auxiliary/inherited_stability.rs new file mode 100644 index 0000000000000..af3dd94fe1d77 --- /dev/null +++ b/src/test/auxiliary/inherited_stability.rs @@ -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 or the MIT license +// , 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 +} diff --git a/src/test/auxiliary/lint_output_format.rs b/src/test/auxiliary/lint_output_format.rs new file mode 100755 index 0000000000000..00500da655f7f --- /dev/null +++ b/src/test/auxiliary/lint_output_format.rs @@ -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 or the MIT license +// , 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 +} diff --git a/src/test/compile-fail/lint-output-format.rs b/src/test/compile-fail/lint-output-format.rs index ba4cf5d17fb07..db60002b468e1 100644 --- a/src/test/compile-fail/lint-output-format.rs +++ b/src/test/compile-fail/lint-output-format.rs @@ -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 diff --git a/src/test/compile-fail/lint-stability.rs b/src/test/compile-fail/lint-stability.rs index 8509afc983284..5d06ad79c9bdf 100644 --- a/src/test/compile-fail/lint-stability.rs +++ b/src/test/compile-fail/lint-stability.rs @@ -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(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(); } }