From 4bd962b63e319ce040fa525c712af746a301e65c Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 23 Dec 2024 07:08:00 +0000 Subject: [PATCH 01/21] Windows: remove readonly files --- library/std/src/fs/tests.rs | 2 +- library/std/src/sys/pal/windows/fs.rs | 24 ++++++++++++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 0308a5f433a99..559d422144d7c 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1384,7 +1384,7 @@ fn file_try_clone() { } #[test] -#[cfg(not(windows))] +#[cfg(not(target_vendor = "win7"))] fn unlink_readonly() { let tmpdir = tmpdir(); let path = tmpdir.join("file"); diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index 642be872dceb2..bc9c83a0b431e 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -296,6 +296,10 @@ impl OpenOptions { impl File { pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { let path = maybe_verbatim(path)?; + Self::open_native(&path, opts) + } + + fn open_native(path: &[u16], opts: &OpenOptions) -> io::Result { let creation = opts.get_creation_mode()?; let handle = unsafe { c::CreateFileW( @@ -1217,8 +1221,24 @@ pub fn readdir(p: &Path) -> io::Result { pub fn unlink(p: &Path) -> io::Result<()> { let p_u16s = maybe_verbatim(p)?; - cvt(unsafe { c::DeleteFileW(p_u16s.as_ptr()) })?; - Ok(()) + if unsafe { c::DeleteFileW(p_u16s.as_ptr()) } == 0 { + let err = api::get_last_error(); + // if `DeleteFileW` fails with ERROR_ACCESS_DENIED then try to remove + // the file while ignoring the readonly attribute. + // This is accomplished by calling the `posix_delete` function on an open file handle. + if err == WinError::ACCESS_DENIED { + let mut opts = OpenOptions::new(); + opts.access_mode(c::DELETE); + opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT); + if File::open_native(&p_u16s, &opts).map(|f| f.posix_delete()).is_ok() { + return Ok(()); + } + } + // return the original error if any of the above fails. + Err(io::Error::from_raw_os_error(err.code as i32)) + } else { + Ok(()) + } } pub fn rename(old: &Path, new: &Path) -> io::Result<()> { From 6ffc9caea95ed31a7e72bff239dde1efaa9d2515 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Thu, 26 Dec 2024 10:42:06 +0000 Subject: [PATCH 02/21] Update platform information for remove_file --- library/std/src/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 9b752ed14437c..6d034d2729a5d 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -2284,8 +2284,8 @@ impl AsInner for DirEntry { /// /// # Platform-specific behavior /// -/// This function currently corresponds to the `unlink` function on Unix -/// and the `DeleteFile` function on Windows. +/// This function currently corresponds to the `unlink` function on Unix. +/// On Windows, `DeleteFile` is used or `CreateFileW` and `SetInformationByHandle` for readonly files. /// Note that, this [may change in the future][changes]. /// /// [changes]: io#platform-specific-behavior From 0d90d47fb3b5761bd46fcd35d8dba7fd661e3ca2 Mon Sep 17 00:00:00 2001 From: Chris Krycho Date: Tue, 21 Jan 2025 13:51:21 -0700 Subject: [PATCH 03/21] TRPL: more backward-compatible Edition changes - Improve the discussion of `unsafe` blocks within `unsafe` functions. - Fix formatting in Appendix A --- src/doc/book | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book b/src/doc/book index 8a0eee28f7693..8c95f8cc4383c 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 8a0eee28f769387e543882352b12d956aa1b7c38 +Subproject commit 8c95f8cc4383c819cb552e651e932612fd4027b2 From 9cfc4205d334e9e80bbd042f04a7c849a4262b2a Mon Sep 17 00:00:00 2001 From: Chris Krycho Date: Tue, 21 Jan 2025 16:00:20 -0700 Subject: [PATCH 04/21] TRPL: integrate edits to Chapter 17 --- src/doc/book | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book b/src/doc/book index 8c95f8cc4383c..82a4a49789bc9 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 8c95f8cc4383c819cb552e651e932612fd4027b2 +Subproject commit 82a4a49789bc96db1a1b2a210b4c5ed7c9ef0c0d From 4d1c16c09c75b6e44a295fc40ad11bb6ec95dec7 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 6 Dec 2024 08:52:05 +0000 Subject: [PATCH 05/21] Make the wasm_c_abi future compat warning a hard error This is the next step in getting rid of the broken C abi for wasm32-unknown-unknown. --- compiler/rustc_lint/messages.ftl | 3 -- compiler/rustc_lint/src/early/diagnostics.rs | 1 - compiler/rustc_lint/src/lints.rs | 4 -- compiler/rustc_lint_defs/src/builtin.rs | 39 -------------------- compiler/rustc_lint_defs/src/lib.rs | 1 - compiler/rustc_metadata/messages.ftl | 3 ++ compiler/rustc_metadata/src/creader.rs | 7 +--- compiler/rustc_metadata/src/errors.rs | 7 ++++ 8 files changed, 11 insertions(+), 54 deletions(-) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 14f0787de3eda..551e7176f77ef 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -974,6 +974,3 @@ lint_use_let_underscore_ignore_suggestion = use `let _ = ...` to ignore the expr lint_variant_size_differences = enum variant is more than three times larger ({$largest} bytes) than the next largest - -lint_wasm_c_abi = - older versions of the `wasm-bindgen` crate will be incompatible with future versions of Rust; please update to `wasm-bindgen` v0.2.88 diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 6d73715562b2e..92dbc76a7b5ec 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -430,7 +430,6 @@ pub(super) fn decorate_lint( BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => { lints::UnusedCrateDependency { extern_crate, local_crate }.decorate_lint(diag) } - BuiltinLintDiag::WasmCAbi => lints::WasmCAbi.decorate_lint(diag), BuiltinLintDiag::IllFormedAttributeInput { suggestions } => { lints::IllFormedAttributeInput { num_suggestions: suggestions.len(), diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index fea3d67ffeb72..47f42d7dc6213 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2561,10 +2561,6 @@ pub(crate) struct UnusedCrateDependency { pub local_crate: Symbol, } -#[derive(LintDiagnostic)] -#[diag(lint_wasm_c_abi)] -pub(crate) struct WasmCAbi; - #[derive(LintDiagnostic)] #[diag(lint_ill_formed_attribute_input)] pub(crate) struct IllFormedAttributeInput { diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 9fc527a6a3ab3..aba28c9b7ef06 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -143,7 +143,6 @@ declare_lint_pass! { UNUSED_VARIABLES, USELESS_DEPRECATED, WARNINGS, - WASM_C_ABI, // tidy-alphabetical-end ] } @@ -4647,44 +4646,6 @@ declare_lint! { }; } -declare_lint! { - /// The `wasm_c_abi` lint detects crate dependencies that are incompatible - /// with future versions of Rust that will emit spec-compliant C ABI. - /// - /// ### Example - /// - /// ```rust,ignore (needs extern crate) - /// #![deny(wasm_c_abi)] - /// ``` - /// - /// This will produce: - /// - /// ```text - /// error: the following packages contain code that will be rejected by a future version of Rust: wasm-bindgen v0.2.87 - /// | - /// note: the lint level is defined here - /// --> src/lib.rs:1:9 - /// | - /// 1 | #![deny(wasm_c_abi)] - /// | ^^^^^^^^^^ - /// ``` - /// - /// ### Explanation - /// - /// Rust has historically emitted non-spec-compliant C ABI. This has caused - /// incompatibilities between other compilers and Wasm targets. In a future - /// version of Rust this will be fixed and therefore dependencies relying - /// on the non-spec-compliant C ABI will stop functioning. - pub WASM_C_ABI, - Deny, - "detects dependencies that are incompatible with the Wasm C ABI", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, - reference: "issue #71871 ", - }; - crate_level_only -} - declare_lint! { /// The `uncovered_param_in_projection` lint detects a violation of one of Rust's orphan rules for /// foreign trait implementations that concerns the use of type parameters inside trait associated diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 7786d3eb59af8..2956fc212533d 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -783,7 +783,6 @@ pub enum BuiltinLintDiag { extern_crate: Symbol, local_crate: Symbol, }, - WasmCAbi, IllFormedAttributeInput { suggestions: Vec, }, diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl index 6d7d88fa8d7af..d2b5ae5318592 100644 --- a/compiler/rustc_metadata/messages.ftl +++ b/compiler/rustc_metadata/messages.ftl @@ -290,6 +290,9 @@ metadata_unsupported_abi = metadata_unsupported_abi_i686 = ABI not supported by `#[link(kind = "raw-dylib")]` on i686 +metadata_wasm_c_abi = + older versions of the `wasm-bindgen` crate are incompatible with current versions of Rust; please update to `wasm-bindgen` v0.2.88 + metadata_wasm_import_form = wasm import module must be of the form `wasm_import_module = "string"` diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index a6db12f893255..a6cd0ecafd0de 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -1076,12 +1076,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { // Make a point span rather than covering the whole file let span = krate.spans.inner_span.shrink_to_lo(); - self.sess.psess.buffer_lint( - lint::builtin::WASM_C_ABI, - span, - ast::CRATE_NODE_ID, - BuiltinLintDiag::WasmCAbi, - ); + self.sess.dcx().emit_err(errors::WasmCAbi { span }); } } diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index b6c5619ec18ae..cefc6498f68fe 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -732,3 +732,10 @@ pub struct ImportNameTypeRaw { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(metadata_wasm_c_abi)] +pub(crate) struct WasmCAbi { + #[primary_span] + pub span: Span, +} From 49c3aaabaaf383da35d5544817feb54d1800832c Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 9 Jan 2025 09:59:04 +0000 Subject: [PATCH 06/21] Add test Co-Authored-By: Alex Crichton --- tests/ui/wasm/wasm-bindgen-broken-error.rs | 28 +++++++++++++++++++ .../wasm-bindgen-broken-error.v0_1_0.stderr | 8 ++++++ .../wasm-bindgen-broken-error.v0_2_87.stderr | 8 ++++++ 3 files changed, 44 insertions(+) create mode 100644 tests/ui/wasm/wasm-bindgen-broken-error.rs create mode 100644 tests/ui/wasm/wasm-bindgen-broken-error.v0_1_0.stderr create mode 100644 tests/ui/wasm/wasm-bindgen-broken-error.v0_2_87.stderr diff --git a/tests/ui/wasm/wasm-bindgen-broken-error.rs b/tests/ui/wasm/wasm-bindgen-broken-error.rs new file mode 100644 index 0000000000000..d985e87980314 --- /dev/null +++ b/tests/ui/wasm/wasm-bindgen-broken-error.rs @@ -0,0 +1,28 @@ +//@ only-wasm32 +//@ revisions: v0_1_0 v0_2_87 v0_2_88 v0_3_0 v1_0_0 +//@[v0_1_0] check-fail +//@[v0_1_0] rustc-env:CARGO_PKG_VERSION_MAJOR=0 +//@[v0_1_0] rustc-env:CARGO_PKG_VERSION_MINOR=1 +//@[v0_1_0] rustc-env:CARGO_PKG_VERSION_PATCH=0 +//@[v0_2_87] check-fail +//@[v0_2_87] rustc-env:CARGO_PKG_VERSION_MAJOR=0 +//@[v0_2_87] rustc-env:CARGO_PKG_VERSION_MINOR=2 +//@[v0_2_87] rustc-env:CARGO_PKG_VERSION_PATCH=87 +//@[v0_2_88] check-pass +//@[v0_2_88] rustc-env:CARGO_PKG_VERSION_MAJOR=0 +//@[v0_2_88] rustc-env:CARGO_PKG_VERSION_MINOR=2 +//@[v0_2_88] rustc-env:CARGO_PKG_VERSION_PATCH=88 +//@[v0_3_0] check-pass +//@[v0_3_0] rustc-env:CARGO_PKG_VERSION_MAJOR=0 +//@[v0_3_0] rustc-env:CARGO_PKG_VERSION_MINOR=3 +//@[v0_3_0] rustc-env:CARGO_PKG_VERSION_PATCH=0 +//@[v1_0_0] check-pass +//@[v1_0_0] rustc-env:CARGO_PKG_VERSION_MAJOR=1 +//@[v1_0_0] rustc-env:CARGO_PKG_VERSION_MINOR=0 +//@[v1_0_0] rustc-env:CARGO_PKG_VERSION_PATCH=0 + +#![crate_name = "wasm_bindgen"] +//[v0_1_0]~^ ERROR: older versions of the `wasm-bindgen` crate +//[v0_2_87]~^^ ERROR: older versions of the `wasm-bindgen` crate + +fn main() {} diff --git a/tests/ui/wasm/wasm-bindgen-broken-error.v0_1_0.stderr b/tests/ui/wasm/wasm-bindgen-broken-error.v0_1_0.stderr new file mode 100644 index 0000000000000..e1c1ec7ef3392 --- /dev/null +++ b/tests/ui/wasm/wasm-bindgen-broken-error.v0_1_0.stderr @@ -0,0 +1,8 @@ +error: older versions of the `wasm-bindgen` crate are incompatible with current versions of Rust; please update to `wasm-bindgen` v0.2.88 + --> $DIR/wasm-bindgen-broken-error.rs:24:1 + | +LL | #![crate_name = "wasm_bindgen"] + | ^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/wasm/wasm-bindgen-broken-error.v0_2_87.stderr b/tests/ui/wasm/wasm-bindgen-broken-error.v0_2_87.stderr new file mode 100644 index 0000000000000..e1c1ec7ef3392 --- /dev/null +++ b/tests/ui/wasm/wasm-bindgen-broken-error.v0_2_87.stderr @@ -0,0 +1,8 @@ +error: older versions of the `wasm-bindgen` crate are incompatible with current versions of Rust; please update to `wasm-bindgen` v0.2.88 + --> $DIR/wasm-bindgen-broken-error.rs:24:1 + | +LL | #![crate_name = "wasm_bindgen"] + | ^ + +error: aborting due to 1 previous error + From 1f6517b5908433a91057a2a6ba8291e11328ab33 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Fri, 17 Jan 2025 16:55:10 +0100 Subject: [PATCH 07/21] Move `std::io::pipe` code into its own file --- library/std/src/io/mod.rs | 252 +----------------------------- library/std/src/io/pipe.rs | 253 +++++++++++++++++++++++++++++++ library/std/src/io/pipe/tests.rs | 18 +++ library/std/src/io/tests.rs | 17 --- 4 files changed, 274 insertions(+), 266 deletions(-) create mode 100644 library/std/src/io/pipe.rs create mode 100644 library/std/src/io/pipe/tests.rs diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 231c8712ebd55..cfd03b8e3d6d0 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -310,6 +310,8 @@ pub use self::error::RawOsError; pub use self::error::SimpleMessage; #[unstable(feature = "io_const_error", issue = "133448")] pub use self::error::const_error; +#[unstable(feature = "anonymous_pipe", issue = "127154")] +pub use self::pipe::{PipeReader, PipeWriter, pipe}; #[stable(feature = "is_terminal", since = "1.70.0")] pub use self::stdio::IsTerminal; pub(crate) use self::stdio::attempt_print_to_stderr; @@ -330,7 +332,6 @@ pub use self::{ }; use crate::mem::take; use crate::ops::{Deref, DerefMut}; -use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner}; use crate::{cmp, fmt, slice, str, sys}; mod buffered; @@ -338,6 +339,7 @@ pub(crate) mod copy; mod cursor; mod error; mod impls; +mod pipe; pub mod prelude; mod stdio; mod util; @@ -3251,251 +3253,3 @@ impl Iterator for Lines { } } } - -/// Create anonymous pipe that is close-on-exec and blocking. -/// -/// # Behavior -/// -/// A pipe is a synchronous, unidirectional data channel between two or more processes, like an -/// interprocess [`mpsc`](crate::sync::mpsc) provided by the OS. In particular: -/// -/// * A read on a [`PipeReader`] blocks until the pipe is non-empty. -/// * A write on a [`PipeWriter`] blocks when the pipe is full. -/// * When all copies of a [`PipeWriter`] are closed, a read on the corresponding [`PipeReader`] -/// returns EOF. -/// * [`PipeReader`] can be shared, but only one process will consume the data in the pipe. -/// -/// # Capacity -/// -/// Pipe capacity is platform dependent. To quote the Linux [man page]: -/// -/// > Different implementations have different limits for the pipe capacity. Applications should -/// > not rely on a particular capacity: an application should be designed so that a reading process -/// > consumes data as soon as it is available, so that a writing process does not remain blocked. -/// -/// # Examples -/// -/// ```no_run -/// #![feature(anonymous_pipe)] -/// # #[cfg(miri)] fn main() {} -/// # #[cfg(not(miri))] -/// # fn main() -> std::io::Result<()> { -/// # use std::process::Command; -/// # use std::io::{Read, Write}; -/// let (ping_rx, mut ping_tx) = std::io::pipe()?; -/// let (mut pong_rx, pong_tx) = std::io::pipe()?; -/// -/// // Spawn a process that echoes its input. -/// let mut echo_server = Command::new("cat").stdin(ping_rx).stdout(pong_tx).spawn()?; -/// -/// ping_tx.write_all(b"hello")?; -/// // Close to unblock echo_server's reader. -/// drop(ping_tx); -/// -/// let mut buf = String::new(); -/// // Block until echo_server's writer is closed. -/// pong_rx.read_to_string(&mut buf)?; -/// assert_eq!(&buf, "hello"); -/// -/// echo_server.wait()?; -/// # Ok(()) -/// # } -/// ``` -/// [pipe]: https://man7.org/linux/man-pages/man2/pipe.2.html -/// [CreatePipe]: https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-createpipe -/// [man page]: https://man7.org/linux/man-pages/man7/pipe.7.html -#[unstable(feature = "anonymous_pipe", issue = "127154")] -#[inline] -pub fn pipe() -> Result<(PipeReader, PipeWriter)> { - pipe_inner().map(|(reader, writer)| (PipeReader(reader), PipeWriter(writer))) -} - -/// Read end of the anonymous pipe. -#[unstable(feature = "anonymous_pipe", issue = "127154")] -#[derive(Debug)] -pub struct PipeReader(pub(crate) AnonPipe); - -/// Write end of the anonymous pipe. -#[unstable(feature = "anonymous_pipe", issue = "127154")] -#[derive(Debug)] -pub struct PipeWriter(pub(crate) AnonPipe); - -impl PipeReader { - /// Create a new [`PipeReader`] instance that shares the same underlying file description. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(anonymous_pipe)] - /// # #[cfg(miri)] fn main() {} - /// # #[cfg(not(miri))] - /// # fn main() -> std::io::Result<()> { - /// # use std::fs; - /// # use std::io::Write; - /// # use std::process::Command; - /// const NUM_SLOT: u8 = 2; - /// const NUM_PROC: u8 = 5; - /// const OUTPUT: &str = "work.txt"; - /// - /// let mut jobs = vec![]; - /// let (reader, mut writer) = std::io::pipe()?; - /// - /// // Write NUM_SLOT characters the pipe. - /// writer.write_all(&[b'|'; NUM_SLOT as usize])?; - /// - /// // Spawn several processes that read a character from the pipe, do some work, then - /// // write back to the pipe. When the pipe is empty, the processes block, so only - /// // NUM_SLOT processes can be working at any given time. - /// for _ in 0..NUM_PROC { - /// jobs.push( - /// Command::new("bash") - /// .args(["-c", - /// &format!( - /// "read -n 1\n\ - /// echo -n 'x' >> '{OUTPUT}'\n\ - /// echo -n '|'", - /// ), - /// ]) - /// .stdin(reader.try_clone()?) - /// .stdout(writer.try_clone()?) - /// .spawn()?, - /// ); - /// } - /// - /// // Wait for all jobs to finish. - /// for mut job in jobs { - /// job.wait()?; - /// } - /// - /// // Check our work and clean up. - /// let xs = fs::read_to_string(OUTPUT)?; - /// fs::remove_file(OUTPUT)?; - /// assert_eq!(xs, "x".repeat(NUM_PROC.into())); - /// # Ok(()) - /// # } - /// ``` - #[unstable(feature = "anonymous_pipe", issue = "127154")] - pub fn try_clone(&self) -> Result { - self.0.try_clone().map(Self) - } -} - -impl PipeWriter { - /// Create a new [`PipeWriter`] instance that shares the same underlying file description. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(anonymous_pipe)] - /// # #[cfg(miri)] fn main() {} - /// # #[cfg(not(miri))] - /// # fn main() -> std::io::Result<()> { - /// # use std::process::Command; - /// # use std::io::Read; - /// let (mut reader, writer) = std::io::pipe()?; - /// - /// // Spawn a process that writes to stdout and stderr. - /// let mut peer = Command::new("bash") - /// .args([ - /// "-c", - /// "echo -n foo\n\ - /// echo -n bar >&2" - /// ]) - /// .stdout(writer.try_clone()?) - /// .stderr(writer) - /// .spawn()?; - /// - /// // Read and check the result. - /// let mut msg = String::new(); - /// reader.read_to_string(&mut msg)?; - /// assert_eq!(&msg, "foobar"); - /// - /// peer.wait()?; - /// # Ok(()) - /// # } - /// ``` - #[unstable(feature = "anonymous_pipe", issue = "127154")] - pub fn try_clone(&self) -> Result { - self.0.try_clone().map(Self) - } -} - -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl Read for &PipeReader { - fn read(&mut self, buf: &mut [u8]) -> Result { - self.0.read(buf) - } - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result { - self.0.read_vectored(bufs) - } - #[inline] - fn is_read_vectored(&self) -> bool { - self.0.is_read_vectored() - } - fn read_to_end(&mut self, buf: &mut Vec) -> Result { - self.0.read_to_end(buf) - } - fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> Result<()> { - self.0.read_buf(buf) - } -} - -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl Read for PipeReader { - fn read(&mut self, buf: &mut [u8]) -> Result { - self.0.read(buf) - } - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result { - self.0.read_vectored(bufs) - } - #[inline] - fn is_read_vectored(&self) -> bool { - self.0.is_read_vectored() - } - fn read_to_end(&mut self, buf: &mut Vec) -> Result { - self.0.read_to_end(buf) - } - fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> Result<()> { - self.0.read_buf(buf) - } -} - -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl Write for &PipeWriter { - fn write(&mut self, buf: &[u8]) -> Result { - self.0.write(buf) - } - #[inline] - fn flush(&mut self) -> Result<()> { - Ok(()) - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result { - self.0.write_vectored(bufs) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - self.0.is_write_vectored() - } -} - -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl Write for PipeWriter { - fn write(&mut self, buf: &[u8]) -> Result { - self.0.write(buf) - } - #[inline] - fn flush(&mut self) -> Result<()> { - Ok(()) - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result { - self.0.write_vectored(bufs) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - self.0.is_write_vectored() - } -} diff --git a/library/std/src/io/pipe.rs b/library/std/src/io/pipe.rs new file mode 100644 index 0000000000000..c6c34fbb15c58 --- /dev/null +++ b/library/std/src/io/pipe.rs @@ -0,0 +1,253 @@ +use crate::io; +use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner}; + +/// Create anonymous pipe that is close-on-exec and blocking. +/// +/// This function provides support for anonymous OS pipes, like [pipe] on Linux or [CreatePipe] on +/// Windows. +/// +/// # Behavior +/// +/// A pipe is a synchronous, unidirectional data channel between two or more processes, like an +/// interprocess [`mpsc`](crate::sync::mpsc) provided by the OS. In particular: +/// +/// * A read on a [`PipeReader`] blocks until the pipe is non-empty. +/// * A write on a [`PipeWriter`] blocks when the pipe is full. +/// * When all copies of a [`PipeWriter`] are closed, a read on the corresponding [`PipeReader`] +/// returns EOF. +/// * [`PipeReader`] can be shared, but only one process will consume the data in the pipe. +/// +/// # Capacity +/// +/// Pipe capacity is platform dependent. To quote the Linux [man page]: +/// +/// > Different implementations have different limits for the pipe capacity. Applications should +/// > not rely on a particular capacity: an application should be designed so that a reading process +/// > consumes data as soon as it is available, so that a writing process does not remain blocked. +/// +/// # Examples +/// +/// ```no_run +/// #![feature(anonymous_pipe)] +/// # #[cfg(miri)] fn main() {} +/// # #[cfg(not(miri))] +/// # fn main() -> std::io::Result<()> { +/// # use std::process::Command; +/// # use std::io::{Read, Write}; +/// let (ping_rx, mut ping_tx) = std::pipe::pipe()?; +/// let (mut pong_rx, pong_tx) = std::pipe::pipe()?; +/// +/// // Spawn a process that echoes its input. +/// let mut echo_server = Command::new("cat").stdin(ping_rx).stdout(pong_tx).spawn()?; +/// +/// ping_tx.write_all(b"hello")?; +/// // Close to unblock echo_server's reader. +/// drop(ping_tx); +/// +/// let mut buf = String::new(); +/// // Block until echo_server's writer is closed. +/// pong_rx.read_to_string(&mut buf)?; +/// assert_eq!(&buf, "hello"); +/// +/// echo_server.wait()?; +/// # Ok(()) +/// # } +/// ``` +/// [pipe]: https://man7.org/linux/man-pages/man2/pipe.2.html +/// [CreatePipe]: https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-createpipe +/// [man page]: https://man7.org/linux/man-pages/man7/pipe.7.html +#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[inline] +pub fn pipe() -> io::Result<(PipeReader, PipeWriter)> { + pipe_inner().map(|(reader, writer)| (PipeReader(reader), PipeWriter(writer))) +} + +/// Read end of the anonymous pipe. +#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[derive(Debug)] +pub struct PipeReader(pub(crate) AnonPipe); + +/// Write end of the anonymous pipe. +#[unstable(feature = "anonymous_pipe", issue = "127154")] +#[derive(Debug)] +pub struct PipeWriter(pub(crate) AnonPipe); + +impl PipeReader { + /// Create a new [`PipeReader`] instance that shares the same underlying file description. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(anonymous_pipe)] + /// # #[cfg(miri)] fn main() {} + /// # #[cfg(not(miri))] + /// # fn main() -> std::io::Result<()> { + /// # use std::fs; + /// # use std::io::Write; + /// # use std::process::Command; + /// const NUM_SLOT: u8 = 2; + /// const NUM_PROC: u8 = 5; + /// const OUTPUT: &str = "work.txt"; + /// + /// let mut jobs = vec![]; + /// let (reader, mut writer) = std::pipe::pipe()?; + /// + /// // Write NUM_SLOT characters the pipe. + /// writer.write_all(&[b'|'; NUM_SLOT as usize])?; + /// + /// // Spawn several processes that read a character from the pipe, do some work, then + /// // write back to the pipe. When the pipe is empty, the processes block, so only + /// // NUM_SLOT processes can be working at any given time. + /// for _ in 0..NUM_PROC { + /// jobs.push( + /// Command::new("bash") + /// .args(["-c", + /// &format!( + /// "read -n 1\n\ + /// echo -n 'x' >> '{OUTPUT}'\n\ + /// echo -n '|'", + /// ), + /// ]) + /// .stdin(reader.try_clone()?) + /// .stdout(writer.try_clone()?) + /// .spawn()?, + /// ); + /// } + /// + /// // Wait for all jobs to finish. + /// for mut job in jobs { + /// job.wait()?; + /// } + /// + /// // Check our work and clean up. + /// let xs = fs::read_to_string(OUTPUT)?; + /// fs::remove_file(OUTPUT)?; + /// assert_eq!(xs, "x".repeat(NUM_PROC.into())); + /// # Ok(()) + /// # } + /// ``` + #[unstable(feature = "anonymous_pipe", issue = "127154")] + pub fn try_clone(&self) -> io::Result { + self.0.try_clone().map(Self) + } +} + +impl PipeWriter { + /// Create a new [`PipeWriter`] instance that shares the same underlying file description. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(anonymous_pipe)] + /// # #[cfg(miri)] fn main() {} + /// # #[cfg(not(miri))] + /// # fn main() -> std::io::Result<()> { + /// # use std::process::Command; + /// # use std::io::Read; + /// let (mut reader, writer) = std::pipe::pipe()?; + /// + /// // Spawn a process that writes to stdout and stderr. + /// let mut peer = Command::new("bash") + /// .args([ + /// "-c", + /// "echo -n foo\n\ + /// echo -n bar >&2" + /// ]) + /// .stdout(writer.try_clone()?) + /// .stderr(writer) + /// .spawn()?; + /// + /// // Read and check the result. + /// let mut msg = String::new(); + /// reader.read_to_string(&mut msg)?; + /// assert_eq!(&msg, "foobar"); + /// + /// peer.wait()?; + /// # Ok(()) + /// # } + /// ``` + #[unstable(feature = "anonymous_pipe", issue = "127154")] + pub fn try_clone(&self) -> io::Result { + self.0.try_clone().map(Self) + } +} + +#[unstable(feature = "anonymous_pipe", issue = "127154")] +impl io::Read for &PipeReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result { + self.0.read_vectored(bufs) + } + #[inline] + fn is_read_vectored(&self) -> bool { + self.0.is_read_vectored() + } + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { + self.0.read_to_end(buf) + } + fn read_buf(&mut self, buf: io::BorrowedCursor<'_>) -> io::Result<()> { + self.0.read_buf(buf) + } +} + +#[unstable(feature = "anonymous_pipe", issue = "127154")] +impl io::Read for PipeReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result { + self.0.read_vectored(bufs) + } + #[inline] + fn is_read_vectored(&self) -> bool { + self.0.is_read_vectored() + } + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { + self.0.read_to_end(buf) + } + fn read_buf(&mut self, buf: io::BorrowedCursor<'_>) -> io::Result<()> { + self.0.read_buf(buf) + } +} + +#[unstable(feature = "anonymous_pipe", issue = "127154")] +impl io::Write for &PipeWriter { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } + + fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result { + self.0.write_vectored(bufs) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } +} + +#[unstable(feature = "anonymous_pipe", issue = "127154")] +impl io::Write for PipeWriter { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } + + fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result { + self.0.write_vectored(bufs) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } +} diff --git a/library/std/src/io/pipe/tests.rs b/library/std/src/io/pipe/tests.rs new file mode 100644 index 0000000000000..c1f3f192ca2d7 --- /dev/null +++ b/library/std/src/io/pipe/tests.rs @@ -0,0 +1,18 @@ +use crate::io::{Read, Write, pipe}; + +#[test] +#[cfg(all(windows, unix, not(miri)))] +fn pipe_creation_clone_and_rw() { + let (rx, tx) = pipe().unwrap(); + + tx.try_clone().unwrap().write_all(b"12345").unwrap(); + drop(tx); + + let mut rx2 = rx.try_clone().unwrap(); + drop(rx); + + let mut s = String::new(); + rx2.read_to_string(&mut s).unwrap(); + drop(rx2); + assert_eq!(s, "12345"); +} diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs index 85098b3bb181f..47cbb9614afdd 100644 --- a/library/std/src/io/tests.rs +++ b/library/std/src/io/tests.rs @@ -823,20 +823,3 @@ fn try_oom_error() { let io_err = io::Error::from(reserve_err); assert_eq!(io::ErrorKind::OutOfMemory, io_err.kind()); } - -#[test] -#[cfg(all(windows, unix, not(miri)))] -fn pipe_creation_clone_and_rw() { - let (rx, tx) = std::io::pipe().unwrap(); - - tx.try_clone().unwrap().write_all(b"12345").unwrap(); - drop(tx); - - let mut rx2 = rx.try_clone().unwrap(); - drop(rx); - - let mut s = String::new(); - rx2.read_to_string(&mut s).unwrap(); - drop(rx2); - assert_eq!(s, "12345"); -} From f770f390551158b083822955f428cf27581fa450 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Fri, 17 Jan 2025 17:11:08 +0100 Subject: [PATCH 08/21] Update `std::io::{pipe, PipeReader, PipeWriter}` docs the new location Also create a section "Platform-specific behavior", don't hide required imports for code examples. --- library/std/src/io/pipe.rs | 41 +++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/library/std/src/io/pipe.rs b/library/std/src/io/pipe.rs index c6c34fbb15c58..7066ae460664a 100644 --- a/library/std/src/io/pipe.rs +++ b/library/std/src/io/pipe.rs @@ -1,10 +1,7 @@ use crate::io; use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner}; -/// Create anonymous pipe that is close-on-exec and blocking. -/// -/// This function provides support for anonymous OS pipes, like [pipe] on Linux or [CreatePipe] on -/// Windows. +/// Create an anonymous pipe. /// /// # Behavior /// @@ -17,6 +14,13 @@ use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner}; /// returns EOF. /// * [`PipeReader`] can be shared, but only one process will consume the data in the pipe. /// +/// # Platform-specific behavior +/// +/// This function currently corresponds to the `pipe` function on Unix and the +/// `CreatePipe` function on Windows. +/// +/// Note that this [may change in the future][changes]. +/// /// # Capacity /// /// Pipe capacity is platform dependent. To quote the Linux [man page]: @@ -32,10 +36,10 @@ use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner}; /// # #[cfg(miri)] fn main() {} /// # #[cfg(not(miri))] /// # fn main() -> std::io::Result<()> { -/// # use std::process::Command; -/// # use std::io::{Read, Write}; -/// let (ping_rx, mut ping_tx) = std::pipe::pipe()?; -/// let (mut pong_rx, pong_tx) = std::pipe::pipe()?; +/// use std::process::Command; +/// use std::io::{pipe, Read, Write}; +/// let (ping_rx, mut ping_tx) = pipe()?; +/// let (mut pong_rx, pong_tx) = pipe()?; /// /// // Spawn a process that echoes its input. /// let mut echo_server = Command::new("cat").stdin(ping_rx).stdout(pong_tx).spawn()?; @@ -53,8 +57,7 @@ use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner}; /// # Ok(()) /// # } /// ``` -/// [pipe]: https://man7.org/linux/man-pages/man2/pipe.2.html -/// [CreatePipe]: https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-createpipe +/// [changes]: io#platform-specific-behavior /// [man page]: https://man7.org/linux/man-pages/man7/pipe.7.html #[unstable(feature = "anonymous_pipe", issue = "127154")] #[inline] @@ -82,15 +85,15 @@ impl PipeReader { /// # #[cfg(miri)] fn main() {} /// # #[cfg(not(miri))] /// # fn main() -> std::io::Result<()> { - /// # use std::fs; - /// # use std::io::Write; - /// # use std::process::Command; + /// use std::fs; + /// use std::io::{pipe, Write}; + /// use std::process::Command; /// const NUM_SLOT: u8 = 2; /// const NUM_PROC: u8 = 5; /// const OUTPUT: &str = "work.txt"; /// /// let mut jobs = vec![]; - /// let (reader, mut writer) = std::pipe::pipe()?; + /// let (reader, mut writer) = pipe()?; /// /// // Write NUM_SLOT characters the pipe. /// writer.write_all(&[b'|'; NUM_SLOT as usize])?; @@ -142,9 +145,9 @@ impl PipeWriter { /// # #[cfg(miri)] fn main() {} /// # #[cfg(not(miri))] /// # fn main() -> std::io::Result<()> { - /// # use std::process::Command; - /// # use std::io::Read; - /// let (mut reader, writer) = std::pipe::pipe()?; + /// use std::process::Command; + /// use std::io::{pipe, Read}; + /// let (mut reader, writer) = pipe()?; /// /// // Spawn a process that writes to stdout and stderr. /// let mut peer = Command::new("bash") @@ -221,11 +224,9 @@ impl io::Write for &PipeWriter { fn flush(&mut self) -> io::Result<()> { Ok(()) } - fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result { self.0.write_vectored(bufs) } - #[inline] fn is_write_vectored(&self) -> bool { self.0.is_write_vectored() @@ -241,11 +242,9 @@ impl io::Write for PipeWriter { fn flush(&mut self) -> io::Result<()> { Ok(()) } - fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result { self.0.write_vectored(bufs) } - #[inline] fn is_write_vectored(&self) -> bool { self.0.is_write_vectored() From 84c80151cf496d0c6e6823493fd4a07d242ce311 Mon Sep 17 00:00:00 2001 From: Florian Bartels Date: Thu, 28 Nov 2024 14:06:34 +0100 Subject: [PATCH 09/21] Add new target for supporting Neutrino QNX 6.1 with `io-socket` network stack on aarch64 Signed-off-by: Florian Bartels --- compiler/rustc_target/src/spec/mod.rs | 1 + .../aarch64_unknown_nto_qnx710_iosock.rs | 27 +++++++++++++++++++ library/std/Cargo.toml | 3 ++- .../src/sys/pal/unix/process/process_unix.rs | 7 ++--- src/bootstrap/src/core/sanity.rs | 1 + src/doc/rustc/src/platform-support.md | 4 ++- src/doc/rustc/src/platform-support/nto-qnx.md | 15 ++++++++--- tests/assembly/targets/targets-elf.rs | 3 +++ tests/ui/check-cfg/well-known-values.stderr | 2 +- 9 files changed, 54 insertions(+), 9 deletions(-) create mode 100644 compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710_iosock.rs diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 37564ab38fca4..df6d117f37600 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1963,6 +1963,7 @@ supported_targets! { ("aarch64-unknown-nto-qnx700", aarch64_unknown_nto_qnx700), ("aarch64-unknown-nto-qnx710", aarch64_unknown_nto_qnx710), + ("aarch64-unknown-nto-qnx710_iosock", aarch64_unknown_nto_qnx710_iosock), ("x86_64-pc-nto-qnx710", x86_64_pc_nto_qnx710), ("i586-pc-nto-qnx700", i586_pc_nto_qnx700), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710_iosock.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710_iosock.rs new file mode 100644 index 0000000000000..c9ffc0e072c30 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710_iosock.rs @@ -0,0 +1,27 @@ +use crate::spec::{Cc, LinkerFlavor, Lld, Target, TargetOptions}; + +pub(crate) fn target() -> Target { + let mut target = super::aarch64_unknown_nto_qnx710::target(); + target.options.env = "nto71_iosock".into(); + target.options.pre_link_args = + TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &[ + "-Vgcc_ntoaarch64le_cxx", + get_iosock_param(), + ]); + target +} + +// When using `io-sock` on QNX, we must add a search path for the linker so +// that it prefers the io-sock version. +// The path depends on the host, i.e. we cannot hard-code it here, but have +// to determine it when the compiler runs. +// When using the QNX toolchain, the environment variable QNX_TARGET is always set. +// More information: +// https://www.qnx.com/developers/docs/7.1/index.html#com.qnx.doc.neutrino.io_sock/topic/migrate_app.html +fn get_iosock_param() -> &'static str { + let target_dir = + std::env::var("QNX_TARGET").unwrap_or_else(|_| "PLEASE_SET_ENV_VAR_QNX_TARGET".into()); + let linker_param = format!("-L{target_dir}/aarch64le/io-sock/lib"); + + linker_param.leak() +} diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index da58d7c13bd12..b91b89b7761bc 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -139,7 +139,8 @@ test = true level = "warn" check-cfg = [ 'cfg(bootstrap)', - 'cfg(target_arch, values("xtensa"))', + 'cfg(target_arch, values("xtensa", "aarch64-unknown-nto-qnx710_iosock"))', + 'cfg(target_env, values("nto71_iosock"))', # std use #[path] imports to portable-simd `std_float` crate # and to the `backtrace` crate which messes-up with Cargo list # of declared features, we therefor expect any feature cfg diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs index ec4965c1d7196..cc22b3ecbd0f6 100644 --- a/library/std/src/sys/pal/unix/process/process_unix.rs +++ b/library/std/src/sys/pal/unix/process/process_unix.rs @@ -20,7 +20,7 @@ use crate::{fmt, mem, sys}; cfg_if::cfg_if! { // This workaround is only needed for QNX 7.0 and 7.1. The bug should have been fixed in 8.0 - if #[cfg(any(target_env = "nto70", target_env = "nto71"))] { + if #[cfg(any(target_env = "nto70", target_env = "nto71", target_env = "nto71_iosock"))] { use crate::thread; use libc::{c_char, posix_spawn_file_actions_t, posix_spawnattr_t}; use crate::time::Duration; @@ -191,7 +191,8 @@ impl Command { target_os = "watchos", target_os = "tvos", target_env = "nto70", - target_env = "nto71" + target_env = "nto71", + target_env = "nto71_iosock", )))] unsafe fn do_fork(&mut self) -> Result { cvt(libc::fork()) @@ -202,7 +203,7 @@ impl Command { // Documentation says "... or try calling fork() again". This is what we do here. // See also https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/f/fork.html // This workaround is only needed for QNX 7.0 and 7.1. The bug should have been fixed in 8.0 - #[cfg(any(target_env = "nto70", target_env = "nto71"))] + #[cfg(any(target_env = "nto70", target_env = "nto71", target_env = "nto71_iosock"))] unsafe fn do_fork(&mut self) -> Result { use crate::sys::os::errno; diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index ed0155622c226..418ebbbfb42c8 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -34,6 +34,7 @@ pub struct Finder { // Targets can be removed from this list once they are present in the stage0 compiler (usually by updating the beta compiler of the bootstrap). const STAGE0_MISSING_TARGETS: &[&str] = &[ // just a dummy comment so the list doesn't get onelined + "aarch64-unknown-nto-qnx710_iosock", ]; /// Minimum version threshold for libstdc++ required when using prebuilt LLVM diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index a706926f7435c..d25eaa49dd5e7 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -254,12 +254,14 @@ target | std | host | notes [`aarch64-kmc-solid_asp3`](platform-support/kmc-solid.md) | ✓ | | ARM64 SOLID with TOPPERS/ASP3 [`aarch64-nintendo-switch-freestanding`](platform-support/aarch64-nintendo-switch-freestanding.md) | * | | ARM64 Nintendo Switch, Horizon [`aarch64-unknown-freebsd`](platform-support/freebsd.md) | ✓ | ✓ | ARM64 FreeBSD +`aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD [`aarch64-unknown-hermit`](platform-support/hermit.md) | ✓ | | ARM64 Hermit [`aarch64-unknown-illumos`](platform-support/illumos.md) | ✓ | ✓ | ARM64 illumos `aarch64-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (ILP32 ABI) [`aarch64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD -[`aarch64-unknown-nto-qnx700`](platform-support/nto-qnx.md) | ? | | ARM64 QNX Neutrino 7.0 RTOS | +[`aarch64-unknown-nto-qnx710_iosock`](platform-support/nto-qnx.md) | ✓ | | ARM64 QNX Neutrino 7.1 RTOS with new network stack (io-sock) | [`aarch64-unknown-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | ARM64 QNX Neutrino 7.1 RTOS | +[`aarch64-unknown-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | ARM64 QNX Neutrino 7.1 RTOS with default network stack (io-pkt) | [`aarch64-unknown-nuttx`](platform-support/nuttx.md) | * | | ARM64 with NuttX [`aarch64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | ARM64 OpenBSD [`aarch64-unknown-redox`](platform-support/redox.md) | ✓ | | ARM64 Redox OS diff --git a/src/doc/rustc/src/platform-support/nto-qnx.md b/src/doc/rustc/src/platform-support/nto-qnx.md index 96e3b58f47150..7d6d9ff3223ce 100644 --- a/src/doc/rustc/src/platform-support/nto-qnx.md +++ b/src/doc/rustc/src/platform-support/nto-qnx.md @@ -22,11 +22,15 @@ Currently, the following QNX Neutrino versions and compilation targets are suppo | QNX Neutrino Version | Target Architecture | Full support | `no_std` support | |----------------------|---------------------|:------------:|:----------------:| -| 7.1 | AArch64 | ✓ | ✓ | +| 7.1 with io-pkt | AArch64 | ✓ | ✓ | +| 7.1 with io-sock | AArch64 | ✓ | ✓ | | 7.1 | x86_64 | ✓ | ✓ | | 7.0 | AArch64 | ? | ✓ | | 7.0 | x86 | | ✓ | +On QNX 7.0 and 7.1, `io-pkt` is used as network stack by default. QNX 7.1 includes +the optional network stack `io-sock`. + Adding other architectures that are supported by QNX Neutrino is possible. In the table above, 'full support' indicates support for building Rust applications with the full standard library. @@ -107,7 +111,8 @@ There are no further known requirements. For conditional compilation, following QNX Neutrino specific attributes are defined: - `target_os` = `"nto"` -- `target_env` = `"nto71"` (for QNX Neutrino 7.1) +- `target_env` = `"nto71"` (for QNX Neutrino 7.1 with "classic" network stack "io_pkt") +- `target_env` = `"nto71_iosock"` (for QNX Neutrino 7.1 with network stack "io_sock") - `target_env` = `"nto70"` (for QNX Neutrino 7.0) ## Building the target @@ -134,6 +139,10 @@ export build_env=' CFLAGS_aarch64-unknown-nto-qnx710=-Vgcc_ntoaarch64le_cxx CXX_aarch64-unknown-nto-qnx710=qcc AR_aarch64_unknown_nto_qnx710=ntoaarch64-ar + CC_aarch64-unknown-nto-qnx710_iosock=qcc + CFLAGS_aarch64-unknown-nto-qnx710_iosock=-Vgcc_ntoaarch64le_cxx + CXX_aarch64-unknown-nto-qnx710_iosock=qcc + AR_aarch64_unknown_nto_qnx710_iosock=ntoaarch64-ar CC_x86_64-pc-nto-qnx710=qcc CFLAGS_x86_64-pc-nto-qnx710=-Vgcc_ntox86_64_cxx CXX_x86_64-pc-nto-qnx710=qcc @@ -141,7 +150,7 @@ export build_env=' env $build_env \ ./x.py build \ - --target aarch64-unknown-nto-qnx710,x86_64-pc-nto-qnx710,x86_64-unknown-linux-gnu \ + --target aarch64-unknown-nto-qnx710_iosock,aarch64-unknown-nto-qnx710,x86_64-pc-nto-qnx710,x86_64-unknown-linux-gnu \ rustc library/core library/alloc library/std ``` diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs index 6bb3389c40959..b9d6aaf7929bb 100644 --- a/tests/assembly/targets/targets-elf.rs +++ b/tests/assembly/targets/targets-elf.rs @@ -57,6 +57,9 @@ //@ revisions: aarch64_unknown_nto_qnx710 //@ [aarch64_unknown_nto_qnx710] compile-flags: --target aarch64-unknown-nto-qnx710 //@ [aarch64_unknown_nto_qnx710] needs-llvm-components: aarch64 +//@ revisions: aarch64_unknown_nto_qnx710_iosock +//@ [aarch64_unknown_nto_qnx710_iosock] compile-flags: --target aarch64-unknown-nto-qnx710_iosock +//@ [aarch64_unknown_nto_qnx710_iosock] needs-llvm-components: aarch64 //@ revisions: aarch64_unknown_openbsd //@ [aarch64_unknown_openbsd] compile-flags: --target aarch64-unknown-openbsd //@ [aarch64_unknown_openbsd] needs-llvm-components: aarch64 diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index 5c1898a0ae365..29bc30815b877 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -156,7 +156,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_env = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_env` are: ``, `gnu`, `msvc`, `musl`, `newlib`, `nto70`, `nto71`, `ohos`, `p1`, `p2`, `relibc`, `sgx`, and `uclibc` + = note: expected values for `target_env` are: ``, `gnu`, `msvc`, `musl`, `newlib`, `nto70`, `nto71`, `nto71_iosock`, `ohos`, `p1`, `p2`, `relibc`, `sgx`, and `uclibc` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` From efe53ddd587333a405fcb95d78a72696932275cd Mon Sep 17 00:00:00 2001 From: Florian Bartels Date: Fri, 29 Nov 2024 18:15:05 +0100 Subject: [PATCH 10/21] Add support for QNX 7.1 with io-sock on x64 Signed-off-by: Florian Bartels --- compiler/rustc_target/src/spec/mod.rs | 1 + .../targets/x86_64_pc_nto_qnx710_iosock.rs | 27 +++++++++++++++++++ library/std/Cargo.toml | 2 +- src/bootstrap/src/core/sanity.rs | 1 + src/doc/rustc/src/platform-support.md | 3 ++- src/doc/rustc/src/platform-support/nto-qnx.md | 11 ++++---- tests/assembly/targets/targets-elf.rs | 3 +++ 7 files changed, 41 insertions(+), 7 deletions(-) create mode 100644 compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710_iosock.rs diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index df6d117f37600..fdfc72b1bea6c 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1965,6 +1965,7 @@ supported_targets! { ("aarch64-unknown-nto-qnx710", aarch64_unknown_nto_qnx710), ("aarch64-unknown-nto-qnx710_iosock", aarch64_unknown_nto_qnx710_iosock), ("x86_64-pc-nto-qnx710", x86_64_pc_nto_qnx710), + ("x86_64-pc-nto-qnx710_iosock", x86_64_pc_nto_qnx710_iosock), ("i586-pc-nto-qnx700", i586_pc_nto_qnx700), ("aarch64-unknown-linux-ohos", aarch64_unknown_linux_ohos), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710_iosock.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710_iosock.rs new file mode 100644 index 0000000000000..9a1035fd78eed --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710_iosock.rs @@ -0,0 +1,27 @@ +use crate::spec::{Cc, LinkerFlavor, Lld, Target, TargetOptions}; + +pub(crate) fn target() -> Target { + let mut target = super::x86_64_pc_nto_qnx710::target(); + target.options.env = "nto71_iosock".into(); + target.options.pre_link_args = + TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &[ + "-Vgcc_ntox86_64_cxx", + get_iosock_param(), + ]); + target +} + +// When using `io-sock` on QNX, we must add a search path for the linker so +// that it prefers the io-sock version. +// The path depends on the host, i.e. we cannot hard-code it here, but have +// to determine it when the compiler runs. +// When using the QNX toolchain, the environment variable QNX_TARGET is always set. +// More information: +// https://www.qnx.com/developers/docs/7.1/index.html#com.qnx.doc.neutrino.io_sock/topic/migrate_app.html +fn get_iosock_param() -> &'static str { + let target_dir = + std::env::var("QNX_TARGET").unwrap_or_else(|_| "PLEASE_SET_ENV_VAR_QNX_TARGET".into()); + let linker_param = format!("-L{target_dir}/x86_64/io-sock/lib"); + + linker_param.leak() +} diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index b91b89b7761bc..16e7cb5c3a8bb 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -139,7 +139,7 @@ test = true level = "warn" check-cfg = [ 'cfg(bootstrap)', - 'cfg(target_arch, values("xtensa", "aarch64-unknown-nto-qnx710_iosock"))', + 'cfg(target_arch, values("xtensa", "aarch64-unknown-nto-qnx710_iosock", "x86_64-pc-nto-qnx710_iosock"))', 'cfg(target_env, values("nto71_iosock"))', # std use #[path] imports to portable-simd `std_float` crate # and to the `backtrace` crate which messes-up with Cargo list diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 418ebbbfb42c8..87d273abf17ed 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -35,6 +35,7 @@ pub struct Finder { const STAGE0_MISSING_TARGETS: &[&str] = &[ // just a dummy comment so the list doesn't get onelined "aarch64-unknown-nto-qnx710_iosock", + "x86_64-pc-nto-qnx710_iosock", ]; /// Minimum version threshold for libstdc++ required when using prebuilt LLVM diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index d25eaa49dd5e7..de950dbfbe0cc 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -406,7 +406,8 @@ target | std | host | notes [`wasm64-unknown-unknown`](platform-support/wasm64-unknown-unknown.md) | ? | | WebAssembly [`x86_64-apple-tvos`](platform-support/apple-tvos.md) | ✓ | | x86 64-bit tvOS [`x86_64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ | | x86 64-bit Apple WatchOS simulator -[`x86_64-pc-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX Neutrino 7.1 RTOS | +[`x86_64-pc-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX Neutrino 7.1 RTOS with default network stack (io-pkt) | +[`x86_64-pc-nto-qnx710_iosock`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX Neutrino 7.1 RTOS with new network stack (io-sock) | [`x86_64-unikraft-linux-musl`](platform-support/unikraft-linux-musl.md) | ✓ | | 64-bit Unikraft with musl 1.2.3 `x86_64-unknown-dragonfly` | ✓ | ✓ | 64-bit DragonFlyBSD `x86_64-unknown-haiku` | ✓ | ✓ | 64-bit Haiku diff --git a/src/doc/rustc/src/platform-support/nto-qnx.md b/src/doc/rustc/src/platform-support/nto-qnx.md index 7d6d9ff3223ce..1bfd97b8f3426 100644 --- a/src/doc/rustc/src/platform-support/nto-qnx.md +++ b/src/doc/rustc/src/platform-support/nto-qnx.md @@ -22,11 +22,12 @@ Currently, the following QNX Neutrino versions and compilation targets are suppo | QNX Neutrino Version | Target Architecture | Full support | `no_std` support | |----------------------|---------------------|:------------:|:----------------:| -| 7.1 with io-pkt | AArch64 | ✓ | ✓ | -| 7.1 with io-sock | AArch64 | ✓ | ✓ | -| 7.1 | x86_64 | ✓ | ✓ | -| 7.0 | AArch64 | ? | ✓ | -| 7.0 | x86 | | ✓ | +| 7.1 with io-pkt | AArch64 | ✓ | ✓ | +| 7.1 with io-sock | AArch64 | ? | ✓ | +| 7.1 with io-pkt | x86_64 | ✓ | ✓ | +| 7.1 with io-sock | x86_64 | ? | ✓ | +| 7.0 | AArch64 | ? | ✓ | +| 7.0 | x86 | | ✓ | On QNX 7.0 and 7.1, `io-pkt` is used as network stack by default. QNX 7.1 includes the optional network stack `io-sock`. diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs index b9d6aaf7929bb..9f2711880c795 100644 --- a/tests/assembly/targets/targets-elf.rs +++ b/tests/assembly/targets/targets-elf.rs @@ -567,6 +567,9 @@ //@ revisions: x86_64_pc_nto_qnx710 //@ [x86_64_pc_nto_qnx710] compile-flags: --target x86_64-pc-nto-qnx710 //@ [x86_64_pc_nto_qnx710] needs-llvm-components: x86 +//@ revisions: x86_64_pc_nto_qnx710_iosock +//@ [x86_64_pc_nto_qnx710_iosock] compile-flags: --target x86_64-pc-nto-qnx710_iosock +//@ [x86_64_pc_nto_qnx710_iosock] needs-llvm-components: x86 //@ revisions: x86_64_pc_solaris //@ [x86_64_pc_solaris] compile-flags: --target x86_64-pc-solaris //@ [x86_64_pc_solaris] needs-llvm-components: x86 From 62661f25921770fd973567e62836adf6e3246ac9 Mon Sep 17 00:00:00 2001 From: Florian Bartels Date: Sat, 30 Nov 2024 10:34:46 +0100 Subject: [PATCH 11/21] Move common code to mod nto_qnx Signed-off-by: Florian Bartels --- .../rustc_target/src/spec/base/nto_qnx.rs | 97 ++++++++++++++++++- .../targets/aarch64_unknown_nto_qnx700.rs | 42 ++------ .../targets/aarch64_unknown_nto_qnx710.rs | 12 ++- .../aarch64_unknown_nto_qnx710_iosock.rs | 29 ++---- .../src/spec/targets/i586_pc_nto_qnx700.rs | 20 ++-- .../src/spec/targets/x86_64_pc_nto_qnx710.rs | 34 ++----- .../targets/x86_64_pc_nto_qnx710_iosock.rs | 29 ++---- src/doc/rustc/src/platform-support/nto-qnx.md | 43 ++++---- 8 files changed, 169 insertions(+), 137 deletions(-) diff --git a/compiler/rustc_target/src/spec/base/nto_qnx.rs b/compiler/rustc_target/src/spec/base/nto_qnx.rs index 65475d068d7e9..819e68a0500d6 100644 --- a/compiler/rustc_target/src/spec/base/nto_qnx.rs +++ b/compiler/rustc_target/src/spec/base/nto_qnx.rs @@ -1,4 +1,6 @@ -use crate::spec::{RelroLevel, TargetOptions, cvs}; +use crate::spec::{ + Cc, LinkArgs, LinkerFlavor, Lld, RelroLevel, Target, TargetMetadata, TargetOptions, cvs, +}; pub(crate) fn opts() -> TargetOptions { TargetOptions { @@ -16,3 +18,96 @@ pub(crate) fn opts() -> TargetOptions { ..Default::default() } } + +pub(crate) fn meta() -> TargetMetadata { + TargetMetadata { description: None, tier: Some(3), host_tools: Some(false), std: Some(true) } +} + +pub(crate) fn aarch64() -> Target { + Target { + llvm_target: "aarch64-unknown-unknown".into(), + metadata: meta(), + pointer_width: 64, + // from: https://llvm.org/docs/LangRef.html#data-layout + // e = little endian + // m:e = ELF mangling: Private symbols get a .L prefix + // i8:8:32 = 8-bit-integer, minimum_alignment=8, preferred_alignment=32 + // i16:16:32 = 16-bit-integer, minimum_alignment=16, preferred_alignment=32 + // i64:64 = 64-bit-integer, minimum_alignment=64, preferred_alignment=64 + // i128:128 = 128-bit-integer, minimum_alignment=128, preferred_alignment=128 + // n32:64 = 32 and 64 are native integer widths; Elements of this set are considered to support most general arithmetic operations efficiently. + // S128 = 128 bits are the natural alignment of the stack in bits. + data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), + arch: "aarch64".into(), + options: TargetOptions { + features: "+v8a".into(), + max_atomic_width: Some(128), + ..opts() + } + } +} + +pub(crate) fn x86_64() -> Target { + Target { + llvm_target: "x86_64-pc-unknown".into(), + metadata: meta(), + pointer_width: 64, + data_layout: + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), + arch: "x86_64".into(), + options: TargetOptions { + cpu: "x86-64".into(), + plt_by_default: false, + max_atomic_width: Some(64), + vendor: "pc".into(), + ..opts() + }, + } +} + +pub(crate) fn pre_link_args(api_var: ApiVariant, arch: Arch) -> LinkArgs { + let (qcc_arg, arch_lib_dir) = match arch { + Arch::Aarch64 => ("-Vgcc_ntoaarch64le_cxx", "aarch64le"), + Arch::I586 => { + ("-Vgcc_ntox86_cxx", "notSupportedByQnx_compiler/rustc_target/src/spec/base/nto_qnx.rs") + } + Arch::X86_64 => ("-Vgcc_ntox86_64_cxx", "x86_64"), + }; + match api_var { + ApiVariant::Default => { + TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &[qcc_arg]) + } + ApiVariant::IoSock => TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &[ + qcc_arg, + get_iosock_param(arch_lib_dir), + ]), + } +} + +pub(crate) enum ApiVariant { + Default, + IoSock, +} + +pub(crate) enum Arch { + Aarch64, + I586, + X86_64, +} + +// When using `io-sock` on QNX, we must add a search path for the linker so +// that it prefers the io-sock version. +// The path depends on the host, i.e. we cannot hard-code it here, but have +// to determine it when the compiler runs. +// When using the QNX toolchain, the environment variable QNX_TARGET is always set. +// More information: +// https://www.qnx.com/developers/docs/7.1/index.html#com.qnx.doc.neutrino.io_sock/topic/migrate_app.html +fn get_iosock_param(arch_lib_dir: &str) -> &'static str { + let target_dir = std::env::var("QNX_TARGET") + .unwrap_or_else(|_| "QNX_TARGET_not_set_please_source_qnxsdp-env.sh".into()); + let linker_param = format!("-L{target_dir}/{arch_lib_dir}/io-sock/lib"); + + // FIXME: leaking this is kind of weird: we're feeding these into something that expects an + // `AsRef`, but often converts to `OsString` anyways, so shouldn't we just demand an `OsString`? + linker_param.leak() +} diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx700.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx700.rs index 441ed7cf1535e..b26e6f19e1ab5 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx700.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx700.rs @@ -1,37 +1,11 @@ -use crate::spec::{Cc, LinkerFlavor, Lld, Target, TargetOptions, base}; +use crate::spec::Target; +use crate::spec::base::nto_qnx; pub(crate) fn target() -> Target { - // In QNX, libc does not provide a compatible ABI between versions. - // To distinguish between QNX versions, we needed a stable conditional compilation switch, - // which is why we needed to implement different targets in the compiler. - Target { - llvm_target: "aarch64-unknown-unknown".into(), - metadata: crate::spec::TargetMetadata { - description: Some("ARM64 QNX Neutrino 7.0 RTOS".into()), - tier: Some(3), - host_tools: Some(false), - std: Some(true), - }, - pointer_width: 64, - // from: https://llvm.org/docs/LangRef.html#data-layout - // e = little endian - // m:e = ELF mangling: Private symbols get a .L prefix - // i8:8:32 = 8-bit-integer, minimum_alignment=8, preferred_alignment=32 - // i16:16:32 = 16-bit-integer, minimum_alignment=16, preferred_alignment=32 - // i64:64 = 64-bit-integer, minimum_alignment=64, preferred_alignment=64 - // i128:128 = 128-bit-integer, minimum_alignment=128, preferred_alignment=128 - // n32:64 = 32 and 64 are native integer widths; Elements of this set are considered to support most general arithmetic operations efficiently. - // S128 = 128 bits are the natural alignment of the stack in bits. - data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), - arch: "aarch64".into(), - options: TargetOptions { - features: "+v8a".into(), - max_atomic_width: Some(128), - pre_link_args: TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &[ - "-Vgcc_ntoaarch64le_cxx", - ]), - env: "nto70".into(), - ..base::nto_qnx::opts() - }, - } + let mut target = nto_qnx::aarch64(); + target.metadata.description = Some("ARM64 QNX Neutrino 7.0 RTOS".into()); + target.options.pre_link_args = + nto_qnx::pre_link_args(nto_qnx::ApiVariant::Default, nto_qnx::Arch::Aarch64); + target.options.env = "nto70".into(); + target } diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710.rs index 5b5a21fca9527..3a78952c36c4e 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710.rs @@ -1,8 +1,12 @@ use crate::spec::Target; +use crate::spec::base::nto_qnx; pub(crate) fn target() -> Target { - let mut base = super::aarch64_unknown_nto_qnx700::target(); - base.metadata.description = Some("ARM64 QNX Neutrino 7.1 RTOS".into()); - base.options.env = "nto71".into(); - base + let mut target = nto_qnx::aarch64(); + target.metadata.description = + Some("ARM64 QNX Neutrino 7.1 RTOS with io-pkt network stack".into()); + target.options.pre_link_args = + nto_qnx::pre_link_args(nto_qnx::ApiVariant::Default, nto_qnx::Arch::Aarch64); + target.options.env = "nto71".into(); + target } diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710_iosock.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710_iosock.rs index c9ffc0e072c30..4964f4078f5cf 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710_iosock.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710_iosock.rs @@ -1,27 +1,12 @@ -use crate::spec::{Cc, LinkerFlavor, Lld, Target, TargetOptions}; +use crate::spec::Target; +use crate::spec::base::nto_qnx; pub(crate) fn target() -> Target { - let mut target = super::aarch64_unknown_nto_qnx710::target(); - target.options.env = "nto71_iosock".into(); + let mut target = nto_qnx::aarch64(); + target.metadata.description = + Some("ARM64 QNX Neutrino 7.1 RTOS with io-sock network stack".into()); target.options.pre_link_args = - TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &[ - "-Vgcc_ntoaarch64le_cxx", - get_iosock_param(), - ]); + nto_qnx::pre_link_args(nto_qnx::ApiVariant::IoSock, nto_qnx::Arch::Aarch64); + target.options.env = "nto71_iosock".into(); target } - -// When using `io-sock` on QNX, we must add a search path for the linker so -// that it prefers the io-sock version. -// The path depends on the host, i.e. we cannot hard-code it here, but have -// to determine it when the compiler runs. -// When using the QNX toolchain, the environment variable QNX_TARGET is always set. -// More information: -// https://www.qnx.com/developers/docs/7.1/index.html#com.qnx.doc.neutrino.io_sock/topic/migrate_app.html -fn get_iosock_param() -> &'static str { - let target_dir = - std::env::var("QNX_TARGET").unwrap_or_else(|_| "PLEASE_SET_ENV_VAR_QNX_TARGET".into()); - let linker_param = format!("-L{target_dir}/aarch64le/io-sock/lib"); - - linker_param.leak() -} diff --git a/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs b/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs index 7648f81fd4d9a..fa21cfbab8a3c 100644 --- a/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs +++ b/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs @@ -1,14 +1,13 @@ -use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions, base}; +use crate::spec::base::nto_qnx; +use crate::spec::{StackProbeType, Target, TargetOptions, base}; pub(crate) fn target() -> Target { + let mut meta = nto_qnx::meta(); + meta.description = Some("32-bit x86 QNX Neutrino 7.0 RTOS".into()); + meta.std = Some(false); Target { llvm_target: "i586-pc-unknown".into(), - metadata: crate::spec::TargetMetadata { - description: Some("32-bit x86 QNX Neutrino 7.0 RTOS".into()), - tier: Some(3), - host_tools: Some(false), - std: Some(false), - }, + metadata: meta, pointer_width: 32, data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ i128:128-f64:32:64-f80:32-n8:16:32-S128" @@ -17,9 +16,10 @@ pub(crate) fn target() -> Target { options: TargetOptions { cpu: "pentium4".into(), max_atomic_width: Some(64), - pre_link_args: TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &[ - "-Vgcc_ntox86_cxx", - ]), + pre_link_args: nto_qnx::pre_link_args( + nto_qnx::ApiVariant::Default, + nto_qnx::Arch::I586, + ), env: "nto70".into(), vendor: "pc".into(), stack_probes: StackProbeType::Inline, diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs index 245a5f0676547..248aa91862c92 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs @@ -1,28 +1,12 @@ -use crate::spec::{Cc, LinkerFlavor, Lld, Target, TargetOptions, base}; +use crate::spec::Target; +use crate::spec::base::nto_qnx; pub(crate) fn target() -> Target { - Target { - llvm_target: "x86_64-pc-unknown".into(), - metadata: crate::spec::TargetMetadata { - description: Some("x86 64-bit QNX Neutrino 7.1 RTOS".into()), - tier: Some(3), - host_tools: Some(false), - std: Some(true), - }, - pointer_width: 64, - data_layout: - "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), - arch: "x86_64".into(), - options: TargetOptions { - cpu: "x86-64".into(), - plt_by_default: false, - max_atomic_width: Some(64), - pre_link_args: TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &[ - "-Vgcc_ntox86_64_cxx", - ]), - env: "nto71".into(), - vendor: "pc".into(), - ..base::nto_qnx::opts() - }, - } + let mut target = nto_qnx::x86_64(); + target.metadata.description = + Some("x86 64-bit QNX Neutrino 7.1 RTOS with io-pkt network stack".into()); + target.options.pre_link_args = + nto_qnx::pre_link_args(nto_qnx::ApiVariant::Default, nto_qnx::Arch::X86_64); + target.options.env = "nto71".into(); + target } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710_iosock.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710_iosock.rs index 9a1035fd78eed..8f4c4924a295d 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710_iosock.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710_iosock.rs @@ -1,27 +1,12 @@ -use crate::spec::{Cc, LinkerFlavor, Lld, Target, TargetOptions}; +use crate::spec::Target; +use crate::spec::base::nto_qnx; pub(crate) fn target() -> Target { - let mut target = super::x86_64_pc_nto_qnx710::target(); - target.options.env = "nto71_iosock".into(); + let mut target = nto_qnx::x86_64(); + target.metadata.description = + Some("x86 64-bit QNX Neutrino 7.1 RTOS with io-sock network stack".into()); target.options.pre_link_args = - TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &[ - "-Vgcc_ntox86_64_cxx", - get_iosock_param(), - ]); + nto_qnx::pre_link_args(nto_qnx::ApiVariant::IoSock, nto_qnx::Arch::X86_64); + target.options.env = "nto71_iosock".into(); target } - -// When using `io-sock` on QNX, we must add a search path for the linker so -// that it prefers the io-sock version. -// The path depends on the host, i.e. we cannot hard-code it here, but have -// to determine it when the compiler runs. -// When using the QNX toolchain, the environment variable QNX_TARGET is always set. -// More information: -// https://www.qnx.com/developers/docs/7.1/index.html#com.qnx.doc.neutrino.io_sock/topic/migrate_app.html -fn get_iosock_param() -> &'static str { - let target_dir = - std::env::var("QNX_TARGET").unwrap_or_else(|_| "PLEASE_SET_ENV_VAR_QNX_TARGET".into()); - let linker_param = format!("-L{target_dir}/x86_64/io-sock/lib"); - - linker_param.leak() -} diff --git a/src/doc/rustc/src/platform-support/nto-qnx.md b/src/doc/rustc/src/platform-support/nto-qnx.md index 1bfd97b8f3426..75f8cbad959ea 100644 --- a/src/doc/rustc/src/platform-support/nto-qnx.md +++ b/src/doc/rustc/src/platform-support/nto-qnx.md @@ -136,18 +136,31 @@ To compile for QNX Neutrino (aarch64 and x86_64) and Linux (x86_64): ```bash export build_env=' - CC_aarch64-unknown-nto-qnx710=qcc - CFLAGS_aarch64-unknown-nto-qnx710=-Vgcc_ntoaarch64le_cxx - CXX_aarch64-unknown-nto-qnx710=qcc + CC_i586_pc_nto_qnx700=qcc + CFLAGS_i586_pc_nto_qnx700=-Vgcc_ntox86_cxx + CXX_i586_pc_nto_qnx700=qcc + AR_i586_pc_nto_qnx700=ntox86-ar + + CC_aarch64_unknown_nto_qnx710=qcc + CFLAGS_aarch64_unknown_nto_qnx710=-Vgcc_ntoaarch64le_cxx + CXX_aarch64_unknown_nto_qnx710=qcc AR_aarch64_unknown_nto_qnx710=ntoaarch64-ar - CC_aarch64-unknown-nto-qnx710_iosock=qcc - CFLAGS_aarch64-unknown-nto-qnx710_iosock=-Vgcc_ntoaarch64le_cxx - CXX_aarch64-unknown-nto-qnx710_iosock=qcc + + CC_aarch64_unknown_nto_qnx710_iosock=qcc + CFLAGS_aarch64_unknown_nto_qnx710_iosock=-Vgcc_ntoaarch64le_cxx + CXX_aarch64_unknown_nto_qnx710_iosock=qcc AR_aarch64_unknown_nto_qnx710_iosock=ntoaarch64-ar - CC_x86_64-pc-nto-qnx710=qcc - CFLAGS_x86_64-pc-nto-qnx710=-Vgcc_ntox86_64_cxx - CXX_x86_64-pc-nto-qnx710=qcc - AR_x86_64_pc_nto_qnx710=ntox86_64-ar' + + CC_aarch64_unknown_nto_qnx700=qcc + CFLAGS_aarch64_unknown_nto_qnx700=-Vgcc_ntoaarch64le_cxx + CXX_aarch64_unknown_nto_qnx700=qcc + AR_aarch64_unknown_nto_qnx700=ntoaarch64-ar + + CC_x86_64_pc_nto_qnx710=qcc + CFLAGS_x86_64_pc_nto_qnx710=-Vgcc_ntox86_64_cxx + CXX_x86_64_pc_nto_qnx710=qcc + AR_x86_64_pc_nto_qnx710=ntox86_64-ar + ' env $build_env \ ./x.py build \ @@ -167,15 +180,7 @@ To run all tests on a x86_64 QNX Neutrino target: ```bash export TEST_DEVICE_ADDR="localhost:12345" # must address the test target, can be a SSH tunnel -export build_env=' - CC_aarch64-unknown-nto-qnx710=qcc - CFLAGS_aarch64-unknown-nto-qnx710=-Vgcc_ntoaarch64le_cxx - CXX_aarch64-unknown-nto-qnx710=qcc - AR_aarch64_unknown_nto_qnx710=ntoaarch64-ar - CC_x86_64-pc-nto-qnx710=qcc - CFLAGS_x86_64-pc-nto-qnx710=-Vgcc_ntox86_64_cxx - CXX_x86_64-pc-nto-qnx710=qcc - AR_x86_64_pc_nto_qnx710=ntox86_64-ar' +export build_env= # Disable tests that only work on the host or don't make sense for this target. # See also: From 3f045c9d2e186402c135caf6cbc7fc8a41a684b6 Mon Sep 17 00:00:00 2001 From: AkhilTThomas Date: Fri, 6 Dec 2024 11:38:25 +0100 Subject: [PATCH 12/21] add nto80 x86-64 and aarch64 target Signed-off-by: Florian Bartels --- compiler/rustc_target/src/spec/mod.rs | 2 ++ .../src/spec/targets/aarch64_unknown_nto_qnx800.rs | 11 +++++++++++ .../src/spec/targets/x86_64_pc_nto_qnx800.rs | 11 +++++++++++ library/std/Cargo.toml | 4 ++-- .../std/src/sys/pal/unix/process/process_unix.rs | 14 +++----------- src/bootstrap/src/core/sanity.rs | 2 ++ src/doc/rustc/src/platform-support/nto-qnx.md | 1 + tests/assembly/targets/targets-elf.rs | 6 ++++++ tests/ui/check-cfg/well-known-values.stderr | 2 +- 9 files changed, 39 insertions(+), 14 deletions(-) create mode 100644 compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx800.rs create mode 100644 compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx800.rs diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index fdfc72b1bea6c..bcd2aff54bb11 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1964,8 +1964,10 @@ supported_targets! { ("aarch64-unknown-nto-qnx700", aarch64_unknown_nto_qnx700), ("aarch64-unknown-nto-qnx710", aarch64_unknown_nto_qnx710), ("aarch64-unknown-nto-qnx710_iosock", aarch64_unknown_nto_qnx710_iosock), + ("aarch64-unknown-nto-qnx800", aarch64_unknown_nto_qnx800), ("x86_64-pc-nto-qnx710", x86_64_pc_nto_qnx710), ("x86_64-pc-nto-qnx710_iosock", x86_64_pc_nto_qnx710_iosock), + ("x86_64-pc-nto-qnx800", x86_64_pc_nto_qnx800), ("i586-pc-nto-qnx700", i586_pc_nto_qnx700), ("aarch64-unknown-linux-ohos", aarch64_unknown_linux_ohos), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx800.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx800.rs new file mode 100644 index 0000000000000..5b820681efe99 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx800.rs @@ -0,0 +1,11 @@ +use crate::spec::Target; +use crate::spec::base::nto_qnx; + +pub(crate) fn target() -> Target { + let mut target = nto_qnx::aarch64(); + target.metadata.description = Some("ARM64 QNX Neutrino 8.0 RTOS".into()); + target.options.pre_link_args = + nto_qnx::pre_link_args(nto_qnx::ApiVariant::Default, nto_qnx::Arch::Aarch64); + target.options.env = "nto80".into(); + target +} diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx800.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx800.rs new file mode 100644 index 0000000000000..d91a94a2ba55a --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx800.rs @@ -0,0 +1,11 @@ +use crate::spec::Target; +use crate::spec::base::nto_qnx; + +pub(crate) fn target() -> Target { + let mut target = nto_qnx::x86_64(); + target.metadata.description = Some("x86 64-bit QNX Neutrino 8.0 RTOS".into()); + target.options.pre_link_args = + nto_qnx::pre_link_args(nto_qnx::ApiVariant::Default, nto_qnx::Arch::X86_64); + target.options.env = "nto80".into(); + target +} diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 16e7cb5c3a8bb..9eab75b06961f 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -139,8 +139,8 @@ test = true level = "warn" check-cfg = [ 'cfg(bootstrap)', - 'cfg(target_arch, values("xtensa", "aarch64-unknown-nto-qnx710_iosock", "x86_64-pc-nto-qnx710_iosock"))', - 'cfg(target_env, values("nto71_iosock"))', + 'cfg(target_arch, values("xtensa", "aarch64-unknown-nto-qnx710_iosock", "x86_64-pc-nto-qnx710_iosock", "x86_64-pc-nto-qnx800","aarch64-unknown-nto-qnx800"))', + 'cfg(target_env, values("nto71_iosock", "nto80"))', # std use #[path] imports to portable-simd `std_float` crate # and to the `backtrace` crate which messes-up with Cargo list # of declared features, we therefor expect any feature cfg diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs index cc22b3ecbd0f6..2bff192a5bd83 100644 --- a/library/std/src/sys/pal/unix/process/process_unix.rs +++ b/library/std/src/sys/pal/unix/process/process_unix.rs @@ -19,8 +19,7 @@ use crate::sys::process::process_common::*; use crate::{fmt, mem, sys}; cfg_if::cfg_if! { - // This workaround is only needed for QNX 7.0 and 7.1. The bug should have been fixed in 8.0 - if #[cfg(any(target_env = "nto70", target_env = "nto71", target_env = "nto71_iosock"))] { + if #[cfg(target_os = "nto")] { use crate::thread; use libc::{c_char, posix_spawn_file_actions_t, posix_spawnattr_t}; use crate::time::Duration; @@ -187,13 +186,7 @@ impl Command { // Attempts to fork the process. If successful, returns Ok((0, -1)) // in the child, and Ok((child_pid, -1)) in the parent. - #[cfg(not(any( - target_os = "watchos", - target_os = "tvos", - target_env = "nto70", - target_env = "nto71", - target_env = "nto71_iosock", - )))] + #[cfg(not(any(target_os = "watchos", target_os = "tvos", target_os = "nto")))] unsafe fn do_fork(&mut self) -> Result { cvt(libc::fork()) } @@ -202,8 +195,7 @@ impl Command { // or closed a file descriptor while the fork() was occurring". // Documentation says "... or try calling fork() again". This is what we do here. // See also https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/f/fork.html - // This workaround is only needed for QNX 7.0 and 7.1. The bug should have been fixed in 8.0 - #[cfg(any(target_env = "nto70", target_env = "nto71", target_env = "nto71_iosock"))] + #[cfg(target_os = "nto")] unsafe fn do_fork(&mut self) -> Result { use crate::sys::os::errno; diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 87d273abf17ed..6c8cda18548ef 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -36,6 +36,8 @@ const STAGE0_MISSING_TARGETS: &[&str] = &[ // just a dummy comment so the list doesn't get onelined "aarch64-unknown-nto-qnx710_iosock", "x86_64-pc-nto-qnx710_iosock", + "x86_64-pc-nto-qnx800", + "aarch64-unknown-nto-qnx800", ]; /// Minimum version threshold for libstdc++ required when using prebuilt LLVM diff --git a/src/doc/rustc/src/platform-support/nto-qnx.md b/src/doc/rustc/src/platform-support/nto-qnx.md index 75f8cbad959ea..4c4bd0494febc 100644 --- a/src/doc/rustc/src/platform-support/nto-qnx.md +++ b/src/doc/rustc/src/platform-support/nto-qnx.md @@ -115,6 +115,7 @@ For conditional compilation, following QNX Neutrino specific attributes are defi - `target_env` = `"nto71"` (for QNX Neutrino 7.1 with "classic" network stack "io_pkt") - `target_env` = `"nto71_iosock"` (for QNX Neutrino 7.1 with network stack "io_sock") - `target_env` = `"nto70"` (for QNX Neutrino 7.0) +- `target_env` = `"nto80"` (for QNX Neutrino 8.0) ## Building the target diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs index 9f2711880c795..0ff886653a477 100644 --- a/tests/assembly/targets/targets-elf.rs +++ b/tests/assembly/targets/targets-elf.rs @@ -60,6 +60,9 @@ //@ revisions: aarch64_unknown_nto_qnx710_iosock //@ [aarch64_unknown_nto_qnx710_iosock] compile-flags: --target aarch64-unknown-nto-qnx710_iosock //@ [aarch64_unknown_nto_qnx710_iosock] needs-llvm-components: aarch64 +//@ revisions: aarch64_unknown_nto_qnx800 +//@ [aarch64_unknown_nto_qnx800] compile-flags: --target aarch64-unknown-nto-qnx800 +//@ [aarch64_unknown_nto_qnx800] needs-llvm-components: aarch64 //@ revisions: aarch64_unknown_openbsd //@ [aarch64_unknown_openbsd] compile-flags: --target aarch64-unknown-openbsd //@ [aarch64_unknown_openbsd] needs-llvm-components: aarch64 @@ -570,6 +573,9 @@ //@ revisions: x86_64_pc_nto_qnx710_iosock //@ [x86_64_pc_nto_qnx710_iosock] compile-flags: --target x86_64-pc-nto-qnx710_iosock //@ [x86_64_pc_nto_qnx710_iosock] needs-llvm-components: x86 +//@ revisions: x86_64_pc_nto_qnx800 +//@ [x86_64_pc_nto_qnx800] compile-flags: --target x86_64-pc-nto-qnx800 +//@ [x86_64_pc_nto_qnx800] needs-llvm-components: x86 //@ revisions: x86_64_pc_solaris //@ [x86_64_pc_solaris] compile-flags: --target x86_64-pc-solaris //@ [x86_64_pc_solaris] needs-llvm-components: x86 diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index 29bc30815b877..8ac3cb7ac3c25 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -156,7 +156,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_env = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_env` are: ``, `gnu`, `msvc`, `musl`, `newlib`, `nto70`, `nto71`, `nto71_iosock`, `ohos`, `p1`, `p2`, `relibc`, `sgx`, and `uclibc` + = note: expected values for `target_env` are: ``, `gnu`, `msvc`, `musl`, `newlib`, `nto70`, `nto71`, `nto71_iosock`, `nto80`, `ohos`, `p1`, `p2`, `relibc`, `sgx`, and `uclibc` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` From 46a03338fbadc7652425f0018a94f115ae173455 Mon Sep 17 00:00:00 2001 From: Florian Bartels Date: Tue, 10 Dec 2024 08:14:59 +0100 Subject: [PATCH 13/21] Update documentation to include QNX 8.0 Signed-off-by: Florian Bartels --- src/doc/rustc/src/platform-support.md | 7 +- src/doc/rustc/src/platform-support/nto-qnx.md | 88 ++++++++++--------- 2 files changed, 51 insertions(+), 44 deletions(-) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index de950dbfbe0cc..c964c29768f9c 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -254,14 +254,14 @@ target | std | host | notes [`aarch64-kmc-solid_asp3`](platform-support/kmc-solid.md) | ✓ | | ARM64 SOLID with TOPPERS/ASP3 [`aarch64-nintendo-switch-freestanding`](platform-support/aarch64-nintendo-switch-freestanding.md) | * | | ARM64 Nintendo Switch, Horizon [`aarch64-unknown-freebsd`](platform-support/freebsd.md) | ✓ | ✓ | ARM64 FreeBSD -`aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD [`aarch64-unknown-hermit`](platform-support/hermit.md) | ✓ | | ARM64 Hermit [`aarch64-unknown-illumos`](platform-support/illumos.md) | ✓ | ✓ | ARM64 illumos `aarch64-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (ILP32 ABI) [`aarch64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD -[`aarch64-unknown-nto-qnx710_iosock`](platform-support/nto-qnx.md) | ✓ | | ARM64 QNX Neutrino 7.1 RTOS with new network stack (io-sock) | -[`aarch64-unknown-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | ARM64 QNX Neutrino 7.1 RTOS | +[`aarch64-unknown-nto-qnx700`](platform-support/nto-qnx.md) | ? | | ARM64 QNX Neutrino 7.0 RTOS | [`aarch64-unknown-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | ARM64 QNX Neutrino 7.1 RTOS with default network stack (io-pkt) | +[`aarch64-unknown-nto-qnx710_iosock`](platform-support/nto-qnx.md) | ✓ | | ARM64 QNX Neutrino 7.1 RTOS with new network stack (io-sock) | +[`aarch64-unknown-nto-qnx800`](platform-support/nto-qnx.md) | ✓ | | ARM64 QNX Neutrino 8.0 RTOS | [`aarch64-unknown-nuttx`](platform-support/nuttx.md) | * | | ARM64 with NuttX [`aarch64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | ARM64 OpenBSD [`aarch64-unknown-redox`](platform-support/redox.md) | ✓ | | ARM64 Redox OS @@ -408,6 +408,7 @@ target | std | host | notes [`x86_64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ | | x86 64-bit Apple WatchOS simulator [`x86_64-pc-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX Neutrino 7.1 RTOS with default network stack (io-pkt) | [`x86_64-pc-nto-qnx710_iosock`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX Neutrino 7.1 RTOS with new network stack (io-sock) | +[`x86_64-pc-nto-qnx800`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX Neutrino 8.0 RTOS | [`x86_64-unikraft-linux-musl`](platform-support/unikraft-linux-musl.md) | ✓ | | 64-bit Unikraft with musl 1.2.3 `x86_64-unknown-dragonfly` | ✓ | ✓ | 64-bit DragonFlyBSD `x86_64-unknown-haiku` | ✓ | ✓ | 64-bit Haiku diff --git a/src/doc/rustc/src/platform-support/nto-qnx.md b/src/doc/rustc/src/platform-support/nto-qnx.md index 4c4bd0494febc..4ac77f804497c 100644 --- a/src/doc/rustc/src/platform-support/nto-qnx.md +++ b/src/doc/rustc/src/platform-support/nto-qnx.md @@ -22,6 +22,8 @@ Currently, the following QNX Neutrino versions and compilation targets are suppo | QNX Neutrino Version | Target Architecture | Full support | `no_std` support | |----------------------|---------------------|:------------:|:----------------:| +| 8.0 | AArch64 | ? | ✓ | +| 8.0 | x86 | ? | ✓ | | 7.1 with io-pkt | AArch64 | ✓ | ✓ | | 7.1 with io-sock | AArch64 | ? | ✓ | | 7.1 with io-pkt | x86_64 | ✓ | ✓ | @@ -31,6 +33,8 @@ Currently, the following QNX Neutrino versions and compilation targets are suppo On QNX 7.0 and 7.1, `io-pkt` is used as network stack by default. QNX 7.1 includes the optional network stack `io-sock`. +QNX 8.0 always uses `io-sock`. QNX 8.0 support is currently in development +and not tested. Adding other architectures that are supported by QNX Neutrino is possible. @@ -121,53 +125,55 @@ For conditional compilation, following QNX Neutrino specific attributes are defi 1. Create a `config.toml` -Example content: + Example content: -```toml -profile = "compiler" -change-id = 115898 -``` + ```toml + profile = "compiler" + change-id = 999999 + ``` -2. Compile the Rust toolchain for an `x86_64-unknown-linux-gnu` host (for both `aarch64` and `x86_64` targets) +2. Compile the Rust toolchain for an `x86_64-unknown-linux-gnu` host -Compiling the Rust toolchain requires the same environment variables used for compiling C binaries. -Refer to the [QNX developer manual](https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.prog/topic/devel_OS_version.html). + Compiling the Rust toolchain requires the same environment variables used for compiling C binaries. + Refer to the [QNX developer manual](https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.prog/topic/devel_OS_version.html). -To compile for QNX Neutrino (aarch64 and x86_64) and Linux (x86_64): + To compile for QNX Neutrino, environment variables must be set to use the correct tools and compiler switches: -```bash -export build_env=' - CC_i586_pc_nto_qnx700=qcc - CFLAGS_i586_pc_nto_qnx700=-Vgcc_ntox86_cxx - CXX_i586_pc_nto_qnx700=qcc - AR_i586_pc_nto_qnx700=ntox86-ar - - CC_aarch64_unknown_nto_qnx710=qcc - CFLAGS_aarch64_unknown_nto_qnx710=-Vgcc_ntoaarch64le_cxx - CXX_aarch64_unknown_nto_qnx710=qcc - AR_aarch64_unknown_nto_qnx710=ntoaarch64-ar - - CC_aarch64_unknown_nto_qnx710_iosock=qcc - CFLAGS_aarch64_unknown_nto_qnx710_iosock=-Vgcc_ntoaarch64le_cxx - CXX_aarch64_unknown_nto_qnx710_iosock=qcc - AR_aarch64_unknown_nto_qnx710_iosock=ntoaarch64-ar - - CC_aarch64_unknown_nto_qnx700=qcc - CFLAGS_aarch64_unknown_nto_qnx700=-Vgcc_ntoaarch64le_cxx - CXX_aarch64_unknown_nto_qnx700=qcc - AR_aarch64_unknown_nto_qnx700=ntoaarch64-ar - - CC_x86_64_pc_nto_qnx710=qcc - CFLAGS_x86_64_pc_nto_qnx710=-Vgcc_ntox86_64_cxx - CXX_x86_64_pc_nto_qnx710=qcc - AR_x86_64_pc_nto_qnx710=ntox86_64-ar - ' + - `CC_=qcc` + - `CFLAGS_=` + - `CXX_=qcc` + - `AR_=` -env $build_env \ - ./x.py build \ - --target aarch64-unknown-nto-qnx710_iosock,aarch64-unknown-nto-qnx710,x86_64-pc-nto-qnx710,x86_64-unknown-linux-gnu \ - rustc library/core library/alloc library/std -``` + With: + + - `` target triplet using underscores instead of hyphens, e.g. `aarch64_unknown_nto_qnx710` + - `` + + - `-Vgcc_ntox86_cxx` for x86 (32 bit) + - `-Vgcc_ntox86_64_cxx` for x86_64 (64 bit) + - `-Vgcc_ntoaarch64le_cxx` for Aarch64 (64 bit) + + - `` + + - `ntox86-ar` for x86 (32 bit) + - `ntox86_64-ar` for x86_64 (64 bit) + - `ntoaarch64-ar` for Aarch64 (64 bit) + + Example to build the Rust toolchain including a standard library for x86_64-linux-gnu and Aarch64-QNX-7.1: + + ```bash + export build_env=' + CC_aarch64_unknown_nto_qnx710=qcc + CFLAGS_aarch64_unknown_nto_qnx710=-Vgcc_ntoaarch64le_cxx + CXX_aarch64_unknown_nto_qnx710=qcc + AR_aarch64_unknown_nto_qnx710=ntoaarch64-ar + ' + + env $build_env \ + ./x.py build \ + --target x86_64-unknown-linux-gnu,aarch64-unknown-nto-qnx710 \ + rustc library/core library/alloc library/std + ``` ## Running the Rust test suite From 04628266c377b560afbceca5a1ba263bb2f5d162 Mon Sep 17 00:00:00 2001 From: Jonathan Pallant Date: Mon, 13 Jan 2025 14:56:01 +0000 Subject: [PATCH 14/21] Review nto-qnx.md. QNX SDP 8.0 comes with newly renamed QNX OS 8.0, so update the page to talk about QNX, QNX Neutrino 7.0, QNX Neutrino 7.1 or QNX OS 8.0. Also actually add a list of target triples. --- src/doc/rustc/src/platform-support/nto-qnx.md | 59 ++++++++++--------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/src/doc/rustc/src/platform-support/nto-qnx.md b/src/doc/rustc/src/platform-support/nto-qnx.md index 4ac77f804497c..339741f14727d 100644 --- a/src/doc/rustc/src/platform-support/nto-qnx.md +++ b/src/doc/rustc/src/platform-support/nto-qnx.md @@ -2,11 +2,13 @@ **Tier: 3** -[QNX®][BlackBerry] Neutrino (nto) Real-time operating system. -The support has been implemented jointly by [Elektrobit Automotive GmbH][Elektrobit] -and [Blackberry QNX][BlackBerry]. +The [QNX®][qnx.com] Neutrino (nto) Real-time operating system. Known as QNX OS +from version 8 onwards. -[BlackBerry]: https://blackberry.qnx.com +This support has been implemented jointly by [Elektrobit Automotive GmbH][Elektrobit] +and [QNX][qnx.com]. + +[qnx.com]: https://blackberry.qnx.com [Elektrobit]: https://www.elektrobit.com ## Target maintainers @@ -18,30 +20,29 @@ and [Blackberry QNX][BlackBerry]. ## Requirements -Currently, the following QNX Neutrino versions and compilation targets are supported: +Currently, the following QNX versions and compilation targets are supported: -| QNX Neutrino Version | Target Architecture | Full support | `no_std` support | -|----------------------|---------------------|:------------:|:----------------:| -| 8.0 | AArch64 | ? | ✓ | -| 8.0 | x86 | ? | ✓ | -| 7.1 with io-pkt | AArch64 | ✓ | ✓ | -| 7.1 with io-sock | AArch64 | ? | ✓ | -| 7.1 with io-pkt | x86_64 | ✓ | ✓ | -| 7.1 with io-sock | x86_64 | ? | ✓ | -| 7.0 | AArch64 | ? | ✓ | -| 7.0 | x86 | | ✓ | +| Target Tuple | QNX Version | Target Architecture | Full support | `no_std` support | +| ----------------------------------- | ----------------------------- | ------------------- | :----------: | :--------------: | +| `aarch64-unknown-nto-qnx800` | QNX OS 8.0 | AArch64 | ? | ✓ | +| `x86_64-pc-nto-qnx800` | QNX OS 8.0 | x86_64 | ? | ✓ | +| `aarch64-unknown-nto-qnx710` | QNX Neutrino 7.1 with io-pkt | AArch64 | ✓ | ✓ | +| `x86_64-pc-nto-qnx710` | QNX Neutrino 7.1 with io-pkt | x86_64 | ✓ | ✓ | +| `aarch64-unknown-nto-qnx710_iosock` | QNX Neutrino 7.1 with io-sock | AArch64 | ? | ✓ | +| `x86_64-pc-nto-qnx710_iosock` | QNX Neutrino 7.1 with io-sock | x86_64 | ? | ✓ | +| `aarch64-unknown-nto-qnx700` | QNX Neutrino 7.0 | AArch64 | ? | ✓ | +| `i586-pc-nto-qnx700` | QNX Neutrino 7.0 | x86 | | ✓ | -On QNX 7.0 and 7.1, `io-pkt` is used as network stack by default. QNX 7.1 includes -the optional network stack `io-sock`. -QNX 8.0 always uses `io-sock`. QNX 8.0 support is currently in development -and not tested. +On QNX Neutrino 7.0 and 7.1, `io-pkt` is used as network stack by default. +QNX Neutrino 7.1 includes the optional network stack `io-sock`. +QNX OS 8.0 always uses `io-sock`. QNX OS 8.0 support is currently work in progress. -Adding other architectures that are supported by QNX Neutrino is possible. +Adding other architectures that are supported by QNX is possible. -In the table above, 'full support' indicates support for building Rust applications with the full standard library. -'`no_std` support' indicates that only `core` and `alloc` are available. +In the table above, 'full support' indicates support for building Rust applications with the full standard library. A '?' means that support is in-progress. +'`no_std` support' is for building `#![no_std]` applications where only `core` and `alloc` are available. -For building or using the Rust toolchain for QNX Neutrino, the +For building or using the Rust toolchain for QNX, the [QNX Software Development Platform (SDP)](https://blackberry.qnx.com/en/products/foundation-software/qnx-software-development-platform) must be installed and initialized. Initialization is usually done by sourcing `qnxsdp-env.sh` (this will be installed as part of the SDP, see also installation instruction provided with the SDP). @@ -107,19 +108,19 @@ fn panic(_panic: &PanicInfo<'_>) -> ! { pub extern "C" fn rust_eh_personality() {} ``` -The QNX Neutrino support of Rust has been tested with QNX Neutrino 7.0 and 7.1. +The QNX support in Rust has been tested with QNX Neutrino 7.0 and 7.1. Support for QNX OS 8.0 is a work in progress. There are no further known requirements. ## Conditional compilation -For conditional compilation, following QNX Neutrino specific attributes are defined: +For conditional compilation, following QNX specific attributes are defined: - `target_os` = `"nto"` - `target_env` = `"nto71"` (for QNX Neutrino 7.1 with "classic" network stack "io_pkt") - `target_env` = `"nto71_iosock"` (for QNX Neutrino 7.1 with network stack "io_sock") - `target_env` = `"nto70"` (for QNX Neutrino 7.0) -- `target_env` = `"nto80"` (for QNX Neutrino 8.0) +- `target_env` = `"nto80"` (for QNX OS 8.0) ## Building the target @@ -137,7 +138,7 @@ For conditional compilation, following QNX Neutrino specific attributes are defi Compiling the Rust toolchain requires the same environment variables used for compiling C binaries. Refer to the [QNX developer manual](https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.prog/topic/devel_OS_version.html). - To compile for QNX Neutrino, environment variables must be set to use the correct tools and compiler switches: + To compile for QNX, environment variables must be set to use the correct tools and compiler switches: - `CC_=qcc` - `CFLAGS_=` @@ -183,7 +184,7 @@ addition of the TEST_DEVICE_ADDR environment variable. The TEST_DEVICE_ADDR variable controls the remote runner and should point to the target, despite localhost being shown in the following example. Note that some tests are failing which is why they are currently excluded by the target maintainers which can be seen in the following example. -To run all tests on a x86_64 QNX Neutrino target: +To run all tests on a x86_64 QNX Neutrino 7.1 target: ```bash export TEST_DEVICE_ADDR="localhost:12345" # must address the test target, can be a SSH tunnel @@ -217,7 +218,7 @@ or build your own copy of `core` by using `build-std` or similar. ## Testing -Compiled executables can run directly on QNX Neutrino. +Compiled executables can run directly on QNX. ### Rust std library test suite From 2444adf27c3c4e638c121b685bc3d4d57bb9d51f Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 13 Dec 2024 14:49:40 -0600 Subject: [PATCH 15/21] fix(libtest): Deprecate '--logfile' rust-lang/testing-devex-team#9 proposed changing the behavior of `--logfile`. The given reasons were: (1) Bazel can't programmatically process stdout. This seems like a limitation in Bazel and we recommend focusing on that. If we look at the wider Rust ecosystem, Rustc and Cargo don't support any such mechanism and the Cargo team rejected having one. Expecting this in libtest when its not supported elsewhere seems too specialized. (2) Tests that leak out non-programmatic output that intermixes with programmatic output. We acknowledge this is a problem to be evaluated but we need to make sure we are stepping back and gathering requirements, rather than assuming `--logfile` will fit the needs. Independent of the motive, regarding using or changing `--logfile` (1) Most ways to do it would be a breaking change, like if we respect any stable `--format`. As suggested above, we could specialize this to new `--format` values but that would be confusing for some values to apply but not others. (2) Other ways of solving this add new features to lib`test` when we are instead wanting to limit the feature set it has to minimize the compatibility surface that has to be maintained and the burden it would put on third party harnesses which are a focus area. Examples include `--format compact` or a `--log-format` flag (3) The existence of `--logfile` dates back quite a ways (https://github.com/rust-lang/rust/commit/5cc050b265509c19717e11e12dd785d8c73f5b11, rust-lang/rust#2127) and the history gives the impression this more of slipped through rather than being an intended feature (see also https://github.com/rust-lang/rust/pull/82350#discussion_r579732071). Deprecation would better match to how it has been treated. By deprecating this, we do not expect custom test harnesses (rust-lang/testing-devex-team#2) to implement this. T-testing-devex held an FCP for deprecating in rust-lang/testing-devex-team#9 though according to [RFC #3455](https://rust-lang.github.io/rfcs/3455-t-test.html), this is still subject to final approval from T-libs-api. --- library/test/src/cli.rs | 8 ++++++-- src/doc/rustc/src/tests/index.md | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/library/test/src/cli.rs b/library/test/src/cli.rs index 52c8091762346..ef6786f431670 100644 --- a/library/test/src/cli.rs +++ b/library/test/src/cli.rs @@ -1,7 +1,7 @@ //! Module converting command-line arguments into test configuration. use std::env; -use std::io::{self, IsTerminal}; +use std::io::{self, IsTerminal, Write}; use std::path::PathBuf; use super::options::{ColorConfig, Options, OutputFormat, RunIgnored}; @@ -58,7 +58,7 @@ fn optgroups() -> getopts::Options { .optflag("", "bench", "Run benchmarks instead of tests") .optflag("", "list", "List all tests and benchmarks") .optflag("h", "help", "Display this message") - .optopt("", "logfile", "Write logs to the specified file", "PATH") + .optopt("", "logfile", "Write logs to the specified file (deprecated)", "PATH") .optflag( "", "nocapture", @@ -281,6 +281,10 @@ fn parse_opts_impl(matches: getopts::Matches) -> OptRes { let options = Options::new().display_output(matches.opt_present("show-output")); + if logfile.is_some() { + let _ = write!(io::stderr(), "warning: `--logfile` is deprecated"); + } + let test_opts = TestOpts { list, filters, diff --git a/src/doc/rustc/src/tests/index.md b/src/doc/rustc/src/tests/index.md index 32baed9c94498..d2026513d2f0d 100644 --- a/src/doc/rustc/src/tests/index.md +++ b/src/doc/rustc/src/tests/index.md @@ -268,6 +268,8 @@ Controls the format of the output. Valid options: Writes the results of the tests to the given file. +This option is deprecated. + #### `--report-time` ⚠️ 🚧 This option is [unstable](#unstable-options), and requires the `-Z From 8eebbbaac2adabf4e442eadccf71e6f470871b37 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 23 Jan 2025 12:28:52 -0800 Subject: [PATCH 16/21] ci.py: check the return code in `run-local` If the run fails, it should report that and return a non-zero exit status. The simplest way to do that is with `run(..., check=True)`, which raises a `CalledProcessError`. --- src/ci/github-actions/ci.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/github-actions/ci.py b/src/ci/github-actions/ci.py index b7dac412dbecf..c93766ef33a0d 100755 --- a/src/ci/github-actions/ci.py +++ b/src/ci/github-actions/ci.py @@ -249,7 +249,7 @@ def run_workflow_locally(job_data: Dict[str, Any], job_name: str, pr_jobs: bool) env = os.environ.copy() env.update(custom_env) - subprocess.run(args, env=env) + subprocess.run(args, env=env, check=True) def calculate_job_matrix(job_data: Dict[str, Any]): From 492d98564e42bf14f96996f1dea33c0228838e93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Fri, 24 Jan 2025 18:17:15 +0000 Subject: [PATCH 17/21] extract principal MIR dump function for cases where we want to dump the MIR to a given writer instead of a new file as the default does. this will be used when dumping the MIR to a buffer to process differently, e.g. post-process to escape for an HTML dump. --- compiler/rustc_middle/src/mir/pretty.rs | 63 ++++++++++++++++--------- 1 file changed, 42 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index ea35323ccc7f2..3b4fba97e60b9 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1,8 +1,7 @@ use std::collections::BTreeSet; use std::fmt::{Display, Write as _}; -use std::fs; -use std::io::{self, Write as _}; use std::path::{Path, PathBuf}; +use std::{fs, io}; use rustc_abi::Size; use rustc_ast::InlineAsmTemplatePiece; @@ -149,37 +148,59 @@ pub fn dump_enabled(tcx: TyCtxt<'_>, pass_name: &str, def_id: DefId) -> bool { // `def_path_str()` would otherwise trigger `type_of`, and this can // run while we are already attempting to evaluate `type_of`. +/// Most use-cases of dumping MIR should use the [dump_mir] entrypoint instead, which will also +/// check if dumping MIR is enabled, and if this body matches the filters passed on the CLI. +/// +/// That being said, if the above requirements have been validated already, this function is where +/// most of the MIR dumping occurs, if one needs to export it to a file they have created with +/// [create_dump_file], rather than to a new file created as part of [dump_mir], or to stdout/stderr +/// for debugging purposes. +pub fn dump_mir_to_writer<'tcx, F>( + tcx: TyCtxt<'tcx>, + pass_name: &str, + disambiguator: &dyn Display, + body: &Body<'tcx>, + w: &mut dyn io::Write, + mut extra_data: F, + options: PrettyPrintMirOptions, +) -> io::Result<()> +where + F: FnMut(PassWhere, &mut dyn io::Write) -> io::Result<()>, +{ + // see notes on #41697 above + let def_path = + ty::print::with_forced_impl_filename_line!(tcx.def_path_str(body.source.def_id())); + // ignore-tidy-odd-backticks the literal below is fine + write!(w, "// MIR for `{def_path}")?; + match body.source.promoted { + None => write!(w, "`")?, + Some(promoted) => write!(w, "::{promoted:?}`")?, + } + writeln!(w, " {disambiguator} {pass_name}")?; + if let Some(ref layout) = body.coroutine_layout_raw() { + writeln!(w, "/* coroutine_layout = {layout:#?} */")?; + } + writeln!(w)?; + extra_data(PassWhere::BeforeCFG, w)?; + write_user_type_annotations(tcx, body, w)?; + write_mir_fn(tcx, body, &mut extra_data, w, options)?; + extra_data(PassWhere::AfterCFG, w) +} + fn dump_matched_mir_node<'tcx, F>( tcx: TyCtxt<'tcx>, pass_num: bool, pass_name: &str, disambiguator: &dyn Display, body: &Body<'tcx>, - mut extra_data: F, + extra_data: F, options: PrettyPrintMirOptions, ) where F: FnMut(PassWhere, &mut dyn io::Write) -> io::Result<()>, { let _: io::Result<()> = try { let mut file = create_dump_file(tcx, "mir", pass_num, pass_name, disambiguator, body)?; - // see notes on #41697 above - let def_path = - ty::print::with_forced_impl_filename_line!(tcx.def_path_str(body.source.def_id())); - // ignore-tidy-odd-backticks the literal below is fine - write!(file, "// MIR for `{def_path}")?; - match body.source.promoted { - None => write!(file, "`")?, - Some(promoted) => write!(file, "::{promoted:?}`")?, - } - writeln!(file, " {disambiguator} {pass_name}")?; - if let Some(ref layout) = body.coroutine_layout_raw() { - writeln!(file, "/* coroutine_layout = {layout:#?} */")?; - } - writeln!(file)?; - extra_data(PassWhere::BeforeCFG, &mut file)?; - write_user_type_annotations(tcx, body, &mut file)?; - write_mir_fn(tcx, body, &mut extra_data, &mut file, options)?; - extra_data(PassWhere::AfterCFG, &mut file)?; + dump_mir_to_writer(tcx, pass_name, disambiguator, body, &mut file, extra_data, options)?; }; if tcx.sess.opts.unstable_opts.dump_mir_graphviz { From 3631c15b17e53bd093333cc977dfe0376302a519 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Fri, 24 Jan 2025 18:19:09 +0000 Subject: [PATCH 18/21] use more explicit MIR dumping process --- compiler/rustc_borrowck/src/polonius/dump.rs | 40 ++++++++++++++++++-- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_borrowck/src/polonius/dump.rs b/compiler/rustc_borrowck/src/polonius/dump.rs index a6d8014903440..b59976dfdfcf6 100644 --- a/compiler/rustc_borrowck/src/polonius/dump.rs +++ b/compiler/rustc_borrowck/src/polonius/dump.rs @@ -1,6 +1,8 @@ use std::io; -use rustc_middle::mir::pretty::{PrettyPrintMirOptions, dump_mir_with_options}; +use rustc_middle::mir::pretty::{ + PrettyPrintMirOptions, create_dump_file, dump_enabled, dump_mir_to_writer, +}; use rustc_middle::mir::{Body, ClosureRegionRequirements, PassWhere}; use rustc_middle::ty::TyCtxt; use rustc_session::config::MirIncludeSpans; @@ -26,9 +28,39 @@ pub(crate) fn dump_polonius_mir<'tcx>( return; } + if !dump_enabled(tcx, "polonius", body.source.def_id()) { + return; + } + let localized_outlives_constraints = localized_outlives_constraints .expect("missing localized constraints with `-Zpolonius=next`"); + let _: io::Result<()> = try { + let mut file = create_dump_file(tcx, "mir", false, "polonius", &0, body)?; + emit_polonius_dump( + tcx, + body, + regioncx, + borrow_set, + localized_outlives_constraints, + closure_region_requirements, + &mut file, + )?; + }; +} + +/// The polonius dump consists of: +/// - the NLL MIR +/// - the list of polonius localized constraints +fn emit_polonius_dump<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + regioncx: &RegionInferenceContext<'tcx>, + borrow_set: &BorrowSet<'tcx>, + localized_outlives_constraints: LocalizedOutlivesConstraintSet, + closure_region_requirements: &Option>, + out: &mut dyn io::Write, +) -> io::Result<()> { // We want the NLL extra comments printed by default in NLL MIR dumps (they were removed in // #112346). Specifying `-Z mir-include-spans` on the CLI still has priority: for example, // they're always disabled in mir-opt tests to make working with blessed dumps easier. @@ -39,12 +71,12 @@ pub(crate) fn dump_polonius_mir<'tcx>( ), }; - dump_mir_with_options( + dump_mir_to_writer( tcx, - false, "polonius", &0, body, + out, |pass_where, out| { emit_polonius_mir( tcx, @@ -57,7 +89,7 @@ pub(crate) fn dump_polonius_mir<'tcx>( ) }, options, - ); + ) } /// Produces the actual NLL + Polonius MIR sections to emit during the dumping process. From 6baa65e36659b5f4fe1cdfa94acf2aa9ba98f786 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Fri, 24 Jan 2025 21:28:16 +0000 Subject: [PATCH 19/21] switch polonius MIR dump to HTML escape the regular raw MIR into its own section --- compiler/rustc_borrowck/src/polonius/dump.rs | 76 +++++++++++++++++--- 1 file changed, 67 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_borrowck/src/polonius/dump.rs b/compiler/rustc_borrowck/src/polonius/dump.rs index b59976dfdfcf6..25191fd349795 100644 --- a/compiler/rustc_borrowck/src/polonius/dump.rs +++ b/compiler/rustc_borrowck/src/polonius/dump.rs @@ -12,9 +12,6 @@ use crate::polonius::{LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSe use crate::{BorrowckInferCtxt, RegionInferenceContext}; /// `-Zdump-mir=polonius` dumps MIR annotated with NLL and polonius specific information. -// Note: this currently duplicates most of NLL MIR, with some additions for the localized outlives -// constraints. This is ok for now as this dump will change in the near future to an HTML file to -// become more useful. pub(crate) fn dump_polonius_mir<'tcx>( infcx: &BorrowckInferCtxt<'tcx>, body: &Body<'tcx>, @@ -36,7 +33,7 @@ pub(crate) fn dump_polonius_mir<'tcx>( .expect("missing localized constraints with `-Zpolonius=next`"); let _: io::Result<()> = try { - let mut file = create_dump_file(tcx, "mir", false, "polonius", &0, body)?; + let mut file = create_dump_file(tcx, "html", false, "polonius", &0, body)?; emit_polonius_dump( tcx, body, @@ -61,9 +58,50 @@ fn emit_polonius_dump<'tcx>( closure_region_requirements: &Option>, out: &mut dyn io::Write, ) -> io::Result<()> { - // We want the NLL extra comments printed by default in NLL MIR dumps (they were removed in - // #112346). Specifying `-Z mir-include-spans` on the CLI still has priority: for example, - // they're always disabled in mir-opt tests to make working with blessed dumps easier. + // Prepare the HTML dump file prologue. + writeln!(out, "")?; + writeln!(out, "")?; + writeln!(out, "Polonius MIR dump")?; + writeln!(out, "")?; + + // Section 1: the NLL + Polonius MIR. + writeln!(out, "
")?; + writeln!(out, "Raw MIR dump")?; + writeln!(out, "
")?;
+    emit_html_mir(
+        tcx,
+        body,
+        regioncx,
+        borrow_set,
+        localized_outlives_constraints,
+        closure_region_requirements,
+        out,
+    )?;
+    writeln!(out, "
")?; + writeln!(out, "
")?; + + // Finalize the dump with the HTML epilogue. + writeln!(out, "")?; + writeln!(out, "")?; + + Ok(()) +} + +/// Emits the polonius MIR, as escaped HTML. +fn emit_html_mir<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + regioncx: &RegionInferenceContext<'tcx>, + borrow_set: &BorrowSet<'tcx>, + localized_outlives_constraints: LocalizedOutlivesConstraintSet, + closure_region_requirements: &Option>, + out: &mut dyn io::Write, +) -> io::Result<()> { + // Buffer the regular MIR dump to be able to escape it. + let mut buffer = Vec::new(); + + // We want the NLL extra comments printed by default in NLL MIR dumps. Specifying `-Z + // mir-include-spans` on the CLI still has priority. let options = PrettyPrintMirOptions { include_extra_comments: matches!( tcx.sess.opts.unstable_opts.mir_include_spans, @@ -76,7 +114,7 @@ fn emit_polonius_dump<'tcx>( "polonius", &0, body, - out, + &mut buffer, |pass_where, out| { emit_polonius_mir( tcx, @@ -89,7 +127,27 @@ fn emit_polonius_dump<'tcx>( ) }, options, - ) + )?; + + // Escape the handful of characters that need it. We don't need to be particularly efficient: + // we're actually writing into a buffered writer already. Note that MIR dumps are valid UTF-8. + let buffer = String::from_utf8_lossy(&buffer); + for ch in buffer.chars() { + let escaped = match ch { + '>' => ">", + '<' => "<", + '&' => "&", + '\'' => "'", + '"' => """, + _ => { + // The common case, no escaping needed. + write!(out, "{}", ch)?; + continue; + } + }; + write!(out, "{}", escaped)?; + } + Ok(()) } /// Produces the actual NLL + Polonius MIR sections to emit during the dumping process. From 82c016846e0675df214f55be02d444037b322423 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Fri, 24 Jan 2025 22:04:18 +0000 Subject: [PATCH 20/21] fix terminator edges comments --- compiler/rustc_middle/src/mir/terminator.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 473b817aed076..c04a8251fbc5e 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -581,9 +581,11 @@ impl<'tcx> TerminatorKind<'tcx> { pub enum TerminatorEdges<'mir, 'tcx> { /// For terminators that have no successor, like `return`. None, - /// For terminators that a single successor, like `goto`, and `assert` without cleanup block. + /// For terminators that have a single successor, like `goto`, and `assert` without a cleanup + /// block. Single(BasicBlock), - /// For terminators that two successors, `assert` with cleanup block and `falseEdge`. + /// For terminators that have two successors, like `assert` with a cleanup block, and + /// `falseEdge`. Double(BasicBlock, BasicBlock), /// Special action for `Yield`, `Call` and `InlineAsm` terminators. AssignOnReturn { From 09fb70afb9dc64278f13be78e2f740fdc3c4d80e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Fri, 24 Jan 2025 22:04:37 +0000 Subject: [PATCH 21/21] add CFG to polonius MIR dump --- compiler/rustc_borrowck/src/polonius/dump.rs | 73 +++++++++++++++++++- 1 file changed, 71 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_borrowck/src/polonius/dump.rs b/compiler/rustc_borrowck/src/polonius/dump.rs index 25191fd349795..40e801d03885c 100644 --- a/compiler/rustc_borrowck/src/polonius/dump.rs +++ b/compiler/rustc_borrowck/src/polonius/dump.rs @@ -1,9 +1,9 @@ use std::io; use rustc_middle::mir::pretty::{ - PrettyPrintMirOptions, create_dump_file, dump_enabled, dump_mir_to_writer, + PassWhere, PrettyPrintMirOptions, create_dump_file, dump_enabled, dump_mir_to_writer, }; -use rustc_middle::mir::{Body, ClosureRegionRequirements, PassWhere}; +use rustc_middle::mir::{Body, ClosureRegionRequirements}; use rustc_middle::ty::TyCtxt; use rustc_session::config::MirIncludeSpans; @@ -49,6 +49,7 @@ pub(crate) fn dump_polonius_mir<'tcx>( /// The polonius dump consists of: /// - the NLL MIR /// - the list of polonius localized constraints +/// - a mermaid graph of the CFG fn emit_polonius_dump<'tcx>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, @@ -80,7 +81,23 @@ fn emit_polonius_dump<'tcx>( writeln!(out, "")?; writeln!(out, "")?; + // Section 2: mermaid visualization of the CFG. + writeln!(out, "
")?; + writeln!(out, "Control-flow graph")?; + writeln!(out, "
")?;
+    emit_mermaid_cfg(body, out)?;
+    writeln!(out, "
")?; + writeln!(out, "
")?; + // Finalize the dump with the HTML epilogue. + writeln!( + out, + "" + )?; + writeln!(out, "")?; writeln!(out, "")?; writeln!(out, "")?; @@ -192,3 +209,55 @@ fn emit_polonius_mir<'tcx>( Ok(()) } + +/// Emits a mermaid flowchart of the CFG blocks and edges, similar to the graphviz version. +fn emit_mermaid_cfg(body: &Body<'_>, out: &mut dyn io::Write) -> io::Result<()> { + use rustc_middle::mir::{TerminatorEdges, TerminatorKind}; + + // The mermaid chart type: a top-down flowchart. + writeln!(out, "flowchart TD")?; + + // Emit the block nodes. + for (block_idx, block) in body.basic_blocks.iter_enumerated() { + let block_idx = block_idx.as_usize(); + let cleanup = if block.is_cleanup { " (cleanup)" } else { "" }; + writeln!(out, "{block_idx}[\"bb{block_idx}{cleanup}\"]")?; + } + + // Emit the edges between blocks, from the terminator edges. + for (block_idx, block) in body.basic_blocks.iter_enumerated() { + let block_idx = block_idx.as_usize(); + let terminator = block.terminator(); + match terminator.edges() { + TerminatorEdges::None => {} + TerminatorEdges::Single(bb) => { + writeln!(out, "{block_idx} --> {}", bb.as_usize())?; + } + TerminatorEdges::Double(bb1, bb2) => { + if matches!(terminator.kind, TerminatorKind::FalseEdge { .. }) { + writeln!(out, "{block_idx} --> {}", bb1.as_usize())?; + writeln!(out, "{block_idx} -- imaginary --> {}", bb2.as_usize())?; + } else { + writeln!(out, "{block_idx} --> {}", bb1.as_usize())?; + writeln!(out, "{block_idx} -- unwind --> {}", bb2.as_usize())?; + } + } + TerminatorEdges::AssignOnReturn { return_, cleanup, .. } => { + for to_idx in return_ { + writeln!(out, "{block_idx} --> {}", to_idx.as_usize())?; + } + + if let Some(to_idx) = cleanup { + writeln!(out, "{block_idx} -- unwind --> {}", to_idx.as_usize())?; + } + } + TerminatorEdges::SwitchInt { targets, .. } => { + for to_idx in targets.all_targets() { + writeln!(out, "{block_idx} --> {}", to_idx.as_usize())?; + } + } + } + } + + Ok(()) +}