diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 46be4b75226..30553d62719 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -289,15 +289,19 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { if !cross_crate { return } match *stab { - Some(&Stability { level: attr::Unstable, ref feature, ref reason, .. }) => { + Some(&Stability { level: attr::Unstable, ref feature, ref reason, issue, .. }) => { self.used_features.insert(feature.clone(), attr::Unstable); if !self.active_features.contains(feature) { - let msg = match *reason { + let mut msg = match *reason { Some(ref r) => format!("use of unstable library feature '{}': {}", &feature, &r), None => format!("use of unstable library feature '{}'", &feature) }; + if let Some(n) = issue { + use std::fmt::Write; + write!(&mut msg, " (see issue #{})", n).unwrap(); + } emit_feature_err(&self.tcx.sess.parse_sess.span_diagnostic, &feature, span, &msg); diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 3cc141106bb..ed3ee768708 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -378,6 +378,8 @@ pub struct Stability { // 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. @@ -412,41 +414,54 @@ fn find_stability_generic<'a, used_attrs.push(attr); - let (feature, since, reason) = match attr.meta_item_list() { + 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 { - if meta.name() == "feature" { - match meta.value_str() { - Some(v) => feature = Some(v), - None => { - diagnostic.span_err(meta.span, "incorrect meta item"); - continue 'outer; + match &*meta.name() { + "feature" => { + match meta.value_str() { + Some(v) => feature = Some(v), + None => { + diagnostic.span_err(meta.span, "incorrect meta item"); + continue 'outer; + } } } - } - if &meta.name()[..] == "since" { - match meta.value_str() { - Some(v) => since = 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; + } } } - } - if &meta.name()[..] == "reason" { - match meta.value_str() { - Some(v) => reason = 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) + (feature, since, reason, issue) } None => { diagnostic.span_err(attr.span(), "incorrect stability attribute type"); @@ -480,7 +495,8 @@ fn find_stability_generic<'a, feature: feature.unwrap_or(intern_and_get_ident("bogus")), since: since, deprecated_since: None, - reason: reason + reason: reason, + issue: issue, }); } else { // "deprecated" if deprecated.is_some() { @@ -504,6 +520,12 @@ fn find_stability_generic<'a, 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. + // FIXME: uncomment this error + // diagnostic.span_err(item_sp, + // "non-deprecated unstable items need to point \ + // to an issue with `issue = \"NNN\"`"); } (stab, used_attrs) diff --git a/src/test/auxiliary/stability_attribute_issue.rs b/src/test/auxiliary/stability_attribute_issue.rs new file mode 100644 index 00000000000..69560d15b5f --- /dev/null +++ b/src/test/auxiliary/stability_attribute_issue.rs @@ -0,0 +1,20 @@ +// 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. + +#![feature(staged_api)] +#![staged_api] +#![stable(feature = "foo", since = "1.2.0")] + + +#[unstable(feature = "foo", issue = "1")] +pub fn unstable() {} + +#[unstable(feature = "foo", reason = "message", issue = "2")] +pub fn unstable_msg() {} diff --git a/src/test/compile-fail/stability-attribute-issue.rs b/src/test/compile-fail/stability-attribute-issue.rs new file mode 100644 index 00000000000..c473bdd23b5 --- /dev/null +++ b/src/test/compile-fail/stability-attribute-issue.rs @@ -0,0 +1,21 @@ +// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:stability_attribute_issue.rs + +#![deny(deprecated)] + +extern crate stability_attribute_issue; +use stability_attribute_issue::*; + +fn main() { + unstable(); //~ ERROR use of unstable library feature 'foo' (see issue #1) + unstable_msg(); //~ ERROR use of unstable library feature 'foo': message (see issue #2) +}