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:
Aaron Turon 2014-06-11 17:23:11 -07:00
parent f05cd6e04e
commit 6008f2c982
15 changed files with 385 additions and 109 deletions

View 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`"

View file

@ -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);

View 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 {

View file

@ -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,

View file

@ -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)
}

View 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>>

View 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 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()));

View file

@ -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

View 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)
}
}

View file

@ -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)
}
}

View 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,

View 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
}

View 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
}

View 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

View 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 @@ 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();
}
}