Refactor attr::Stability

Stricter checking + enforcement of invariants at compile time
This commit is contained in:
Vadim Petrochenkov 2015-10-13 06:01:31 +03:00
parent 843e528fd0
commit ab671552c3
17 changed files with 307 additions and 894 deletions

View File

@ -11,6 +11,8 @@
//! A pass that annotates every item and method with its stability level,
//! propagating default levels lexically from parent to children ast nodes.
pub use self::StabilityLevel::*;
use session::Session;
use lint;
use metadata::cstore::LOCAL_CRATE;
@ -34,6 +36,18 @@ use rustc_front::visit::{self, FnKind, Visitor};
use std::mem::replace;
use std::cmp::Ordering;
#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Copy, Debug, Eq, Hash)]
pub enum StabilityLevel {
Unstable,
Stable,
}
impl StabilityLevel {
pub fn from_attr_level(level: &attr::StabilityLevel) -> Self {
if level.is_stable() { Stable } else { Unstable }
}
}
/// A stability index, giving the stability level for items and methods.
pub struct Index<'tcx> {
/// This is mostly a cache, except the stabilities of local items
@ -67,10 +81,9 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
// if parent is deprecated and we're not, inherit this by merging
// deprecated_since and its reason.
if let Some(parent_stab) = self.parent {
if parent_stab.deprecated_since.is_some()
&& stab.deprecated_since.is_none() {
stab.deprecated_since = parent_stab.deprecated_since.clone();
stab.reason = parent_stab.reason.clone();
if parent_stab.depr.is_some()
&& stab.depr.is_none() {
stab.depr = parent_stab.depr.clone()
}
}
@ -78,9 +91,9 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
// Check if deprecated_since < stable_since. If it is,
// this is *almost surely* an accident.
let deprecated_predates_stable = match (stab.deprecated_since.as_ref(),
stab.since.as_ref()) {
(Some(dep_since), Some(stab_since)) => {
let deprecated_predates_stable = match (&stab.depr, &stab.level) {
(&Some(attr::Deprecation {since: ref dep_since, ..}),
&attr::Stable {since: ref stab_since}) => {
// explicit version of iter::order::lt to handle parse errors properly
let mut is_less = false;
for (dep_v, stab_v) in dep_since.split(".").zip(stab_since.split(".")) {
@ -117,7 +130,7 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
self.index.map.insert(def_id, Some(stab));
// Don't inherit #[stable(feature = "rust1", since = "1.0.0")]
if stab.level != attr::Stable {
if !stab.level.is_stable() {
let parent = replace(&mut self.parent, Some(stab));
f(self);
self.parent = parent;
@ -261,7 +274,7 @@ impl<'tcx> Index<'tcx> {
/// features and possibly prints errors. Returns a list of all
/// features used.
pub fn check_unstable_api_usage(tcx: &ty::ctxt)
-> FnvHashMap<InternedString, attr::StabilityLevel> {
-> FnvHashMap<InternedString, StabilityLevel> {
let ref active_lib_features = tcx.sess.features.borrow().declared_lib_features;
// Put the active features into a map for quick lookup
@ -284,7 +297,7 @@ pub fn check_unstable_api_usage(tcx: &ty::ctxt)
struct Checker<'a, 'tcx: 'a> {
tcx: &'a ty::ctxt<'tcx>,
active_features: FnvHashSet<InternedString>,
used_features: FnvHashMap<InternedString, attr::StabilityLevel>,
used_features: FnvHashMap<InternedString, StabilityLevel>,
// Within a block where feature gate checking can be skipped.
in_skip_block: u32,
}
@ -303,8 +316,8 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
}
match *stab {
Some(&Stability { level: attr::Unstable, ref feature, ref reason, issue, .. }) => {
self.used_features.insert(feature.clone(), attr::Unstable);
Some(&Stability { level: attr::Unstable {ref reason, issue}, ref feature, .. }) => {
self.used_features.insert(feature.clone(), Unstable);
if !self.active_features.contains(feature) {
let msg = match *reason {
@ -312,13 +325,12 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
&feature, &r),
None => format!("use of unstable library feature '{}'", &feature)
};
emit_feature_err(&self.tcx.sess.parse_sess.span_diagnostic,
&feature, span, GateIssue::Library(issue), &msg);
&feature, span, GateIssue::Library(Some(issue)), &msg);
}
}
Some(&Stability { level, ref feature, .. }) => {
self.used_features.insert(feature.clone(), level);
Some(&Stability { ref level, ref feature, .. }) => {
self.used_features.insert(feature.clone(), StabilityLevel::from_attr_level(level));
// Stable APIs are always ok to call and deprecated APIs are
// handled by a lint.
@ -636,7 +648,7 @@ fn lookup_uncached<'tcx>(tcx: &ty::ctxt<'tcx>, id: DefId) -> Option<&'tcx Stabil
/// libraries, identify activated features that don't exist and error about them.
pub fn check_unused_or_stable_features(sess: &Session,
lib_features_used: &FnvHashMap<InternedString,
attr::StabilityLevel>) {
StabilityLevel>) {
let ref declared_lib_features = sess.features.borrow().declared_lib_features;
let mut remaining_lib_features: FnvHashMap<InternedString, Span>
= declared_lib_features.clone().into_iter().collect();
@ -653,7 +665,7 @@ pub fn check_unused_or_stable_features(sess: &Session,
for (used_lib_feature, level) in lib_features_used {
match remaining_lib_features.remove(used_lib_feature) {
Some(span) => {
if *level == attr::Stable {
if *level == Stable {
sess.add_lint(lint::builtin::STABLE_FEATURES,
ast::CRATE_NODE_ID,
span,

View File

@ -1,625 +0,0 @@
// Copyright 2012-2015 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.
// Functions dealing with attributes and meta items
pub use self::StabilityLevel::*;
pub use self::ReprAttr::*;
pub use self::IntType::*;
use hir;
use syntax::codemap::{Span, Spanned, spanned, dummy_spanned};
use syntax::codemap::BytePos;
use syntax::diagnostic::SpanHandler;
use syntax::attr as syntax_attr;
use syntax::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
use syntax::parse::token::{InternedString, intern_and_get_ident};
use syntax::parse::token;
use syntax::ptr::P;
use std::cell::Cell;
use std::collections::HashSet;
use std::fmt;
pub fn mark_used(attr: &Attribute) {
syntax_attr::mark_used(&unlower_attribute(attr))
}
pub trait AttrMetaMethods {
fn check_name(&self, name: &str) -> bool {
name == &self.name()[..]
}
/// Retrieve the name of the meta item, e.g. `foo` in `#[foo]`,
/// `#[foo="bar"]` and `#[foo(bar)]`
fn name(&self) -> InternedString;
/// Gets the string value if self is a MetaNameValue variant
/// containing a string, otherwise None.
fn value_str(&self) -> Option<InternedString>;
/// Gets a list of inner meta items from a list MetaItem type.
fn meta_item_list<'a>(&'a self) -> Option<&'a [P<MetaItem>]>;
fn span(&self) -> Span;
}
impl AttrMetaMethods for Attribute {
fn check_name(&self, name: &str) -> bool {
let matches = name == &self.name()[..];
if matches {
syntax_attr::mark_used(&unlower_attribute(self));
}
matches
}
fn name(&self) -> InternedString { self.meta().name() }
fn value_str(&self) -> Option<InternedString> {
self.meta().value_str()
}
fn meta_item_list<'a>(&'a self) -> Option<&'a [P<MetaItem>]> {
self.node.value.meta_item_list()
}
fn span(&self) -> Span { self.meta().span }
}
impl AttrMetaMethods for MetaItem {
fn name(&self) -> InternedString {
match self.node {
MetaWord(ref n) => (*n).clone(),
MetaNameValue(ref n, _) => (*n).clone(),
MetaList(ref n, _) => (*n).clone(),
}
}
fn value_str(&self) -> Option<InternedString> {
match self.node {
MetaNameValue(_, ref v) => {
match v.node {
hir::LitStr(ref s, _) => Some((*s).clone()),
_ => None,
}
},
_ => None
}
}
fn meta_item_list<'a>(&'a self) -> Option<&'a [P<MetaItem>]> {
match self.node {
MetaList(_, ref l) => Some(&l[..]),
_ => None
}
}
fn span(&self) -> Span { self.span }
}
// Annoying, but required to get test_cfg to work
impl AttrMetaMethods for P<MetaItem> {
fn name(&self) -> InternedString { (**self).name() }
fn value_str(&self) -> Option<InternedString> { (**self).value_str() }
fn meta_item_list<'a>(&'a self) -> Option<&'a [P<MetaItem>]> {
(**self).meta_item_list()
}
fn span(&self) -> Span { (**self).span() }
}
pub trait AttributeMethods {
fn meta<'a>(&'a self) -> &'a MetaItem;
fn with_desugared_doc<T, F>(&self, f: F) -> T where
F: FnOnce(&Attribute) -> T;
}
impl AttributeMethods for Attribute {
/// Extract the MetaItem from inside this Attribute.
fn meta<'a>(&'a self) -> &'a MetaItem {
&*self.node.value
}
/// Convert self to a normal #[doc="foo"] comment, if it is a
/// comment like `///` or `/** */`. (Returns self unchanged for
/// non-sugared doc attributes.)
fn with_desugared_doc<T, F>(&self, f: F) -> T where
F: FnOnce(&Attribute) -> T,
{
if self.node.is_sugared_doc {
let comment = self.value_str().unwrap();
let meta = mk_name_value_item_str(
InternedString::new("doc"),
token::intern_and_get_ident(&strip_doc_comment_decoration(
&comment)));
if self.node.style == hir::AttrOuter {
f(&mk_attr_outer(self.node.id, meta))
} else {
f(&mk_attr_inner(self.node.id, meta))
}
} else {
f(self)
}
}
}
/* Constructors */
pub fn mk_name_value_item_str(name: InternedString, value: InternedString)
-> P<MetaItem> {
let value_lit = dummy_spanned(hir::LitStr(value, hir::CookedStr));
mk_name_value_item(name, value_lit)
}
pub fn mk_name_value_item(name: InternedString, value: hir::Lit)
-> P<MetaItem> {
P(dummy_spanned(MetaNameValue(name, value)))
}
pub fn mk_list_item(name: InternedString, items: Vec<P<MetaItem>>) -> P<MetaItem> {
P(dummy_spanned(MetaList(name, items)))
}
pub fn mk_word_item(name: InternedString) -> P<MetaItem> {
P(dummy_spanned(MetaWord(name)))
}
thread_local! { static NEXT_ATTR_ID: Cell<usize> = Cell::new(0) }
pub fn mk_attr_id() -> AttrId {
let id = NEXT_ATTR_ID.with(|slot| {
let r = slot.get();
slot.set(r + 1);
r
});
AttrId(id)
}
/// Returns an inner attribute with the given value.
pub fn mk_attr_inner(id: AttrId, item: P<MetaItem>) -> Attribute {
dummy_spanned(Attribute_ {
id: id,
style: hir::AttrStyle::Inner,
value: item,
is_sugared_doc: false,
})
}
/// Returns an outer attribute with the given value.
pub fn mk_attr_outer(id: AttrId, item: P<MetaItem>) -> Attribute {
dummy_spanned(Attribute_ {
id: id,
style: hir::AttrStyle::Outer,
value: item,
is_sugared_doc: false,
})
}
pub fn mk_sugared_doc_attr(id: AttrId, text: InternedString, lo: BytePos,
hi: BytePos)
-> Attribute {
let style = lower_attr_style(doc_comment_style(&text));
let lit = spanned(lo, hi, hir::LitStr(text, hir::CookedStr));
let attr = Attribute_ {
id: id,
style: style,
value: P(spanned(lo, hi, MetaNameValue(InternedString::new("doc"),
lit))),
is_sugared_doc: true
};
spanned(lo, hi, attr)
}
/* Searching */
/// Check if `needle` occurs in `haystack` by a structural
/// comparison. This is slightly subtle, and relies on ignoring the
/// span included in the `==` comparison a plain MetaItem.
pub fn contains(haystack: &[P<MetaItem>], needle: &MetaItem) -> bool {
debug!("attr::contains (name={})", needle.name());
haystack.iter().any(|item| {
debug!(" testing: {}", item.name());
item.node == needle.node
})
}
pub fn contains_name<AM: AttrMetaMethods>(metas: &[AM], name: &str) -> bool {
debug!("attr::contains_name (name={})", name);
metas.iter().any(|item| {
debug!(" testing: {}", item.name());
item.check_name(name)
})
}
pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: &str)
-> Option<InternedString> {
attrs.iter()
.find(|at| at.check_name(name))
.and_then(|at| at.value_str())
}
pub fn last_meta_item_value_str_by_name(items: &[P<MetaItem>], name: &str)
-> Option<InternedString> {
items.iter()
.rev()
.find(|mi| mi.check_name(name))
.and_then(|i| i.value_str())
}
/* Higher-level applications */
pub fn sort_meta_items(items: Vec<P<MetaItem>>) -> Vec<P<MetaItem>> {
// This is sort of stupid here, but we need to sort by
// human-readable strings.
let mut v = items.into_iter()
.map(|mi| (mi.name(), mi))
.collect::<Vec<(InternedString, P<MetaItem>)>>();
v.sort_by(|&(ref a, _), &(ref b, _)| a.cmp(b));
// There doesn't seem to be a more optimal way to do this
v.into_iter().map(|(_, m)| m.map(|Spanned {node, span}| {
Spanned {
node: match node {
MetaList(n, mis) => MetaList(n, sort_meta_items(mis)),
_ => node
},
span: span
}
})).collect()
}
pub fn find_crate_name(attrs: &[Attribute]) -> Option<InternedString> {
first_attr_value_str_by_name(attrs, "crate_name")
}
/// Find the value of #[export_name=*] attribute and check its validity.
pub fn find_export_name_attr(diag: &SpanHandler, attrs: &[Attribute]) -> Option<InternedString> {
attrs.iter().fold(None, |ia,attr| {
if attr.check_name("export_name") {
if let s@Some(_) = attr.value_str() {
s
} else {
diag.span_err(attr.span, "export_name attribute has invalid format");
diag.handler.help("use #[export_name=\"*\"]");
None
}
} else {
ia
}
})
}
#[derive(Copy, Clone, PartialEq)]
pub enum InlineAttr {
None,
Hint,
Always,
Never,
}
/// Determine what `#[inline]` attribute is present in `attrs`, if any.
pub fn find_inline_attr(diagnostic: Option<&SpanHandler>, attrs: &[Attribute]) -> InlineAttr {
attrs.iter().fold(InlineAttr::None, |ia,attr| {
match attr.node.value.node {
MetaWord(ref n) if *n == "inline" => {
syntax_attr::mark_used(&unlower_attribute(attr));
InlineAttr::Hint
}
MetaList(ref n, ref items) if *n == "inline" => {
syntax_attr::mark_used(&unlower_attribute(attr));
if items.len() != 1 {
diagnostic.map(|d|{ d.span_err(attr.span, "expected one argument"); });
InlineAttr::None
} else if contains_name(&items[..], "always") {
InlineAttr::Always
} else if contains_name(&items[..], "never") {
InlineAttr::Never
} else {
diagnostic.map(|d|{ d.span_err((*items[0]).span, "invalid argument"); });
InlineAttr::None
}
}
_ => ia
}
})
}
/// True if `#[inline]` or `#[inline(always)]` is present in `attrs`.
pub fn requests_inline(attrs: &[Attribute]) -> bool {
match find_inline_attr(None, attrs) {
InlineAttr::Hint | InlineAttr::Always => true,
InlineAttr::None | InlineAttr::Never => false,
}
}
/// Represents the #[deprecated] and friends attributes.
#[derive(RustcEncodable, RustcDecodable, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Stability {
pub level: StabilityLevel,
pub feature: InternedString,
pub since: Option<InternedString>,
pub deprecated_since: Option<InternedString>,
// The reason for the current stability level. If deprecated, the
// reason for deprecation.
pub reason: Option<InternedString>,
// The relevant rust-lang issue
pub issue: Option<u32>
}
/// The available stability levels.
#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Copy, Eq, Hash)]
pub enum StabilityLevel {
Unstable,
Stable,
}
impl fmt::Display for StabilityLevel {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self, f)
}
}
fn find_stability_generic<'a,
AM: AttrMetaMethods,
I: Iterator<Item=&'a AM>>
(diagnostic: &SpanHandler, attrs: I, item_sp: Span)
-> (Option<Stability>, Vec<&'a AM>) {
let mut stab: Option<Stability> = None;
let mut deprecated: Option<(Option<InternedString>, Option<InternedString>)> = None;
let mut used_attrs: Vec<&'a AM> = vec![];
'outer: for attr in attrs {
let tag = attr.name();
let tag = &tag[..];
if tag != "deprecated" && tag != "unstable" && tag != "stable" {
continue // not a stability level
}
used_attrs.push(attr);
let (feature, since, reason, issue) = match attr.meta_item_list() {
Some(metas) => {
let mut feature = None;
let mut since = None;
let mut reason = None;
let mut issue = None;
for meta in metas {
match &*meta.name() {
"feature" => {
match meta.value_str() {
Some(v) => feature = Some(v),
None => {
diagnostic.span_err(meta.span, "incorrect meta item");
continue 'outer;
}
}
}
"since" => {
match meta.value_str() {
Some(v) => since = Some(v),
None => {
diagnostic.span_err(meta.span, "incorrect meta item");
continue 'outer;
}
}
}
"reason" => {
match meta.value_str() {
Some(v) => reason = Some(v),
None => {
diagnostic.span_err(meta.span, "incorrect meta item");
continue 'outer;
}
}
}
"issue" => {
match meta.value_str().and_then(|s| s.parse().ok()) {
Some(v) => issue = Some(v),
None => {
diagnostic.span_err(meta.span, "incorrect meta item");
continue 'outer;
}
}
}
_ => {}
}
}
(feature, since, reason, issue)
}
None => {
diagnostic.span_err(attr.span(), "incorrect stability attribute type");
continue
}
};
// Deprecated tags don't require feature names
if feature == None && tag != "deprecated" {
diagnostic.span_err(attr.span(), "missing 'feature'");
}
// Unstable tags don't require a version
if since == None && tag != "unstable" {
diagnostic.span_err(attr.span(), "missing 'since'");
}
if tag == "unstable" || tag == "stable" {
if stab.is_some() {
diagnostic.span_err(item_sp, "multiple stability levels");
}
let level = match tag {
"unstable" => Unstable,
"stable" => Stable,
_ => unreachable!()
};
stab = Some(Stability {
level: level,
feature: feature.unwrap_or(intern_and_get_ident("bogus")),
since: since,
deprecated_since: None,
reason: reason,
issue: issue,
});
} else { // "deprecated"
if deprecated.is_some() {
diagnostic.span_err(item_sp, "multiple deprecated attributes");
}
deprecated = Some((since, reason));
}
}
// Merge the deprecation info into the stability info
if deprecated.is_some() {
match stab {
Some(ref mut s) => {
let (since, reason) = deprecated.unwrap();
s.deprecated_since = since;
s.reason = reason;
}
None => {
diagnostic.span_err(item_sp, "deprecated attribute must be paired with \
either stable or unstable attribute");
}
}
} else if stab.as_ref().map_or(false, |s| s.level == Unstable && s.issue.is_none()) {
// non-deprecated unstable items need to point to issues.
diagnostic.span_err(item_sp,
"non-deprecated unstable items need to point \
to an issue with `issue = \"NNN\"`");
}
(stab, used_attrs)
}
/// Find the first stability attribute. `None` if none exists.
pub fn find_stability(diagnostic: &SpanHandler, attrs: &[Attribute],
item_sp: Span) -> Option<Stability> {
let (s, used) = find_stability_generic(diagnostic, attrs.iter(), item_sp);
for used in used { syntax_attr::mark_used(&unlower_attribute(used)) }
return s;
}
pub fn require_unique_names(diagnostic: &SpanHandler, metas: &[P<MetaItem>]) {
let mut set = HashSet::new();
for meta in metas {
let name = meta.name();
if !set.insert(name.clone()) {
panic!(diagnostic.span_fatal(meta.span,
&format!("duplicate meta item `{}`", name)));
}
}
}
/// Parse #[repr(...)] forms.
///
/// Valid repr contents: any of the primitive integral type names (see
/// `int_type_of_word`, below) to specify enum discriminant type; `C`, to use
/// the same discriminant size that the corresponding C enum would or C
/// structure layout, and `packed` to remove padding.
pub fn find_repr_attrs(diagnostic: &SpanHandler, attr: &Attribute) -> Vec<ReprAttr> {
let mut acc = Vec::new();
match attr.node.value.node {
hir::MetaList(ref s, ref items) if *s == "repr" => {
syntax_attr::mark_used(&unlower_attribute(attr));
for item in items {
match item.node {
hir::MetaWord(ref word) => {
let hint = match &word[..] {
// Can't use "extern" because it's not a lexical identifier.
"C" => Some(ReprExtern),
"packed" => Some(ReprPacked),
"simd" => Some(ReprSimd),
_ => match int_type_of_word(&word) {
Some(ity) => Some(ReprInt(item.span, ity)),
None => {
// Not a word we recognize
diagnostic.span_err(item.span,
"unrecognized representation hint");
None
}
}
};
match hint {
Some(h) => acc.push(h),
None => { }
}
}
// Not a word:
_ => diagnostic.span_err(item.span, "unrecognized enum representation hint")
}
}
}
// Not a "repr" hint: ignore.
_ => { }
}
acc
}
fn int_type_of_word(s: &str) -> Option<IntType> {
match s {
"i8" => Some(SignedInt(hir::TyI8)),
"u8" => Some(UnsignedInt(hir::TyU8)),
"i16" => Some(SignedInt(hir::TyI16)),
"u16" => Some(UnsignedInt(hir::TyU16)),
"i32" => Some(SignedInt(hir::TyI32)),
"u32" => Some(UnsignedInt(hir::TyU32)),
"i64" => Some(SignedInt(hir::TyI64)),
"u64" => Some(UnsignedInt(hir::TyU64)),
"isize" => Some(SignedInt(hir::TyIs)),
"usize" => Some(UnsignedInt(hir::TyUs)),
_ => None
}
}
#[derive(PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
pub enum ReprAttr {
ReprAny,
ReprInt(Span, IntType),
ReprExtern,
ReprPacked,
ReprSimd,
}
impl ReprAttr {
pub fn is_ffi_safe(&self) -> bool {
match *self {
ReprAny => false,
ReprInt(_sp, ity) => ity.is_ffi_safe(),
ReprExtern => true,
ReprPacked => false,
ReprSimd => true,
}
}
}
#[derive(Eq, Hash, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
pub enum IntType {
SignedInt(hir::IntTy),
UnsignedInt(hir::UintTy)
}
impl IntType {
#[inline]
pub fn is_signed(self) -> bool {
match self {
SignedInt(..) => true,
UnsignedInt(..) => false
}
}
fn is_ffi_safe(self) -> bool {
match self {
SignedInt(hir::TyI8) | UnsignedInt(hir::TyU8) |
SignedInt(hir::TyI16) | UnsignedInt(hir::TyU16) |
SignedInt(hir::TyI32) | UnsignedInt(hir::TyU32) |
SignedInt(hir::TyI64) | UnsignedInt(hir::TyU64) => true,
SignedInt(hir::TyIs) | UnsignedInt(hir::TyUs) => false
}
}
}

View File

@ -674,7 +674,7 @@ impl Stability {
span: Span, stability: &Option<&attr::Stability>) {
// Deprecated attributes apply in-crate and cross-crate.
let (lint, label) = match *stability {
Some(&attr::Stability { deprecated_since: Some(_), .. }) =>
Some(&attr::Stability { depr: Some(_), .. }) =>
(DEPRECATED, "deprecated"),
_ => return
};
@ -684,8 +684,8 @@ impl Stability {
fn output(cx: &LateContext, span: Span, stability: &Option<&attr::Stability>,
lint: &'static Lint, label: &'static str) {
let msg = match *stability {
Some(&attr::Stability { reason: Some(ref s), .. }) => {
format!("use of {} item: {}", label, *s)
Some(&attr::Stability {depr: Some(attr::Deprecation {ref reason, ..}), ..}) => {
format!("use of {} item: {}", label, reason)
}
_ => format!("use of {} item", label)
};
@ -695,20 +695,6 @@ impl Stability {
}
}
fn hir_to_ast_stability(stab: &attr::Stability) -> attr::Stability {
attr::Stability {
level: match stab.level {
attr::Unstable => attr::Unstable,
attr::Stable => attr::Stable,
},
feature: stab.feature.clone(),
since: stab.since.clone(),
deprecated_since: stab.deprecated_since.clone(),
reason: stab.reason.clone(),
issue: stab.issue,
}
}
impl LintPass for Stability {
fn get_lints(&self) -> LintArray {
lint_array!(DEPRECATED)
@ -719,36 +705,31 @@ impl LateLintPass for Stability {
fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
stability::check_item(cx.tcx, item, false,
&mut |id, sp, stab|
self.lint(cx, id, sp,
&stab.map(|s| hir_to_ast_stability(s)).as_ref()));
self.lint(cx, id, sp, &stab));
}
fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
stability::check_expr(cx.tcx, e,
&mut |id, sp, stab|
self.lint(cx, id, sp,
&stab.map(|s| hir_to_ast_stability(s)).as_ref()));
self.lint(cx, id, sp, &stab));
}
fn check_path(&mut self, cx: &LateContext, path: &hir::Path, id: ast::NodeId) {
stability::check_path(cx.tcx, path, id,
&mut |id, sp, stab|
self.lint(cx, id, sp,
&stab.map(|s| hir_to_ast_stability(s)).as_ref()));
self.lint(cx, id, sp, &stab));
}
fn check_path_list_item(&mut self, cx: &LateContext, item: &hir::PathListItem) {
stability::check_path_list_item(cx.tcx, item,
&mut |id, sp, stab|
self.lint(cx, id, sp,
&stab.map(|s| hir_to_ast_stability(s)).as_ref()));
self.lint(cx, id, sp, &stab));
}
fn check_pat(&mut self, cx: &LateContext, pat: &hir::Pat) {
stability::check_pat(cx.tcx, pat,
&mut |id, sp, stab|
self.lint(cx, id, sp,
&stab.map(|s| hir_to_ast_stability(s)).as_ref()));
self.lint(cx, id, sp, &stab));
}
}

View File

@ -324,8 +324,8 @@ impl Item {
match self.stability {
Some(ref s) => {
let mut base = match s.level {
attr::Unstable => "unstable".to_string(),
attr::Stable => String::new(),
stability::Unstable => "unstable".to_string(),
stability::Stable => String::new(),
};
if !s.deprecated_since.is_empty() {
base.push_str(" deprecated");
@ -2679,7 +2679,7 @@ impl Clean<Item> for doctree::Macro {
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct Stability {
pub level: attr::StabilityLevel,
pub level: stability::StabilityLevel,
pub feature: String,
pub since: String,
pub deprecated_since: String,
@ -2690,32 +2690,31 @@ pub struct Stability {
impl Clean<Stability> for attr::Stability {
fn clean(&self, _: &DocContext) -> Stability {
Stability {
level: self.level,
level: stability::StabilityLevel::from_attr_level(&self.level),
feature: self.feature.to_string(),
since: self.since.as_ref().map_or("".to_string(),
|interned| interned.to_string()),
deprecated_since: self.deprecated_since.as_ref().map_or("".to_string(),
|istr| istr.to_string()),
reason: self.reason.as_ref().map_or("".to_string(),
|interned| interned.to_string()),
issue: self.issue,
since: match self.level {
attr::Stable {ref since} => since.to_string(),
_ => "".to_string(),
},
deprecated_since: match self.depr {
Some(attr::Deprecation {ref since, ..}) => since.to_string(),
_=> "".to_string(),
},
reason: match self.level {
attr::Unstable {reason: Some(ref reason), ..} => reason.to_string(),
_ => "".to_string(),
},
issue: match self.level {
attr::Unstable {issue, ..} => Some(issue),
_ => None,
}
}
}
}
impl<'a> Clean<Stability> for &'a attr::Stability {
fn clean(&self, _: &DocContext) -> Stability {
Stability {
level: self.level,
feature: self.feature.to_string(),
since: self.since.as_ref().map_or("".to_string(),
|interned| interned.to_string()),
deprecated_since: self.deprecated_since.as_ref().map_or("".to_string(),
|istr| istr.to_string()),
reason: self.reason.as_ref().map_or("".to_string(),
|interned| interned.to_string()),
issue: self.issue,
}
fn clean(&self, dc: &DocContext) -> Stability {
(**self).clean(dc)
}
}

View File

@ -52,9 +52,10 @@ use std::sync::Arc;
use externalfiles::ExternalHtml;
use serialize::json::{self, ToJson};
use syntax::{abi, ast, attr};
use syntax::{abi, ast};
use rustc::metadata::cstore::LOCAL_CRATE;
use rustc::middle::def_id::{CRATE_DEF_INDEX, DefId};
use rustc::middle::stability;
use rustc::util::nodemap::DefIdSet;
use rustc_front::hir;
@ -1608,8 +1609,8 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
let s1 = i1.stability.as_ref().map(|s| s.level);
let s2 = i2.stability.as_ref().map(|s| s.level);
match (s1, s2) {
(Some(attr::Unstable), Some(attr::Stable)) => return Ordering::Greater,
(Some(attr::Stable), Some(attr::Unstable)) => return Ordering::Less,
(Some(stability::Unstable), Some(stability::Stable)) => return Ordering::Greater,
(Some(stability::Stable), Some(stability::Unstable)) => return Ordering::Less,
_ => {}
}
i1.name.cmp(&i2.name)
@ -1724,7 +1725,7 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Optio
String::new()
};
format!("Deprecated{}{}", since, Markdown(&reason))
} else if stab.level == attr::Unstable {
} else if stab.level == stability::Unstable {
let unstable_extra = if show_reason {
match (!stab.feature.is_empty(), &cx.issue_tracker_base_url, stab.issue) {
(true, &Some(ref tracker_url), Some(issue_no)) =>

View File

@ -27,7 +27,6 @@ use ptr::P;
use std::cell::{RefCell, Cell};
use std::collections::HashSet;
use std::fmt;
thread_local! {
static USED_ATTRS: RefCell<Vec<u64>> = RefCell::new(Vec::new())
@ -382,174 +381,223 @@ pub fn cfg_matches(diagnostic: &SpanHandler, cfgs: &[P<MetaItem>], cfg: &ast::Me
}
}
/// Represents the #[deprecated] and friends attributes.
/// Represents the #[stable], #[unstable] and #[deprecated] attributes.
#[derive(RustcEncodable, RustcDecodable, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Stability {
pub level: StabilityLevel,
pub feature: InternedString,
pub since: Option<InternedString>,
pub deprecated_since: Option<InternedString>,
// The reason for the current stability level. If deprecated, the
// reason for deprecation.
pub reason: Option<InternedString>,
// The relevant rust-lang issue
pub issue: Option<u32>
pub depr: Option<Deprecation>,
}
/// The available stability levels.
#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Copy, Eq, Hash)]
#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)]
pub enum StabilityLevel {
Unstable,
Stable,
// Reason for the current stability level and the relevant rust-lang issue
Unstable { reason: Option<InternedString>, issue: u32 },
Stable { since: InternedString },
}
impl fmt::Display for StabilityLevel {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self, f)
}
#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)]
pub struct Deprecation {
pub since: InternedString,
pub reason: InternedString,
}
fn find_stability_generic<'a,
AM: AttrMetaMethods,
I: Iterator<Item=&'a AM>>
(diagnostic: &SpanHandler, attrs: I, item_sp: Span)
-> (Option<Stability>, Vec<&'a AM>) {
impl StabilityLevel {
pub fn is_unstable(&self) -> bool { if let Unstable {..} = *self { true } else { false }}
pub fn is_stable(&self) -> bool { if let Stable {..} = *self { true } else { false }}
}
fn find_stability_generic<'a, I>(diagnostic: &SpanHandler,
attrs_iter: I,
item_sp: Span)
-> Option<Stability>
where I: Iterator<Item = &'a Attribute>
{
let mut stab: Option<Stability> = None;
let mut deprecated: Option<(Option<InternedString>, Option<InternedString>)> = None;
let mut used_attrs: Vec<&'a AM> = vec![];
let mut depr: Option<Deprecation> = None;
'outer: for attr in attrs {
'outer: for attr in attrs_iter {
let tag = attr.name();
let tag = &tag[..];
let tag = &*tag;
if tag != "deprecated" && tag != "unstable" && tag != "stable" {
continue // not a stability level
}
used_attrs.push(attr);
mark_used(attr);
let (feature, since, reason, issue) = match attr.meta_item_list() {
Some(metas) => {
let mut feature = None;
let mut since = None;
let mut reason = None;
let mut issue = None;
for meta in metas {
match &*meta.name() {
"feature" => {
match meta.value_str() {
Some(v) => feature = Some(v),
None => {
diagnostic.span_err(meta.span, "incorrect meta item");
continue 'outer;
}
}
}
"since" => {
match meta.value_str() {
Some(v) => since = Some(v),
None => {
diagnostic.span_err(meta.span, "incorrect meta item");
continue 'outer;
}
}
}
"reason" => {
match meta.value_str() {
Some(v) => reason = Some(v),
None => {
diagnostic.span_err(meta.span, "incorrect meta item");
continue 'outer;
}
}
}
"issue" => {
match meta.value_str().and_then(|s| s.parse().ok()) {
Some(v) => issue = Some(v),
None => {
diagnostic.span_err(meta.span, "incorrect meta item");
continue 'outer;
}
}
}
_ => {}
}
if let Some(metas) = attr.meta_item_list() {
let get = |meta: &MetaItem, item: &mut Option<InternedString>| {
if item.is_some() {
diagnostic.span_err(meta.span, &format!("multiple '{}' items",
meta.name()));
return false
}
if let Some(v) = meta.value_str() {
*item = Some(v);
true
} else {
diagnostic.span_err(meta.span, "incorrect meta item");
false
}
(feature, since, reason, issue)
}
None => {
diagnostic.span_err(attr.span(), "incorrect stability attribute type");
continue
}
};
// Deprecated tags don't require feature names
if feature == None && tag != "deprecated" {
diagnostic.span_err(attr.span(), "missing 'feature'");
}
// Unstable tags don't require a version
if since == None && tag != "unstable" {
diagnostic.span_err(attr.span(), "missing 'since'");
}
if tag == "unstable" || tag == "stable" {
if stab.is_some() {
diagnostic.span_err(item_sp, "multiple stability levels");
}
let level = match tag {
"unstable" => Unstable,
"stable" => Stable,
_ => unreachable!()
};
stab = Some(Stability {
level: level,
feature: feature.unwrap_or(intern_and_get_ident("bogus")),
since: since,
deprecated_since: None,
reason: reason,
issue: issue,
});
} else { // "deprecated"
if deprecated.is_some() {
diagnostic.span_err(item_sp, "multiple deprecated attributes");
}
match tag {
"deprecated" => {
if depr.is_some() {
diagnostic.span_err(item_sp, "multiple deprecated attributes");
break
}
deprecated = Some((since, reason));
let mut since = None;
let mut reason = None;
for meta in metas {
match &*meta.name() {
"since" => if !get(meta, &mut since) { continue 'outer },
"reason" => if !get(meta, &mut reason) { continue 'outer },
_ => {
diagnostic.span_err(meta.span, &format!("unknown meta item '{}'",
meta.name()));
continue 'outer
}
}
}
match (since, reason) {
(Some(since), Some(reason)) => {
depr = Some(Deprecation {
since: since,
reason: reason,
})
}
(None, _) => {
diagnostic.span_err(attr.span(), "missing 'since'");
continue
}
_ => {
diagnostic.span_err(attr.span(), "missing 'reason'");
continue
}
}
}
"unstable" => {
if stab.is_some() {
diagnostic.span_err(item_sp, "multiple stability levels");
break
}
let mut feature = None;
let mut reason = None;
let mut issue = None;
for meta in metas {
match &*meta.name() {
"feature" => if !get(meta, &mut feature) { continue 'outer },
"reason" => if !get(meta, &mut reason) { continue 'outer },
"issue" => if !get(meta, &mut issue) { continue 'outer },
_ => {
diagnostic.span_err(meta.span, &format!("unknown meta item '{}'",
meta.name()));
continue 'outer
}
}
}
match (feature, reason, issue) {
(Some(feature), reason, Some(issue)) => {
stab = Some(Stability {
level: Unstable {
reason: reason,
issue: {
if let Ok(issue) = issue.parse() {
issue
} else {
diagnostic.span_err(attr.span(), "incorrect 'issue'");
continue
}
}
},
feature: feature,
depr: None,
})
}
(None, _, _) => {
diagnostic.span_err(attr.span(), "missing 'feature'");
continue
}
_ => {
diagnostic.span_err(attr.span(), "missing 'issue'");
continue
}
}
}
"stable" => {
if stab.is_some() {
diagnostic.span_err(item_sp, "multiple stability levels");
break
}
let mut feature = None;
let mut since = None;
for meta in metas {
match &*meta.name() {
"feature" => if !get(meta, &mut feature) { continue 'outer },
"since" => if !get(meta, &mut since) { continue 'outer },
_ => {
diagnostic.span_err(meta.span, &format!("unknown meta item '{}'",
meta.name()));
continue 'outer
}
}
}
match (feature, since) {
(Some(feature), Some(since)) => {
stab = Some(Stability {
level: Stable {
since: since,
},
feature: feature,
depr: None,
})
}
(None, _) => {
diagnostic.span_err(attr.span(), "missing 'feature'");
continue
}
_ => {
diagnostic.span_err(attr.span(), "missing 'since'");
continue
}
}
}
_ => unreachable!()
}
} else {
diagnostic.span_err(attr.span(), "incorrect stability attribute type");
continue
}
}
// Merge the deprecation info into the stability info
if deprecated.is_some() {
match stab {
Some(ref mut s) => {
let (since, reason) = deprecated.unwrap();
s.deprecated_since = since;
s.reason = reason;
}
None => {
diagnostic.span_err(item_sp, "deprecated attribute must be paired with \
either stable or unstable attribute");
if let Some(depr) = depr {
if let Some(ref mut stab) = stab {
if let Unstable {reason: ref mut reason @ None, ..} = stab.level {
*reason = Some(depr.reason.clone())
}
stab.depr = Some(depr);
} else {
diagnostic.span_err(item_sp, "deprecated attribute must be paired with \
either stable or unstable attribute");
}
} else if stab.as_ref().map_or(false, |s| s.level == Unstable && s.issue.is_none()) {
// non-deprecated unstable items need to point to issues.
diagnostic.span_err(item_sp,
"non-deprecated unstable items need to point \
to an issue with `issue = \"NNN\"`");
}
(stab, used_attrs)
stab
}
/// Find the first stability attribute. `None` if none exists.
pub fn find_stability(diagnostic: &SpanHandler, attrs: &[Attribute],
item_sp: Span) -> Option<Stability> {
let (s, used) = find_stability_generic(diagnostic, attrs.iter(), item_sp);
for used in used { mark_used(used) }
return s;
find_stability_generic(diagnostic, attrs.iter(), item_sp)
}
pub fn require_unique_names(diagnostic: &SpanHandler, metas: &[P<MetaItem>]) {

View File

@ -593,7 +593,7 @@ impl<'a> ExtCtxt<'a> {
}
}
#[unstable(feature = "rustc_private")]
#[unstable(feature = "rustc_private", issue = "0")]
#[deprecated(since = "1.0.0",
reason = "Replaced with `expander().fold_expr()`")]
pub fn expand_expr(&mut self, e: P<ast::Expr>) -> P<ast::Expr> {

View File

@ -129,7 +129,7 @@ impl<T> SmallVector<T> {
}
/// Deprecated: use `into_iter`.
#[unstable(feature = "rustc_private")]
#[unstable(feature = "rustc_private", issue = "0")]
#[deprecated(since = "1.0.0", reason = "use into_iter")]
pub fn move_iter(self) -> IntoIter<T> {
self.into_iter()

View File

@ -29,7 +29,7 @@ pub mod stable_mod {
#[unstable(feature = "test_feature", issue = "0")]
pub mod unstable_mod {
#[stable(feature = "test_feature", since = "1.0.0")]
#[deprecated(since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
pub fn deprecated() {}
pub fn unstable() {}

View File

@ -15,7 +15,7 @@
#![unstable(feature = "test_feature", issue = "0")]
#[stable(feature = "test_feature", since = "1.0.0")]
#[deprecated(since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
pub fn foo() -> usize {
20
}

View File

@ -14,14 +14,14 @@
#![stable(feature = "lint_stability", since = "1.0.0")]
#[stable(feature = "test_feature", since = "1.0.0")]
#[deprecated(since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
pub fn deprecated() {}
#[stable(feature = "test_feature", since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
pub fn deprecated_text() {}
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
pub fn deprecated_unstable() {}
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0", reason = "text")]
@ -34,7 +34,7 @@ pub fn unstable_text() {}
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stable() {}
#[stable(feature = "rust1", since = "1.0.0", reason = "text")]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stable_text() {}
#[stable(feature = "rust1", since = "1.0.0")]
@ -42,14 +42,14 @@ pub struct MethodTester;
impl MethodTester {
#[stable(feature = "test_feature", since = "1.0.0")]
#[deprecated(since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
pub fn method_deprecated(&self) {}
#[stable(feature = "test_feature", since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
pub fn method_deprecated_text(&self) {}
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
pub fn method_deprecated_unstable(&self) {}
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0", reason = "text")]
@ -62,21 +62,21 @@ impl MethodTester {
#[stable(feature = "rust1", since = "1.0.0")]
pub fn method_stable(&self) {}
#[stable(feature = "rust1", since = "1.0.0", reason = "text")]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn method_stable_text(&self) {}
}
#[stable(feature = "test_feature", since = "1.0.0")]
pub trait Trait {
#[stable(feature = "test_feature", since = "1.0.0")]
#[deprecated(since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
fn trait_deprecated(&self) {}
#[stable(feature = "test_feature", since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
fn trait_deprecated_text(&self) {}
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
fn trait_deprecated_unstable(&self) {}
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0", reason = "text")]
@ -89,7 +89,7 @@ pub trait Trait {
#[stable(feature = "rust1", since = "1.0.0")]
fn trait_stable(&self) {}
#[stable(feature = "rust1", since = "1.0.0", reason = "text")]
#[stable(feature = "rust1", since = "1.0.0")]
fn trait_stable_text(&self) {}
}
@ -99,12 +99,12 @@ impl Trait for MethodTester {}
pub trait UnstableTrait { fn dummy(&self) { } }
#[stable(feature = "test_feature", since = "1.0.0")]
#[deprecated(since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
pub struct DeprecatedStruct {
#[stable(feature = "test_feature", since = "1.0.0")] pub i: isize
}
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
pub struct DeprecatedUnstableStruct {
#[stable(feature = "test_feature", since = "1.0.0")] pub i: isize
}
@ -118,10 +118,10 @@ pub struct StableStruct {
}
#[stable(feature = "test_feature", since = "1.0.0")]
#[deprecated(since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
pub struct DeprecatedUnitStruct;
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
pub struct DeprecatedUnstableUnitStruct;
#[unstable(feature = "test_feature", issue = "0")]
pub struct UnstableUnitStruct;
@ -131,10 +131,10 @@ pub struct StableUnitStruct;
#[stable(feature = "test_feature", since = "1.0.0")]
pub enum Enum {
#[stable(feature = "test_feature", since = "1.0.0")]
#[deprecated(since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
DeprecatedVariant,
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
DeprecatedUnstableVariant,
#[unstable(feature = "test_feature", issue = "0")]
UnstableVariant,
@ -144,10 +144,10 @@ pub enum Enum {
}
#[stable(feature = "test_feature", since = "1.0.0")]
#[deprecated(since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
pub struct DeprecatedTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub isize);
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
pub struct DeprecatedUnstableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub isize);
#[unstable(feature = "test_feature", issue = "0")]
pub struct UnstableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub isize);

View File

@ -18,7 +18,7 @@ pub struct Stable {
pub inherit: u8, // it's a lie (stable doesn't inherit)
#[unstable(feature = "test_feature", issue = "0")]
pub override1: u8,
#[deprecated(since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
#[unstable(feature = "test_feature", issue = "0")]
pub override2: u8,
}
@ -27,14 +27,14 @@ pub struct Stable {
pub struct Stable2(#[stable(feature = "rust1", since = "1.0.0")] pub u8,
#[unstable(feature = "test_feature", issue = "0")] pub u8,
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0")] pub u8);
#[deprecated(since = "1.0.0", reason = "text")] pub u8);
#[unstable(feature = "test_feature", issue = "0")]
pub struct Unstable {
pub inherit: u8,
#[stable(feature = "rust1", since = "1.0.0")]
pub override1: u8,
#[deprecated(since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
#[unstable(feature = "test_feature", issue = "0")]
pub override2: u8,
}
@ -43,10 +43,10 @@ pub struct Unstable {
pub struct Unstable2(pub u8,
#[stable(feature = "rust1", since = "1.0.0")] pub u8,
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0")] pub u8);
#[deprecated(since = "1.0.0", reason = "text")] pub u8);
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(feature = "rust1", since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
pub struct Deprecated {
pub inherit: u8,
#[stable(feature = "rust1", since = "1.0.0")]
@ -56,7 +56,7 @@ pub struct Deprecated {
}
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(feature = "rust1", since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
pub struct Deprecated2(pub u8,
#[stable(feature = "rust1", since = "1.0.0")] pub u8,
#[unstable(feature = "test_feature", issue = "0")] pub u8);

View File

@ -15,8 +15,8 @@
struct Foo;
impl Foo {
#[unstable(feature = "test_feature")]
#[deprecated(since = "1.0.0")]
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0", reason = "text")]
fn foo(self) {}
}

View File

@ -15,7 +15,7 @@
extern crate lint_output_format; //~ ERROR use of unstable library feature
use lint_output_format::{foo, bar}; //~ ERROR use of unstable library feature
//~^ WARNING use of deprecated item,
//~^ WARNING use of deprecated item: text,
fn main() {
let _x = foo(); //~ WARNING #[warn(deprecated)] on by default

View File

@ -189,7 +189,7 @@ mod this_crate {
inherit: u8,
#[unstable(feature = "test_feature", issue = "0")]
override1: u8,
#[deprecated(since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
#[unstable(feature = "test_feature", issue = "0")]
override2: u8,
}
@ -198,14 +198,14 @@ mod this_crate {
struct Stable2(u8,
#[stable(feature = "rust1", since = "1.0.0")] u8,
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0")] u8);
#[deprecated(since = "1.0.0", reason = "text")] u8);
#[unstable(feature = "test_feature", issue = "0")]
struct Unstable {
inherit: u8,
#[stable(feature = "rust1", since = "1.0.0")]
override1: u8,
#[deprecated(since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
#[unstable(feature = "test_feature", issue = "0")]
override2: u8,
}
@ -214,10 +214,10 @@ mod this_crate {
struct Unstable2(u8,
#[stable(feature = "rust1", since = "1.0.0")] u8,
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0")] u8);
#[deprecated(since = "1.0.0", reason = "text")] u8);
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(feature = "rust1", since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
struct Deprecated {
inherit: u8,
#[stable(feature = "rust1", since = "1.0.0")]
@ -227,7 +227,7 @@ mod this_crate {
}
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(feature = "rust1", since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
struct Deprecated2(u8,
#[stable(feature = "rust1", since = "1.0.0")] u8,
#[unstable(feature = "test_feature", issue = "0")] u8);

View File

@ -258,7 +258,7 @@ mod inheritance {
mod this_crate {
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
pub fn deprecated() {}
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0", reason = "text")]
@ -271,7 +271,7 @@ mod this_crate {
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stable() {}
#[stable(feature = "rust1", since = "1.0.0", reason = "text")]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stable_text() {}
#[stable(feature = "rust1", since = "1.0.0")]
@ -279,7 +279,7 @@ mod this_crate {
impl MethodTester {
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
pub fn method_deprecated(&self) {}
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0", reason = "text")]
@ -292,13 +292,13 @@ mod this_crate {
#[stable(feature = "rust1", since = "1.0.0")]
pub fn method_stable(&self) {}
#[stable(feature = "rust1", since = "1.0.0", reason = "text")]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn method_stable_text(&self) {}
}
pub trait Trait {
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
fn trait_deprecated(&self) {}
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0", reason = "text")]
@ -311,14 +311,14 @@ mod this_crate {
#[stable(feature = "rust1", since = "1.0.0")]
fn trait_stable(&self) {}
#[stable(feature = "rust1", since = "1.0.0", reason = "text")]
#[stable(feature = "rust1", since = "1.0.0")]
fn trait_stable_text(&self) {}
}
impl Trait for MethodTester {}
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
pub struct DeprecatedStruct {
#[stable(feature = "test_feature", since = "1.0.0")] i: isize
}
@ -332,7 +332,7 @@ mod this_crate {
}
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
pub struct DeprecatedUnitStruct;
#[unstable(feature = "test_feature", issue = "0")]
pub struct UnstableUnitStruct;
@ -341,7 +341,7 @@ mod this_crate {
pub enum Enum {
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
DeprecatedVariant,
#[unstable(feature = "test_feature", issue = "0")]
UnstableVariant,
@ -351,7 +351,7 @@ mod this_crate {
}
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
pub struct DeprecatedTupleStruct(isize);
#[unstable(feature = "test_feature", issue = "0")]
pub struct UnstableTupleStruct(isize);
@ -472,7 +472,7 @@ mod this_crate {
}
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
fn test_fn_body() {
fn fn_in_body() {}
fn_in_body();
@ -480,7 +480,7 @@ mod this_crate {
impl MethodTester {
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
fn test_method_body(&self) {
fn fn_in_body() {}
fn_in_body();
@ -488,7 +488,7 @@ mod this_crate {
}
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
pub trait DeprecatedTrait {
fn dummy(&self) { }
}

View File

@ -14,22 +14,19 @@
#![staged_api]
mod bogus_attribute_types_1 {
#[stable(feature = "a", since = "a", reason)] //~ ERROR incorrect meta item
#[stable(feature = "a", since = "a", reason)] //~ ERROR unknown meta item 'reason'
fn f1() { }
#[stable(feature = "a", since, reason = "a")] //~ ERROR incorrect meta item
#[stable(feature = "a", since)] //~ ERROR incorrect meta item
fn f2() { }
#[stable(feature, since = "a", reason = "a")] //~ ERROR incorrect meta item
#[stable(feature, since = "a")] //~ ERROR incorrect meta item
fn f3() { }
#[stable(feature = "a", since = "a", reason(b))] //~ ERROR incorrect meta item
fn f4() { }
#[stable(feature = "a", since(b), reason = "a")] //~ ERROR incorrect meta item
#[stable(feature = "a", since(b))] //~ ERROR incorrect meta item
fn f5() { }
#[stable(feature(b), since = "a", reason = "a")] //~ ERROR incorrect meta item
#[stable(feature(b), since = "a")] //~ ERROR incorrect meta item
fn f6() { }
}
@ -56,11 +53,11 @@ mod bogus_attribute_types_2 {
}
mod missing_feature_names {
#[unstable(since = "a", issue = "0")] //~ ERROR missing 'feature'
#[unstable(issue = "0")] //~ ERROR missing 'feature'
fn f1() { }
#[unstable(feature = "a")]
fn f2() { } //~ ERROR need to point to an issue
#[unstable(feature = "a")] //~ ERROR missing 'issue'
fn f2() { }
#[stable(since = "a")] //~ ERROR missing 'feature'
fn f3() { }
@ -75,12 +72,12 @@ mod missing_version {
fn f2() { }
}
#[unstable(feature = "a", since = "b", issue = "0")]
#[unstable(feature = "a", issue = "0")]
#[stable(feature = "a", since = "b")]
fn multiple1() { } //~ ERROR multiple stability levels
#[unstable(feature = "a", since = "b", issue = "0")]
#[unstable(feature = "a", since = "b", issue = "0")]
#[unstable(feature = "a", issue = "0")]
#[unstable(feature = "a", issue = "0")]
fn multiple2() { } //~ ERROR multiple stability levels
#[stable(feature = "a", since = "b")]
@ -88,12 +85,12 @@ fn multiple2() { } //~ ERROR multiple stability levels
fn multiple3() { } //~ ERROR multiple stability levels
#[stable(feature = "a", since = "b")]
#[deprecated(since = "b")]
#[deprecated(since = "b")]
#[deprecated(since = "b", reason = "text")]
#[deprecated(since = "b", reason = "text")]
fn multiple4() { } //~ ERROR multiple deprecated attributes
//~^ ERROR Invalid stability or deprecation version found
#[deprecated(since = "a")]
#[deprecated(since = "a", reason = "text")]
fn deprecated_without_unstable_or_stable() { } //~ ERROR deprecated attribute must be paired
fn main() { }