diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index c8055100d3096..630a89cc7cbfc 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2888,6 +2888,14 @@ pub fn fn_can_unwind<'tcx>(tcx: TyCtxt<'tcx>, fn_def_id: Option, abi: Spe return false; } + // With `-C panic=abort`, all non-FFI functions are required to not unwind. + // + // Note that this is true regardless ABI specified on the function -- a `extern "C-unwind"` + // function defined in Rust is also required to abort. + if tcx.sess.panic_strategy() == PanicStrategy::Abort && !tcx.is_foreign_item(did) { + return false; + } + // With -Z panic-in-drop=abort, drop_in_place never unwinds. // // This is not part of `codegen_fn_attrs` as it can differ between crates diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index a231f533d190b..dbc3d2923ed59 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -496,9 +496,10 @@ macro_rules! r#try { #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "write_macro")] macro_rules! write { - ($dst:expr, $($arg:tt)*) => { - $dst.write_fmt($crate::format_args!($($arg)*)) - }; + ($dst:expr, $($arg:tt)*) => {{ + let result = $dst.write_fmt($crate::format_args!($($arg)*)); + result + }}; } /// Write formatted data into a buffer, with a newline appended. @@ -553,9 +554,10 @@ macro_rules! writeln { ($dst:expr $(,)?) => { $crate::write!($dst, "\n") }; - ($dst:expr, $($arg:tt)*) => { - $dst.write_fmt($crate::format_args_nl!($($arg)*)) - }; + ($dst:expr, $($arg:tt)*) => {{ + let result = $dst.write_fmt($crate::format_args_nl!($($arg)*)); + result + }}; } /// Indicates unreachable code. diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs index e512c0d81a0f3..646744a50eb88 100644 --- a/library/std/src/macros.rs +++ b/library/std/src/macros.rs @@ -62,9 +62,9 @@ macro_rules! panic { #[cfg_attr(not(test), rustc_diagnostic_item = "print_macro")] #[allow_internal_unstable(print_internals)] macro_rules! print { - ($($arg:tt)*) => { - $crate::io::_print($crate::format_args!($($arg)*)) - }; + ($($arg:tt)*) => {{ + $crate::io::_print($crate::format_args!($($arg)*)); + }}; } /// Prints to the standard output, with a newline. @@ -133,9 +133,9 @@ macro_rules! println { #[cfg_attr(not(test), rustc_diagnostic_item = "eprint_macro")] #[allow_internal_unstable(print_internals)] macro_rules! eprint { - ($($arg:tt)*) => { - $crate::io::_eprint($crate::format_args!($($arg)*)) - }; + ($($arg:tt)*) => {{ + $crate::io::_eprint($crate::format_args!($($arg)*)); + }}; } /// Prints to the standard error, with a newline. diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index 290b7f0d08a72..f27970eaaf122 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -22,8 +22,10 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; /// so it can be used in FFI in places where a handle is passed as an argument, /// it is not captured or consumed. /// -/// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is -/// sometimes a valid handle value. See [here] for the full story. +/// Note that it *may* have the value `-1`, which in `BorrowedHandle` always +/// represents a valid handle value, such as [the current process handle], and +/// not `INVALID_HANDLE_VALUE`, despite the two having the same value. See +/// [here] for the full story. /// /// And, it *may* have the value `NULL` (0), which can occur when consoles are /// detached from processes, or when `windows_subsystem` is used. @@ -33,6 +35,7 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; /// handle, which is then borrowed under the same lifetime. /// /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 +/// [the current process handle]: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess#remarks #[derive(Copy, Clone)] #[repr(transparent)] #[unstable(feature = "io_safety", issue = "87074")] @@ -45,8 +48,10 @@ pub struct BorrowedHandle<'handle> { /// /// This closes the handle on drop. /// -/// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is -/// sometimes a valid handle value. See [here] for the full story. +/// Note that it *may* have the value `-1`, which in `OwnedHandle` always +/// represents a valid handle value, such as [the current process handle], and +/// not `INVALID_HANDLE_VALUE`, despite the two having the same value. See +/// [here] for the full story. /// /// And, it *may* have the value `NULL` (0), which can occur when consoles are /// detached from processes, or when `windows_subsystem` is used. @@ -59,6 +64,7 @@ pub struct BorrowedHandle<'handle> { /// [`RegCloseKey`]: https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regclosekey /// /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 +/// [the current process handle]: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess#remarks #[repr(transparent)] #[unstable(feature = "io_safety", issue = "87074")] pub struct OwnedHandle { @@ -75,11 +81,13 @@ pub struct OwnedHandle { /// `NULL`. This ensures that such FFI calls cannot start using the handle without /// checking for `NULL` first. /// -/// This type considers any value other than `NULL` to be valid, including `INVALID_HANDLE_VALUE`. -/// This is because APIs that use `NULL` as their sentry value don't treat `INVALID_HANDLE_VALUE` -/// as special. +/// This type may hold any handle value that [`OwnedHandle`] may hold. As with `OwnedHandle`, when +/// it holds `-1`, that value is interpreted as a valid handle value, such as +/// [the current process handle], and not `INVALID_HANDLE_VALUE`. /// -/// If this holds a valid handle, it will close the handle on drop. +/// If this holds a non-null handle, it will close the handle on drop. +/// +/// [the current process handle]: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess#remarks #[repr(transparent)] #[unstable(feature = "io_safety", issue = "87074")] #[derive(Debug)] @@ -95,11 +103,10 @@ pub struct HandleOrNull(OwnedHandle); /// `INVALID_HANDLE_VALUE`. This ensures that such FFI calls cannot start using the handle without /// checking for `INVALID_HANDLE_VALUE` first. /// -/// This type considers any value other than `INVALID_HANDLE_VALUE` to be valid, including `NULL`. -/// This is because APIs that use `INVALID_HANDLE_VALUE` as their sentry value may return `NULL` -/// under `windows_subsystem = "windows"` or other situations where I/O devices are detached. +/// This type may hold any handle value that [`OwnedHandle`] may hold, except that when it holds +/// `-1`, that value is interpreted to mean `INVALID_HANDLE_VALUE`. /// -/// If this holds a valid handle, it will close the handle on drop. +/// If holds a handle other than `INVALID_HANDLE_VALUE`, it will close the handle on drop. #[repr(transparent)] #[unstable(feature = "io_safety", issue = "87074")] #[derive(Debug)] diff --git a/library/std/src/os/windows/io/raw.rs b/library/std/src/os/windows/io/raw.rs index 68fa8918a56a0..49e4f304f5dba 100644 --- a/library/std/src/os/windows/io/raw.rs +++ b/library/std/src/os/windows/io/raw.rs @@ -32,8 +32,15 @@ pub trait AsRawHandle { /// raw handle to the caller, and the handle is only guaranteed /// to be valid while the original object has not yet been destroyed. /// + /// This function may return null, such as when called on [`Stdin`], + /// [`Stdout`], or [`Stderr`] when the console is detached. + /// /// However, borrowing is not strictly required. See [`AsHandle::as_handle`] /// for an API which strictly borrows a handle. + /// + /// [`Stdin`]: io::Stdin + /// [`Stdout`]: io::Stdout + /// [`Stderr`]: io::Stderr #[stable(feature = "rust1", since = "1.0.0")] fn as_raw_handle(&self) -> RawHandle; } diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index d3e91c75837a0..4ab502e90526f 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -507,6 +507,7 @@ mod dist { config.stage = 0; config.cmd = Subcommand::Test { paths: vec!["library/std".into()], + skip: vec![], test_args: vec![], rustc_args: vec![], fail_fast: true, @@ -577,6 +578,7 @@ mod dist { let mut config = configure(&["A"], &["A"]); config.cmd = Subcommand::Test { paths: vec![], + skip: vec![], test_args: vec![], rustc_args: vec![], fail_fast: true, diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 58571ea129c19..4cd835ade6421 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -111,6 +111,7 @@ pub enum Subcommand { compare_mode: Option, pass: Option, run: Option, + skip: Vec, test_args: Vec, rustc_args: Vec, fail_fast: bool, @@ -261,6 +262,7 @@ To learn more about a subcommand, run `./x.py -h`", match subcommand { Kind::Test => { opts.optflag("", "no-fail-fast", "Run all tests regardless of failure"); + opts.optmulti("", "skip", "skips tests matching SUBSTRING, if supported by test tool. May be passed multiple times", "SUBSTRING"); opts.optmulti( "", "test-args", @@ -545,6 +547,7 @@ Arguments: compare_mode: matches.opt_str("compare-mode"), pass: matches.opt_str("pass"), run: matches.opt_str("run"), + skip: matches.opt_strs("skip"), test_args: matches.opt_strs("test-args"), rustc_args: matches.opt_strs("rustc-args"), fail_fast: !matches.opt_present("no-fail-fast"), @@ -689,12 +692,26 @@ impl Subcommand { } pub fn test_args(&self) -> Vec<&str> { + let mut args = vec![]; + + match *self { + Subcommand::Test { ref skip, .. } => { + for s in skip { + args.push("--skip"); + args.push(s.as_str()); + } + } + _ => (), + }; + match *self { Subcommand::Test { ref test_args, .. } | Subcommand::Bench { ref test_args, .. } => { - test_args.iter().flat_map(|s| s.split_whitespace()).collect() + args.extend(test_args.iter().flat_map(|s| s.split_whitespace())) } - _ => Vec::new(), + _ => (), } + + args } pub fn rustc_args(&self) -> Vec<&str> { diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 7754d626e209e..b596adf32c6fd 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -119,7 +119,7 @@ window.initSearch = rawSearchIndex => { */ let searchIndex; let currentResults; - const ALIASES = {}; + const ALIASES = Object.create(null); const params = searchState.getQueryStringParams(); // Populate search bar with query string search term when provided, @@ -1953,7 +1953,7 @@ window.initSearch = rawSearchIndex => { } if (aliases) { - ALIASES[crate] = {}; + ALIASES[crate] = Object.create(null); for (const alias_name in aliases) { if (!hasOwnPropertyRustdoc(aliases, alias_name)) { continue; diff --git a/src/test/codegen/unwind-abis/c-unwind-abi-panic-abort.rs b/src/test/codegen/unwind-abis/c-unwind-abi-panic-abort.rs index 398937a04c923..af6879880ae3b 100644 --- a/src/test/codegen/unwind-abis/c-unwind-abi-panic-abort.rs +++ b/src/test/codegen/unwind-abis/c-unwind-abi-panic-abort.rs @@ -1,22 +1,27 @@ // compile-flags: -C panic=abort -// Test that `nounwind` atributes are not applied to `C-unwind` extern functions -// even when the code is compiled with `panic=abort`. +// Test that `nounwind` atributes are also applied to extern `C-unwind` Rust functions +// when the code is compiled with `panic=abort`. #![crate_type = "lib"] #![feature(c_unwind)] -extern "C-unwind" { - fn may_unwind(); -} - // CHECK: @rust_item_that_can_unwind() unnamed_addr #0 #[no_mangle] pub unsafe extern "C-unwind" fn rust_item_that_can_unwind() { + // CHECK: call void @_ZN4core9panicking15panic_no_unwind may_unwind(); } +extern "C-unwind" { + // CHECK: @may_unwind() unnamed_addr #1 + fn may_unwind(); +} + // Now, make sure that the LLVM attributes for this functions are correct. First, make // sure that the first item is correctly marked with the `nounwind` attribute: // -// CHECK-NOT: attributes #0 = { {{.*}}nounwind{{.*}} } +// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } +// +// Now, check that foreign item is correctly marked without the `nounwind` attribute. +// CHECK-NOT: attributes #1 = { {{.*}}nounwind{{.*}} } diff --git a/src/test/rustdoc-js/prototype.js b/src/test/rustdoc-js/prototype.js new file mode 100644 index 0000000000000..2f1d841c3be19 --- /dev/null +++ b/src/test/rustdoc-js/prototype.js @@ -0,0 +1,16 @@ +// exact-check + +const QUERY = ['constructor', '__proto__']; + +const EXPECTED = [ + { + 'others': [], + 'returned': [], + 'in_args': [], + }, + { + 'others': [], + 'returned': [], + 'in_args': [], + }, +]; diff --git a/src/test/rustdoc-js/prototype.rs b/src/test/rustdoc-js/prototype.rs new file mode 100644 index 0000000000000..5f6d73cc19626 --- /dev/null +++ b/src/test/rustdoc-js/prototype.rs @@ -0,0 +1,4 @@ +// The alias needed to be there to reproduce the bug +// that used to be here. +#[doc(alias="other_alias")] +pub fn something_else() {} diff --git a/src/test/ui/macros/format-args-temporaries.rs b/src/test/ui/macros/format-args-temporaries.rs new file mode 100644 index 0000000000000..ddd4c9754bfa4 --- /dev/null +++ b/src/test/ui/macros/format-args-temporaries.rs @@ -0,0 +1,70 @@ +// check-pass + +use std::fmt::{self, Display}; + +struct Mutex; + +impl Mutex { + fn lock(&self) -> MutexGuard { + MutexGuard(self) + } +} + +struct MutexGuard<'a>(&'a Mutex); + +impl<'a> Drop for MutexGuard<'a> { + fn drop(&mut self) { + // Empty but this is a necessary part of the repro. Otherwise borrow + // checker is fine with 'a dangling at the time that MutexGuard goes out + // of scope. + } +} + +impl<'a> MutexGuard<'a> { + fn write_fmt(&self, _args: fmt::Arguments) {} +} + +impl<'a> Display for MutexGuard<'a> { + fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result { + Ok(()) + } +} + +fn main() { + let _write = { + let out = Mutex; + let mutex = Mutex; + write!(out.lock(), "{}", mutex.lock()) /* no semicolon */ + }; + + let _writeln = { + let out = Mutex; + let mutex = Mutex; + writeln!(out.lock(), "{}", mutex.lock()) /* no semicolon */ + }; + + let _print = { + let mutex = Mutex; + print!("{}", mutex.lock()) /* no semicolon */ + }; + + let _println = { + let mutex = Mutex; + println!("{}", mutex.lock()) /* no semicolon */ + }; + + let _eprint = { + let mutex = Mutex; + eprint!("{}", mutex.lock()) /* no semicolon */ + }; + + let _eprintln = { + let mutex = Mutex; + eprintln!("{}", mutex.lock()) /* no semicolon */ + }; + + let _panic = { + let mutex = Mutex; + panic!("{}", mutex.lock()) /* no semicolon */ + }; +} diff --git a/src/test/ui/macros/macro-comma-support-rpass.rs b/src/test/ui/macros/macro-comma-support-rpass.rs index f6c4f896d67c1..25b8c3cc62e16 100644 --- a/src/test/ui/macros/macro-comma-support-rpass.rs +++ b/src/test/ui/macros/macro-comma-support-rpass.rs @@ -192,6 +192,12 @@ fn line() { let _ = line!(); } +#[test] +fn matches() { + let _ = matches!(1, x if x > 0); + let _ = matches!(1, x if x > 0,); +} + #[test] fn module_path() { let _ = module_path!(); diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 2cb368c688188..ea13ae13208ad 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -246,6 +246,10 @@ pub struct Config { /// Only run tests that match these filters pub filters: Vec, + /// Skip tests tests matching these substrings. Corresponds to + /// `test::TestOpts::skip`. `filter_exact` does not apply to these flags. + pub skip: Vec, + /// Exactly match the filter, rather than a substring pub filter_exact: bool, diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 3d11ea21acf9f..e23cccf6cd129 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -91,6 +91,7 @@ pub fn parse_config(args: Vec) -> Config { ) .optopt("", "run", "whether to execute run-* tests", "auto | always | never") .optflag("", "ignored", "run tests marked as ignored") + .optmulti("", "skip", "skip tests matching SUBSTRING. Can be passed multiple times", "SUBSTRING") .optflag("", "exact", "filters match exactly") .optopt( "", @@ -236,6 +237,7 @@ pub fn parse_config(args: Vec) -> Config { debugger: None, run_ignored, filters: matches.free.clone(), + skip: matches.opt_strs("skip"), filter_exact: matches.opt_present("exact"), force_pass_mode: matches.opt_str("pass").map(|mode| { mode.parse::() @@ -312,6 +314,7 @@ pub fn log_config(config: &Config) { logv(c, format!("mode: {}", config.mode)); logv(c, format!("run_ignored: {}", config.run_ignored)); logv(c, format!("filters: {:?}", config.filters)); + logv(c, format!("skip: {:?}", config.skip)); logv(c, format!("filter_exact: {}", config.filter_exact)); logv( c, @@ -506,7 +509,7 @@ pub fn test_opts(config: &Config) -> test::TestOpts { shuffle: false, shuffle_seed: None, test_threads: None, - skip: vec![], + skip: config.skip.clone(), list: false, options: test::Options::new(), time_options: None, @@ -595,6 +598,7 @@ fn collect_tests_from_dir( debug!("found test file: {:?}", file_path.display()); let paths = TestPaths { file: file_path, relative_dir: relative_dir_path.to_path_buf() }; + tests.extend(make_test(config, &paths, inputs)) } else if file_path.is_dir() { let relative_file_path = relative_dir_path.join(file.file_name());