diff --git a/doc/rust.md b/doc/rust.md index b33006733ab37..cfe0ff4768f77 100644 --- a/doc/rust.md +++ b/doc/rust.md @@ -1038,7 +1038,7 @@ code_. They are defined in the same way as any other Rust function, except that they have the `extern` modifier. ~~~ -// Declares an extern fn, the ABI defaults to "C" +// Declares an extern fn, the ABI defaults to "C" extern fn new_vec() -> ~[int] { ~[] } // Declares an extern fn with "stdcall" ABI @@ -1723,6 +1723,62 @@ Supported traits for `deriving` are: each constituent field of the type must also implement `ToStr` and will have `field.to_str()` invoked to build up the result. +### Stability +One can indicate the stability of an API using the following attributes: + +* `deprecated`: This item should no longer be used, e.g. it has been + replaced. No guarantee of backwards-compatibility. +* `experimental`: This item was only recently introduced or is + otherwise in a state of flux. It may change significantly, or even + be removed. No guarantee of backwards-compatibility. +* `unstable`: This item is still under development, but requires more + testing to be considered stable. No guarantee of backwards-compatibility. +* `stable`: This item is considered stable, and will not change + significantly. Guarantee of backwards-compatibility. +* `frozen`: This item is very stable, and is unlikely to + change. Guarantee of backwards-compatibility. +* `locked`: This item will never change unless a serious bug is + found. Guarantee of backwards-compatibility. + +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 +string that will be displayed when the lint flags the use of an item. + +~~~ {.xfail-test} +#[warn(unstable)]; + +#[deprecated="replaced by `best`"] +fn bad() { + // delete everything +} + +fn better() { + // delete fewer things +} + +#[stable] +fn best() { + // delete nothing +} + +fn main() { + bad(); // "warning: use of deprecated item: replaced by `best`" + + better(); // "warning: use of unmarked item" + + best(); // no warning +} +~~~ + +> **Note:** Currently these are only checked when applied to +> individual functions, structs, methods and enum variants, *not* to +> entire modules, traits, impls or enums themselves. + # Statements and expressions Rust is _primarily_ an expression language. This means that most forms of diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 1b469676773c0..786d1bf324251 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -330,6 +330,7 @@ fn encode_enum_variant_info(ecx: &EncodeContext, encode_name(ecx, ebml_w, variant.node.name); encode_parent_item(ebml_w, local_def(id)); encode_visibility(ebml_w, variant.node.vis); + encode_attributes(ebml_w, variant.node.attrs); match variant.node.kind { ast::tuple_variant_kind(ref args) if args.len() > 0 && generics.ty_params.len() == 0 => { diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index 596fd05b26276..1e1be5f7a13b7 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -12,6 +12,7 @@ use driver::session; use middle::ty; use middle::pat_util; +use metadata::csearch; use util::ppaux::{ty_to_str}; use std::cmp; @@ -27,7 +28,7 @@ use std::u8; use extra::smallintmap::SmallIntMap; use syntax::ast_map; use syntax::attr; -use syntax::attr::AttrMetaMethods; +use syntax::attr::{AttrMetaMethods, AttributeMethods}; use syntax::codemap::Span; use syntax::codemap; use syntax::parse::token; @@ -97,6 +98,10 @@ pub enum lint { missing_doc, unreachable_code, + deprecated, + experimental, + unstable, + warnings, } @@ -281,6 +286,27 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[ default: warn }), + ("deprecated", + LintSpec { + lint: deprecated, + desc: "detects use of #[deprecated] items", + default: warn + }), + + ("experimental", + LintSpec { + lint: experimental, + desc: "detects use of #[experimental] items", + default: warn + }), + + ("unstable", + LintSpec { + lint: unstable, + desc: "detects use of #[unstable] items (incl. items with no stability attribute)", + default: allow + }), + ("warnings", LintSpec { lint: warnings, @@ -1375,6 +1401,107 @@ fn lint_missing_doc() -> @mut OuterLint { @mut MissingDocLintVisitor { stopping_on_items: false } as @mut OuterLint } +/// Checks for use of items with #[deprecated], #[experimental] and +/// #[unstable] (or none of them) attributes. +struct StabilityLintVisitor { stopping_on_items: bool } + +impl StabilityLintVisitor { + fn handle_def(&mut self, sp: Span, def: &ast::Def, cx: @mut Context) { + let id = ast_util::def_id_of_def(*def); + + let stability = if ast_util::is_local(id) { + // this crate + match cx.tcx.items.find(&id.node) { + Some(ast_node) => { + let s = do ast_node.with_attrs |attrs| { + do attrs.map_move |a| { + attr::find_stability(a.iter().map(|a| a.meta())) + } + }; + match s { + Some(s) => s, + + // no possibility of having attributes + // (e.g. it's a local variable), so just + // ignore it. + None => return + } + } + _ => cx.tcx.sess.bug(fmt!("handle_def: %? not found", id)) + } + } else { + // cross-crate + + let mut s = None; + // run through all the attributes and take the first + // stability one. + do csearch::get_item_attrs(cx.tcx.cstore, id) |meta_items| { + if s.is_none() { + s = attr::find_stability(meta_items.move_iter()) + } + } + s + }; + + let (lint, label) = match stability { + // no stability attributes == Unstable + None => (unstable, "unmarked"), + Some(attr::Stability { level: attr::Unstable, _ }) => (unstable, "unstable"), + Some(attr::Stability { level: attr::Experimental, _ }) => { + (experimental, "experimental") + } + Some(attr::Stability { level: attr::Deprecated, _ }) => (deprecated, "deprecated"), + _ => return + }; + + let msg = match stability { + Some(attr::Stability { text: Some(ref s), _ }) => { + fmt!("use of %s item: %s", label, *s) + } + _ => fmt!("use of %s item", label) + }; + + cx.span_lint(lint, sp, msg); + } +} + +impl SubitemStoppableVisitor for StabilityLintVisitor { + fn is_running_on_items(&mut self) -> bool { !self.stopping_on_items } +} + +impl Visitor<@mut Context> for StabilityLintVisitor { + fn visit_item(&mut self, i:@ast::item, e:@mut Context) { + self.OVERRIDE_visit_item(i, e); + } + + fn visit_fn(&mut self, fk:&visit::fn_kind, fd:&ast::fn_decl, + b:&ast::Block, s:Span, n:ast::NodeId, e:@mut Context) { + self.OVERRIDE_visit_fn(fk, fd, b, s, n, e); + } + + fn visit_expr(&mut self, ex: @ast::Expr, cx: @mut Context) { + match ex.node { + ast::ExprMethodCall(*) | + ast::ExprPath(*) | + ast::ExprStruct(*) => { + match cx.tcx.def_map.find(&ex.id) { + Some(def) => self.handle_def(ex.span, def, cx), + None => {} + } + } + _ => {} + } + + visit::walk_expr(self, ex, cx) + } +} + +outer_lint_boilerplate_impl!(StabilityLintVisitor) + +fn lint_stability() -> @mut OuterLint { + @mut StabilityLintVisitor { stopping_on_items: false } as @mut OuterLint +} + struct LintCheckVisitor; impl Visitor<@mut Context> for LintCheckVisitor { @@ -1458,6 +1585,7 @@ pub fn check_crate(tcx: ty::ctxt, crate: @ast::Crate) { cx.add_old_lint(lint_unused_mut()); cx.add_old_lint(lint_unnecessary_allocations()); cx.add_old_lint(lint_missing_doc()); + cx.add_old_lint(lint_stability()); cx.add_lint(lint_session(cx)); // Actually perform the lint checks (iterating the ast) diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 3266ec5c9abf4..dc26350d88d42 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -4706,4 +4706,3 @@ pub fn trait_of_method(tcx: ctxt, def_id: ast::DefId) result } - diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs index ccaadcbad4df4..e3023b919f879 100644 --- a/src/libsyntax/ast_map.rs +++ b/src/libsyntax/ast_map.rs @@ -80,6 +80,26 @@ pub enum ast_node { node_callee_scope(@Expr) } +impl ast_node { + pub fn with_attrs(&self, f: &fn(Option<&[Attribute]>) -> T) -> T { + let attrs = match *self { + node_item(i, _) => Some(i.attrs.as_slice()), + node_foreign_item(fi, _, _, _) => Some(fi.attrs.as_slice()), + node_trait_method(tm, _, _) => match *tm { + required(ref type_m) => Some(type_m.attrs.as_slice()), + provided(m) => Some(m.attrs.as_slice()) + }, + node_method(m, _, _) => Some(m.attrs.as_slice()), + node_variant(ref v, _, _) => Some(v.node.attrs.as_slice()), + // unit/tuple structs take the attributes straight from + // the struct definition. + node_struct_ctor(_, strct, _) => Some(strct.attrs.as_slice()), + _ => None + }; + f(attrs) + } +} + pub type map = @mut HashMap; pub struct Ctx { diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 2ed03040fa1f3..fd0887de7224b 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -313,6 +313,44 @@ pub fn test_cfg> no_cfgs || some_cfg_matches } +/// Represents the #[deprecated="foo"] (etc) attributes. +pub struct Stability { + level: StabilityLevel, + text: Option<@str> +} + +/// The available stability levels. +#[deriving(Eq,Ord,Clone)] +pub enum StabilityLevel { + Deprecated, + Experimental, + Unstable, + Stable, + Frozen, + Locked +} + +/// Find the first stability attribute. `None` if none exists. +pub fn find_stability>(mut metas: It) -> Option { + for m in metas { + let level = match m.name().as_slice() { + "deprecated" => Deprecated, + "experimental" => Experimental, + "unstable" => Unstable, + "stable" => Stable, + "frozen" => Frozen, + "locked" => Locked, + _ => loop // not a stability level + }; + + return Some(Stability { + level: level, + text: m.value_str() + }); + } + None +} + pub fn require_unique_names(diagnostic: @mut span_handler, metas: &[@MetaItem]) { let mut set = HashSet::new(); diff --git a/src/test/auxiliary/lint_stability.rs b/src/test/auxiliary/lint_stability.rs new file mode 100644 index 0000000000000..af00a6876c27d --- /dev/null +++ b/src/test/auxiliary/lint_stability.rs @@ -0,0 +1,162 @@ +// Copyright 2013 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. +#[link(name = "lint_stability", + vers = "0.1")]; +#[crate_type = "lib"]; + +#[deprecated] +pub fn deprecated() {} +#[deprecated="text"] +pub fn deprecated_text() {} + +#[experimental] +pub fn experimental() {} +#[experimental="text"] +pub fn experimental_text() {} + +#[unstable] +pub fn unstable() {} +#[unstable="text"] +pub fn unstable_text() {} + +pub fn unmarked() {} + +#[stable] +pub fn stable() {} +#[stable="text"] +pub fn stable_text() {} + +#[locked] +pub fn locked() {} +#[locked="text"] +pub fn locked_text() {} + +#[frozen] +pub fn frozen() {} +#[frozen="text"] +pub fn frozen_text() {} + +#[stable] +pub struct MethodTester; + +impl MethodTester { + #[deprecated] + pub fn method_deprecated(&self) {} + #[deprecated="text"] + pub fn method_deprecated_text(&self) {} + + #[experimental] + pub fn method_experimental(&self) {} + #[experimental="text"] + pub fn method_experimental_text(&self) {} + + #[unstable] + pub fn method_unstable(&self) {} + #[unstable="text"] + pub fn method_unstable_text(&self) {} + + pub fn method_unmarked(&self) {} + + #[stable] + pub fn method_stable(&self) {} + #[stable="text"] + pub fn method_stable_text(&self) {} + + #[locked] + pub fn method_locked(&self) {} + #[locked="text"] + pub fn method_locked_text(&self) {} + + #[frozen] + pub fn method_frozen(&self) {} + #[frozen="text"] + pub fn method_frozen_text(&self) {} +} + +pub trait Trait { + #[deprecated] + fn trait_deprecated(&self) {} + #[deprecated="text"] + fn trait_deprecated_text(&self) {} + + #[experimental] + fn trait_experimental(&self) {} + #[experimental="text"] + fn trait_experimental_text(&self) {} + + #[unstable] + fn trait_unstable(&self) {} + #[unstable="text"] + fn trait_unstable_text(&self) {} + + fn trait_unmarked(&self) {} + + #[stable] + fn trait_stable(&self) {} + #[stable="text"] + fn trait_stable_text(&self) {} + + #[locked] + fn trait_locked(&self) {} + #[locked="text"] + fn trait_locked_text(&self) {} + + #[frozen] + fn trait_frozen(&self) {} + #[frozen="text"] + fn trait_frozen_text(&self) {} +} + +impl Trait for MethodTester {} + +#[deprecated] +pub struct DeprecatedStruct { i: int } +#[experimental] +pub struct ExperimentalStruct { i: int } +#[unstable] +pub struct UnstableStruct { i: int } +pub struct UnmarkedStruct { i: int } +#[stable] +pub struct StableStruct { i: int } +#[frozen] +pub struct FrozenStruct { i: int } +#[locked] +pub struct LockedStruct { i: int } + +#[deprecated] +pub struct DeprecatedUnitStruct; +#[experimental] +pub struct ExperimentalUnitStruct; +#[unstable] +pub struct UnstableUnitStruct; +pub struct UnmarkedUnitStruct; +#[stable] +pub struct StableUnitStruct; +#[frozen] +pub struct FrozenUnitStruct; +#[locked] +pub struct LockedUnitStruct; + +pub enum Enum { + #[deprecated] + DeprecatedVariant, + #[experimental] + ExperimentalVariant, + #[unstable] + UnstableVariant, + + UnmarkedVariant, + #[stable] + StableVariant, + #[frozen] + FrozenVariant, + #[locked] + LockedVariant, +} diff --git a/src/test/compile-fail/lint-stability.rs b/src/test/compile-fail/lint-stability.rs new file mode 100644 index 0000000000000..2c8b768587584 --- /dev/null +++ b/src/test/compile-fail/lint-stability.rs @@ -0,0 +1,338 @@ +// Copyright 2013 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. + +// xfail-fast aux-build +// aux-build:lint_stability.rs + +#[deny(unstable)]; +#[deny(deprecated)]; +#[deny(experimental)]; + +mod cross_crate { + extern mod lint_stability; + use self::lint_stability::*; + + fn test() { + // XXX: attributes on methods are not encoded cross 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_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 + + experimental(); //~ ERROR use of experimental item + foo.method_experimental(); // ~ ERROR use of experimental item + foo.trait_experimental(); // ~ ERROR use of experimental item + + 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 + + unstable(); //~ ERROR use of unstable item + foo.method_unstable(); // ~ ERROR use of unstable item + foo.trait_unstable(); // ~ ERROR use of unstable item + + 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 + + unmarked(); //~ ERROR use of unmarked item + foo.method_unmarked(); // ~ ERROR use of unmarked item + foo.trait_unmarked(); // ~ ERROR use of unmarked item + + stable(); + foo.method_stable(); + foo.trait_stable(); + + stable_text(); + foo.method_stable_text(); + foo.trait_stable_text(); + + frozen(); + foo.method_frozen(); + foo.trait_frozen(); + + frozen_text(); + foo.method_frozen_text(); + foo.trait_frozen_text(); + + locked(); + foo.method_locked(); + foo.trait_locked(); + + locked_text(); + foo.method_locked_text(); + 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 _ = 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 _ = 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 _ = StableVariant; + let _ = FrozenVariant; + let _ = LockedVariant; + } +} + +mod this_crate { + #[deprecated] + pub fn deprecated() {} + #[deprecated="text"] + pub fn deprecated_text() {} + + #[experimental] + pub fn experimental() {} + #[experimental="text"] + pub fn experimental_text() {} + + #[unstable] + pub fn unstable() {} + #[unstable="text"] + pub fn unstable_text() {} + + pub fn unmarked() {} + + #[stable] + pub fn stable() {} + #[stable="text"] + pub fn stable_text() {} + + #[locked] + pub fn locked() {} + #[locked="text"] + pub fn locked_text() {} + + #[frozen] + pub fn frozen() {} + #[frozen="text"] + pub fn frozen_text() {} + + #[stable] + pub struct MethodTester; + + impl MethodTester { + #[deprecated] + pub fn method_deprecated(&self) {} + #[deprecated="text"] + pub fn method_deprecated_text(&self) {} + + #[experimental] + pub fn method_experimental(&self) {} + #[experimental="text"] + pub fn method_experimental_text(&self) {} + + #[unstable] + pub fn method_unstable(&self) {} + #[unstable="text"] + pub fn method_unstable_text(&self) {} + + pub fn method_unmarked(&self) {} + + #[stable] + pub fn method_stable(&self) {} + #[stable="text"] + pub fn method_stable_text(&self) {} + + #[locked] + pub fn method_locked(&self) {} + #[locked="text"] + pub fn method_locked_text(&self) {} + + #[frozen] + pub fn method_frozen(&self) {} + #[frozen="text"] + pub fn method_frozen_text(&self) {} + } + + pub trait Trait { + #[deprecated] + fn trait_deprecated(&self) {} + #[deprecated="text"] + fn trait_deprecated_text(&self) {} + + #[experimental] + fn trait_experimental(&self) {} + #[experimental="text"] + fn trait_experimental_text(&self) {} + + #[unstable] + fn trait_unstable(&self) {} + #[unstable="text"] + fn trait_unstable_text(&self) {} + + fn trait_unmarked(&self) {} + + #[stable] + fn trait_stable(&self) {} + #[stable="text"] + fn trait_stable_text(&self) {} + + #[locked] + fn trait_locked(&self) {} + #[locked="text"] + fn trait_locked_text(&self) {} + + #[frozen] + fn trait_frozen(&self) {} + #[frozen="text"] + fn trait_frozen_text(&self) {} + } + + impl Trait for MethodTester {} + + #[deprecated] + pub struct DeprecatedStruct { i: int } + #[experimental] + pub struct ExperimentalStruct { i: int } + #[unstable] + pub struct UnstableStruct { i: int } + pub struct UnmarkedStruct { i: int } + #[stable] + pub struct StableStruct { i: int } + #[frozen] + pub struct FrozenStruct { i: int } + #[locked] + pub struct LockedStruct { i: int } + + #[deprecated] + pub struct DeprecatedUnitStruct; + #[experimental] + pub struct ExperimentalUnitStruct; + #[unstable] + pub struct UnstableUnitStruct; + pub struct UnmarkedUnitStruct; + #[stable] + pub struct StableUnitStruct; + #[frozen] + pub struct FrozenUnitStruct; + #[locked] + pub struct LockedUnitStruct; + + pub enum Enum { + #[deprecated] + DeprecatedVariant, + #[experimental] + ExperimentalVariant, + #[unstable] + UnstableVariant, + + UnmarkedVariant, + #[stable] + StableVariant, + #[frozen] + FrozenVariant, + #[locked] + LockedVariant, + } + + fn test() { + 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_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 + + experimental(); //~ ERROR use of experimental item + foo.method_experimental(); // ~ ERROR use of experimental item + foo.trait_experimental(); // ~ ERROR use of experimental item + + 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 + + unstable(); //~ ERROR use of unstable item + foo.method_unstable(); // ~ ERROR use of unstable item + foo.trait_unstable(); // ~ ERROR use of unstable item + + 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 + + unmarked(); //~ ERROR use of unmarked item + foo.method_unmarked(); // ~ ERROR use of unmarked item + foo.trait_unmarked(); // ~ ERROR use of unmarked item + + stable(); + foo.method_stable(); + foo.trait_stable(); + + stable_text(); + foo.method_stable_text(); + foo.trait_stable_text(); + + frozen(); + foo.method_frozen(); + foo.trait_frozen(); + + frozen_text(); + foo.method_frozen_text(); + foo.trait_frozen_text(); + + locked(); + foo.method_locked(); + foo.trait_locked(); + + locked_text(); + foo.method_locked_text(); + 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 _ = 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 _ = 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 _ = StableVariant; + let _ = FrozenVariant; + let _ = LockedVariant; + } +} + +fn main() {}