From 7e3c51d085d9eaa2204cc18763bc7d98b66435fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Thu, 16 Jan 2020 00:00:00 +0000 Subject: [PATCH 1/9] Instrument C / C++ in MemorySanitizer example Modify the example to instrument C / C++ in addition to Rust, since it will be generally required (e.g., when using libbacktrace for symbolication). Additionally use rustc specific flag to track the origins of unitialized memory rather than LLVM one. --- .../unstable-book/src/compiler-flags/sanitizer.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md index cbb90bd3bb331..c799374354b3e 100644 --- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md +++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md @@ -96,7 +96,7 @@ Shadow byte legend (one shadow byte represents 8 application bytes): ## MemorySanitizer Use of uninitialized memory. Note that we are using `-Zbuild-std` to instrument -standard library, and passing `-msan-track-origins=2` to the LLVM to track +the standard library, and passing `-Zsanitizer-track-origins` to track the origins of uninitialized memory: ```shell @@ -111,7 +111,15 @@ fn main() { } } -$ env RUSTFLAGS="-Zsanitizer=memory -Cllvm-args=-msan-track-origins=2" cargo -Zbuild-std run --target x86_64-unknown-linux-gnu +$ export \ + CC=clang \ + CXX=clang++ \ + CFLAGS='-fsanitize=memory -fsanitize-memory-track-origins' \ + CXXFLAGS='-fsanitize=memory -fsanitize-memory-track-origins' \ + RUSTFLAGS='-Zsanitizer=memory -Zsanitizer-memory-track-origins' \ + RUSTDOCFLAGS='-Zsanitizer=memory -Zsanitizer-memory-track-origins' +$ cargo clean +$ cargo -Zbuild-std run --target x86_64-unknown-linux-gnu ==9416==WARNING: MemorySanitizer: use-of-uninitialized-value #0 0x560c04f7488a in core::fmt::num::imp::fmt_u64::haa293b0b098501ca $RUST/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/src/rust/src/libcore/fmt/num.rs:202:16 ... From 276734d6a4997088b6d2e7416f5d4c07b4c8acf5 Mon Sep 17 00:00:00 2001 From: David Ross Date: Sat, 1 Feb 2020 18:04:07 -0800 Subject: [PATCH 2/9] Fix 59191 This adds an explicit error for when macros replace the crate root with a non-module item. --- src/librustc_expand/expand.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index ea459064b0957..1aa4f11a13026 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -363,7 +363,15 @@ impl<'a, 'b> MacroExpander<'a, 'b> { krate.attrs = vec![]; krate.module = ast::Mod { inner: orig_mod_span, items: vec![], inline: true }; } - _ => unreachable!(), + Some(ast::Item { span, kind, .. }) => { + self.cx.span_fatal( + span, + &format!( + "expected crate top-level item to be a module after macro expansion, found a {}", + kind.descriptive_variant() + ), + ); + } }; self.cx.trace_macros_diag(); krate From 410114b9d243020482689a94f7b254600f4d819e Mon Sep 17 00:00:00 2001 From: David Ross Date: Sat, 1 Feb 2020 18:07:26 -0800 Subject: [PATCH 3/9] Add tests for issue 59191 --- src/test/ui/proc-macro/auxiliary/issue-59191.rs | 16 ++++++++++++++++ .../issue-59191-replace-root-with-fn.rs | 7 +++++++ .../issue-59191-replace-root-with-fn.stderr | 8 ++++++++ 3 files changed, 31 insertions(+) create mode 100644 src/test/ui/proc-macro/auxiliary/issue-59191.rs create mode 100644 src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs create mode 100644 src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr diff --git a/src/test/ui/proc-macro/auxiliary/issue-59191.rs b/src/test/ui/proc-macro/auxiliary/issue-59191.rs new file mode 100644 index 0000000000000..d9ee77067ecb7 --- /dev/null +++ b/src/test/ui/proc-macro/auxiliary/issue-59191.rs @@ -0,0 +1,16 @@ +// edition:2018 +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn no_main(_attrs: TokenStream, _input: TokenStream) -> TokenStream { + let new_krate = r#" + fn main() {} + "#; + new_krate.parse().unwrap() +} diff --git a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs new file mode 100644 index 0000000000000..039878af56eb6 --- /dev/null +++ b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs @@ -0,0 +1,7 @@ +// edition:2018 +// aux-crate:issue_59191=issue-59191.rs +// Test that using a macro to replace the entire crate tree with a non-'mod' item errors out nicely. +// `issue_59191::no_main` replaces whatever's passed in with `fn main() {}`. +#![feature(custom_inner_attributes)] +#![issue_59191::no_main] +//~^ ERROR expected crate top-level item to be a module after macro expansion, found a function diff --git a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr new file mode 100644 index 0000000000000..1bda86551d418 --- /dev/null +++ b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr @@ -0,0 +1,8 @@ +error: expected crate top-level item to be a module after macro expansion, found a function + --> $DIR/issue-59191-replace-root-with-fn.rs:6:1 + | +LL | #![issue_59191::no_main] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + From 152811d8bf389fce7328ba7bc50c26c34afb0d81 Mon Sep 17 00:00:00 2001 From: David Date: Sun, 2 Feb 2020 11:28:32 -0800 Subject: [PATCH 4/9] Change expansion error to be non-fatal Changes the error handler for inner attributes that replace the root with a non-module. Previously it would emit a fatal error. It now emits an empty expasion and a non-fatal error like the existing handler for a failed expansion. --- src/librustc_expand/expand.rs | 4 +++- .../proc-macro/issue-59191-replace-root-with-fn.rs | 1 + .../issue-59191-replace-root-with-fn.stderr | 13 +++++++++++-- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index 1aa4f11a13026..4e0fec9ce1d1c 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -364,7 +364,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> { krate.module = ast::Mod { inner: orig_mod_span, items: vec![], inline: true }; } Some(ast::Item { span, kind, .. }) => { - self.cx.span_fatal( + krate.attrs = vec![]; + krate.module = ast::Mod { inner: orig_mod_span, items: vec![], inline: true }; + self.cx.span_err( span, &format!( "expected crate top-level item to be a module after macro expansion, found a {}", diff --git a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs index 039878af56eb6..a59cacb8bde1f 100644 --- a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs +++ b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs @@ -3,5 +3,6 @@ // Test that using a macro to replace the entire crate tree with a non-'mod' item errors out nicely. // `issue_59191::no_main` replaces whatever's passed in with `fn main() {}`. #![feature(custom_inner_attributes)] +//~^ ERROR `main` function not found in crate `issue_59191_replace_root_with_fn` [E0601] #![issue_59191::no_main] //~^ ERROR expected crate top-level item to be a module after macro expansion, found a function diff --git a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr index 1bda86551d418..e0a3caef9db88 100644 --- a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr +++ b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr @@ -1,8 +1,17 @@ error: expected crate top-level item to be a module after macro expansion, found a function - --> $DIR/issue-59191-replace-root-with-fn.rs:6:1 + --> $DIR/issue-59191-replace-root-with-fn.rs:7:1 | LL | #![issue_59191::no_main] | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error[E0601]: `main` function not found in crate `issue_59191_replace_root_with_fn` + --> $DIR/issue-59191-replace-root-with-fn.rs:5:1 + | +LL | / #![feature(custom_inner_attributes)] +LL | | +LL | | #![issue_59191::no_main] + | |________________________^ consider adding a `main` function to `$DIR/issue-59191-replace-root-with-fn.rs` + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0601`. From 5f979e9afab42dd7536ca93994de66169880361e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Mon, 3 Feb 2020 20:13:30 +0100 Subject: [PATCH 5/9] bootstrap: fix clippy warnings --- src/bootstrap/bin/rustc.rs | 6 +++--- src/bootstrap/bin/rustdoc.rs | 2 +- src/bootstrap/builder.rs | 24 ++++++++---------------- src/bootstrap/builder/tests.rs | 1 - src/bootstrap/compile.rs | 20 ++++++++++---------- src/bootstrap/config.rs | 7 +++---- src/bootstrap/dist.rs | 4 ++-- src/bootstrap/doc.rs | 2 +- src/bootstrap/flags.rs | 2 +- src/bootstrap/install.rs | 5 ++--- src/bootstrap/lib.rs | 6 +++--- src/bootstrap/metadata.rs | 1 - src/bootstrap/native.rs | 4 +--- src/bootstrap/test.rs | 9 +++------ src/bootstrap/tool.rs | 2 +- src/bootstrap/toolstate.rs | 2 +- src/bootstrap/util.rs | 2 +- 17 files changed, 41 insertions(+), 58 deletions(-) diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index a34ec44566bc1..a8c00c8c3ca88 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -47,7 +47,7 @@ fn main() { }; let stage = env::var("RUSTC_STAGE").expect("RUSTC_STAGE was not set"); let sysroot = env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set"); - let on_fail = env::var_os("RUSTC_ON_FAIL").map(|of| Command::new(of)); + let on_fail = env::var_os("RUSTC_ON_FAIL").map(Command::new); let rustc = env::var_os(rustc).unwrap_or_else(|| panic!("{:?} was not set", rustc)); let libdir = env::var_os(libdir).unwrap_or_else(|| panic!("{:?} was not set", libdir)); @@ -64,7 +64,7 @@ fn main() { if let Some(crate_name) = crate_name { if let Some(target) = env::var_os("RUSTC_TIME") { if target == "all" - || target.into_string().unwrap().split(",").any(|c| c.trim() == crate_name) + || target.into_string().unwrap().split(',').any(|c| c.trim() == crate_name) { cmd.arg("-Ztime"); } @@ -189,7 +189,7 @@ fn main() { crate_name, is_test, dur.as_secs(), - dur.subsec_nanos() / 1_000_000 + dur.subsec_millis() ); match status.code() { diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs index 8c8b33a4e4e0a..04345867bf5c1 100644 --- a/src/bootstrap/bin/rustdoc.rs +++ b/src/bootstrap/bin/rustdoc.rs @@ -61,7 +61,7 @@ fn main() { } // Needed to be able to run all rustdoc tests. - if let Some(_) = env::var_os("RUSTDOC_GENERATE_REDIRECT_PAGES") { + if env::var_os("RUSTDOC_GENERATE_REDIRECT_PAGES").is_some() { // This "unstable-options" can be removed when `--generate-redirect-pages` is stabilized if !has_unstable { cmd.arg("-Z").arg("unstable-options"); diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index d9c894aa9c6b1..18f6fda760846 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -510,7 +510,7 @@ impl<'a> Builder<'a> { Subcommand::Format { .. } | Subcommand::Clean { .. } => panic!(), }; - let builder = Builder { + Builder { build, top_stage: build.config.stage.unwrap_or(2), kind, @@ -518,9 +518,7 @@ impl<'a> Builder<'a> { stack: RefCell::new(Vec::new()), time_spent_on_dependencies: Cell::new(Duration::new(0, 0)), paths: paths.to_owned(), - }; - - builder + } } pub fn execute_cli(&self) { @@ -753,13 +751,12 @@ impl<'a> Builder<'a> { cargo.env("RUST_CHECK", "1"); } - let stage; - if compiler.stage == 0 && self.local_rebuild { + let stage = if compiler.stage == 0 && self.local_rebuild { // Assume the local-rebuild rustc already has stage1 features. - stage = 1; + 1 } else { - stage = compiler.stage; - } + compiler.stage + }; let mut rustflags = Rustflags::new(&target); if stage != 0 { @@ -1252,12 +1249,7 @@ impl<'a> Builder<'a> { }; if self.config.print_step_timings && dur > Duration::from_millis(100) { - println!( - "[TIMING] {:?} -- {}.{:03}", - step, - dur.as_secs(), - dur.subsec_nanos() / 1_000_000 - ); + println!("[TIMING] {:?} -- {}.{:03}", step, dur.as_secs(), dur.subsec_millis()); } { @@ -1302,7 +1294,7 @@ impl Rustflags { fn arg(&mut self, arg: &str) -> &mut Self { assert_eq!(arg.split_whitespace().count(), 1); - if self.0.len() > 0 { + if !self.0.is_empty() { self.0.push_str(" "); } self.0.push_str(arg); diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index 5fefb972866a9..cca8ab80c93b1 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -19,7 +19,6 @@ fn configure(host: &[&str], target: &[&str]) -> Config { config.out = dir; config.build = INTERNER.intern_str("A"); config.hosts = vec![config.build] - .clone() .into_iter() .chain(host.iter().map(|s| INTERNER.intern_str(s))) .collect::>(); diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index eced03506ab9f..7dded96e18efd 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -18,7 +18,6 @@ use std::str; use build_helper::{output, t, up_to_date}; use filetime::FileTime; use serde::Deserialize; -use serde_json; use crate::builder::Cargo; use crate::dist; @@ -149,7 +148,8 @@ fn copy_third_party_objects( // which is provided by std for this target. if target == "x86_64-fortanix-unknown-sgx" { let src_path_env = "X86_FORTANIX_SGX_LIBS"; - let src = env::var(src_path_env).expect(&format!("{} not found in env", src_path_env)); + let src = + env::var(src_path_env).unwrap_or_else(|_| panic!("{} not found in env", src_path_env)); copy_and_stamp(Path::new(&src), "libunwind.a"); } @@ -361,7 +361,7 @@ impl Step for StartupObjects { ); } - let target = sysroot_dir.join(file.to_string() + ".o"); + let target = sysroot_dir.join((*file).to_string() + ".o"); builder.copy(dst_file, &target); target_deps.push(target); } @@ -515,7 +515,7 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: Interne .env("CFG_VERSION", builder.rust_version()) .env("CFG_PREFIX", builder.config.prefix.clone().unwrap_or_default()); - let libdir_relative = builder.config.libdir_relative().unwrap_or(Path::new("lib")); + let libdir_relative = builder.config.libdir_relative().unwrap_or_else(|| Path::new("lib")); cargo.env("CFG_LIBDIR_RELATIVE", libdir_relative); if let Some(ref ver_date) = builder.rust_info.commit_date() { @@ -843,11 +843,11 @@ pub fn run_cargo( }; for filename in filenames { // Skip files like executables - if !filename.ends_with(".rlib") - && !filename.ends_with(".lib") - && !filename.ends_with(".a") - && !is_dylib(&filename) - && !(is_check && filename.ends_with(".rmeta")) + if !(filename.ends_with(".rlib") + || filename.ends_with(".lib") + || filename.ends_with(".a") + || is_dylib(&filename) + || (is_check && filename.ends_with(".rmeta"))) { continue; } @@ -905,7 +905,7 @@ pub fn run_cargo( for (prefix, extension, expected_len) in toplevel { let candidates = contents.iter().filter(|&&(_, ref filename, ref meta)| { filename.starts_with(&prefix[..]) - && filename[prefix.len()..].starts_with("-") + && filename[prefix.len()..].starts_with('-') && filename.ends_with(&extension[..]) && meta.len() == expected_len }); diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 110c8b844d54c..709cf2908eadf 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -16,7 +16,6 @@ use crate::flags::Flags; pub use crate::flags::Subcommand; use build_helper::t; use serde::Deserialize; -use toml; /// Global configuration for the entire build and/or bootstrap. /// @@ -440,7 +439,7 @@ impl Config { } } }) - .unwrap_or_else(|| TomlConfig::default()); + .unwrap_or_else(TomlConfig::default); let build = toml.build.clone().unwrap_or_default(); // set by bootstrap.py @@ -539,7 +538,7 @@ impl Config { config.llvm_ldflags = llvm.ldflags.clone(); set(&mut config.llvm_use_libcxx, llvm.use_libcxx); config.llvm_use_linker = llvm.use_linker.clone(); - config.llvm_allow_old_toolchain = llvm.allow_old_toolchain.clone(); + config.llvm_allow_old_toolchain = llvm.allow_old_toolchain; } if let Some(ref rust) = toml.rust { @@ -606,7 +605,7 @@ impl Config { target.ar = cfg.ar.clone().map(PathBuf::from); target.ranlib = cfg.ranlib.clone().map(PathBuf::from); target.linker = cfg.linker.clone().map(PathBuf::from); - target.crt_static = cfg.crt_static.clone(); + target.crt_static = cfg.crt_static; target.musl_root = cfg.musl_root.clone().map(PathBuf::from); target.wasi_root = cfg.wasi_root.clone().map(PathBuf::from); target.qemu_rootfs = cfg.qemu_rootfs.clone().map(PathBuf::from); diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 8d13df3ee21a4..651506dbaa8ab 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -827,7 +827,7 @@ impl Step for Analysis { assert!(builder.config.extended); let name = pkgname(builder, "rust-analysis"); - if &compiler.host != builder.config.build { + if compiler.host != builder.config.build { return distdir(builder).join(format!("{}-{}.tar.gz", name, target)); } @@ -876,7 +876,7 @@ fn copy_src_dirs(builder: &Builder<'_>, src_dirs: &[&str], exclude_dirs: &[&str] Some(path) => path, None => return false, }; - if spath.ends_with("~") || spath.ends_with(".pyc") { + if spath.ends_with('~') || spath.ends_with(".pyc") { return false; } diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 204056598d900..b0d9a5b94641c 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -560,7 +560,7 @@ impl Step for Rustdoc { builder.ensure(Rustc { stage, target }); // Build rustdoc. - builder.ensure(tool::Rustdoc { compiler: compiler }); + builder.ensure(tool::Rustdoc { compiler }); // Symlink compiler docs to the output directory of rustdoc documentation. let out_dir = builder.stage_out(compiler, Mode::ToolRustc).join(target).join("doc"); diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 2101ef27f9d42..516be6a30c235 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -571,7 +571,7 @@ fn split(s: &[String]) -> Vec { } fn parse_deny_warnings(matches: &getopts::Matches) -> Option { - match matches.opt_str("warnings").as_ref().map(|v| v.as_str()) { + match matches.opt_str("warnings").as_deref() { Some("deny") => Some(true), Some("warn") => Some(false), Some(value) => { diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index f8734ebdf4254..6549262811b9f 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -126,9 +126,8 @@ fn add_destdir(path: &Path, destdir: &Option) -> PathBuf { None => return path.to_path_buf(), }; for part in path.components() { - match part { - Component::Normal(s) => ret.push(s), - _ => {} + if let Component::Normal(s) = part { + ret.push(s) } } ret diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 1fee3fd9ac1d2..0db4fb3890100 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -444,7 +444,7 @@ impl Build { builder.execute_cli(); } else { let builder = builder::Builder::new(&self); - let _ = builder.execute_cli(); + builder.execute_cli(); } // Check for postponed failures from `test --no-fail-fast`. @@ -839,7 +839,7 @@ impl Build { .target_config .get(&target) .and_then(|t| t.musl_root.as_ref()) - .or(self.config.musl_root.as_ref()) + .or_else(|| self.config.musl_root.as_ref()) .map(|p| &**p) } @@ -1026,7 +1026,7 @@ impl Build { } fn llvm_link_tools_dynamically(&self, target: Interned) -> bool { - (target.contains("linux-gnu") || target.contains("apple-darwin")) + target.contains("linux-gnu") || target.contains("apple-darwin") } /// Returns the `version` string associated with this compiler for Rust diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/metadata.rs index 8a26adc7ed501..292aa3b1e24a7 100644 --- a/src/bootstrap/metadata.rs +++ b/src/bootstrap/metadata.rs @@ -5,7 +5,6 @@ use std::process::Command; use build_helper::output; use serde::Deserialize; -use serde_json; use crate::cache::INTERNER; use crate::{Build, Crate}; diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 5bbd9f47fc907..1cfb4b2f63b57 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -15,8 +15,6 @@ use std::path::{Path, PathBuf}; use std::process::Command; use build_helper::{output, t}; -use cc; -use cmake; use crate::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::cache::Interned; @@ -205,7 +203,7 @@ impl Step for Llvm { cfg.define("LLVM_ENABLE_LIBXML2", "OFF"); } - if enabled_llvm_projects.len() > 0 { + if !enabled_llvm_projects.is_empty() { enabled_llvm_projects.sort(); enabled_llvm_projects.dedup(); cfg.define("LLVM_ENABLE_PROJECTS", enabled_llvm_projects.join(";")); diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 6adf9ddaf3438..8d9e62010015b 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1424,13 +1424,10 @@ impl Step for ErrorIndex { } fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> bool { - match fs::read_to_string(markdown) { - Ok(contents) => { - if !contents.contains("```") { - return true; - } + if let Ok(contents) = fs::read_to_string(markdown) { + if !contents.contains("```") { + return true; } - Err(_) => {} } builder.info(&format!("doc tests for: {}", markdown.display())); diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 7f24768a4f10e..67e0ed5c58029 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -234,7 +234,7 @@ pub fn prepare_tool_cargo( cargo.env("RUSTC_EXTERNAL_TOOL", "1"); } - let mut features = extra_features.iter().cloned().collect::>(); + let mut features = extra_features.to_vec(); if builder.build.config.cargo_native_static { if path.ends_with("cargo") || path.ends_with("rls") diff --git a/src/bootstrap/toolstate.rs b/src/bootstrap/toolstate.rs index b068c8200acec..bb012a3885511 100644 --- a/src/bootstrap/toolstate.rs +++ b/src/bootstrap/toolstate.rs @@ -124,7 +124,7 @@ fn check_changed_files(toolstates: &HashMap, ToolState>) { let output = t!(String::from_utf8(output.stdout)); for (tool, submodule) in STABLE_TOOLS.iter().chain(NIGHTLY_TOOLS.iter()) { - let changed = output.lines().any(|l| l.starts_with("M") && l.ends_with(submodule)); + let changed = output.lines().any(|l| l.starts_with('M') && l.ends_with(submodule)); eprintln!("Verifying status of {}...", tool); if !changed { continue; diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 7d1efe4610f9c..eac790fe504b8 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -98,7 +98,7 @@ impl Drop for TimeIt { fn drop(&mut self) { let time = self.1.elapsed(); if !self.0 { - println!("\tfinished in {}.{:03}", time.as_secs(), time.subsec_nanos() / 1_000_000); + println!("\tfinished in {}.{:03}", time.as_secs(), time.subsec_millis()); } } } From 5f689fe466b6ed0d63e5d5f732804bb74c07b58d Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Mon, 3 Feb 2020 22:30:17 +0000 Subject: [PATCH 6/9] Remove Copy impl from OnceWith Iterators typically don't implement `Copy` and this shouldn't be an exception. --- src/libcore/iter/sources.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index 5a31acab273f1..a1d4e1b31e9b1 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -398,7 +398,7 @@ pub fn once(value: T) -> Once { /// See its documentation for more. /// /// [`once_with`]: fn.once_with.html -#[derive(Copy, Clone, Debug)] +#[derive(Clone, Debug)] #[stable(feature = "iter_once_with", since = "1.43.0")] pub struct OnceWith { gen: Option, From 697ef95c9f22376232e5dd60ab429fe4a31b6332 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Tue, 4 Feb 2020 01:05:45 +0100 Subject: [PATCH 7/9] remove redundant imports (clippy::single_component_path_imports) --- src/librustc/traits/mod.rs | 1 - src/librustc/traits/structural_impls.rs | 1 - src/librustc/ty/mod.rs | 1 - src/librustc_builtin_macros/log_syntax.rs | 1 - src/librustc_interface/callbacks.rs | 1 - src/librustc_interface/passes.rs | 4 ---- src/librustc_macros/src/lift.rs | 2 -- src/librustc_macros/src/query.rs | 1 - src/librustc_macros/src/symbols.rs | 1 - src/librustc_macros/src/type_foldable.rs | 2 -- src/librustc_passes/dead.rs | 1 - src/librustc_session/config.rs | 4 ---- src/librustc_session/options.rs | 2 -- src/librustc_session/session.rs | 1 - src/librustc_typeck/variance/mod.rs | 1 - src/librustdoc/clean/utils.rs | 1 - src/librustdoc/config.rs | 2 -- src/librustdoc/core.rs | 1 - src/librustdoc/html/render.rs | 2 -- src/librustdoc/markdown.rs | 1 - src/librustdoc/passes/collect_intra_doc_links.rs | 1 - src/librustdoc/test.rs | 1 - src/libtest/cli.rs | 1 - src/libtest/console.rs | 2 -- 24 files changed, 36 deletions(-) diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index daaba95cf6b13..b1b3d44044ebc 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -31,7 +31,6 @@ use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use crate::ty::subst::{InternalSubsts, SubstsRef}; use crate::ty::{self, AdtKind, GenericParamDefKind, List, ToPredicate, Ty, TyCtxt, WithConstness}; use crate::util::common::ErrorReported; -use chalk_engine; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 58204a460d7df..1db83c5bafac9 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -2,7 +2,6 @@ use crate::traits; use crate::traits::project::Normalized; use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use crate::ty::{self, Lift, Ty, TyCtxt}; -use chalk_engine; use rustc_span::symbol::Symbol; use smallvec::SmallVec; diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index f417b907a3811..ea29a718b23a3 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -46,7 +46,6 @@ use rustc_target::abi::Align; use syntax::ast::{self, Constness, Ident, Name}; use syntax::node_id::{NodeId, NodeMap, NodeSet}; -use smallvec; use std::cell::RefCell; use std::cmp::{self, Ordering}; use std::fmt; diff --git a/src/librustc_builtin_macros/log_syntax.rs b/src/librustc_builtin_macros/log_syntax.rs index 6d9bfbfd05f0a..ac7ba49ba185d 100644 --- a/src/librustc_builtin_macros/log_syntax.rs +++ b/src/librustc_builtin_macros/log_syntax.rs @@ -1,6 +1,5 @@ use rustc_ast_pretty::pprust; use rustc_expand::base; -use rustc_span; use syntax::tokenstream::TokenStream; pub fn expand_log_syntax<'cx>( diff --git a/src/librustc_interface/callbacks.rs b/src/librustc_interface/callbacks.rs index eb9c118bb0100..803e895857202 100644 --- a/src/librustc_interface/callbacks.rs +++ b/src/librustc_interface/callbacks.rs @@ -11,7 +11,6 @@ use rustc::ty::tls; use rustc_errors::{Diagnostic, TRACK_DIAGNOSTICS}; -use rustc_span; use std::fmt; /// This is a callback from libsyntax as it cannot access the implicit state diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 0be73e55e9c1d..bf8bcd71efa41 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -17,7 +17,6 @@ use rustc::traits; use rustc::ty::steal::Steal; use rustc::ty::{self, GlobalCtxt, ResolverOutputs, TyCtxt}; use rustc::util::common::ErrorReported; -use rustc_builtin_macros; use rustc_codegen_ssa::back::link::emit_metadata; use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc_codegen_utils::link::filename_for_metadata; @@ -26,18 +25,15 @@ use rustc_data_structures::{box_region_allow_access, declare_box_region_type, pa use rustc_errors::PResult; use rustc_expand::base::ExtCtxt; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; -use rustc_incremental; use rustc_lint::LintStore; use rustc_mir as mir; use rustc_mir_build as mir_build; use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str}; use rustc_passes::{self, hir_stats, layout_test}; use rustc_plugin_impl as plugin; -use rustc_privacy; use rustc_resolve::{Resolver, ResolverArenas}; use rustc_span::symbol::Symbol; use rustc_span::FileName; -use rustc_traits; use rustc_typeck as typeck; use syntax::mut_visit::MutVisitor; use syntax::{self, ast, visit}; diff --git a/src/librustc_macros/src/lift.rs b/src/librustc_macros/src/lift.rs index 1b91fc5018a23..a246b34b2c295 100644 --- a/src/librustc_macros/src/lift.rs +++ b/src/librustc_macros/src/lift.rs @@ -1,7 +1,5 @@ -use proc_macro2; use quote::quote; use syn::{self, parse_quote}; -use synstructure; pub fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { s.add_bounds(synstructure::AddBounds::Generics); diff --git a/src/librustc_macros/src/query.rs b/src/librustc_macros/src/query.rs index f680b0d64cded..6dc4f7f251595 100644 --- a/src/librustc_macros/src/query.rs +++ b/src/librustc_macros/src/query.rs @@ -2,7 +2,6 @@ use itertools::Itertools; use proc_macro::TokenStream; use proc_macro2::{Delimiter, TokenTree}; use quote::quote; -use syn; use syn::parse::{Parse, ParseStream, Result}; use syn::punctuated::Punctuated; use syn::spanned::Spanned; diff --git a/src/librustc_macros/src/symbols.rs b/src/librustc_macros/src/symbols.rs index c692c7f399541..feddcd5f99429 100644 --- a/src/librustc_macros/src/symbols.rs +++ b/src/librustc_macros/src/symbols.rs @@ -1,7 +1,6 @@ use proc_macro::TokenStream; use quote::quote; use std::collections::HashSet; -use syn; use syn::parse::{Parse, ParseStream, Result}; use syn::{braced, parse_macro_input, Ident, LitStr, Token}; diff --git a/src/librustc_macros/src/type_foldable.rs b/src/librustc_macros/src/type_foldable.rs index 3d58984a9009b..687401e33449b 100644 --- a/src/librustc_macros/src/type_foldable.rs +++ b/src/librustc_macros/src/type_foldable.rs @@ -1,6 +1,4 @@ use quote::quote; -use syn; -use synstructure; pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { if let syn::Data::Union(_) = s.ast().data { diff --git a/src/librustc_passes/dead.rs b/src/librustc_passes/dead.rs index 2ff9d744f2c4d..9367909d10c30 100644 --- a/src/librustc_passes/dead.rs +++ b/src/librustc_passes/dead.rs @@ -15,7 +15,6 @@ use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::{Node, PatKind, TyKind}; use rustc_session::lint; -use rustc_span; use rustc_span::symbol::sym; use syntax::{ast, attr}; diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs index 813d14d616d42..ad1a6c4906ea3 100644 --- a/src/librustc_session/config.rs +++ b/src/librustc_session/config.rs @@ -22,8 +22,6 @@ use rustc_span::symbol::{sym, Symbol}; use rustc_errors::emitter::HumanReadableErrorType; use rustc_errors::{ColorConfig, FatalError, Handler, HandlerFlags}; -use getopts; - use std::collections::btree_map::{ Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter, }; @@ -816,7 +814,6 @@ mod opt { #![allow(dead_code)] use super::RustcOptGroup; - use getopts; pub type R = RustcOptGroup; pub type S = &'static str; @@ -1862,7 +1859,6 @@ pub fn parse_crate_types_from_list(list_list: Vec) -> Result bool { diff --git a/src/librustc_session/options.rs b/src/librustc_session/options.rs index be0e668a467b2..d6b71641da52f 100644 --- a/src/librustc_session/options.rs +++ b/src/librustc_session/options.rs @@ -11,8 +11,6 @@ use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel use rustc_feature::UnstableFeatures; use rustc_span::edition::Edition; -use getopts; - use std::collections::BTreeMap; use std::collections::hash_map::DefaultHasher; diff --git a/src/librustc_session/session.rs b/src/librustc_session/session.rs index a40d6451b958c..f8cba58f9d904 100644 --- a/src/librustc_session/session.rs +++ b/src/librustc_session/session.rs @@ -33,7 +33,6 @@ use rustc_data_structures::jobserver::{self, Client}; use rustc_data_structures::profiling::{SelfProfiler, SelfProfilerRef}; use rustc_target::spec::{PanicStrategy, RelroLevel, Target, TargetTriple}; -use std; use std::cell::{self, RefCell}; use std::env; use std::fmt; diff --git a/src/librustc_typeck/variance/mod.rs b/src/librustc_typeck/variance/mod.rs index 27dc03bbbe206..32bd7e4c4c1d0 100644 --- a/src/librustc_typeck/variance/mod.rs +++ b/src/librustc_typeck/variance/mod.rs @@ -3,7 +3,6 @@ //! //! [rustc guide]: https://rust-lang.github.io/rustc-guide/variance.html -use arena; use hir::Node; use rustc::ty::query::Providers; use rustc::ty::{self, CrateVariancesMap, TyCtxt}; diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index e110545c6f27b..356660763a755 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -16,7 +16,6 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; -use rustc_span; use rustc_span::symbol::{kw, sym, Symbol}; use std::mem; diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 22f5d0dc2c078..1b776930d7a78 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -3,7 +3,6 @@ use std::ffi::OsStr; use std::fmt; use std::path::PathBuf; -use getopts; use rustc::lint::Level; use rustc::session; use rustc::session::config::{ @@ -13,7 +12,6 @@ use rustc::session::config::{ use rustc::session::config::{parse_crate_types_from_list, parse_externs, CrateType}; use rustc::session::config::{CodegenOptions, DebuggingOptions, ErrorOutputType, Externs}; use rustc::session::search_paths::SearchPath; -use rustc_driver; use rustc_span::edition::{Edition, DEFAULT_EDITION}; use rustc_target::spec::TargetTriple; diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index a8baa89c6f181..429988db9d843 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -11,7 +11,6 @@ use rustc_hir::def::Namespace::TypeNS; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE}; use rustc_hir::HirId; use rustc_interface::interface; -use rustc_lint; use rustc_resolve as resolve; use rustc_session::lint; diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index c670641394267..e2a0126a8fabb 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -73,8 +73,6 @@ use crate::html::markdown::{self, ErrorCodes, IdMap, Markdown, MarkdownHtml, Mar use crate::html::sources; use crate::html::{highlight, layout, static_files}; -use minifier; - #[cfg(test)] mod tests; diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 912a40722b8af..a37efc22c9305 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -5,7 +5,6 @@ use std::path::PathBuf; use rustc_feature::UnstableFeatures; use rustc_span::edition::Edition; use rustc_span::source_map::DUMMY_SP; -use testing; use crate::config::{Options, RenderOptions}; use crate::externalfiles::{load_string, LoadStringError}; diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 50d5f70f4889a..332d19fbfaeca 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -13,7 +13,6 @@ use rustc_hir::def_id::DefId; use rustc_resolve::ParentScope; use rustc_span::symbol::Symbol; use rustc_span::DUMMY_SP; -use syntax; use syntax::ast::{self, Ident}; use std::ops::Range; diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 936f63975a58e..2892c4b153790 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -20,7 +20,6 @@ use std::str; use syntax::ast; use syntax::with_globals; use tempfile::Builder as TempFileBuilder; -use testing; use crate::clean::Attributes; use crate::config::Options; diff --git a/src/libtest/cli.rs b/src/libtest/cli.rs index edff8bea0f3d0..778600b2196b7 100644 --- a/src/libtest/cli.rs +++ b/src/libtest/cli.rs @@ -1,6 +1,5 @@ //! Module converting command-line arguments into test configuration. -use getopts; use std::env; use std::path::PathBuf; diff --git a/src/libtest/console.rs b/src/libtest/console.rs index ebdfb16294759..149c9202e6e2d 100644 --- a/src/libtest/console.rs +++ b/src/libtest/console.rs @@ -4,8 +4,6 @@ use std::fs::File; use std::io; use std::io::prelude::Write; -use term; - use super::{ bench::fmt_bench_samples, cli::TestOpts, From fe1314dbc42da3331062c9348f7117b3585ad6bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Tue, 4 Feb 2020 02:28:11 +0100 Subject: [PATCH 8/9] fix couple of perf related clipyp warnings librustc: don't clone a type that is copy librustc_incremental: use faster vector initialization librustc_typeck: don't clone a type that is copy librustdoc: don't create a vector where a slice will do --- src/librustc/ty/mod.rs | 2 +- src/librustc_incremental/persist/file_format.rs | 3 +-- src/librustc_typeck/astconv.rs | 6 ++---- src/librustdoc/html/render.rs | 9 +-------- 4 files changed, 5 insertions(+), 15 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index f417b907a3811..9cfd64d638234 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1344,7 +1344,7 @@ pub trait ToPredicate<'tcx> { impl<'tcx> ToPredicate<'tcx> for ConstnessAnd> { fn to_predicate(&self) -> Predicate<'tcx> { ty::Predicate::Trait( - ty::Binder::dummy(ty::TraitPredicate { trait_ref: self.value.clone() }), + ty::Binder::dummy(ty::TraitPredicate { trait_ref: self.value }), self.constness, ) } diff --git a/src/librustc_incremental/persist/file_format.rs b/src/librustc_incremental/persist/file_format.rs index 7534b7e9ef429..5c72b049d97e9 100644 --- a/src/librustc_incremental/persist/file_format.rs +++ b/src/librustc_incremental/persist/file_format.rs @@ -90,8 +90,7 @@ pub fn read_file( let mut rustc_version_str_len = [0u8; 1]; file.read_exact(&mut rustc_version_str_len)?; let rustc_version_str_len = rustc_version_str_len[0] as usize; - let mut buffer = Vec::with_capacity(rustc_version_str_len); - buffer.resize(rustc_version_str_len, 0); + let mut buffer = vec![0; rustc_version_str_len]; file.read_exact(&mut buffer)?; if buffer != rustc_version().as_bytes() { diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index c2123876b679b..231aed48fb6be 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1438,10 +1438,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Expand trait aliases recursively and check that only one regular (non-auto) trait // is used and no 'maybe' bounds are used. - let expanded_traits = traits::expand_trait_aliases( - tcx, - bounds.trait_bounds.iter().map(|&(a, b, _)| (a.clone(), b)), - ); + let expanded_traits = + traits::expand_trait_aliases(tcx, bounds.trait_bounds.iter().map(|&(a, b, _)| (a, b))); let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) = expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id())); if regular_traits.len() > 1 { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index c670641394267..a16f7248baac7 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -3629,14 +3629,7 @@ fn render_impl( for it in &i.inner_impl().items { if let clean::TypedefItem(ref tydef, _) = it.inner { write!(w, " "); - assoc_type( - w, - it, - &vec![], - Some(&tydef.type_), - AssocItemLink::Anchor(None), - "", - ); + assoc_type(w, it, &[], Some(&tydef.type_), AssocItemLink::Anchor(None), ""); write!(w, ";"); } } From 0f73133be6a6915e2d5836ce9986eaffc1b2954d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 3 Feb 2020 17:58:28 -0800 Subject: [PATCH 9/9] Suggest `split_at_mut` on multiple mutable index access --- .../diagnostics/conflict_errors.rs | 27 +++++++++++++++++-- .../ui/suggestions/suggest-split-at-mut.rs | 8 ++++++ .../suggestions/suggest-split-at-mut.stderr | 15 +++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/suggestions/suggest-split-at-mut.rs create mode 100644 src/test/ui/suggestions/suggest-split-at-mut.stderr diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs index a8e534a9f650c..67254cd0c4842 100644 --- a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs @@ -395,14 +395,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { (BorrowKind::Mut { .. }, BorrowKind::Mut { .. }) => { first_borrow_desc = "first "; - self.cannot_mutably_borrow_multiply( + let mut err = self.cannot_mutably_borrow_multiply( span, &desc_place, &msg_place, issued_span, &msg_borrow, None, - ) + ); + self.suggest_split_at_mut_if_applicable( + &mut err, + &place, + &issued_borrow.borrowed_place, + ); + err } (BorrowKind::Unique, BorrowKind::Unique) => { @@ -547,6 +553,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err } + fn suggest_split_at_mut_if_applicable( + &self, + err: &mut DiagnosticBuilder<'_>, + place: &Place<'tcx>, + borrowed_place: &Place<'tcx>, + ) { + match (&place.projection[..], &borrowed_place.projection[..]) { + ([ProjectionElem::Index(_)], [ProjectionElem::Index(_)]) => { + err.help( + "consider using `.split_at_mut(position)` or similar method to obtain \ + two mutable non-overlapping sub-slices", + ); + } + _ => {} + } + } + /// Returns the description of the root place for a conflicting borrow and the full /// descriptions of the places that caused the conflict. /// diff --git a/src/test/ui/suggestions/suggest-split-at-mut.rs b/src/test/ui/suggestions/suggest-split-at-mut.rs new file mode 100644 index 0000000000000..d294c20b8240e --- /dev/null +++ b/src/test/ui/suggestions/suggest-split-at-mut.rs @@ -0,0 +1,8 @@ +fn main() { + let mut foo = [1, 2, 3, 4]; + let a = &mut foo[2]; + let b = &mut foo[3]; //~ ERROR cannot borrow `foo[_]` as mutable more than once at a time + *a = 5; + *b = 6; + println!("{:?} {:?}", a, b); +} diff --git a/src/test/ui/suggestions/suggest-split-at-mut.stderr b/src/test/ui/suggestions/suggest-split-at-mut.stderr new file mode 100644 index 0000000000000..330f012b2a9be --- /dev/null +++ b/src/test/ui/suggestions/suggest-split-at-mut.stderr @@ -0,0 +1,15 @@ +error[E0499]: cannot borrow `foo[_]` as mutable more than once at a time + --> $DIR/suggest-split-at-mut.rs:4:13 + | +LL | let a = &mut foo[2]; + | ----------- first mutable borrow occurs here +LL | let b = &mut foo[3]; + | ^^^^^^^^^^^ second mutable borrow occurs here +LL | *a = 5; + | ------ first borrow later used here + | + = help: consider using `.split_at_mut(position)` or similar method to obtain two mutable non-overlapping sub-slices + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0499`.