Auto merge of #105849 - matthiaskrgr:rollup-ya4s1n2, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - #104854 (Symlink `build/host` -> `build/$HOST_TRIPLE`) - #105458 (Allow blocking `Command::output`) - #105559 (bootstrap: Allow installing `llvm-tools`) - #105789 (rustdoc: clean up margin CSS for scraped examples) - #105792 (docs: add long error explanation for error E0320) - #105814 (Support call and drop terminators in custom mir) - #105829 (Speed up tidy) - #105836 (std::fmt: Use args directly in example code) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
24368ecdc4
@ -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
|
||||
|
27
compiler/rustc_error_codes/src/error_codes/E0320.md
Normal file
27
compiler/rustc_error_codes/src/error_codes/E0320.md
Normal file
@ -0,0 +1,27 @@
|
||||
Recursion limit reached while creating drop-check rules.
|
||||
|
||||
Example of erroneous code:
|
||||
|
||||
```compile_fail,E0320
|
||||
enum A<T> {
|
||||
B,
|
||||
C(T, Box<A<(T, T)>>)
|
||||
}
|
||||
|
||||
fn foo<T>() {
|
||||
A::<T>::B; // error: overflow while adding drop-check rules for A<T>
|
||||
}
|
||||
```
|
||||
|
||||
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
|
@ -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<TerminatorKind<'tcx>> {
|
||||
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::<PResult<Vec<_>>>()?;
|
||||
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<Rvalue<'tcx>> {
|
||||
parse_by_kind!(self, expr_id, _, "rvalue",
|
||||
@call("mir_discriminant", args) => self.parse_place(args[0]).map(Rvalue::Discriminant),
|
||||
|
@ -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"));
|
||||
//! ```
|
||||
|
@ -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<T>(v: &mut Vec<T>, 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<T>(place: T, goto: BasicBlock));
|
||||
define!("mir_drop_and_replace", fn DropAndReplace<T>(place: T, value: T, goto: BasicBlock));
|
||||
define!("mir_call", fn Call<T>(place: T, goto: BasicBlock, call: T));
|
||||
define!("mir_retag", fn Retag<T>(place: T));
|
||||
define!("mir_retag_raw", fn RetagRaw<T>(place: T));
|
||||
define!("mir_move", fn Move<T>(place: T) -> T);
|
||||
|
@ -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<u8>) -> io::Result<usize> {
|
||||
self.inner.read_to_end(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<AnonPipe> for ChildStdout {
|
||||
@ -907,10 +911,8 @@ impl Command {
|
||||
/// ```
|
||||
#[stable(feature = "process", since = "1.0.0")]
|
||||
pub fn output(&mut self) -> io::Result<Output> {
|
||||
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
|
||||
|
@ -58,6 +58,10 @@ impl AnonPipe {
|
||||
self.0.is_read_vectored()
|
||||
}
|
||||
|
||||
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
self.0.read_to_end(buf)
|
||||
}
|
||||
|
||||
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.0.write(buf)
|
||||
}
|
||||
|
@ -35,6 +35,11 @@ impl Command {
|
||||
Ok((Process { handle: Handle::new(process_handle) }, ours))
|
||||
}
|
||||
|
||||
pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
|
||||
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!(
|
||||
|
@ -133,6 +133,11 @@ impl Command {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
|
||||
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"))]
|
||||
|
@ -20,6 +20,10 @@ impl Command {
|
||||
unsupported()
|
||||
}
|
||||
|
||||
pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
|
||||
unsupported()
|
||||
}
|
||||
|
||||
pub fn exec(&mut self, _default: Stdio) -> io::Error {
|
||||
unsupported_err()
|
||||
}
|
||||
|
@ -108,6 +108,11 @@ impl Command {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
|
||||
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 {
|
||||
|
@ -15,6 +15,10 @@ impl AnonPipe {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn read_to_end(&self, _buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
|
||||
self.0
|
||||
}
|
||||
|
@ -75,6 +75,10 @@ impl Command {
|
||||
) -> io::Result<(Process, StdioPipes)> {
|
||||
unsupported()
|
||||
}
|
||||
|
||||
pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
|
||||
unsupported()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AnonPipe> for Stdio {
|
||||
|
@ -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<u8>) -> io::Result<usize> {
|
||||
self.handle().read_to_end(buf)
|
||||
}
|
||||
|
||||
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let len = crate::cmp::min(buf.len(), c::DWORD::MAX as usize) as c::DWORD;
|
||||
|
@ -351,6 +351,11 @@ impl Command {
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
|
||||
let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?;
|
||||
crate::sys_common::process::wait_with_output(proc, pipes)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Command {
|
||||
|
@ -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<u8>, Vec<u8>)> {
|
||||
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))
|
||||
}
|
||||
|
@ -744,6 +744,7 @@ impl<'a> Builder<'a> {
|
||||
install::RustDemangler,
|
||||
install::Clippy,
|
||||
install::Miri,
|
||||
install::LlvmTools,
|
||||
install::Analysis,
|
||||
install::Src,
|
||||
install::Rustc
|
||||
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -2003,7 +2003,6 @@ in storage.js
|
||||
|
||||
.more-examples-toggle .hide-more {
|
||||
margin-left: 25px;
|
||||
margin-bottom: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@ -2031,18 +2030,14 @@ in storage.js
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.more-scraped-examples .scraped-example {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.more-scraped-examples .scraped-example:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.example-links a {
|
||||
.more-scraped-examples .scraped-example, .example-links {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.more-scraped-examples .scraped-example:first-child {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.example-links ul {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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::<i32>(_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::<i32>}, val: Value(<ZST>) }
|
||||
}
|
||||
|
||||
bb1: {
|
||||
return; // scope 0 at $DIR/terminators.rs:+7:13: +7:21
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
108
src/test/mir-opt/building/custom/terminators.rs
Normal file
108
src/test/mir-opt/building/custom/terminators.rs
Normal file
@ -0,0 +1,108 @@
|
||||
#![feature(custom_mir, core_intrinsics)]
|
||||
|
||||
extern crate core;
|
||||
use core::intrinsics::mir::*;
|
||||
|
||||
fn ident<T>(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));
|
||||
}
|
@ -8,3 +8,4 @@ LL | let ft =
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0320`.
|
||||
|
@ -8,3 +8,4 @@ LL | let ft =
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0320`.
|
||||
|
@ -16,3 +16,4 @@ LL | Some(Wrapper::Simple::<u32>);
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0320`.
|
||||
|
@ -8,3 +8,4 @@ LL | fn f(x: S<u32>) {}
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0320`.
|
||||
|
@ -35,15 +35,26 @@ fn main() {
|
||||
|
||||
let bad = std::sync::Arc::new(AtomicBool::new(false));
|
||||
|
||||
let drain_handles = |handles: &mut VecDeque<ScopedJoinHandle<'_, ()>>| {
|
||||
// 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<ScopedJoinHandle<'_, ()>> =
|
||||
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 {
|
||||
|
@ -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 = |_| {
|
||||
|
Loading…
x
Reference in New Issue
Block a user