From 5479fe5f70bb32f037ff97de03ed185bdf2f54b7 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Thu, 8 Dec 2022 18:12:15 +0530 Subject: [PATCH 01/11] Add read_to_end for AnonPipe Add `read_to_end` method for `sys::{target}::pipe::AnonPipe`. This allows having a more optimized version of `read_to_end` for ChildStdout. Signed-off-by: Ayush Singh --- library/std/src/process.rs | 4 ++++ library/std/src/sys/unix/pipe.rs | 4 ++++ library/std/src/sys/unsupported/pipe.rs | 4 ++++ library/std/src/sys/windows/pipe.rs | 6 +++++- 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 400d25beb26f3..1ff7bba85d23a 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -362,6 +362,10 @@ impl Read for ChildStdout { fn is_read_vectored(&self) -> bool { self.inner.is_read_vectored() } + + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { + self.inner.read_to_end(buf) + } } impl AsInner for ChildStdout { diff --git a/library/std/src/sys/unix/pipe.rs b/library/std/src/sys/unix/pipe.rs index a56c275c94207..a744d0ab64043 100644 --- a/library/std/src/sys/unix/pipe.rs +++ b/library/std/src/sys/unix/pipe.rs @@ -58,6 +58,10 @@ impl AnonPipe { self.0.is_read_vectored() } + pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { + self.0.read_to_end(buf) + } + pub fn write(&self, buf: &[u8]) -> io::Result { self.0.write(buf) } diff --git a/library/std/src/sys/unsupported/pipe.rs b/library/std/src/sys/unsupported/pipe.rs index 25514c2322fa4..75ce75467963b 100644 --- a/library/std/src/sys/unsupported/pipe.rs +++ b/library/std/src/sys/unsupported/pipe.rs @@ -15,6 +15,10 @@ impl AnonPipe { self.0 } + pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { + self.0 + } + pub fn write(&self, _buf: &[u8]) -> io::Result { self.0 } diff --git a/library/std/src/sys/windows/pipe.rs b/library/std/src/sys/windows/pipe.rs index 9f26acc45205c..7b25edaa556f0 100644 --- a/library/std/src/sys/windows/pipe.rs +++ b/library/std/src/sys/windows/pipe.rs @@ -1,7 +1,7 @@ use crate::os::windows::prelude::*; use crate::ffi::OsStr; -use crate::io::{self, IoSlice, IoSliceMut}; +use crate::io::{self, IoSlice, IoSliceMut, Read}; use crate::mem; use crate::path::Path; use crate::ptr; @@ -261,6 +261,10 @@ impl AnonPipe { self.inner.is_read_vectored() } + pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { + self.handle().read_to_end(buf) + } + pub fn write(&self, buf: &[u8]) -> io::Result { unsafe { let len = crate::cmp::min(buf.len(), c::DWORD::MAX as usize) as c::DWORD; From a94793d8d17e4cfe2e727c30c36e174b8d6b6ee3 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Thu, 8 Dec 2022 18:22:33 +0530 Subject: [PATCH 02/11] Implement blocking output This allows decoupling `Command::spawn` and `Command::output`. This is useful for targets which do support launching programs in blocking mode but do not support multitasking (Eg: UEFI). This was originally conceived when working on https://github.com/rust-lang/rust/pull/100316 Signed-off-by: Ayush Singh --- library/std/src/process.rs | 6 ++-- .../src/sys/unix/process/process_fuchsia.rs | 5 +++ .../std/src/sys/unix/process/process_unix.rs | 5 +++ .../sys/unix/process/process_unsupported.rs | 4 +++ .../src/sys/unix/process/process_vxworks.rs | 5 +++ library/std/src/sys/unsupported/pipe.rs | 2 +- library/std/src/sys/unsupported/process.rs | 4 +++ library/std/src/sys/windows/process.rs | 5 +++ library/std/src/sys_common/process.rs | 31 ++++++++++++++++++- 9 files changed, 61 insertions(+), 6 deletions(-) diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 1ff7bba85d23a..17aff342c1599 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -911,10 +911,8 @@ impl Command { /// ``` #[stable(feature = "process", since = "1.0.0")] pub fn output(&mut self) -> io::Result { - self.inner - .spawn(imp::Stdio::MakePipe, false) - .map(Child::from_inner) - .and_then(|p| p.wait_with_output()) + let (status, stdout, stderr) = self.inner.output()?; + Ok(Output { status: ExitStatus(status), stdout, stderr }) } /// Executes a command as a child process, waiting for it to finish and diff --git a/library/std/src/sys/unix/process/process_fuchsia.rs b/library/std/src/sys/unix/process/process_fuchsia.rs index 66ea3db2015a4..4c99d758c93a3 100644 --- a/library/std/src/sys/unix/process/process_fuchsia.rs +++ b/library/std/src/sys/unix/process/process_fuchsia.rs @@ -35,6 +35,11 @@ impl Command { Ok((Process { handle: Handle::new(process_handle) }, ours)) } + pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { + let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?; + crate::sys_common::process::wait_with_output(proc, pipes) + } + pub fn exec(&mut self, default: Stdio) -> io::Error { if self.saw_nul() { return io::const_io_error!( diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 56a805cef7318..45616850a3719 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -132,6 +132,11 @@ impl Command { } } + pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { + let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?; + crate::sys_common::process::wait_with_output(proc, pipes) + } + // Attempts to fork the process. If successful, returns Ok((0, -1)) // in the child, and Ok((child_pid, -1)) in the parent. #[cfg(not(target_os = "linux"))] diff --git a/library/std/src/sys/unix/process/process_unsupported.rs b/library/std/src/sys/unix/process/process_unsupported.rs index 72f9f3f9ca74c..f28ca58d02038 100644 --- a/library/std/src/sys/unix/process/process_unsupported.rs +++ b/library/std/src/sys/unix/process/process_unsupported.rs @@ -20,6 +20,10 @@ impl Command { unsupported() } + pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { + unsupported() + } + pub fn exec(&mut self, _default: Stdio) -> io::Error { unsupported_err() } diff --git a/library/std/src/sys/unix/process/process_vxworks.rs b/library/std/src/sys/unix/process/process_vxworks.rs index 200ef67196798..f549d37c30116 100644 --- a/library/std/src/sys/unix/process/process_vxworks.rs +++ b/library/std/src/sys/unix/process/process_vxworks.rs @@ -108,6 +108,11 @@ impl Command { } } + pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { + let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?; + crate::sys_common::process::wait_with_output(proc, pipes) + } + pub fn exec(&mut self, default: Stdio) -> io::Error { let ret = Command::spawn(self, default, false); match ret { diff --git a/library/std/src/sys/unsupported/pipe.rs b/library/std/src/sys/unsupported/pipe.rs index 75ce75467963b..0bba673b458cb 100644 --- a/library/std/src/sys/unsupported/pipe.rs +++ b/library/std/src/sys/unsupported/pipe.rs @@ -15,7 +15,7 @@ impl AnonPipe { self.0 } - pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { + pub fn read_to_end(&self, _buf: &mut Vec) -> io::Result { self.0 } diff --git a/library/std/src/sys/unsupported/process.rs b/library/std/src/sys/unsupported/process.rs index 633f17c054bc6..a494f2d6b4c15 100644 --- a/library/std/src/sys/unsupported/process.rs +++ b/library/std/src/sys/unsupported/process.rs @@ -75,6 +75,10 @@ impl Command { ) -> io::Result<(Process, StdioPipes)> { unsupported() } + + pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { + unsupported() + } } impl From for Stdio { diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs index 31e9b34fb9efd..10bc949e1f45f 100644 --- a/library/std/src/sys/windows/process.rs +++ b/library/std/src/sys/windows/process.rs @@ -351,6 +351,11 @@ impl Command { )) } } + + pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { + let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?; + crate::sys_common::process::wait_with_output(proc, pipes) + } } impl fmt::Debug for Command { diff --git a/library/std/src/sys_common/process.rs b/library/std/src/sys_common/process.rs index 9f978789a6232..ae11412067b54 100644 --- a/library/std/src/sys_common/process.rs +++ b/library/std/src/sys_common/process.rs @@ -4,7 +4,9 @@ use crate::collections::BTreeMap; use crate::env; use crate::ffi::{OsStr, OsString}; -use crate::sys::process::EnvKey; +use crate::io; +use crate::sys::pipe::read2; +use crate::sys::process::{EnvKey, ExitStatus, Process, StdioPipes}; // Stores a set of changes to an environment #[derive(Clone, Debug)] @@ -117,3 +119,30 @@ impl<'a> ExactSizeIterator for CommandEnvs<'a> { self.iter.is_empty() } } + +pub fn wait_with_output( + mut process: Process, + mut pipes: StdioPipes, +) -> io::Result<(ExitStatus, Vec, Vec)> { + drop(pipes.stdin.take()); + + let (mut stdout, mut stderr) = (Vec::new(), Vec::new()); + match (pipes.stdout.take(), pipes.stderr.take()) { + (None, None) => {} + (Some(out), None) => { + let res = out.read_to_end(&mut stdout); + res.unwrap(); + } + (None, Some(err)) => { + let res = err.read_to_end(&mut stderr); + res.unwrap(); + } + (Some(out), Some(err)) => { + let res = read2(out, &mut stdout, err, &mut stderr); + res.unwrap(); + } + } + + let status = process.wait()?; + Ok((status, stdout, stderr)) +} From 23a34c18f7b2ce8b20fed717ef48e2be1776246b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Sun, 11 Dec 2022 12:19:17 +0100 Subject: [PATCH 03/11] bootstrap: Allow installing llvm-tools --- src/bootstrap/builder.rs | 1 + src/bootstrap/install.rs | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 8ee6d49da8f0e..3f551dc119b5d 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -744,6 +744,7 @@ impl<'a> Builder<'a> { install::RustDemangler, install::Clippy, install::Miri, + install::LlvmTools, install::Analysis, install::Src, install::Rustc diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index 7672b7c913594..c53d0d7e4cb7c 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -205,6 +205,12 @@ install!((self, builder, _config), .expect("missing miri"); install_sh(builder, "miri", self.compiler.stage, Some(self.target), &tarball); }; + LlvmTools, alias = "llvm-tools", Self::should_build(_config), only_hosts: true, { + let tarball = builder + .ensure(dist::LlvmTools { target: self.target }) + .expect("missing llvm-tools"); + install_sh(builder, "llvm-tools", self.compiler.stage, Some(self.target), &tarball); + }; Rustfmt, alias = "rustfmt", Self::should_build(_config), only_hosts: true, { if let Some(tarball) = builder.ensure(dist::Rustfmt { compiler: self.compiler, From f309934b5ee074a74229546d859252dd7e946b2d Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 16 Dec 2022 10:11:37 -0700 Subject: [PATCH 04/11] rustdoc: clean up margin CSS for scraped examples * This stops applying a margin to the additional example links. Because these links are `display: inline`, it doesn't actually do anything. * This switches from using a margin-bottom with a special exception for the examples themselves, plus an additional margin on the hide button, to instead using just margin-top on the examples, with an exception for the first one. No user-visible changes should result from this. --- src/librustdoc/html/static/css/rustdoc.css | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index a527e9feaec37..7b0e6439cfea9 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -2009,7 +2009,6 @@ in storage.js .more-examples-toggle .hide-more { margin-left: 25px; - margin-bottom: 5px; cursor: pointer; } @@ -2037,16 +2036,12 @@ in storage.js height: 100%; } -.more-scraped-examples .scraped-example { - margin-bottom: 20px; -} - -.more-scraped-examples .scraped-example:last-child { - margin-bottom: 0; +.more-scraped-examples .scraped-example, .example-links { + margin-top: 20px; } -.example-links a { - margin-top: 20px; +.more-scraped-examples .scraped-example:first-child { + margin-top: 5px; } .example-links ul { From fe528829866f08bac8cf6615085ec4609db352e9 Mon Sep 17 00:00:00 2001 From: Ezra Shaw Date: Fri, 16 Dec 2022 18:24:14 +1300 Subject: [PATCH 05/11] docs: add long error explanation for error E0320 --- compiler/rustc_error_codes/src/error_codes.rs | 2 +- .../src/error_codes/E0320.md | 27 +++++++++++++++++++ .../dropck_no_diverge_on_nonregular_1.stderr | 1 + .../dropck_no_diverge_on_nonregular_2.stderr | 1 + .../dropck_no_diverge_on_nonregular_3.stderr | 1 + ...-38591-non-regular-dropck-recursion.stderr | 1 + 6 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0320.md diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 31a709c36d4bc..67c512e98d68d 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -163,6 +163,7 @@ E0311: include_str!("./error_codes/E0311.md"), E0312: include_str!("./error_codes/E0312.md"), E0316: include_str!("./error_codes/E0316.md"), E0317: include_str!("./error_codes/E0317.md"), +E0320: include_str!("./error_codes/E0320.md"), E0321: include_str!("./error_codes/E0321.md"), E0322: include_str!("./error_codes/E0322.md"), E0323: include_str!("./error_codes/E0323.md"), @@ -575,7 +576,6 @@ E0791: include_str!("./error_codes/E0791.md"), // E0314, // closure outlives stack frame // E0315, // cannot invoke closure outside of its lifetime // E0319, // trait impls for defaulted traits allowed just for structs/enums - E0320, // recursive overflow during dropck // E0372, // coherence not object safe E0377, // the trait `CoerceUnsized` may only be implemented for a coercion // between structures with the same definition diff --git a/compiler/rustc_error_codes/src/error_codes/E0320.md b/compiler/rustc_error_codes/src/error_codes/E0320.md new file mode 100644 index 0000000000000..e6e1b7c19a566 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0320.md @@ -0,0 +1,27 @@ +Recursion limit reached while creating drop-check rules. + +Example of erroneous code: + +```compile_fail,E0320 +enum A { + B, + C(T, Box>) +} + +fn foo() { + A::::B; // error: overflow while adding drop-check rules for A +} +``` + +The Rust compiler must be able to reason about how a type is [`Drop`]ped, and +by extension the types of its fields, to be able to generate the glue to +properly drop a value. The code example above shows a type where this inference +is impossible because it is recursive. Note that this is *not* the same as +[E0072](E0072.html), where a type has an infinite size; the type here has a +finite size but any attempt to `Drop` it would recurse infinitely. For more +information, read [the `Drop` docs](../std/ops/trait.Drop.html). + +It is not possible to define a type with recursive drop-check rules. All such +recursion must be removed. + +[`Drop`]: ../std/ops/trait.Drop.html diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr index c447e2f7987cc..3e39d15f9b0cd 100644 --- a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr +++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr @@ -8,3 +8,4 @@ LL | let ft = error: aborting due to previous error +For more information about this error, try `rustc --explain E0320`. diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr index cd4706dd903f4..dbb7435447138 100644 --- a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr +++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr @@ -8,3 +8,4 @@ LL | let ft = error: aborting due to previous error +For more information about this error, try `rustc --explain E0320`. diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr index 18cd1b6cd413b..deaf116b647af 100644 --- a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr +++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr @@ -16,3 +16,4 @@ LL | Some(Wrapper::Simple::); error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0320`. diff --git a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr index 1da29be43db86..002dfe115b03f 100644 --- a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr +++ b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr @@ -8,3 +8,4 @@ LL | fn f(x: S) {} error: aborting due to previous error +For more information about this error, try `rustc --explain E0320`. From 3d849ae44c0eabea326bd8ccccc3a6ab702115ff Mon Sep 17 00:00:00 2001 From: Jakob Degen Date: Fri, 16 Dec 2022 19:41:40 -0800 Subject: [PATCH 06/11] Support call and drop terminators in custom mir --- .../src/build/custom/parse/instruction.rs | 49 ++++++++ library/core/src/intrinsics/mir.rs | 39 ++++++- ...terminators.assert_nonzero.built.after.mir | 17 +++ .../terminators.direct_call.built.after.mir | 16 +++ .../terminators.drop_first.built.after.mir | 13 +++ .../terminators.drop_second.built.after.mir | 13 +++ .../terminators.indirect_call.built.after.mir | 13 +++ .../mir-opt/building/custom/terminators.rs | 108 ++++++++++++++++++ 8 files changed, 266 insertions(+), 2 deletions(-) create mode 100644 src/test/mir-opt/building/custom/terminators.assert_nonzero.built.after.mir create mode 100644 src/test/mir-opt/building/custom/terminators.direct_call.built.after.mir create mode 100644 src/test/mir-opt/building/custom/terminators.drop_first.built.after.mir create mode 100644 src/test/mir-opt/building/custom/terminators.drop_second.built.after.mir create mode 100644 src/test/mir-opt/building/custom/terminators.indirect_call.built.after.mir create mode 100644 src/test/mir-opt/building/custom/terminators.rs diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index 2f26499a3b6e9..ecc3e4de8d1da 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -42,6 +42,29 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { @call("mir_goto", args) => { Ok(TerminatorKind::Goto { target: self.parse_block(args[0])? } ) }, + @call("mir_unreachable", _args) => { + Ok(TerminatorKind::Unreachable) + }, + @call("mir_drop", args) => { + Ok(TerminatorKind::Drop { + place: self.parse_place(args[0])?, + target: self.parse_block(args[1])?, + unwind: None, + }) + }, + @call("mir_drop_and_replace", args) => { + Ok(TerminatorKind::DropAndReplace { + place: self.parse_place(args[0])?, + value: self.parse_operand(args[1])?, + target: self.parse_block(args[2])?, + unwind: None, + }) + }, + @call("mir_call", args) => { + let destination = self.parse_place(args[0])?; + let target = self.parse_block(args[1])?; + self.parse_call(args[2], destination, target) + }, ExprKind::Match { scrutinee, arms } => { let discr = self.parse_operand(*scrutinee)?; self.parse_match(arms, expr.span).map(|t| TerminatorKind::SwitchInt { discr, targets: t }) @@ -86,6 +109,32 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { Ok(SwitchTargets::new(values.into_iter().zip(targets), otherwise)) } + fn parse_call( + &self, + expr_id: ExprId, + destination: Place<'tcx>, + target: BasicBlock, + ) -> PResult> { + parse_by_kind!(self, expr_id, _, "function call", + ExprKind::Call { fun, args, from_hir_call, fn_span, .. } => { + let fun = self.parse_operand(*fun)?; + let args = args + .iter() + .map(|arg| self.parse_operand(*arg)) + .collect::>>()?; + Ok(TerminatorKind::Call { + func: fun, + args, + destination, + target: Some(target), + cleanup: None, + from_hir_call: *from_hir_call, + fn_span: *fn_span, + }) + }, + ) + } + fn parse_rvalue(&self, expr_id: ExprId) -> PResult> { parse_by_kind!(self, expr_id, _, "rvalue", @call("mir_discriminant", args) => self.parse_place(args[0]).map(Rvalue::Discriminant), diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs index 0910ce599b7c0..e08a15571fcbe 100644 --- a/library/core/src/intrinsics/mir.rs +++ b/library/core/src/intrinsics/mir.rs @@ -44,7 +44,8 @@ //! if you want your MIR to be modified by the full MIR pipeline, or `#![custom_mir(dialect = //! "runtime", phase = "optimized")] if you don't. //! -//! [dialect docs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/enum.MirPhase.html +//! [dialect docs]: +//! https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/enum.MirPhase.html //! //! The input to the [`mir!`] macro is: //! @@ -99,6 +100,30 @@ //! Return() //! }) //! } +//! +//! #[custom_mir(dialect = "runtime", phase = "optimized")] +//! fn push_and_pop(v: &mut Vec, value: T) { +//! mir!( +//! let unused; +//! let popped; +//! +//! { +//! Call(unused, pop, Vec::push(v, value)) +//! } +//! +//! pop = { +//! Call(popped, drop, Vec::pop(v)) +//! } +//! +//! drop = { +//! Drop(popped, ret) +//! } +//! +//! ret = { +//! Return() +//! } +//! ) +//! } //! ``` //! //! We can also set off compilation failures that happen in sufficiently late stages of the @@ -195,10 +220,16 @@ //! //! #### Terminators //! -//! - [`Goto`] and [`Return`] have associated functions. +//! Custom MIR does not currently support cleanup blocks or non-trivial unwind paths. As such, there +//! are no resume and abort terminators, and terminators that might unwind do not have any way to +//! indicate the unwind block. +//! +//! - [`Goto`], [`Return`], [`Unreachable`], [`Drop`](Drop()), and [`DropAndReplace`] have associated functions. //! - `match some_int_operand` becomes a `SwitchInt`. Each arm should be `literal => basic_block` //! - The exception is the last arm, which must be `_ => basic_block` and corresponds to the //! otherwise branch. +//! - [`Call`] has an associated function as well. The third argument of this function is a normal +//! function call expresion, for example `my_other_function(a, 5)`. //! #![unstable( @@ -223,6 +254,10 @@ macro_rules! define { define!("mir_return", fn Return() -> BasicBlock); define!("mir_goto", fn Goto(destination: BasicBlock) -> BasicBlock); +define!("mir_unreachable", fn Unreachable() -> BasicBlock); +define!("mir_drop", fn Drop(place: T, goto: BasicBlock)); +define!("mir_drop_and_replace", fn DropAndReplace(place: T, value: T, goto: BasicBlock)); +define!("mir_call", fn Call(place: T, goto: BasicBlock, call: T)); define!("mir_retag", fn Retag(place: T)); define!("mir_retag_raw", fn RetagRaw(place: T)); define!("mir_move", fn Move(place: T) -> T); diff --git a/src/test/mir-opt/building/custom/terminators.assert_nonzero.built.after.mir b/src/test/mir-opt/building/custom/terminators.assert_nonzero.built.after.mir new file mode 100644 index 0000000000000..a1a27226b4e92 --- /dev/null +++ b/src/test/mir-opt/building/custom/terminators.assert_nonzero.built.after.mir @@ -0,0 +1,17 @@ +// MIR for `assert_nonzero` after built + +fn assert_nonzero(_1: i32) -> () { + let mut _0: (); // return place in scope 0 at $DIR/terminators.rs:+0:27: +0:27 + + bb0: { + switchInt(_1) -> [0: bb1, otherwise: bb2]; // scope 0 at $DIR/terminators.rs:+3:13: +6:14 + } + + bb1: { + unreachable; // scope 0 at $DIR/terminators.rs:+10:13: +10:26 + } + + bb2: { + return; // scope 0 at $DIR/terminators.rs:+14:13: +14:21 + } +} diff --git a/src/test/mir-opt/building/custom/terminators.direct_call.built.after.mir b/src/test/mir-opt/building/custom/terminators.direct_call.built.after.mir new file mode 100644 index 0000000000000..1b2345a965ed0 --- /dev/null +++ b/src/test/mir-opt/building/custom/terminators.direct_call.built.after.mir @@ -0,0 +1,16 @@ +// MIR for `direct_call` after built + +fn direct_call(_1: i32) -> i32 { + let mut _0: i32; // return place in scope 0 at $DIR/terminators.rs:+0:27: +0:30 + + bb0: { + _0 = ident::(_1) -> bb1; // scope 0 at $DIR/terminators.rs:+3:13: +3:42 + // mir::Constant + // + span: $DIR/terminators.rs:15:33: 15:38 + // + literal: Const { ty: fn(i32) -> i32 {ident::}, val: Value() } + } + + bb1: { + return; // scope 0 at $DIR/terminators.rs:+7:13: +7:21 + } +} diff --git a/src/test/mir-opt/building/custom/terminators.drop_first.built.after.mir b/src/test/mir-opt/building/custom/terminators.drop_first.built.after.mir new file mode 100644 index 0000000000000..c903e5946961b --- /dev/null +++ b/src/test/mir-opt/building/custom/terminators.drop_first.built.after.mir @@ -0,0 +1,13 @@ +// MIR for `drop_first` after built + +fn drop_first(_1: WriteOnDrop<'_>, _2: WriteOnDrop<'_>) -> () { + let mut _0: (); // return place in scope 0 at $DIR/terminators.rs:+0:59: +0:59 + + bb0: { + replace(_1 <- move _2) -> bb1; // scope 0 at $DIR/terminators.rs:+3:13: +3:49 + } + + bb1: { + return; // scope 0 at $DIR/terminators.rs:+7:13: +7:21 + } +} diff --git a/src/test/mir-opt/building/custom/terminators.drop_second.built.after.mir b/src/test/mir-opt/building/custom/terminators.drop_second.built.after.mir new file mode 100644 index 0000000000000..f14246f2d1206 --- /dev/null +++ b/src/test/mir-opt/building/custom/terminators.drop_second.built.after.mir @@ -0,0 +1,13 @@ +// MIR for `drop_second` after built + +fn drop_second(_1: WriteOnDrop<'_>, _2: WriteOnDrop<'_>) -> () { + let mut _0: (); // return place in scope 0 at $DIR/terminators.rs:+0:60: +0:60 + + bb0: { + drop(_2) -> bb1; // scope 0 at $DIR/terminators.rs:+3:13: +3:30 + } + + bb1: { + return; // scope 0 at $DIR/terminators.rs:+7:13: +7:21 + } +} diff --git a/src/test/mir-opt/building/custom/terminators.indirect_call.built.after.mir b/src/test/mir-opt/building/custom/terminators.indirect_call.built.after.mir new file mode 100644 index 0000000000000..2f1b14069abe0 --- /dev/null +++ b/src/test/mir-opt/building/custom/terminators.indirect_call.built.after.mir @@ -0,0 +1,13 @@ +// MIR for `indirect_call` after built + +fn indirect_call(_1: i32, _2: fn(i32) -> i32) -> i32 { + let mut _0: i32; // return place in scope 0 at $DIR/terminators.rs:+0:48: +0:51 + + bb0: { + _0 = _2(_1) -> bb1; // scope 0 at $DIR/terminators.rs:+3:13: +3:38 + } + + bb1: { + return; // scope 0 at $DIR/terminators.rs:+7:13: +7:21 + } +} diff --git a/src/test/mir-opt/building/custom/terminators.rs b/src/test/mir-opt/building/custom/terminators.rs new file mode 100644 index 0000000000000..c23233fcf9aca --- /dev/null +++ b/src/test/mir-opt/building/custom/terminators.rs @@ -0,0 +1,108 @@ +#![feature(custom_mir, core_intrinsics)] + +extern crate core; +use core::intrinsics::mir::*; + +fn ident(t: T) -> T { + t +} + +// EMIT_MIR terminators.direct_call.built.after.mir +#[custom_mir(dialect = "built")] +fn direct_call(x: i32) -> i32 { + mir!( + { + Call(RET, retblock, ident(x)) + } + + retblock = { + Return() + } + ) +} + +// EMIT_MIR terminators.indirect_call.built.after.mir +#[custom_mir(dialect = "built")] +fn indirect_call(x: i32, f: fn(i32) -> i32) -> i32 { + mir!( + { + Call(RET, retblock, f(x)) + } + + retblock = { + Return() + } + ) +} + +struct WriteOnDrop<'a>(&'a mut i32, i32); + +impl<'a> Drop for WriteOnDrop<'a> { + fn drop(&mut self) { + *self.0 = self.1; + } +} + +// EMIT_MIR terminators.drop_first.built.after.mir +#[custom_mir(dialect = "built")] +fn drop_first<'a>(a: WriteOnDrop<'a>, b: WriteOnDrop<'a>) { + mir!( + { + DropAndReplace(a, Move(b), retblock) + } + + retblock = { + Return() + } + ) +} + +// EMIT_MIR terminators.drop_second.built.after.mir +#[custom_mir(dialect = "built")] +fn drop_second<'a>(a: WriteOnDrop<'a>, b: WriteOnDrop<'a>) { + mir!( + { + Drop(b, retblock) + } + + retblock = { + Return() + } + ) +} + +// EMIT_MIR terminators.assert_nonzero.built.after.mir +#[custom_mir(dialect = "built")] +fn assert_nonzero(a: i32) { + mir!( + { + match a { + 0 => unreachable, + _ => retblock + } + } + + unreachable = { + Unreachable() + } + + retblock = { + Return() + } + ) +} + +fn main() { + assert_eq!(direct_call(5), 5); + assert_eq!(indirect_call(5, ident), 5); + + let mut a = 0; + let mut b = 0; + drop_first(WriteOnDrop(&mut a, 1), WriteOnDrop(&mut b, 1)); + assert_eq!((a, b), (1, 0)); + + let mut a = 0; + let mut b = 0; + drop_second(WriteOnDrop(&mut a, 1), WriteOnDrop(&mut b, 1)); + assert_eq!((a, b), (0, 1)); +} From f7bfc4879390117e850da74ad73eb9f9df588350 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Tue, 22 Nov 2022 00:25:43 +0100 Subject: [PATCH 07/11] optimize line-by-line style checks in tidy --- src/tools/tidy/src/style.rs | 59 ++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index e3a094caf919a..f91e38262f64f 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -17,7 +17,7 @@ //! `// ignore-tidy-CHECK-NAME`. use crate::walk::{filter_dirs, walk}; -use regex::Regex; +use regex::{Regex, RegexSet}; use std::path::Path; /// Error code markdown is restricted to 80 columns because they can be @@ -225,6 +225,7 @@ pub fn check(path: &Path, bad: &mut bool) { .chain(PROBLEMATIC_CONSTS.iter().map(|v| format!("{:x}", v))) .chain(PROBLEMATIC_CONSTS.iter().map(|v| format!("{:X}", v))) .collect(); + let problematic_regex = RegexSet::new(problematic_consts_strings.as_slice()).unwrap(); walk(path, &mut skip, &mut |entry, contents| { let file = entry.path(); let filename = file.file_name().unwrap().to_string_lossy(); @@ -281,7 +282,27 @@ pub fn check(path: &Path, bad: &mut bool) { let mut trailing_new_lines = 0; let mut lines = 0; let mut last_safety_comment = false; + let is_test = file.components().any(|c| c.as_os_str() == "tests"); + // scanning the whole file for multiple needles at once is more efficient than + // executing lines times needles separate searches. + let any_problematic_line = problematic_regex.is_match(contents); for (i, line) in contents.split('\n').enumerate() { + if line.is_empty() { + if i == 0 { + leading_new_lines = true; + } + trailing_new_lines += 1; + continue; + } else { + trailing_new_lines = 0; + } + + let trimmed = line.trim(); + + if !trimmed.starts_with("//") { + lines += 1; + } + let mut err = |msg: &str| { tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg); }; @@ -308,28 +329,29 @@ pub fn check(path: &Path, bad: &mut bool) { suppressible_tidy_err!(err, skip_cr, "CR character"); } if filename != "style.rs" { - if line.contains("TODO") { + if trimmed.contains("TODO") { err("TODO is deprecated; use FIXME") } - if line.contains("//") && line.contains(" XXX") { + if trimmed.contains("//") && trimmed.contains(" XXX") { err("XXX is deprecated; use FIXME") } - for s in problematic_consts_strings.iter() { - if line.contains(s) { - err("Don't use magic numbers that spell things (consider 0x12345678)"); + if any_problematic_line { + for s in problematic_consts_strings.iter() { + if trimmed.contains(s) { + err("Don't use magic numbers that spell things (consider 0x12345678)"); + } } } } - let is_test = || file.components().any(|c| c.as_os_str() == "tests"); // for now we just check libcore - if line.contains("unsafe {") && !line.trim().starts_with("//") && !last_safety_comment { - if file.components().any(|c| c.as_os_str() == "core") && !is_test() { + if trimmed.contains("unsafe {") && !trimmed.starts_with("//") && !last_safety_comment { + if file.components().any(|c| c.as_os_str() == "core") && !is_test { suppressible_tidy_err!(err, skip_undocumented_unsafe, "undocumented unsafe"); } } - if line.contains("// SAFETY:") { + if trimmed.contains("// SAFETY:") { last_safety_comment = true; - } else if line.trim().starts_with("//") || line.trim().is_empty() { + } else if trimmed.starts_with("//") || trimmed.is_empty() { // keep previous value } else { last_safety_comment = false; @@ -337,7 +359,8 @@ pub fn check(path: &Path, bad: &mut bool) { if (line.starts_with("// Copyright") || line.starts_with("# Copyright") || line.starts_with("Copyright")) - && (line.contains("Rust Developers") || line.contains("Rust Project Developers")) + && (trimmed.contains("Rust Developers") + || trimmed.contains("Rust Project Developers")) { suppressible_tidy_err!( err, @@ -351,18 +374,6 @@ pub fn check(path: &Path, bad: &mut bool) { if filename.ends_with(".cpp") && line.contains("llvm_unreachable") { err(LLVM_UNREACHABLE_INFO); } - if line.is_empty() { - if i == 0 { - leading_new_lines = true; - } - trailing_new_lines += 1; - } else { - trailing_new_lines = 0; - } - - if !line.trim().starts_with("//") { - lines += 1; - } } if leading_new_lines { let mut err = |_| { From 5620afc4e088beb299dfdcc3c3a903ac1f80cc9f Mon Sep 17 00:00:00 2001 From: The 8472 Date: Tue, 22 Nov 2022 00:30:05 +0100 Subject: [PATCH 08/11] poll tidy threads for completion before waiting --- src/tools/tidy/src/main.rs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index b0b11cafca5a8..6714c63ee62a1 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -35,15 +35,26 @@ fn main() { let bad = std::sync::Arc::new(AtomicBool::new(false)); + let drain_handles = |handles: &mut VecDeque>| { + // poll all threads for completion before awaiting the oldest one + for i in (0..handles.len()).rev() { + if handles[i].is_finished() { + handles.swap_remove_back(i).unwrap().join().unwrap(); + } + } + + while handles.len() >= concurrency.get() { + handles.pop_front().unwrap().join().unwrap(); + } + }; + scope(|s| { let mut handles: VecDeque> = VecDeque::with_capacity(concurrency.get()); macro_rules! check { ($p:ident $(, $args:expr)* ) => { - while handles.len() >= concurrency.get() { - handles.pop_front().unwrap().join().unwrap(); - } + drain_handles(&mut handles); let handle = s.spawn(|| { let mut flag = false; @@ -97,9 +108,8 @@ fn main() { check!(alphabetical, &library_path); let collected = { - while handles.len() >= concurrency.get() { - handles.pop_front().unwrap().join().unwrap(); - } + drain_handles(&mut handles); + let mut flag = false; let r = features::check(&src_path, &compiler_path, &library_path, &mut flag, verbose); if flag { From ab7d76965168f1104488549feaebd24ffa69b3b7 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Tue, 22 Nov 2022 00:38:50 +0100 Subject: [PATCH 09/11] poll rustfmt child processes --- src/bootstrap/format.rs | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/format.rs b/src/bootstrap/format.rs index 5e7264fe765a9..b2f6afead7980 100644 --- a/src/bootstrap/format.rs +++ b/src/bootstrap/format.rs @@ -8,7 +8,7 @@ use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; use std::sync::mpsc::SyncSender; -fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl FnMut() { +fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl FnMut(bool) -> bool { let mut cmd = Command::new(&rustfmt); // avoid the submodule config paths from coming into play, // we only allow a single global config for the workspace for now @@ -23,7 +23,13 @@ fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl F let cmd_debug = format!("{:?}", cmd); let mut cmd = cmd.spawn().expect("running rustfmt"); // poor man's async: return a closure that'll wait for rustfmt's completion - move || { + move |block: bool| -> bool { + if !block { + match cmd.try_wait() { + Ok(Some(_)) => {} + _ => return false, + } + } let status = cmd.wait().unwrap(); if !status.success() { eprintln!( @@ -34,6 +40,7 @@ fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl F ); crate::detail_exit(1); } + true } } @@ -146,15 +153,23 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) { let child = rustfmt(&src, &rustfmt_path, paths.as_slice(), check); children.push_back(child); + // poll completion before waiting + for i in (0..children.len()).rev() { + if children[i](false) { + children.swap_remove_back(i); + break; + } + } + if children.len() >= max_processes { // await oldest child - children.pop_front().unwrap()(); + children.pop_front().unwrap()(true); } } // await remaining children for mut child in children { - child(); + child(true); } }); From ab2151cbf8270be61db8add6bfb1aea03230803f Mon Sep 17 00:00:00 2001 From: Evan Jones Date: Sat, 17 Dec 2022 13:43:08 -0500 Subject: [PATCH 10/11] std::fmt: Use args directly in example code The lint "clippy::uninlined_format_args" recommends inline variables in format strings. Fix two places in the docs that do not do this. I noticed this because I copy/pasted one example in to my project, then noticed this lint error. This fixes: error: variables can be used directly in the `format!` string --> src/main.rs:30:22 | 30 | let string = format!("{:.*}", decimals, magnitude); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: variables can be used directly in the `format!` string --> src/main.rs:39:2 | 39 | write!(&mut io::stdout(), "{}", args).unwrap(); --- library/alloc/src/fmt.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs index 799ce9d5daa88..eadb35cb96d42 100644 --- a/library/alloc/src/fmt.rs +++ b/library/alloc/src/fmt.rs @@ -419,7 +419,7 @@ //! // documentation for details, and the function `pad` can be used //! // to pad strings. //! let decimals = f.precision().unwrap_or(3); -//! let string = format!("{:.*}", decimals, magnitude); +//! let string = format!("{magnitude:.decimals$}"); //! f.pad_integral(true, "", &string) //! } //! } @@ -518,7 +518,7 @@ //! write!(&mut some_writer, "{}", format_args!("print with a {}", "macro")); //! //! fn my_fmt_fn(args: fmt::Arguments) { -//! write!(&mut io::stdout(), "{}", args); +//! write!(&mut io::stdout(), "{args}"); //! } //! my_fmt_fn(format_args!(", or a {} too", "function")); //! ``` From 6f0fc2fd337757a02fa0d948e78638d66a46f518 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Thu, 24 Nov 2022 20:39:40 -0500 Subject: [PATCH 11/11] Symlink `build/host` -> `build/x86_64-unknown-linux-gnu` (as appropriate per target) This allows us to use a consistent path in the documentation, without having to worry about which platform people are using. --- src/bootstrap/lib.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 570fe6484e3db..f0c9a948727f0 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -108,6 +108,7 @@ use std::collections::{HashMap, HashSet}; use std::env; use std::fs::{self, File}; use std::io; +use std::io::ErrorKind; use std::path::{Path, PathBuf}; use std::process::Command; use std::str; @@ -119,7 +120,9 @@ use once_cell::sync::OnceCell; use crate::builder::Kind; use crate::config::{LlvmLibunwind, TargetSelection}; -use crate::util::{exe, libdir, mtime, output, run, run_suppressed, try_run_suppressed, CiEnv}; +use crate::util::{ + exe, libdir, mtime, output, run, run_suppressed, symlink_dir, try_run_suppressed, CiEnv, +}; mod bolt; mod builder; @@ -586,6 +589,20 @@ impl Build { metadata::build(&mut build); } + // Make a symbolic link so we can use a consistent directory in the documentation. + let build_triple = build.out.join(&build.build.triple); + let host = build.out.join("host"); + if let Err(e) = symlink_dir(&build.config, &build_triple, &host) { + if e.kind() != ErrorKind::AlreadyExists { + panic!( + "symlink_dir({} => {}) failed with {}", + host.display(), + build_triple.display(), + e + ); + } + } + build }