mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-27 09:14:20 +00:00
Refactor attr::Stability
Stricter checking + enforcement of invariants at compile time
This commit is contained in:
parent
843e528fd0
commit
ab671552c3
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)) =>
|
||||
|
@ -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>]) {
|
||||
|
@ -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> {
|
||||
|
@ -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()
|
||||
|
@ -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() {}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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) {}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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) { }
|
||||
}
|
||||
|
@ -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() { }
|
||||
|
Loading…
Reference in New Issue
Block a user