about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/liballoc/lib.rs1
-rw-r--r--src/libcore/cmp.rs51
-rw-r--r--src/librustc_mir/transform/check_unsafety.rs57
-rw-r--r--src/librustc_parse/parser/stmt.rs21
-rw-r--r--src/libstd/sys/unix/thread.rs4
-rw-r--r--src/libsyntax/attr/builtin.rs55
-rw-r--r--src/test/ui/feature-gate/unstable-attribute-allow-issue-0.rs4
-rw-r--r--src/test/ui/feature-gate/unstable-attribute-allow-issue-0.stderr8
-rw-r--r--src/test/ui/parser/doc-comment-in-stmt.rs20
-rw-r--r--src/test/ui/parser/doc-comment-in-stmt.stderr50
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-sanity-2.rs2
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-sanity-2.stderr8
12 files changed, 188 insertions, 93 deletions
diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs
index 38c6fa91cc5..ffa4176cc79 100644
--- a/src/liballoc/lib.rs
+++ b/src/liballoc/lib.rs
@@ -60,6 +60,7 @@
 #![stable(feature = "alloc", since = "1.36.0")]
 #![doc(
     html_root_url = "https://doc.rust-lang.org/nightly/",
+    html_playground_url = "https://play.rust-lang.org/",
     issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
     test(no_crate_inject, attr(allow(unused_variables), deny(warnings)))
 )]
diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs
index 3ea4baa57b4..e41a7afd3e2 100644
--- a/src/libcore/cmp.rs
+++ b/src/libcore/cmp.rs
@@ -35,7 +35,7 @@ use self::Ordering::*;
 ///
 /// This trait allows for partial equality, for types that do not have a full
 /// equivalence relation. For example, in floating point numbers `NaN != NaN`,
-/// so floating point types implement `PartialEq` but not `Eq`.
+/// so floating point types implement `PartialEq` but not [`Eq`].
 ///
 /// Formally, the equality must be (for all `a`, `b` and `c`):
 ///
@@ -55,12 +55,12 @@ use self::Ordering::*;
 ///
 /// ## How can I implement `PartialEq`?
 ///
-/// PartialEq only requires the `eq` method to be implemented; `ne` is defined
-/// in terms of it by default. Any manual implementation of `ne` *must* respect
-/// the rule that `eq` is a strict inverse of `ne`; that is, `!(a == b)` if and
+/// `PartialEq` only requires the [`eq`] method to be implemented; [`ne`] is defined
+/// in terms of it by default. Any manual implementation of [`ne`] *must* respect
+/// the rule that [`eq`] is a strict inverse of [`ne`]; that is, `!(a == b)` if and
 /// only if `a != b`.
 ///
-/// Implementations of `PartialEq`, `PartialOrd`, and `Ord` *must* agree with
+/// Implementations of `PartialEq`, [`PartialOrd`], and [`Ord`] *must* agree with
 /// each other. It's easy to accidentally make them disagree by deriving some
 /// of the traits and manually implementing others.
 ///
@@ -190,6 +190,9 @@ use self::Ordering::*;
 /// assert_eq!(x == y, false);
 /// assert_eq!(x.eq(&y), false);
 /// ```
+///
+/// [`eq`]: PartialEq::eq
+/// [`ne`]: PartialEq::ne
 #[lang = "eq"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(alias = "==")]
