]> git.lizzy.rs Git - rust.git/commitdiff
Add stability inheritance
authorAaron Turon <aturon@mozilla.com>
Thu, 12 Jun 2014 00:23:11 +0000 (17:23 -0700)
committerAaron Turon <aturon@mozilla.com>
Thu, 19 Jun 2014 05:22:26 +0000 (22:22 -0700)
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.

15 files changed:
src/doc/rust.md
src/librustc/driver/driver.rs
src/librustc/lib.rs
src/librustc/metadata/common.rs
src/librustc/metadata/csearch.rs
src/librustc/metadata/decoder.rs
src/librustc/metadata/encoder.rs
src/librustc/middle/lint.rs
src/librustc/middle/stability.rs [new file with mode: 0644]
src/librustc/middle/ty.rs
src/libsyntax/attr.rs
src/test/auxiliary/inherited_stability.rs [new file with mode: 0644]
src/test/auxiliary/lint_output_format.rs [new file with mode: 0755]
src/test/compile-fail/lint-output-format.rs
src/test/compile-fail/lint-stability.rs

index 7e5e5b2e67a43be2c92e2f6d9c78d02b38d3db32..831c5bd97c161bb9a9b10a8fff12d3a96db2b493 100644 (file)
@@ -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`"
index e767a7c84f686fb8c489ce55a5c268aa573457bf..ac6558aef651f17e015562920e42389cad24b8b7 100644 (file)
@@ -20,7 +20,7 @@
 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);
index 86529cf198797a82a783fd0a048837e47281f155..f157e6b17e72700ac74a30d038bb8b3ff5c3fcfb 100644 (file)
@@ -80,6 +80,7 @@ pub mod middle {
     pub mod weak_lang_items;
     pub mod save;
     pub mod intrinsicck;
+    pub mod stability;
 }
 
 pub mod front {
index 5a974aecabcb285978201d3febd9017672933ceb..9e1d272f5da2e2ec8c4beb3a129dfe2a628b48d3 100644 (file)
@@ -210,6 +210,9 @@ pub fn from_uint(value : uint) -> Option<astencode_tag> {
 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,
index 43c895a201fa687215b4e33f304ee4ffa6fc4b57..32b7df23d520add0e2fa708227f4583c0e85e263 100644 (file)
@@ -25,6 +25,7 @@
 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)
+}
index 68aa2bacd08e20743661c1ba8ec8ec4a534efb67..548a8c50501ddd97951fe7d7205a16cc07002a2f 100644 (file)
@@ -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>>
index 98d9b45738fd09c138b927b2b7607463d00b9683..a94ea0b98eb6aeb307cdf69cbde723764b10778d 100644 (file)
@@ -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 add_to_index(item: &Item, ebml_w: &Encoder,
            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 add_to_index(item: &Item, ebml_w: &Encoder,
             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 add_to_index(item: &Item, ebml_w: &Encoder,
             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 add_to_index(item: &Item, ebml_w: &Encoder,
             ebml_w.end_tag();
         }
         encode_visibility(ebml_w, vis);
+        encode_stability(ebml_w, stab);
         ebml_w.end_tag();
       }
       ItemTy(..) => {
@@ -979,6 +1002,7 @@ fn add_to_index(item: &Item, ebml_w: &Encoder,
         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 add_to_index(item: &Item, ebml_w: &Encoder,
         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 add_to_index(item: &Item, ebml_w: &Encoder,
         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 add_to_index(item: &Item, ebml_w: &Encoder,
             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 add_to_index(item: &Item, ebml_w: &Encoder,
         // 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 add_to_index(item: &Item, ebml_w: &Encoder,
             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()));
 
index bf42f76f1a2769853ddeb928313d3b96bdd86813..c2a19bb43c8337ab3895ad7f19e354896360d05b 100644 (file)
@@ -372,7 +372,8 @@ pub enum LintSource {
      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 (file)
index 0000000..fc76648
--- /dev/null
@@ -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)
+    }
+}
index ac1b6ca591becaafdb65f5ec42cbe0ac2b4993a0..783c843b7a9c0ccccc569c36a1a8fa03d1c034c7 100644 (file)
@@ -25,6 +25,7 @@
 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)
     }
 }
 
index 18a91fe465ec53bc37d0bd40a145a76da08f6fcc..a037c0ac07e0e14864a0612ac902c60ec8208f6a 100644 (file)
@@ -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,
diff --git a/src/test/auxiliary/inherited_stability.rs b/src/test/auxiliary/inherited_stability.rs
new file mode 100644 (file)
index 0000000..af3dd94
--- /dev/null
@@ -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
+}
diff --git a/src/test/auxiliary/lint_output_format.rs b/src/test/auxiliary/lint_output_format.rs
new file mode 100755 (executable)
index 0000000..00500da
--- /dev/null
@@ -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
+}
index ba4cf5d17fb070036be4af4bfabaa9f266e7530b..db60002b468e11ae48a3fd358b7777383becd975 100644 (file)
@@ -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
index 8509afc983284f16edf91a7c2db678842f383d21..5d06ad79c9bdfe5e33d394ecaf16e4bbf4bd2357 100644 (file)
@@ -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 @@ fn test_method_object(foo: &Trait) {
     }
 }
 
+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 @@ pub enum Enum {
     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 @@ fn test() {
         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();
     }
 }