diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 9459bb7047f5c..58f557ed53693 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -252,6 +252,15 @@ pub fn expand_test_or_bench( "ignore", cx.expr_bool(sp, should_ignore(&cx.sess, &item)), ), + // ignore_message: Some("...") | None + field( + "ignore_message", + if let Some(msg) = should_ignore_message(cx, &item) { + cx.expr_some(sp, cx.expr_str(sp, msg)) + } else { + cx.expr_none(sp) + }, + ), // compile_fail: true | false field("compile_fail", cx.expr_bool(sp, false)), // no_run: true | false @@ -354,6 +363,20 @@ fn should_ignore(sess: &Session, i: &ast::Item) -> bool { sess.contains_name(&i.attrs, sym::ignore) } +fn should_ignore_message(cx: &ExtCtxt<'_>, i: &ast::Item) -> Option { + match cx.sess.find_by_name(&i.attrs, sym::ignore) { + Some(attr) => { + match attr.meta_item_list() { + // Handle #[ignore(bar = "foo")] + Some(_) => None, + // Handle #[ignore] and #[ignore = "message"] + None => attr.value_str(), + } + } + None => None, + } +} + fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic { match cx.sess.find_by_name(&i.attrs, sym::should_panic) { Some(attr) => { diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 2cc15b3e53f46..b8ed75cb6bb74 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -329,6 +329,10 @@ impl<'a> ExtCtxt<'a> { self.expr_call_global(sp, some, vec![expr]) } + pub fn expr_none(&self, sp: Span) -> P { + let none = self.std_path(&[sym::option, sym::Option, sym::None]); + self.expr_path(self.path_global(sp, none)) + } pub fn expr_tuple(&self, sp: Span, exprs: Vec>) -> P { self.expr(sp, ast::ExprKind::Tup(exprs)) } diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index dec1b5270d58b..ebfd12d15337c 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -805,7 +805,7 @@ impl Pin<&'static T> { /// /// This is safe, because `T` is borrowed for the `'static` lifetime, which /// never ends. - #[unstable(feature = "pin_static_ref", issue = "78186")] + #[stable(feature = "pin_static_ref", since = "1.60.0")] #[rustc_const_unstable(feature = "const_pin", issue = "76654")] pub const fn static_ref(r: &'static T) -> Pin<&'static T> { // SAFETY: The 'static borrow guarantees the data will not be @@ -858,7 +858,7 @@ impl Pin<&'static mut T> { /// /// This is safe, because `T` is borrowed for the `'static` lifetime, which /// never ends. - #[unstable(feature = "pin_static_ref", issue = "78186")] + #[stable(feature = "pin_static_ref", since = "1.60.0")] #[rustc_const_unstable(feature = "const_pin", issue = "76654")] pub const fn static_mut(r: &'static mut T) -> Pin<&'static mut T> { // SAFETY: The 'static borrow guarantees the data will not be diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index 304ba7ee5544f..1dba24dd14907 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -79,6 +79,84 @@ impl [u8] { pub fn escape_ascii(&self) -> EscapeAscii<'_> { EscapeAscii { inner: self.iter().flat_map(EscapeByte) } } + + /// Returns a byte slice with leading ASCII whitespace bytes removed. + /// + /// 'Whitespace' refers to the definition used by + /// `u8::is_ascii_whitespace`. + /// + /// # Examples + /// + /// ``` + /// #![feature(byte_slice_trim_ascii)] + /// + /// assert_eq!(b" \t hello world\n".trim_ascii_start(), b"hello world\n"); + /// assert_eq!(b" ".trim_ascii_start(), b""); + /// assert_eq!(b"".trim_ascii_start(), b""); + /// ``` + #[unstable(feature = "byte_slice_trim_ascii", issue = "94035")] + pub const fn trim_ascii_start(&self) -> &[u8] { + let mut bytes = self; + // Note: A pattern matching based approach (instead of indexing) allows + // making the function const. + while let [first, rest @ ..] = bytes { + if first.is_ascii_whitespace() { + bytes = rest; + } else { + break; + } + } + bytes + } + + /// Returns a byte slice with trailing ASCII whitespace bytes removed. + /// + /// 'Whitespace' refers to the definition used by + /// `u8::is_ascii_whitespace`. + /// + /// # Examples + /// + /// ``` + /// #![feature(byte_slice_trim_ascii)] + /// + /// assert_eq!(b"\r hello world\n ".trim_ascii_end(), b"\r hello world"); + /// assert_eq!(b" ".trim_ascii_end(), b""); + /// assert_eq!(b"".trim_ascii_end(), b""); + /// ``` + #[unstable(feature = "byte_slice_trim_ascii", issue = "94035")] + pub const fn trim_ascii_end(&self) -> &[u8] { + let mut bytes = self; + // Note: A pattern matching based approach (instead of indexing) allows + // making the function const. + while let [rest @ .., last] = bytes { + if last.is_ascii_whitespace() { + bytes = rest; + } else { + break; + } + } + bytes + } + + /// Returns a byte slice with leading and trailing ASCII whitespace bytes + /// removed. + /// + /// 'Whitespace' refers to the definition used by + /// `u8::is_ascii_whitespace`. + /// + /// # Examples + /// + /// ``` + /// #![feature(byte_slice_trim_ascii)] + /// + /// assert_eq!(b"\r hello world\n ".trim_ascii(), b"hello world"); + /// assert_eq!(b" ".trim_ascii(), b""); + /// assert_eq!(b"".trim_ascii(), b""); + /// ``` + #[unstable(feature = "byte_slice_trim_ascii", issue = "94035")] + pub const fn trim_ascii(&self) -> &[u8] { + self.trim_ascii_start().trim_ascii_end() + } } impl_fn_for_zst! { diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 9e61defc31e97..c7e34962abb43 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -2472,6 +2472,7 @@ impl<'a, K, V> Entry<'a, K, V> { /// # Examples /// /// ``` + /// #![feature(entry_insert)] /// use std::collections::HashMap; /// /// let mut map: HashMap<&str, String> = HashMap::new(); @@ -2480,7 +2481,7 @@ impl<'a, K, V> Entry<'a, K, V> { /// assert_eq!(entry.key(), &"poneyland"); /// ``` #[inline] - #[stable(feature = "entry_insert", since = "1.59.0")] + #[unstable(feature = "entry_insert", issue = "65225")] pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V> { match self { Occupied(mut entry) => { @@ -2814,6 +2815,7 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { /// # Examples /// /// ``` + /// #![feature(entry_insert)] /// use std::collections::HashMap; /// use std::collections::hash_map::Entry; /// @@ -2825,7 +2827,7 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { /// assert_eq!(map["poneyland"], 37); /// ``` #[inline] - #[stable(feature = "entry_insert", since = "1.59.0")] + #[unstable(feature = "entry_insert", issue = "65225")] pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V> { let base = self.base.insert_entry(value); OccupiedEntry { base } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index a03da0682a5cd..0cc6881899877 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -311,7 +311,6 @@ #![feature(panic_internals)] #![feature(panic_can_unwind)] #![feature(panic_unwind)] -#![feature(pin_static_ref)] #![feature(platform_intrinsics)] #![feature(portable_simd)] #![feature(prelude_import)] diff --git a/library/test/src/console.rs b/library/test/src/console.rs index 920f55ad251a6..22fcd77dccc52 100644 --- a/library/test/src/console.rs +++ b/library/test/src/console.rs @@ -103,17 +103,32 @@ impl ConsoleTestState { exec_time: Option<&TestExecTime>, ) -> io::Result<()> { self.write_log(|| { + let TestDesc { + name, + #[cfg(not(bootstrap))] + ignore_message, + .. + } = test; format!( "{} {}", match *result { TestResult::TrOk => "ok".to_owned(), TestResult::TrFailed => "failed".to_owned(), TestResult::TrFailedMsg(ref msg) => format!("failed: {}", msg), - TestResult::TrIgnored => "ignored".to_owned(), + TestResult::TrIgnored => { + #[cfg(not(bootstrap))] + if let Some(msg) = ignore_message { + format!("ignored, {}", msg) + } else { + "ignored".to_owned() + } + #[cfg(bootstrap)] + "ignored".to_owned() + } TestResult::TrBench(ref bs) => fmt_bench_samples(bs), TestResult::TrTimedFail => "failed (time limit exceeded)".to_owned(), }, - test.name, + name, ) })?; if let Some(exec_time) = exec_time { diff --git a/library/test/src/tests.rs b/library/test/src/tests.rs index d566dbc09f434..e99089e453e7f 100644 --- a/library/test/src/tests.rs +++ b/library/test/src/tests.rs @@ -61,6 +61,8 @@ fn one_ignored_one_unignored_test() -> Vec { desc: TestDesc { name: StaticTestName("1"), ignore: true, + #[cfg(not(bootstrap))] + ignore_message: None, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -74,6 +76,8 @@ fn one_ignored_one_unignored_test() -> Vec { desc: TestDesc { name: StaticTestName("2"), ignore: false, + #[cfg(not(bootstrap))] + ignore_message: None, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -95,6 +99,8 @@ pub fn do_not_run_ignored_tests() { desc: TestDesc { name: StaticTestName("whatever"), ignore: true, + #[cfg(not(bootstrap))] + ignore_message: None, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -117,6 +123,8 @@ pub fn ignored_tests_result_in_ignored() { desc: TestDesc { name: StaticTestName("whatever"), ignore: true, + #[cfg(not(bootstrap))] + ignore_message: None, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -143,6 +151,8 @@ fn test_should_panic() { desc: TestDesc { name: StaticTestName("whatever"), ignore: false, + #[cfg(not(bootstrap))] + ignore_message: None, should_panic: ShouldPanic::Yes, compile_fail: false, no_run: false, @@ -169,6 +179,8 @@ fn test_should_panic_good_message() { desc: TestDesc { name: StaticTestName("whatever"), ignore: false, + #[cfg(not(bootstrap))] + ignore_message: None, should_panic: ShouldPanic::YesWithMessage("error message"), compile_fail: false, no_run: false, @@ -200,6 +212,8 @@ fn test_should_panic_bad_message() { desc: TestDesc { name: StaticTestName("whatever"), ignore: false, + #[cfg(not(bootstrap))] + ignore_message: None, should_panic: ShouldPanic::YesWithMessage(expected), compile_fail: false, no_run: false, @@ -235,6 +249,8 @@ fn test_should_panic_non_string_message_type() { desc: TestDesc { name: StaticTestName("whatever"), ignore: false, + #[cfg(not(bootstrap))] + ignore_message: None, should_panic: ShouldPanic::YesWithMessage(expected), compile_fail: false, no_run: false, @@ -262,6 +278,8 @@ fn test_should_panic_but_succeeds() { desc: TestDesc { name: StaticTestName("whatever"), ignore: false, + #[cfg(not(bootstrap))] + ignore_message: None, should_panic, compile_fail: false, no_run: false, @@ -297,6 +315,8 @@ fn report_time_test_template(report_time: bool) -> Option { desc: TestDesc { name: StaticTestName("whatever"), ignore: false, + #[cfg(not(bootstrap))] + ignore_message: None, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -333,6 +353,8 @@ fn time_test_failure_template(test_type: TestType) -> TestResult { desc: TestDesc { name: StaticTestName("whatever"), ignore: false, + #[cfg(not(bootstrap))] + ignore_message: None, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -373,6 +395,8 @@ fn typed_test_desc(test_type: TestType) -> TestDesc { TestDesc { name: StaticTestName("whatever"), ignore: false, + #[cfg(not(bootstrap))] + ignore_message: None, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -486,6 +510,8 @@ pub fn exclude_should_panic_option() { desc: TestDesc { name: StaticTestName("3"), ignore: false, + #[cfg(not(bootstrap))] + ignore_message: None, should_panic: ShouldPanic::Yes, compile_fail: false, no_run: false, @@ -511,6 +537,8 @@ pub fn exact_filter_match() { desc: TestDesc { name: StaticTestName(name), ignore: false, + #[cfg(not(bootstrap))] + ignore_message: None, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -601,6 +629,8 @@ fn sample_tests() -> Vec { desc: TestDesc { name: DynTestName((*name).clone()), ignore: false, + #[cfg(not(bootstrap))] + ignore_message: None, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -753,6 +783,8 @@ pub fn test_bench_no_iter() { let desc = TestDesc { name: StaticTestName("f"), ignore: false, + #[cfg(not(bootstrap))] + ignore_message: None, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -776,6 +808,8 @@ pub fn test_bench_iter() { let desc = TestDesc { name: StaticTestName("f"), ignore: false, + #[cfg(not(bootstrap))] + ignore_message: None, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -793,6 +827,8 @@ fn should_sort_failures_before_printing_them() { let test_a = TestDesc { name: StaticTestName("a"), ignore: false, + #[cfg(not(bootstrap))] + ignore_message: None, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, @@ -804,6 +840,8 @@ fn should_sort_failures_before_printing_them() { let test_b = TestDesc { name: StaticTestName("b"), ignore: false, + #[cfg(not(bootstrap))] + ignore_message: None, should_panic: ShouldPanic::No, compile_fail: false, no_run: false, diff --git a/library/test/src/types.rs b/library/test/src/types.rs index 43e5a10ebbe95..cc75220aa0032 100644 --- a/library/test/src/types.rs +++ b/library/test/src/types.rs @@ -117,6 +117,8 @@ pub struct TestId(pub usize); pub struct TestDesc { pub name: TestName, pub ignore: bool, + #[cfg(not(bootstrap))] + pub ignore_message: Option<&'static str>, pub should_panic: options::ShouldPanic, pub compile_fail: bool, pub no_run: bool, diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 3a9fb6d14203e..303cb35952b45 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -948,6 +948,8 @@ impl Tester for Collector { Ignore::None => false, Ignore::Some(ref ignores) => ignores.iter().any(|s| target_str.contains(s)), }, + #[cfg(not(bootstrap))] + ignore_message: None, // compiler failures are test failures should_panic: test::ShouldPanic::No, compile_fail: config.compile_fail, diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index da7a19139c65b..8d658432654b3 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -853,6 +853,8 @@ pub fn make_test_description( cfg: Option<&str>, ) -> test::TestDesc { let mut ignore = false; + #[cfg(not(bootstrap))] + let ignore_message: Option = None; let mut should_fail = false; let rustc_has_profiler_support = env::var_os("RUSTC_PROFILER_SUPPORT").is_some(); @@ -921,6 +923,8 @@ pub fn make_test_description( test::TestDesc { name, ignore, + #[cfg(not(bootstrap))] + ignore_message, should_panic, compile_fail: false, no_run: false,