@@ -233,7 +236,7 @@ pub macro PartialEq($item:item) {
 /// - transitive: `a == b` and `b == c` implies `a == c`.
 ///
 /// This property cannot be checked by the compiler, and therefore `Eq` implies
-/// `PartialEq`, and has no extra methods.
+/// [`PartialEq`], and has no extra methods.
 ///
 /// ## Derivable
 ///
@@ -370,6 +373,7 @@ impl Ordering {
     /// Chains two orderings.
     ///
     /// Returns `self` when it's not `Equal`. Otherwise returns `other`.
+    ///
     /// # Examples
     ///
     /// ```
@@ -442,10 +446,12 @@ impl Ordering {
 
 /// A helper struct for reverse ordering.
 ///
-/// This struct is a helper to be used with functions like `Vec::sort_by_key` and
+/// This struct is a helper to be used with functions like [`Vec::sort_by_key`] and
 /// can be used to reverse order a part of a key.
 ///
-/// Example usage:
+/// [`Vec::sort_by_key`]: ../../std/vec/struct.Vec.html#method.sort_by_key
+///
+/// # Examples
 ///
 /// ```
 /// use std::cmp::Reverse;
@@ -506,12 +512,12 @@ impl<T: Ord> Ord for Reverse<T> {
 ///
 /// ## How can I implement `Ord`?
 ///
-/// `Ord` requires that the type also be `PartialOrd` and `Eq` (which requires `PartialEq`).
+/// `Ord` requires that the type also be [`PartialOrd`] and [`Eq`] (which requires [`PartialEq`]).
 ///
-/// Then you must define an implementation for `cmp()`. You may find it useful to use
-/// `cmp()` on your type's fields.
+/// Then you must define an implementation for [`cmp`]. You may find it useful to use
+/// [`cmp`] on your type's fields.
 ///
-/// Implementations of `PartialEq`, `PartialOrd`, and `Ord` *must*
+/// Implementations of [`PartialEq`], [`PartialOrd`], and `Ord` *must*
 /// agree with each other. That is, `a.cmp(b) == Ordering::Equal` if
 /// and only if `a == b` and `Some(a.cmp(b)) == a.partial_cmp(b)` for
 /// all `a` and `b`. It's easy to accidentally make them disagree by
@@ -548,13 +554,15 @@ impl<T: Ord> Ord for Reverse<T> {
 ///     }
 /// }
 /// ```
+///
+/// [`cmp`]: Ord::cmp
 #[doc(alias = "<")]
 #[doc(alias = ">")]
 #[doc(alias = "<=")]
 #[doc(alias = ">=")]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait Ord: Eq + PartialOrd<Self> {
-    /// This method returns an `Ordering` between `self` and `other`.
+    /// This method returns an [`Ordering`] between `self` and `other`.
     ///
     /// By convention, `self.cmp(&other)` returns the ordering matching the expression
     /// `self <operator> other` if true.
@@ -689,20 +697,20 @@ impl PartialOrd for Ordering {
 ///
 /// ## How can I implement `PartialOrd`?
 ///
-/// `PartialOrd` only requires implementation of the `partial_cmp` method, with the others
+/// `PartialOrd` only requires implementation of the [`partial_cmp`] method, with the others
 /// generated from default implementations.
 ///
 /// However it remains possible to implement the others separately for types which do not have a
 /// total order. For example, for floating point numbers, `NaN < 0 == false` and `NaN >= 0 ==
 /// false` (cf. IEEE 754-2008 section 5.11).
 ///
-/// `PartialOrd` requires your type to be `PartialEq`.
+/// `PartialOrd` requires your type to be [`PartialEq`].
 ///
-/// Implementations of `PartialEq`, `PartialOrd`, and `Ord` *must* agree with each other. It's
+/// Implementations of [`PartialEq`], `PartialOrd`, and [`Ord`] *must* agree with each other. It's
 /// easy to accidentally make them disagree by deriving some of the traits and manually
 /// implementing others.
 ///
-/// If your type is `Ord`, you can implement `partial_cmp()` by using `cmp()`:
+/// If your type is [`Ord`], you can implement [`partial_cmp`] by using [`cmp`]:
 ///
 /// ```
 /// use std::cmp::Ordering;
@@ -733,7 +741,7 @@ impl PartialOrd for Ordering {
 /// }
 /// ```
 ///
-/// You may also find it useful to use `partial_cmp()` on your type's fields. Here
+/// You may also find it useful to use [`partial_cmp`] on your type's fields. Here
 /// is an example of `Person` types who have a floating-point `height` field that
 /// is the only field to be used for sorting:
 ///
@@ -768,6 +776,9 @@ impl PartialOrd for Ordering {
 /// assert_eq!(x < y, true);
 /// assert_eq!(x.lt(&y), true);
 /// ```
+///
+/// [`partial_cmp`]: PartialOrd::partial_cmp
+/// [`cmp`]: Ord::cmp
 #[lang = "partial_ord"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(alias = ">")]
@@ -893,7 +904,7 @@ pub macro PartialOrd($item:item) {
 ///
 /// Returns the first argument if the comparison determines them to be equal.
 ///
-/// Internally uses an alias to `Ord::min`.
+/// Internally uses an alias to [`Ord::min`].
 ///
 /// # Examples
 ///
@@ -956,7 +967,7 @@ pub fn min_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T {
 ///
 /// Returns the second argument if the comparison determines them to be equal.
 ///
-/// Internally uses an alias to `Ord::max`.
+/// Internally uses an alias to [`Ord::max`].
 ///
 /// # Examples
 ///
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index cf9a5479afb..8dc185cd82b 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -148,16 +148,10 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
                 let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
                 match (cast_in, cast_out) {
                     (CastTy::Ptr(_), CastTy::Int(_)) | (CastTy::FnPtr, CastTy::Int(_)) => {
-                        self.register_violations(
-                            &[UnsafetyViolation {
-                                source_info: self.source_info,
-                                description: Symbol::intern("cast of pointer to int"),
-                                details: Symbol::intern(
-                                    "casting pointers to integers in constants",
-                                ),
-                                kind: UnsafetyViolationKind::General,
-                            }],
-                            &[],
+                        self.require_unsafe(
+                            "cast of pointer to int",
+                            "casting pointers to integers in constants",
+                            UnsafetyViolationKind::General,
                         );
                     }
                     _ => {}
@@ -171,14 +165,10 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
                 if self.const_context && self.tcx.features().const_compare_raw_pointers =>
             {
                 if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind {
-                    self.register_violations(
-                        &[UnsafetyViolation {
-                            source_info: self.source_info,
-                            description: Symbol::intern("pointer operation"),
-                            details: Symbol::intern("operations on pointers in constants"),
-                            kind: UnsafetyViolationKind::General,
-                        }],
-                        &[],
+                    self.require_unsafe(
+                        "pointer operation",
+                        "operations on pointers in constants",
+                        UnsafetyViolationKind::General,
                     );
                 }
             }
@@ -199,18 +189,12 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
                         .as_ref()
                         .assert_crate_local()
                         .lint_root;
-                    self.register_violations(
-                        &[UnsafetyViolation {
-                            source_info,
-                            description: Symbol::intern("borrow of packed field"),
-                            details: Symbol::intern(
-                                "fields of packed structs might be misaligned: dereferencing a \
-                            misaligned pointer or even just creating a misaligned reference \
-                            is undefined behavior",
-                            ),
-                            kind: UnsafetyViolationKind::BorrowPacked(lint_root),
-                        }],
-                        &[],
+                    self.require_unsafe(
+                        "borrow of packed field",
+                        "fields of packed structs might be misaligned: dereferencing a \
+                        misaligned pointer or even just creating a misaligned reference \
+                        is undefined behavior",
+                        UnsafetyViolationKind::BorrowPacked(lint_root),
                     );
                 }
             }
@@ -434,15 +418,10 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
                                         the field can be changed to invalid values",
                                     )
                                 };
-                                let source_info = self.source_info;
-                                self.register_violations(
-                                    &[UnsafetyViolation {
-                                        source_info,
-                                        description: Symbol::intern(description),
-                                        details: Symbol::intern(details),
-                                        kind: UnsafetyViolationKind::GeneralAndConstFn,
-                                    }],
-                                    &[],
+                                self.require_unsafe(
+                                    description,
+                                    details,
+                                    UnsafetyViolationKind::GeneralAndConstFn,
                                 );
                             }
                         },
diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs
index a94d8228bbe..ae8f1e4db1b 100644
--- a/src/librustc_parse/parser/stmt.rs
+++ b/src/librustc_parse/parser/stmt.rs
@@ -7,13 +7,13 @@ use crate::maybe_whole;
 use crate::DirectoryOwnership;
 
 use rustc_errors::{Applicability, PResult};
-use rustc_span::source_map::{respan, Span};
+use rustc_span::source_map::{respan, BytePos, Span};
 use rustc_span::symbol::{kw, sym, Symbol};
 use syntax::ast;
 use syntax::ast::{AttrStyle, AttrVec, Attribute, Mac, MacStmtStyle, VisibilityKind};
 use syntax::ast::{Block, BlockCheckMode, Expr, ExprKind, Local, Stmt, StmtKind, DUMMY_NODE_ID};
 use syntax::ptr::P;
-use syntax::token;
+use syntax::token::{self, TokenKind};
 use syntax::util::classify;
 
 use std::mem;
@@ -431,6 +431,23 @@ impl<'a> Parser<'a> {
                     if let Err(mut e) =
                         self.expect_one_of(&[], &[token::Semi, token::CloseDelim(token::Brace)])
                     {
+                        if let TokenKind::DocComment(..) = self.token.kind {
+                            if let Ok(snippet) = self.span_to_snippet(self.token.span) {
+                                let sp = self.token.span;
+                                let marker = &snippet[..3];
+                                let (comment_marker, doc_comment_marker) = marker.split_at(2);
+
+                                e.span_suggestion(
+                                    sp.with_hi(sp.lo() + BytePos(marker.len() as u32)),
+                                    &format!(
+                                        "add a space before `{}` to use a regular comment",
+                                        doc_comment_marker,
+                                    ),
+                                    format!("{} {}", comment_marker, doc_comment_marker),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
+                        }
                         e.emit();
                         self.recover_stmt();
                         // Don't complain about type errors in body tail after parse error (#57383).
diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs
index a5b34eeec28..3ca778354e4 100644
--- a/src/libstd/sys/unix/thread.rs
+++ b/src/libstd/sys/unix/thread.rs
@@ -426,8 +426,8 @@ pub mod guard {
 }
 
 // glibc >= 2.15 has a __pthread_get_minstack() function that returns
-// PTHREAD_STACK_MIN plus however many bytes are needed for thread-local
-// storage.  We need that information to avoid blowing up when a small stack
+// PTHREAD_STACK_MIN plus bytes needed for thread-local storage.
+// We need that information to avoid blowing up when a small stack
 // is created in an application with big thread-local storage requirements.
 // See #6233 for rationale and details.
 #[cfg(target_os = "linux")]
diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs
index 6cfe4f2de1e..1da005d70d4 100644
--- a/src/libsyntax/attr/builtin.rs
+++ b/src/libsyntax/attr/builtin.rs
@@ -371,6 +371,7 @@ where
                     let mut feature = None;
                     let mut reason = None;
                     let mut issue = None;
+                    let mut issue_num = None;
                     let mut is_soft = false;
                     for meta in metas {
                         if let Some(mi) = meta.meta_item() {
@@ -389,6 +390,37 @@ where
                                     if !get(mi, &mut issue) {
                                         continue 'outer;
                                     }
+
+                                    // These unwraps are safe because `get` ensures the meta item
+                                    // is a name/value pair string literal.
+                                    issue_num = match &*issue.unwrap().as_str() {
+                                        "none" => None,
+                                        issue => {
+                                            match issue.parse() {
+                                                Ok(num) => {
+                                                    // FIXME(rossmacarthur): disallow 0
+                                                    // Disallowing this requires updates to
+                                                    // some submodules
+                                                    NonZeroU32::new(num)
+                                                }
+                                                Err(err) => {
+                                                    struct_span_err!(
+                                                        diagnostic,
+                                                        mi.span,
+                                                        E0545,
+                                                        "`issue` must be a numeric string \
+                                                        or \"none\"",
+                                                    )
+                                                    .span_label(
+                                                        mi.name_value_literal().unwrap().span,
+                                                        &err.to_string(),
+                                                    )
+                                                    .emit();
+                                                    continue 'outer;
+                                                }
+                                            }
+                                        }
+                                    };
                                 }
                                 sym::soft => {
                                     if !mi.is_word() {
@@ -420,27 +452,8 @@ where
                     }
 
                     match (feature, reason, issue) {
-                        (Some(feature), reason, Some(issue)) => {
-                            let issue = match &*issue.as_str() {
-                                "none" => None,
-                                issue => {
-                                    if let Ok(num) = issue.parse() {
-                                        // FIXME(rossmacarthur): disallow 0
-                                        // Disallowing this requires updates to some submodules
-                                        NonZeroU32::new(num)
-                                    } else {
-                                        struct_span_err!(
-                                            diagnostic,
-                                            attr.span,
-                                            E0545,
-                                            "incorrect 'issue'"
-                                        )
-                                        .emit();
-                                        continue;
-                                    }
-                                }
-                            };
-                            let level = Unstable { reason, issue, is_soft };
+                        (Some(feature), reason, Some(_)) => {
+                            let level = Unstable { reason, issue: issue_num, is_soft };
                             if sym::unstable == meta_name {
                                 stab = Some(Stability { level, feature, rustc_depr: None });
                             } else {
diff --git a/src/test/ui/feature-gate/unstable-attribute-allow-issue-0.rs b/src/test/ui/feature-gate/unstable-attribute-allow-issue-0.rs
index c8ad0d13a14..7a2bf468f89 100644
--- a/src/test/ui/feature-gate/unstable-attribute-allow-issue-0.rs
+++ b/src/test/ui/feature-gate/unstable-attribute-allow-issue-0.rs
@@ -9,5 +9,5 @@ fn unstable_issue_0() {}
 #[unstable(feature = "unstable_test_feature", issue = "none")]
 fn unstable_issue_none() {}
 
-#[unstable(feature = "unstable_test_feature", issue = "something")] //~ ERROR incorrect 'issue'
-fn unstable_issue_not_allowed() {}
+#[unstable(feature = "unstable_test_feature", issue = "something")]
+fn unstable_issue_not_allowed() {} //~^ ERROR `issue` must be a numeric string or "none"
diff --git a/src/test/ui/feature-gate/unstable-attribute-allow-issue-0.stderr b/src/test/ui/feature-gate/unstable-attribute-allow-issue-0.stderr
index 10bd6f373d9..21ff12185ec 100644
--- a/src/test/ui/feature-gate/unstable-attribute-allow-issue-0.stderr
+++ b/src/test/ui/feature-gate/unstable-attribute-allow-issue-0.stderr
@@ -1,8 +1,10 @@
-error[E0545]: incorrect 'issue'
-  --> $DIR/unstable-attribute-allow-issue-0.rs:12:1
+error[E0545]: `issue` must be a numeric string or "none"
+  --> $DIR/unstable-attribute-allow-issue-0.rs:12:47
    |
 LL | #[unstable(feature = "unstable_test_feature", issue = "something")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                               ^^^^^^^^-----------
+   |                                                       |
+   |                                                       invalid digit found in string
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/doc-comment-in-stmt.rs b/src/test/ui/parser/doc-comment-in-stmt.rs
new file mode 100644
index 00000000000..b02df13213f
--- /dev/null
+++ b/src/test/ui/parser/doc-comment-in-stmt.rs
@@ -0,0 +1,20 @@
+fn foo() -> bool {
+    false
+    //!self.allow_ty_infer()
+    //~^ ERROR found doc comment
+}
+
+fn bar() -> bool {
+    false
+    /*! bar */ //~ ERROR found doc comment
+}
+
+fn baz() -> i32 {
+    1 /** baz */ //~ ERROR found doc comment
+}
+
+fn quux() -> i32 {
+    2 /*! quux */ //~ ERROR found doc comment
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/doc-comment-in-stmt.stderr b/src/test/ui/parser/doc-comment-in-stmt.stderr
new file mode 100644
index 00000000000..5d94d6fe69b
--- /dev/null
+++ b/src/test/ui/parser/doc-comment-in-stmt.stderr
@@ -0,0 +1,50 @@
+error: expected one of `.`, `;`, `?`, `}`, or an operator, found doc comment `//!self.allow_ty_infer()`
+  --> $DIR/doc-comment-in-stmt.rs:3:5
+   |
+LL |     false
+   |          - expected one of `.`, `;`, `?`, `}`, or an operator
+LL |     //!self.allow_ty_infer()
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ unexpected token
+   |
+help: add a space before `!` to use a regular comment
+   |
+LL |     // !self.allow_ty_infer()
+   |     ^^^^
+
+error: expected one of `.`, `;`, `?`, `}`, or an operator, found doc comment `/*! bar */`
+  --> $DIR/doc-comment-in-stmt.rs:9:5
+   |
+LL |     false
+   |          - expected one of `.`, `;`, `?`, `}`, or an operator
+LL |     /*! bar */
+   |     ^^^^^^^^^^ unexpected token
+   |
+help: add a space before `!` to use a regular comment
+   |
+LL |     /* ! bar */
+   |     ^^^^
+
+error: expected one of `.`, `;`, `?`, `}`, or an operator, found doc comment `/** baz */`
+  --> $DIR/doc-comment-in-stmt.rs:13:7
+   |
+LL |     1 /** baz */
+   |       ^^^^^^^^^^ expected one of `.`, `;`, `?`, `}`, or an operator
+   |
+help: add a space before `*` to use a regular comment
+   |
+LL |     1 /* * baz */
+   |       ^^^^
+
+error: expected one of `.`, `;`, `?`, `}`, or an operator, found doc comment `/*! quux */`
+  --> $DIR/doc-comment-in-stmt.rs:17:7
+   |
+LL |     2 /*! quux */
+   |       ^^^^^^^^^^^ expected one of `.`, `;`, `?`, `}`, or an operator
+   |
+help: add a space before `!` to use a regular comment
+   |
+LL |     2 /* ! quux */
+   |       ^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity-2.rs b/src/test/ui/stability-attribute/stability-attribute-sanity-2.rs
index 5a67ca0b0c8..e74147ce900 100644
--- a/src/test/ui/stability-attribute/stability-attribute-sanity-2.rs
+++ b/src/test/ui/stability-attribute/stability-attribute-sanity-2.rs
@@ -10,7 +10,7 @@ fn f1() { }
 #[stable(feature = "a", sinse = "1.0.0")] //~ ERROR unknown meta item 'sinse'
 fn f2() { }
 
-#[unstable(feature = "a", issue = "no")] //~ ERROR incorrect 'issue'
+#[unstable(feature = "a", issue = "no")] //~ ERROR `issue` must be a numeric string or "none"
 fn f3() { }
 
 fn main() { }
diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity-2.stderr b/src/test/ui/stability-attribute/stability-attribute-sanity-2.stderr
index d683d089530..541b94afe0f 100644
--- a/src/test/ui/stability-attribute/stability-attribute-sanity-2.stderr
+++ b/src/test/ui/stability-attribute/stability-attribute-sanity-2.stderr
@@ -10,11 +10,13 @@ error[E0541]: unknown meta item 'sinse'
 LL | #[stable(feature = "a", sinse = "1.0.0")]
    |                         ^^^^^^^^^^^^^^^ expected one of `since`, `note`
 
-error[E0545]: incorrect 'issue'
-  --> $DIR/stability-attribute-sanity-2.rs:13:1
+error[E0545]: `issue` must be a numeric string or "none"
+  --> $DIR/stability-attribute-sanity-2.rs:13:27
    |
 LL | #[unstable(feature = "a", issue = "no")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                           ^^^^^^^^----
+   |                                   |
+   |                                   invalid digit found in string
 
 error: aborting due to 3 previous errors