From ab671552c3b44906b63c07f2676492b766f2a7c3 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 13 Oct 2015 06:01:31 +0300 Subject: [PATCH 1/3] Refactor attr::Stability Stricter checking + enforcement of invariants at compile time --- src/librustc/middle/stability.rs | 48 +- src/librustc_front/attr.rs | 625 ------------------ src/librustc_lint/builtin.rs | 35 +- src/librustdoc/clean/mod.rs | 45 +- src/librustdoc/html/render.rs | 9 +- src/libsyntax/attr.rs | 310 +++++---- src/libsyntax/ext/base.rs | 2 +- src/libsyntax/util/small_vector.rs | 2 +- src/test/auxiliary/inherited_stability.rs | 2 +- src/test/auxiliary/lint_output_format.rs | 2 +- src/test/auxiliary/lint_stability.rs | 34 +- src/test/auxiliary/lint_stability_fields.rs | 12 +- src/test/compile-fail/issue-17337.rs | 4 +- src/test/compile-fail/lint-output-format.rs | 2 +- .../compile-fail/lint-stability-fields.rs | 12 +- src/test/compile-fail/lint-stability.rs | 26 +- .../stability-attribute-sanity.rs | 31 +- 17 files changed, 307 insertions(+), 894 deletions(-) delete mode 100644 src/librustc_front/attr.rs diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index c2235591cee..f38ee19a274 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -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 { + -> FnvHashMap { 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, - used_features: FnvHashMap, + used_features: FnvHashMap, // 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) { + StabilityLevel>) { let ref declared_lib_features = sess.features.borrow().declared_lib_features; let mut remaining_lib_features: FnvHashMap = 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, diff --git a/src/librustc_front/attr.rs b/src/librustc_front/attr.rs deleted file mode 100644 index 1a564eb28a3..00000000000 --- a/src/librustc_front/attr.rs +++ /dev/null @@ -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 or the MIT license -// , 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; - /// Gets a list of inner meta items from a list MetaItem type. - fn meta_item_list<'a>(&'a self) -> Option<&'a [P]>; - - 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 { - self.meta().value_str() - } - fn meta_item_list<'a>(&'a self) -> Option<&'a [P]> { - 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 { - 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]> { - 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 { - fn name(&self) -> InternedString { (**self).name() } - fn value_str(&self) -> Option { (**self).value_str() } - fn meta_item_list<'a>(&'a self) -> Option<&'a [P]> { - (**self).meta_item_list() - } - fn span(&self) -> Span { (**self).span() } -} - - -pub trait AttributeMethods { - fn meta<'a>(&'a self) -> &'a MetaItem; - fn with_desugared_doc(&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(&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 { - 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 { - P(dummy_spanned(MetaNameValue(name, value))) -} - -pub fn mk_list_item(name: InternedString, items: Vec>) -> P { - P(dummy_spanned(MetaList(name, items))) -} - -pub fn mk_word_item(name: InternedString) -> P { - P(dummy_spanned(MetaWord(name))) -} - -thread_local! { static NEXT_ATTR_ID: Cell = 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) -> 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) -> 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], 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(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 { - 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], name: &str) - -> Option { - 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>) -> Vec> { - // 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::)>>(); - - 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 { - 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 { - 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, - pub deprecated_since: Option, - // The reason for the current stability level. If deprecated, the - // reason for deprecation. - pub reason: Option, - // The relevant rust-lang issue - pub issue: Option -} - -/// 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> - (diagnostic: &SpanHandler, attrs: I, item_sp: Span) - -> (Option, Vec<&'a AM>) { - - let mut stab: Option = None; - let mut deprecated: Option<(Option, Option)> = 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 { - 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]) { - 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 { - 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 { - 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 - } - } -} diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 1df3c1609b8..490f57e6607 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -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)); } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 160c7e7d754..88e254b86b2 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -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 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 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 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) } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 05d88de812d..d6fee744da6 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -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)) => diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index bd99d33222d..eeb832d48b0 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -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> = RefCell::new(Vec::new()) @@ -382,174 +381,223 @@ pub fn cfg_matches(diagnostic: &SpanHandler, cfgs: &[P], 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, - pub deprecated_since: Option, - // The reason for the current stability level. If deprecated, the - // reason for deprecation. - pub reason: Option, - // The relevant rust-lang issue - pub issue: Option + pub depr: Option, } /// 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, 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> - (diagnostic: &SpanHandler, attrs: I, item_sp: Span) - -> (Option, 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 + where I: Iterator +{ let mut stab: Option = None; - let mut deprecated: Option<(Option, Option)> = None; - let mut used_attrs: Vec<&'a AM> = vec![]; + let mut depr: Option = 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| { + 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 { - 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]) { diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 6196062b08a..3a06ea66d17 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -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) -> P { diff --git a/src/libsyntax/util/small_vector.rs b/src/libsyntax/util/small_vector.rs index 5353d12b678..9743da15a47 100644 --- a/src/libsyntax/util/small_vector.rs +++ b/src/libsyntax/util/small_vector.rs @@ -129,7 +129,7 @@ impl SmallVector { } /// 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 { self.into_iter() diff --git a/src/test/auxiliary/inherited_stability.rs b/src/test/auxiliary/inherited_stability.rs index f4e6f6d7511..60477288f7c 100644 --- a/src/test/auxiliary/inherited_stability.rs +++ b/src/test/auxiliary/inherited_stability.rs @@ -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() {} diff --git a/src/test/auxiliary/lint_output_format.rs b/src/test/auxiliary/lint_output_format.rs index 51fad3ce3cd..8794119a869 100644 --- a/src/test/auxiliary/lint_output_format.rs +++ b/src/test/auxiliary/lint_output_format.rs @@ -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 } diff --git a/src/test/auxiliary/lint_stability.rs b/src/test/auxiliary/lint_stability.rs index 60097393a25..260361634ae 100644 --- a/src/test/auxiliary/lint_stability.rs +++ b/src/test/auxiliary/lint_stability.rs @@ -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); diff --git a/src/test/auxiliary/lint_stability_fields.rs b/src/test/auxiliary/lint_stability_fields.rs index b45af89dd3b..44b4abd38b8 100644 --- a/src/test/auxiliary/lint_stability_fields.rs +++ b/src/test/auxiliary/lint_stability_fields.rs @@ -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); diff --git a/src/test/compile-fail/issue-17337.rs b/src/test/compile-fail/issue-17337.rs index ff640793afe..501f6eb4dea 100644 --- a/src/test/compile-fail/issue-17337.rs +++ b/src/test/compile-fail/issue-17337.rs @@ -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) {} } diff --git a/src/test/compile-fail/lint-output-format.rs b/src/test/compile-fail/lint-output-format.rs index 3febacca73f..c22ad3182dd 100644 --- a/src/test/compile-fail/lint-output-format.rs +++ b/src/test/compile-fail/lint-output-format.rs @@ -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 diff --git a/src/test/compile-fail/lint-stability-fields.rs b/src/test/compile-fail/lint-stability-fields.rs index 7e675ca0bc4..11f64119680 100644 --- a/src/test/compile-fail/lint-stability-fields.rs +++ b/src/test/compile-fail/lint-stability-fields.rs @@ -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); diff --git a/src/test/compile-fail/lint-stability.rs b/src/test/compile-fail/lint-stability.rs index 6cc73ded975..864aafe5a6b 100644 --- a/src/test/compile-fail/lint-stability.rs +++ b/src/test/compile-fail/lint-stability.rs @@ -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) { } } diff --git a/src/test/compile-fail/stability-attribute-sanity.rs b/src/test/compile-fail/stability-attribute-sanity.rs index 00c5be0f211..f71e66ded7e 100644 --- a/src/test/compile-fail/stability-attribute-sanity.rs +++ b/src/test/compile-fail/stability-attribute-sanity.rs @@ -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() { } From 03468330bdd42214220a4e0729c571b2df5ac8ac Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 13 Oct 2015 17:00:47 +0300 Subject: [PATCH 2/3] Some additional tests --- .../stability-attribute-sanity-2.rs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/test/compile-fail/stability-attribute-sanity-2.rs diff --git a/src/test/compile-fail/stability-attribute-sanity-2.rs b/src/test/compile-fail/stability-attribute-sanity-2.rs new file mode 100644 index 00000000000..cdeff7afe1a --- /dev/null +++ b/src/test/compile-fail/stability-attribute-sanity-2.rs @@ -0,0 +1,25 @@ +// Copyright 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// More checks that stability attributes are used correctly + +#![feature(staged_api)] +#![staged_api] + +#[stable(feature = "a", feature = "b", since = "1.0.0")] //~ ERROR multiple 'feature' items +fn f1() { } + +#[stable(feature = "a", sinse = "1.0.0")] //~ ERROR unknown meta item 'sinse' +fn f2() { } + +#[unstable(feature = "a", issue = "no")] //~ ERROR incorrect 'issue' +fn f3() { } + +fn main() { } From 704d598fac81c31e65b0718a63d402ba2fd2ac9d Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 15 Oct 2015 01:28:38 +0300 Subject: [PATCH 3/3] rustdoc: Report deprecation reason first --- src/librustdoc/clean/mod.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 88e254b86b2..defdfc497bd 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2700,9 +2700,14 @@ impl Clean for attr::Stability { 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(), + reason: { + if let Some(ref depr) = self.depr { + depr.reason.to_string() + } else if let attr::Unstable {reason: Some(ref reason), ..} = self.level { + reason.to_string() + } else { + "".to_string() + } }, issue: match self.level { attr::Unstable {issue, ..} => Some(issue),