From 48e812687e25955d62b1fb5e19f2f2ae4e728710 Mon Sep 17 00:00:00 2001 From: overlookmotel Date: Wed, 1 Mar 2023 23:36:41 +0000 Subject: [PATCH 01/69] Fix docs for `alloc::realloc` Fixes #108546 --- library/core/src/alloc/global.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs index 18da70451f299..c582111701a99 100644 --- a/library/core/src/alloc/global.rs +++ b/library/core/src/alloc/global.rs @@ -235,7 +235,8 @@ pub unsafe trait GlobalAlloc { /// * `new_size` must be greater than zero. /// /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`, - /// must not overflow (i.e., the rounded value must be less than `usize::MAX`). + /// must not overflow isize (i.e., the rounded value must be less than or + /// equal to `isize::MAX`). /// /// (Extension subtraits might provide more specific bounds on /// behavior, e.g., guarantee a sentinel address or a null pointer From 272dc5a6d5967c0816564894b4fd86835a860d97 Mon Sep 17 00:00:00 2001 From: bohan Date: Thu, 4 May 2023 16:30:02 +0800 Subject: [PATCH 02/69] fix(parse): return unpected when current token is EOF --- compiler/rustc_parse/src/parser/mod.rs | 4 +++- tests/ui/parser/issues/issue-111148.rs | 2 ++ tests/ui/parser/issues/issue-111148.stderr | 8 ++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 tests/ui/parser/issues/issue-111148.rs create mode 100644 tests/ui/parser/issues/issue-111148.stderr diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 0c265d7af0e6e..c23420661fa59 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -536,7 +536,9 @@ impl<'a> Parser<'a> { } else if inedible.contains(&self.token.kind) { // leave it in the input Ok(false) - } else if self.last_unexpected_token_span == Some(self.token.span) { + } else if self.token.kind != token::Eof + && self.last_unexpected_token_span == Some(self.token.span) + { FatalError.raise(); } else { self.expected_one_of_not_found(edible, inedible) diff --git a/tests/ui/parser/issues/issue-111148.rs b/tests/ui/parser/issues/issue-111148.rs new file mode 100644 index 0000000000000..2502beab44373 --- /dev/null +++ b/tests/ui/parser/issues/issue-111148.rs @@ -0,0 +1,2 @@ +fn a<# +//~^ ERROR expected one of `#`, `>`, `const`, identifier, or lifetime, found `<` diff --git a/tests/ui/parser/issues/issue-111148.stderr b/tests/ui/parser/issues/issue-111148.stderr new file mode 100644 index 0000000000000..e6595a5cbcc45 --- /dev/null +++ b/tests/ui/parser/issues/issue-111148.stderr @@ -0,0 +1,8 @@ +error: expected one of `#`, `>`, `const`, identifier, or lifetime, found `<` + --> $DIR/issue-111148.rs:1:6 + | +LL | fn a<# + | ^ expected one of `#`, `>`, `const`, identifier, or lifetime + +error: aborting due to previous error + From 548978f1d025e9b937cdedabe3a86da70789dbdc Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Tue, 9 May 2023 21:11:13 +0300 Subject: [PATCH 03/69] add lib module to `src/tool/compiletest` Signed-off-by: ozkanonur --- src/tools/compiletest/Cargo.toml | 3 + src/tools/compiletest/src/lib.rs | 1136 ++++++++++++++++++++++++++++ src/tools/compiletest/src/main.rs | 1137 +---------------------------- 3 files changed, 1141 insertions(+), 1135 deletions(-) create mode 100644 src/tools/compiletest/src/lib.rs diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 0d42504c7f4ca..ae43d470ab3e8 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -3,6 +3,9 @@ name = "compiletest" version = "0.0.0" edition = "2021" +[lib] +doctest = false + [dependencies] colored = "2" diff = "0.1.10" diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs new file mode 100644 index 0000000000000..fc48d0159905b --- /dev/null +++ b/src/tools/compiletest/src/lib.rs @@ -0,0 +1,1136 @@ +#![crate_name = "compiletest"] +// The `test` crate is the only unstable feature +// allowed here, just to share similar code. +#![feature(test)] + +extern crate test; + +#[cfg(test)] +mod tests; + +pub mod common; +pub mod compute_diff; +pub mod errors; +pub mod header; +mod json; +mod raise_fd_limit; +mod read2; +pub mod runtest; +pub mod util; + +use crate::common::{expected_output_path, output_base_dir, output_relative_path, UI_EXTENSIONS}; +use crate::common::{Config, Debugger, Mode, PassMode, TestPaths}; +use crate::util::logv; +use build_helper::git::{get_git_modified_files, get_git_untracked_files}; +use core::panic; +use getopts::Options; +use lazycell::AtomicLazyCell; +use std::collections::BTreeSet; +use std::ffi::OsString; +use std::fs; +use std::io::{self, ErrorKind}; +use std::path::{Path, PathBuf}; +use std::process::{Command, Stdio}; +use std::time::SystemTime; +use std::{env, vec}; +use test::ColorConfig; +use tracing::*; +use walkdir::WalkDir; + +use self::header::{make_test_description, EarlyProps}; +use crate::header::HeadersCache; +use std::sync::Arc; + +pub fn parse_config(args: Vec) -> Config { + let mut opts = Options::new(); + opts.reqopt("", "compile-lib-path", "path to host shared libraries", "PATH") + .reqopt("", "run-lib-path", "path to target shared libraries", "PATH") + .reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH") + .optopt("", "rustdoc-path", "path to rustdoc to use for compiling", "PATH") + .optopt("", "rust-demangler-path", "path to rust-demangler to use in tests", "PATH") + .reqopt("", "python", "path to python to use for doc tests", "PATH") + .optopt("", "jsondocck-path", "path to jsondocck to use for doc tests", "PATH") + .optopt("", "jsondoclint-path", "path to jsondoclint to use for doc tests", "PATH") + .optopt("", "valgrind-path", "path to Valgrind executable for Valgrind tests", "PROGRAM") + .optflag("", "force-valgrind", "fail if Valgrind tests cannot be run under Valgrind") + .optopt("", "run-clang-based-tests-with", "path to Clang executable", "PATH") + .optopt("", "llvm-filecheck", "path to LLVM's FileCheck binary", "DIR") + .reqopt("", "src-base", "directory to scan for test files", "PATH") + .reqopt("", "build-base", "directory to deposit test outputs", "PATH") + .reqopt("", "sysroot-base", "directory containing the compiler sysroot", "PATH") + .reqopt("", "stage-id", "the target-stage identifier", "stageN-TARGET") + .reqopt( + "", + "mode", + "which sort of compile tests to run", + "run-pass-valgrind | pretty | debug-info | codegen | rustdoc \ + | rustdoc-json | codegen-units | incremental | run-make | ui | js-doc-test | mir-opt | assembly", + ) + .reqopt( + "", + "suite", + "which suite of compile tests to run. used for nicer error reporting.", + "SUITE", + ) + .optopt( + "", + "pass", + "force {check,build,run}-pass tests to this mode.", + "check | build | run", + ) + .optopt("", "run", "whether to execute run-* tests", "auto | always | never") + .optflag("", "ignored", "run tests marked as ignored") + .optmulti("", "skip", "skip tests matching SUBSTRING. Can be passed multiple times", "SUBSTRING") + .optflag("", "exact", "filters match exactly") + .optopt( + "", + "runtool", + "supervisor program to run tests under \ + (eg. emulator, valgrind)", + "PROGRAM", + ) + .optmulti("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS") + .optmulti("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS") + .optflag("", "optimize-tests", "run tests with optimizations enabled") + .optflag("", "verbose", "run tests verbosely, showing all output") + .optflag( + "", + "bless", + "overwrite stderr/stdout files instead of complaining about a mismatch", + ) + .optflag("", "quiet", "print one character per test instead of one line") + .optopt("", "color", "coloring: auto, always, never", "WHEN") + .optflag("", "json", "emit json output instead of plaintext output") + .optopt("", "logfile", "file to log test execution to", "FILE") + .optopt("", "target", "the target to build for", "TARGET") + .optopt("", "host", "the host to build for", "HOST") + .optopt("", "cdb", "path to CDB to use for CDB debuginfo tests", "PATH") + .optopt("", "gdb", "path to GDB to use for GDB debuginfo tests", "PATH") + .optopt("", "lldb-version", "the version of LLDB used", "VERSION STRING") + .optopt("", "llvm-version", "the version of LLVM used", "VERSION STRING") + .optflag("", "system-llvm", "is LLVM the system LLVM") + .optopt("", "android-cross-path", "Android NDK standalone path", "PATH") + .optopt("", "adb-path", "path to the android debugger", "PATH") + .optopt("", "adb-test-dir", "path to tests for the android debugger", "PATH") + .optopt("", "lldb-python-dir", "directory containing LLDB's python module", "PATH") + .reqopt("", "cc", "path to a C compiler", "PATH") + .reqopt("", "cxx", "path to a C++ compiler", "PATH") + .reqopt("", "cflags", "flags for the C compiler", "FLAGS") + .reqopt("", "cxxflags", "flags for the CXX compiler", "FLAGS") + .optopt("", "ar", "path to an archiver", "PATH") + .optopt("", "target-linker", "path to a linker for the target", "PATH") + .optopt("", "host-linker", "path to a linker for the host", "PATH") + .reqopt("", "llvm-components", "list of LLVM components built in", "LIST") + .optopt("", "llvm-bin-dir", "Path to LLVM's `bin` directory", "PATH") + .optopt("", "nodejs", "the name of nodejs", "PATH") + .optopt("", "npm", "the name of npm", "PATH") + .optopt("", "remote-test-client", "path to the remote test client", "PATH") + .optopt( + "", + "compare-mode", + "mode describing what file the actual ui output will be compared to", + "COMPARE MODE", + ) + .optflag( + "", + "rustfix-coverage", + "enable this to generate a Rustfix coverage file, which is saved in \ + `.//rustfix_missing_coverage.txt`", + ) + .optflag("", "force-rerun", "rerun tests even if the inputs are unchanged") + .optflag("", "only-modified", "only run tests that result been modified") + .optflag("", "nocapture", "") + .optflag("h", "help", "show this message") + .reqopt("", "channel", "current Rust channel", "CHANNEL") + .optflag("", "git-hash", "run tests which rely on commit version being compiled into the binaries") + .optopt("", "edition", "default Rust edition", "EDITION"); + + let (argv0, args_) = args.split_first().unwrap(); + if args.len() == 1 || args[1] == "-h" || args[1] == "--help" { + let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0); + println!("{}", opts.usage(&message)); + println!(); + panic!() + } + + let matches = &match opts.parse(args_) { + Ok(m) => m, + Err(f) => panic!("{:?}", f), + }; + + if matches.opt_present("h") || matches.opt_present("help") { + let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0); + println!("{}", opts.usage(&message)); + println!(); + panic!() + } + + fn opt_path(m: &getopts::Matches, nm: &str) -> PathBuf { + match m.opt_str(nm) { + Some(s) => PathBuf::from(&s), + None => panic!("no option (=path) found for {}", nm), + } + } + + fn make_absolute(path: PathBuf) -> PathBuf { + if path.is_relative() { env::current_dir().unwrap().join(path) } else { path } + } + + let target = opt_str2(matches.opt_str("target")); + let android_cross_path = opt_path(matches, "android-cross-path"); + let (cdb, cdb_version) = analyze_cdb(matches.opt_str("cdb"), &target); + let (gdb, gdb_version, gdb_native_rust) = + analyze_gdb(matches.opt_str("gdb"), &target, &android_cross_path); + let (lldb_version, lldb_native_rust) = matches + .opt_str("lldb-version") + .as_deref() + .and_then(extract_lldb_version) + .map(|(v, b)| (Some(v), b)) + .unwrap_or((None, false)); + let color = match matches.opt_str("color").as_deref() { + Some("auto") | None => ColorConfig::AutoColor, + Some("always") => ColorConfig::AlwaysColor, + Some("never") => ColorConfig::NeverColor, + Some(x) => panic!("argument for --color must be auto, always, or never, but found `{}`", x), + }; + let llvm_version = + matches.opt_str("llvm-version").as_deref().and_then(header::extract_llvm_version).or_else( + || header::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?), + ); + + let src_base = opt_path(matches, "src-base"); + let run_ignored = matches.opt_present("ignored"); + let mode = matches.opt_str("mode").unwrap().parse().expect("invalid mode"); + let has_tidy = if mode == Mode::Rustdoc { + Command::new("tidy") + .arg("--version") + .stdout(Stdio::null()) + .status() + .map_or(false, |status| status.success()) + } else { + // Avoid spawning an external command when we know tidy won't be used. + false + }; + Config { + bless: matches.opt_present("bless"), + compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")), + run_lib_path: make_absolute(opt_path(matches, "run-lib-path")), + rustc_path: opt_path(matches, "rustc-path"), + rustdoc_path: matches.opt_str("rustdoc-path").map(PathBuf::from), + rust_demangler_path: matches.opt_str("rust-demangler-path").map(PathBuf::from), + python: matches.opt_str("python").unwrap(), + jsondocck_path: matches.opt_str("jsondocck-path"), + jsondoclint_path: matches.opt_str("jsondoclint-path"), + valgrind_path: matches.opt_str("valgrind-path"), + force_valgrind: matches.opt_present("force-valgrind"), + run_clang_based_tests_with: matches.opt_str("run-clang-based-tests-with"), + llvm_filecheck: matches.opt_str("llvm-filecheck").map(PathBuf::from), + llvm_bin_dir: matches.opt_str("llvm-bin-dir").map(PathBuf::from), + src_base, + build_base: opt_path(matches, "build-base"), + sysroot_base: opt_path(matches, "sysroot-base"), + stage_id: matches.opt_str("stage-id").unwrap(), + mode, + suite: matches.opt_str("suite").unwrap(), + debugger: None, + run_ignored, + filters: matches.free.clone(), + skip: matches.opt_strs("skip"), + filter_exact: matches.opt_present("exact"), + force_pass_mode: matches.opt_str("pass").map(|mode| { + mode.parse::() + .unwrap_or_else(|_| panic!("unknown `--pass` option `{}` given", mode)) + }), + run: matches.opt_str("run").and_then(|mode| match mode.as_str() { + "auto" => None, + "always" => Some(true), + "never" => Some(false), + _ => panic!("unknown `--run` option `{}` given", mode), + }), + logfile: matches.opt_str("logfile").map(|s| PathBuf::from(&s)), + runtool: matches.opt_str("runtool"), + host_rustcflags: matches.opt_strs("host-rustcflags"), + target_rustcflags: matches.opt_strs("target-rustcflags"), + optimize_tests: matches.opt_present("optimize-tests"), + target, + host: opt_str2(matches.opt_str("host")), + cdb, + cdb_version, + gdb, + gdb_version, + gdb_native_rust, + lldb_version, + lldb_native_rust, + llvm_version, + system_llvm: matches.opt_present("system-llvm"), + android_cross_path, + adb_path: opt_str2(matches.opt_str("adb-path")), + adb_test_dir: opt_str2(matches.opt_str("adb-test-dir")), + adb_device_status: opt_str2(matches.opt_str("target")).contains("android") + && "(none)" != opt_str2(matches.opt_str("adb-test-dir")) + && !opt_str2(matches.opt_str("adb-test-dir")).is_empty(), + lldb_python_dir: matches.opt_str("lldb-python-dir"), + verbose: matches.opt_present("verbose"), + format: match (matches.opt_present("quiet"), matches.opt_present("json")) { + (true, true) => panic!("--quiet and --json are incompatible"), + (true, false) => test::OutputFormat::Terse, + (false, true) => test::OutputFormat::Json, + (false, false) => test::OutputFormat::Pretty, + }, + only_modified: matches.opt_present("only-modified"), + color, + remote_test_client: matches.opt_str("remote-test-client").map(PathBuf::from), + compare_mode: matches + .opt_str("compare-mode") + .map(|s| s.parse().expect("invalid --compare-mode provided")), + rustfix_coverage: matches.opt_present("rustfix-coverage"), + has_tidy, + channel: matches.opt_str("channel").unwrap(), + git_hash: matches.opt_present("git-hash"), + edition: matches.opt_str("edition"), + + cc: matches.opt_str("cc").unwrap(), + cxx: matches.opt_str("cxx").unwrap(), + cflags: matches.opt_str("cflags").unwrap(), + cxxflags: matches.opt_str("cxxflags").unwrap(), + ar: matches.opt_str("ar").unwrap_or_else(|| String::from("ar")), + target_linker: matches.opt_str("target-linker"), + host_linker: matches.opt_str("host-linker"), + llvm_components: matches.opt_str("llvm-components").unwrap(), + nodejs: matches.opt_str("nodejs"), + npm: matches.opt_str("npm"), + + force_rerun: matches.opt_present("force-rerun"), + + target_cfgs: AtomicLazyCell::new(), + + nocapture: matches.opt_present("nocapture"), + } +} + +pub fn log_config(config: &Config) { + let c = config; + logv(c, "configuration:".to_string()); + logv(c, format!("compile_lib_path: {:?}", config.compile_lib_path)); + logv(c, format!("run_lib_path: {:?}", config.run_lib_path)); + logv(c, format!("rustc_path: {:?}", config.rustc_path.display())); + logv(c, format!("rustdoc_path: {:?}", config.rustdoc_path)); + logv(c, format!("rust_demangler_path: {:?}", config.rust_demangler_path)); + logv(c, format!("src_base: {:?}", config.src_base.display())); + logv(c, format!("build_base: {:?}", config.build_base.display())); + logv(c, format!("stage_id: {}", config.stage_id)); + logv(c, format!("mode: {}", config.mode)); + logv(c, format!("run_ignored: {}", config.run_ignored)); + logv(c, format!("filters: {:?}", config.filters)); + logv(c, format!("skip: {:?}", config.skip)); + logv(c, format!("filter_exact: {}", config.filter_exact)); + logv( + c, + format!("force_pass_mode: {}", opt_str(&config.force_pass_mode.map(|m| format!("{}", m))),), + ); + logv(c, format!("runtool: {}", opt_str(&config.runtool))); + logv(c, format!("host-rustcflags: {:?}", config.host_rustcflags)); + logv(c, format!("target-rustcflags: {:?}", config.target_rustcflags)); + logv(c, format!("target: {}", config.target)); + logv(c, format!("host: {}", config.host)); + logv(c, format!("android-cross-path: {:?}", config.android_cross_path.display())); + logv(c, format!("adb_path: {:?}", config.adb_path)); + logv(c, format!("adb_test_dir: {:?}", config.adb_test_dir)); + logv(c, format!("adb_device_status: {}", config.adb_device_status)); + logv(c, format!("ar: {}", config.ar)); + logv(c, format!("target-linker: {:?}", config.target_linker)); + logv(c, format!("host-linker: {:?}", config.host_linker)); + logv(c, format!("verbose: {}", config.verbose)); + logv(c, format!("format: {:?}", config.format)); + logv(c, "\n".to_string()); +} + +pub fn opt_str(maybestr: &Option) -> &str { + match *maybestr { + None => "(none)", + Some(ref s) => s, + } +} + +pub fn opt_str2(maybestr: Option) -> String { + match maybestr { + None => "(none)".to_owned(), + Some(s) => s, + } +} + +pub fn run_tests(config: Arc) { + // If we want to collect rustfix coverage information, + // we first make sure that the coverage file does not exist. + // It will be created later on. + if config.rustfix_coverage { + let mut coverage_file_path = config.build_base.clone(); + coverage_file_path.push("rustfix_missing_coverage.txt"); + if coverage_file_path.exists() { + if let Err(e) = fs::remove_file(&coverage_file_path) { + panic!("Could not delete {} due to {}", coverage_file_path.display(), e) + } + } + } + + // sadly osx needs some file descriptor limits raised for running tests in + // parallel (especially when we have lots and lots of child processes). + // For context, see #8904 + unsafe { + raise_fd_limit::raise_fd_limit(); + } + // Prevent issue #21352 UAC blocking .exe containing 'patch' etc. on Windows + // If #11207 is resolved (adding manifest to .exe) this becomes unnecessary + env::set_var("__COMPAT_LAYER", "RunAsInvoker"); + + // Let tests know which target they're running as + env::set_var("TARGET", &config.target); + + let opts = test_opts(&config); + + let mut configs = Vec::new(); + if let Mode::DebugInfo = config.mode { + // Debugging emscripten code doesn't make sense today + if !config.target.contains("emscripten") { + configs.extend(configure_cdb(&config)); + configs.extend(configure_gdb(&config)); + configs.extend(configure_lldb(&config)); + } + } else { + configs.push(config.clone()); + }; + + let mut tests = Vec::new(); + for c in configs { + let mut found_paths = BTreeSet::new(); + make_tests(c, &mut tests, &mut found_paths); + check_overlapping_tests(&found_paths); + } + + tests.sort_by(|a, b| a.desc.name.as_slice().cmp(&b.desc.name.as_slice())); + + let res = test::run_tests_console(&opts, tests); + match res { + Ok(true) => {} + Ok(false) => { + // We want to report that the tests failed, but we also want to give + // some indication of just what tests we were running. Especially on + // CI, where there can be cross-compiled tests for a lot of + // architectures, without this critical information it can be quite + // easy to miss which tests failed, and as such fail to reproduce + // the failure locally. + + println!( + "Some tests failed in compiletest suite={}{} mode={} host={} target={}", + config.suite, + config + .compare_mode + .as_ref() + .map(|c| format!(" compare_mode={:?}", c)) + .unwrap_or_default(), + config.mode, + config.host, + config.target + ); + + std::process::exit(1); + } + Err(e) => { + // We don't know if tests passed or not, but if there was an error + // during testing we don't want to just succeed (we may not have + // tested something), so fail. + // + // This should realistically "never" happen, so don't try to make + // this a pretty error message. + panic!("I/O failure during tests: {:?}", e); + } + } +} + +fn configure_cdb(config: &Config) -> Option> { + config.cdb.as_ref()?; + + Some(Arc::new(Config { debugger: Some(Debugger::Cdb), ..config.clone() })) +} + +fn configure_gdb(config: &Config) -> Option> { + config.gdb_version?; + + if config.matches_env("msvc") { + return None; + } + + if config.remote_test_client.is_some() && !config.target.contains("android") { + println!( + "WARNING: debuginfo tests are not available when \ + testing with remote" + ); + return None; + } + + if config.target.contains("android") { + println!( + "{} debug-info test uses tcp 5039 port.\ + please reserve it", + config.target + ); + + // android debug-info test uses remote debugger so, we test 1 thread + // at once as they're all sharing the same TCP port to communicate + // over. + // + // we should figure out how to lift this restriction! (run them all + // on different ports allocated dynamically). + env::set_var("RUST_TEST_THREADS", "1"); + } + + Some(Arc::new(Config { debugger: Some(Debugger::Gdb), ..config.clone() })) +} + +fn configure_lldb(config: &Config) -> Option> { + config.lldb_python_dir.as_ref()?; + + if let Some(350) = config.lldb_version { + println!( + "WARNING: The used version of LLDB (350) has a \ + known issue that breaks debuginfo tests. See \ + issue #32520 for more information. Skipping all \ + LLDB-based tests!", + ); + return None; + } + + Some(Arc::new(Config { debugger: Some(Debugger::Lldb), ..config.clone() })) +} + +pub fn test_opts(config: &Config) -> test::TestOpts { + if env::var("RUST_TEST_NOCAPTURE").is_ok() { + eprintln!( + "WARNING: RUST_TEST_NOCAPTURE is no longer used. \ + Use the `--nocapture` flag instead." + ); + } + + test::TestOpts { + exclude_should_panic: false, + filters: config.filters.clone(), + filter_exact: config.filter_exact, + run_ignored: if config.run_ignored { test::RunIgnored::Yes } else { test::RunIgnored::No }, + format: config.format, + logfile: config.logfile.clone(), + run_tests: true, + bench_benchmarks: true, + nocapture: config.nocapture, + color: config.color, + shuffle: false, + shuffle_seed: None, + test_threads: None, + skip: config.skip.clone(), + list: false, + options: test::Options::new(), + time_options: None, + force_run_in_process: false, + fail_fast: std::env::var_os("RUSTC_TEST_FAIL_FAST").is_some(), + } +} + +pub fn make_tests( + config: Arc, + tests: &mut Vec, + found_paths: &mut BTreeSet, +) { + debug!("making tests from {:?}", config.src_base.display()); + let inputs = common_inputs_stamp(&config); + let modified_tests = modified_tests(&config, &config.src_base).unwrap_or_else(|err| { + panic!("modified_tests got error from dir: {}, error: {}", config.src_base.display(), err) + }); + + let cache = HeadersCache::load(&config); + let mut poisoned = false; + collect_tests_from_dir( + config.clone(), + &cache, + &config.src_base, + &PathBuf::new(), + &inputs, + tests, + found_paths, + &modified_tests, + &mut poisoned, + ) + .unwrap_or_else(|_| panic!("Could not read tests from {}", config.src_base.display())); + + if poisoned { + eprintln!(); + panic!("there are errors in tests"); + } +} + +/// Returns a stamp constructed from input files common to all test cases. +fn common_inputs_stamp(config: &Config) -> Stamp { + let rust_src_dir = config.find_rust_src_root().expect("Could not find Rust source root"); + + let mut stamp = Stamp::from_path(&config.rustc_path); + + // Relevant pretty printer files + let pretty_printer_files = [ + "src/etc/rust_types.py", + "src/etc/gdb_load_rust_pretty_printers.py", + "src/etc/gdb_lookup.py", + "src/etc/gdb_providers.py", + "src/etc/lldb_batchmode.py", + "src/etc/lldb_lookup.py", + "src/etc/lldb_providers.py", + ]; + for file in &pretty_printer_files { + let path = rust_src_dir.join(file); + stamp.add_path(&path); + } + + stamp.add_dir(&rust_src_dir.join("src/etc/natvis")); + + stamp.add_dir(&config.run_lib_path); + + if let Some(ref rustdoc_path) = config.rustdoc_path { + stamp.add_path(&rustdoc_path); + stamp.add_path(&rust_src_dir.join("src/etc/htmldocck.py")); + } + + // Compiletest itself. + stamp.add_dir(&rust_src_dir.join("src/tools/compiletest/")); + + stamp +} + +fn modified_tests(config: &Config, dir: &Path) -> Result, String> { + if !config.only_modified { + return Ok(vec![]); + } + let files = + get_git_modified_files(Some(dir), &vec!["rs", "stderr", "fixed"])?.unwrap_or(vec![]); + // Add new test cases to the list, it will be convenient in daily development. + let untracked_files = get_git_untracked_files(None)?.unwrap_or(vec![]); + + let all_paths = [&files[..], &untracked_files[..]].concat(); + let full_paths = { + let mut full_paths: Vec = all_paths + .into_iter() + .map(|f| PathBuf::from(f).with_extension("").with_extension("rs")) + .filter_map(|f| if Path::new(&f).exists() { f.canonicalize().ok() } else { None }) + .collect(); + full_paths.dedup(); + full_paths.sort_unstable(); + full_paths + }; + Ok(full_paths) +} + +fn collect_tests_from_dir( + config: Arc, + cache: &HeadersCache, + dir: &Path, + relative_dir_path: &Path, + inputs: &Stamp, + tests: &mut Vec, + found_paths: &mut BTreeSet, + modified_tests: &Vec, + poisoned: &mut bool, +) -> io::Result<()> { + // Ignore directories that contain a file named `compiletest-ignore-dir`. + if dir.join("compiletest-ignore-dir").exists() { + return Ok(()); + } + + if config.mode == Mode::RunMake && dir.join("Makefile").exists() { + let paths = TestPaths { + file: dir.to_path_buf(), + relative_dir: relative_dir_path.parent().unwrap().to_path_buf(), + }; + tests.extend(make_test(config, cache, &paths, inputs, poisoned)); + return Ok(()); + } + + // If we find a test foo/bar.rs, we have to build the + // output directory `$build/foo` so we can write + // `$build/foo/bar` into it. We do this *now* in this + // sequential loop because otherwise, if we do it in the + // tests themselves, they race for the privilege of + // creating the directories and sometimes fail randomly. + let build_dir = output_relative_path(&config, relative_dir_path); + fs::create_dir_all(&build_dir).unwrap(); + + // Add each `.rs` file as a test, and recurse further on any + // subdirectories we find, except for `aux` directories. + for file in fs::read_dir(dir)? { + let file = file?; + let file_path = file.path(); + let file_name = file.file_name(); + if is_test(&file_name) && (!config.only_modified || modified_tests.contains(&file_path)) { + debug!("found test file: {:?}", file_path.display()); + let rel_test_path = relative_dir_path.join(file_path.file_stem().unwrap()); + found_paths.insert(rel_test_path); + let paths = + TestPaths { file: file_path, relative_dir: relative_dir_path.to_path_buf() }; + + tests.extend(make_test(config.clone(), cache, &paths, inputs, poisoned)) + } else if file_path.is_dir() { + let relative_file_path = relative_dir_path.join(file.file_name()); + if &file_name != "auxiliary" { + debug!("found directory: {:?}", file_path.display()); + collect_tests_from_dir( + config.clone(), + cache, + &file_path, + &relative_file_path, + inputs, + tests, + found_paths, + modified_tests, + poisoned, + )?; + } + } else { + debug!("found other file/directory: {:?}", file_path.display()); + } + } + Ok(()) +} + +/// Returns true if `file_name` looks like a proper test file name. +pub fn is_test(file_name: &OsString) -> bool { + let file_name = file_name.to_str().unwrap(); + + if !file_name.ends_with(".rs") { + return false; + } + + // `.`, `#`, and `~` are common temp-file prefixes. + let invalid_prefixes = &[".", "#", "~"]; + !invalid_prefixes.iter().any(|p| file_name.starts_with(p)) +} + +fn make_test( + config: Arc, + cache: &HeadersCache, + testpaths: &TestPaths, + inputs: &Stamp, + poisoned: &mut bool, +) -> Vec { + let test_path = if config.mode == Mode::RunMake { + // Parse directives in the Makefile + testpaths.file.join("Makefile") + } else { + PathBuf::from(&testpaths.file) + }; + let early_props = EarlyProps::from_file(&config, &test_path); + + // Incremental tests are special, they inherently cannot be run in parallel. + // `runtest::run` will be responsible for iterating over revisions. + let revisions = if early_props.revisions.is_empty() || config.mode == Mode::Incremental { + vec![None] + } else { + early_props.revisions.iter().map(Some).collect() + }; + + revisions + .into_iter() + .map(|revision| { + let src_file = + std::fs::File::open(&test_path).expect("open test file to parse ignores"); + let cfg = revision.map(|v| &**v); + let test_name = crate::make_test_name(&config, testpaths, revision); + let mut desc = make_test_description( + &config, cache, test_name, &test_path, src_file, cfg, poisoned, + ); + // Ignore tests that already run and are up to date with respect to inputs. + if !config.force_rerun { + desc.ignore |= is_up_to_date( + &config, + testpaths, + &early_props, + revision.map(|s| s.as_str()), + inputs, + ); + } + test::TestDescAndFn { + desc, + testfn: make_test_closure(config.clone(), testpaths, revision), + } + }) + .collect() +} + +fn stamp(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf { + output_base_dir(config, testpaths, revision).join("stamp") +} + +fn files_related_to_test( + config: &Config, + testpaths: &TestPaths, + props: &EarlyProps, + revision: Option<&str>, +) -> Vec { + let mut related = vec![]; + + if testpaths.file.is_dir() { + // run-make tests use their individual directory + for entry in WalkDir::new(&testpaths.file) { + let path = entry.unwrap().into_path(); + if path.is_file() { + related.push(path); + } + } + } else { + related.push(testpaths.file.clone()); + } + + for aux in &props.aux { + let path = testpaths.file.parent().unwrap().join("auxiliary").join(aux); + related.push(path); + } + + // UI test files. + for extension in UI_EXTENSIONS { + let path = expected_output_path(testpaths, revision, &config.compare_mode, extension); + related.push(path); + } + + related +} + +fn is_up_to_date( + config: &Config, + testpaths: &TestPaths, + props: &EarlyProps, + revision: Option<&str>, + inputs: &Stamp, +) -> bool { + let stamp_name = stamp(config, testpaths, revision); + // Check hash. + let contents = match fs::read_to_string(&stamp_name) { + Ok(f) => f, + Err(ref e) if e.kind() == ErrorKind::InvalidData => panic!("Can't read stamp contents"), + Err(_) => return false, + }; + let expected_hash = runtest::compute_stamp_hash(config); + if contents != expected_hash { + return false; + } + + // Check timestamps. + let mut inputs = inputs.clone(); + for path in files_related_to_test(config, testpaths, props, revision) { + inputs.add_path(&path); + } + + inputs < Stamp::from_path(&stamp_name) +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +struct Stamp { + time: SystemTime, +} + +impl Stamp { + fn from_path(path: &Path) -> Self { + let mut stamp = Stamp { time: SystemTime::UNIX_EPOCH }; + stamp.add_path(path); + stamp + } + + fn add_path(&mut self, path: &Path) { + let modified = fs::metadata(path) + .and_then(|metadata| metadata.modified()) + .unwrap_or(SystemTime::UNIX_EPOCH); + self.time = self.time.max(modified); + } + + fn add_dir(&mut self, path: &Path) { + for entry in WalkDir::new(path) { + let entry = entry.unwrap(); + if entry.file_type().is_file() { + let modified = entry + .metadata() + .ok() + .and_then(|metadata| metadata.modified().ok()) + .unwrap_or(SystemTime::UNIX_EPOCH); + self.time = self.time.max(modified); + } + } + } +} + +fn make_test_name( + config: &Config, + testpaths: &TestPaths, + revision: Option<&String>, +) -> test::TestName { + // Print the name of the file, relative to the repository root. + // `src_base` looks like `/path/to/rust/tests/ui` + let root_directory = config.src_base.parent().unwrap().parent().unwrap(); + let path = testpaths.file.strip_prefix(root_directory).unwrap(); + let debugger = match config.debugger { + Some(d) => format!("-{}", d), + None => String::new(), + }; + let mode_suffix = match config.compare_mode { + Some(ref mode) => format!(" ({})", mode.to_str()), + None => String::new(), + }; + + test::DynTestName(format!( + "[{}{}{}] {}{}", + config.mode, + debugger, + mode_suffix, + path.display(), + revision.map_or("".to_string(), |rev| format!("#{}", rev)) + )) +} + +fn make_test_closure( + config: Arc, + testpaths: &TestPaths, + revision: Option<&String>, +) -> test::TestFn { + let config = config.clone(); + let testpaths = testpaths.clone(); + let revision = revision.cloned(); + test::DynTestFn(Box::new(move || { + runtest::run(config, &testpaths, revision.as_deref()); + Ok(()) + })) +} + +/// Returns `true` if the given target is an Android target for the +/// purposes of GDB testing. +fn is_android_gdb_target(target: &str) -> bool { + matches!( + &target[..], + "arm-linux-androideabi" | "armv7-linux-androideabi" | "aarch64-linux-android" + ) +} + +/// Returns `true` if the given target is a MSVC target for the purpouses of CDB testing. +fn is_pc_windows_msvc_target(target: &str) -> bool { + target.ends_with("-pc-windows-msvc") +} + +fn find_cdb(target: &str) -> Option { + if !(cfg!(windows) && is_pc_windows_msvc_target(target)) { + return None; + } + + let pf86 = env::var_os("ProgramFiles(x86)").or_else(|| env::var_os("ProgramFiles"))?; + let cdb_arch = if cfg!(target_arch = "x86") { + "x86" + } else if cfg!(target_arch = "x86_64") { + "x64" + } else if cfg!(target_arch = "aarch64") { + "arm64" + } else if cfg!(target_arch = "arm") { + "arm" + } else { + return None; // No compatible CDB.exe in the Windows 10 SDK + }; + + let mut path = PathBuf::new(); + path.push(pf86); + path.push(r"Windows Kits\10\Debuggers"); // We could check 8.1 etc. too? + path.push(cdb_arch); + path.push(r"cdb.exe"); + + if !path.exists() { + return None; + } + + Some(path.into_os_string()) +} + +/// Returns Path to CDB +fn analyze_cdb(cdb: Option, target: &str) -> (Option, Option<[u16; 4]>) { + let cdb = cdb.map(OsString::from).or_else(|| find_cdb(target)); + + let mut version = None; + if let Some(cdb) = cdb.as_ref() { + if let Ok(output) = Command::new(cdb).arg("/version").output() { + if let Some(first_line) = String::from_utf8_lossy(&output.stdout).lines().next() { + version = extract_cdb_version(&first_line); + } + } + } + + (cdb, version) +} + +fn extract_cdb_version(full_version_line: &str) -> Option<[u16; 4]> { + // Example full_version_line: "cdb version 10.0.18362.1" + let version = full_version_line.rsplit(' ').next()?; + let mut components = version.split('.'); + let major: u16 = components.next().unwrap().parse().unwrap(); + let minor: u16 = components.next().unwrap().parse().unwrap(); + let patch: u16 = components.next().unwrap_or("0").parse().unwrap(); + let build: u16 = components.next().unwrap_or("0").parse().unwrap(); + Some([major, minor, patch, build]) +} + +/// Returns (Path to GDB, GDB Version, GDB has Rust Support) +fn analyze_gdb( + gdb: Option, + target: &str, + android_cross_path: &PathBuf, +) -> (Option, Option, bool) { + #[cfg(not(windows))] + const GDB_FALLBACK: &str = "gdb"; + #[cfg(windows)] + const GDB_FALLBACK: &str = "gdb.exe"; + + const MIN_GDB_WITH_RUST: u32 = 7011010; + + let fallback_gdb = || { + if is_android_gdb_target(target) { + let mut gdb_path = match android_cross_path.to_str() { + Some(x) => x.to_owned(), + None => panic!("cannot find android cross path"), + }; + gdb_path.push_str("/bin/gdb"); + gdb_path + } else { + GDB_FALLBACK.to_owned() + } + }; + + let gdb = match gdb { + None => fallback_gdb(), + Some(ref s) if s.is_empty() => fallback_gdb(), // may be empty if configure found no gdb + Some(ref s) => s.to_owned(), + }; + + let mut version_line = None; + if let Ok(output) = Command::new(&gdb).arg("--version").output() { + if let Some(first_line) = String::from_utf8_lossy(&output.stdout).lines().next() { + version_line = Some(first_line.to_string()); + } + } + + let version = match version_line { + Some(line) => extract_gdb_version(&line), + None => return (None, None, false), + }; + + let gdb_native_rust = version.map_or(false, |v| v >= MIN_GDB_WITH_RUST); + + (Some(gdb), version, gdb_native_rust) +} + +fn extract_gdb_version(full_version_line: &str) -> Option { + let full_version_line = full_version_line.trim(); + + // GDB versions look like this: "major.minor.patch?.yyyymmdd?", with both + // of the ? sections being optional + + // We will parse up to 3 digits for each component, ignoring the date + + // We skip text in parentheses. This avoids accidentally parsing + // the openSUSE version, which looks like: + // GNU gdb (GDB; openSUSE Leap 15.0) 8.1 + // This particular form is documented in the GNU coding standards: + // https://www.gnu.org/prep/standards/html_node/_002d_002dversion.html#g_t_002d_002dversion + + let unbracketed_part = full_version_line.split('[').next().unwrap(); + let mut splits = unbracketed_part.trim_end().rsplit(' '); + let version_string = splits.next().unwrap(); + + let mut splits = version_string.split('.'); + let major = splits.next().unwrap(); + let minor = splits.next().unwrap(); + let patch = splits.next(); + + let major: u32 = major.parse().unwrap(); + let (minor, patch): (u32, u32) = match minor.find(not_a_digit) { + None => { + let minor = minor.parse().unwrap(); + let patch: u32 = match patch { + Some(patch) => match patch.find(not_a_digit) { + None => patch.parse().unwrap(), + Some(idx) if idx > 3 => 0, + Some(idx) => patch[..idx].parse().unwrap(), + }, + None => 0, + }; + (minor, patch) + } + // There is no patch version after minor-date (e.g. "4-2012"). + Some(idx) => { + let minor = minor[..idx].parse().unwrap(); + (minor, 0) + } + }; + + Some(((major * 1000) + minor) * 1000 + patch) +} + +/// Returns (LLDB version, LLDB is rust-enabled) +fn extract_lldb_version(full_version_line: &str) -> Option<(u32, bool)> { + // Extract the major LLDB version from the given version string. + // LLDB version strings are different for Apple and non-Apple platforms. + // The Apple variant looks like this: + // + // LLDB-179.5 (older versions) + // lldb-300.2.51 (new versions) + // + // We are only interested in the major version number, so this function + // will return `Some(179)` and `Some(300)` respectively. + // + // Upstream versions look like: + // lldb version 6.0.1 + // + // There doesn't seem to be a way to correlate the Apple version + // with the upstream version, and since the tests were originally + // written against Apple versions, we make a fake Apple version by + // multiplying the first number by 100. This is a hack, but + // normally fine because the only non-Apple version we test is + // rust-enabled. + + let full_version_line = full_version_line.trim(); + + if let Some(apple_ver) = + full_version_line.strip_prefix("LLDB-").or_else(|| full_version_line.strip_prefix("lldb-")) + { + if let Some(idx) = apple_ver.find(not_a_digit) { + let version: u32 = apple_ver[..idx].parse().unwrap(); + return Some((version, full_version_line.contains("rust-enabled"))); + } + } else if let Some(lldb_ver) = full_version_line.strip_prefix("lldb version ") { + if let Some(idx) = lldb_ver.find(not_a_digit) { + let version: u32 = lldb_ver[..idx].parse().ok()?; + return Some((version * 100, full_version_line.contains("rust-enabled"))); + } + } + None +} + +fn not_a_digit(c: char) -> bool { + !c.is_digit(10) +} + +fn check_overlapping_tests(found_paths: &BTreeSet) { + let mut collisions = Vec::new(); + for path in found_paths { + for ancestor in path.ancestors().skip(1) { + if found_paths.contains(ancestor) { + collisions.push((path, ancestor.clone())); + } + } + } + if !collisions.is_empty() { + let collisions: String = collisions + .into_iter() + .map(|(path, check_parent)| format!("test {path:?} clashes with {check_parent:?}\n")) + .collect(); + panic!( + "{collisions}\n\ + Tests cannot have overlapping names. Make sure they use unique prefixes." + ); + } +} diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index c4bef998f3171..34d48559c378d 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -1,45 +1,6 @@ -#![crate_name = "compiletest"] -// The `test` crate is the only unstable feature -// allowed here, just to share similar code. -#![feature(test)] +use std::{env, sync::Arc}; -extern crate test; - -use crate::common::{expected_output_path, output_base_dir, output_relative_path, UI_EXTENSIONS}; -use crate::common::{Config, Debugger, Mode, PassMode, TestPaths}; -use crate::util::logv; -use build_helper::git::{get_git_modified_files, get_git_untracked_files}; -use core::panic; -use getopts::Options; -use lazycell::AtomicLazyCell; -use std::collections::BTreeSet; -use std::ffi::OsString; -use std::fs; -use std::io::{self, ErrorKind}; -use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; -use std::time::SystemTime; -use std::{env, vec}; -use test::ColorConfig; -use tracing::*; -use walkdir::WalkDir; - -use self::header::{make_test_description, EarlyProps}; -use crate::header::HeadersCache; -use std::sync::Arc; - -#[cfg(test)] -mod tests; - -pub mod common; -pub mod compute_diff; -pub mod errors; -pub mod header; -mod json; -mod raise_fd_limit; -mod read2; -pub mod runtest; -pub mod util; +use compiletest::{common::Mode, log_config, parse_config, run_tests}; fn main() { tracing_subscriber::fmt::init(); @@ -57,1097 +18,3 @@ fn main() { log_config(&config); run_tests(config); } - -pub fn parse_config(args: Vec) -> Config { - let mut opts = Options::new(); - opts.reqopt("", "compile-lib-path", "path to host shared libraries", "PATH") - .reqopt("", "run-lib-path", "path to target shared libraries", "PATH") - .reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH") - .optopt("", "rustdoc-path", "path to rustdoc to use for compiling", "PATH") - .optopt("", "rust-demangler-path", "path to rust-demangler to use in tests", "PATH") - .reqopt("", "python", "path to python to use for doc tests", "PATH") - .optopt("", "jsondocck-path", "path to jsondocck to use for doc tests", "PATH") - .optopt("", "jsondoclint-path", "path to jsondoclint to use for doc tests", "PATH") - .optopt("", "valgrind-path", "path to Valgrind executable for Valgrind tests", "PROGRAM") - .optflag("", "force-valgrind", "fail if Valgrind tests cannot be run under Valgrind") - .optopt("", "run-clang-based-tests-with", "path to Clang executable", "PATH") - .optopt("", "llvm-filecheck", "path to LLVM's FileCheck binary", "DIR") - .reqopt("", "src-base", "directory to scan for test files", "PATH") - .reqopt("", "build-base", "directory to deposit test outputs", "PATH") - .reqopt("", "sysroot-base", "directory containing the compiler sysroot", "PATH") - .reqopt("", "stage-id", "the target-stage identifier", "stageN-TARGET") - .reqopt( - "", - "mode", - "which sort of compile tests to run", - "run-pass-valgrind | pretty | debug-info | codegen | rustdoc \ - | rustdoc-json | codegen-units | incremental | run-make | ui | js-doc-test | mir-opt | assembly", - ) - .reqopt( - "", - "suite", - "which suite of compile tests to run. used for nicer error reporting.", - "SUITE", - ) - .optopt( - "", - "pass", - "force {check,build,run}-pass tests to this mode.", - "check | build | run", - ) - .optopt("", "run", "whether to execute run-* tests", "auto | always | never") - .optflag("", "ignored", "run tests marked as ignored") - .optmulti("", "skip", "skip tests matching SUBSTRING. Can be passed multiple times", "SUBSTRING") - .optflag("", "exact", "filters match exactly") - .optopt( - "", - "runtool", - "supervisor program to run tests under \ - (eg. emulator, valgrind)", - "PROGRAM", - ) - .optmulti("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS") - .optmulti("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS") - .optflag("", "optimize-tests", "run tests with optimizations enabled") - .optflag("", "verbose", "run tests verbosely, showing all output") - .optflag( - "", - "bless", - "overwrite stderr/stdout files instead of complaining about a mismatch", - ) - .optflag("", "quiet", "print one character per test instead of one line") - .optopt("", "color", "coloring: auto, always, never", "WHEN") - .optflag("", "json", "emit json output instead of plaintext output") - .optopt("", "logfile", "file to log test execution to", "FILE") - .optopt("", "target", "the target to build for", "TARGET") - .optopt("", "host", "the host to build for", "HOST") - .optopt("", "cdb", "path to CDB to use for CDB debuginfo tests", "PATH") - .optopt("", "gdb", "path to GDB to use for GDB debuginfo tests", "PATH") - .optopt("", "lldb-version", "the version of LLDB used", "VERSION STRING") - .optopt("", "llvm-version", "the version of LLVM used", "VERSION STRING") - .optflag("", "system-llvm", "is LLVM the system LLVM") - .optopt("", "android-cross-path", "Android NDK standalone path", "PATH") - .optopt("", "adb-path", "path to the android debugger", "PATH") - .optopt("", "adb-test-dir", "path to tests for the android debugger", "PATH") - .optopt("", "lldb-python-dir", "directory containing LLDB's python module", "PATH") - .reqopt("", "cc", "path to a C compiler", "PATH") - .reqopt("", "cxx", "path to a C++ compiler", "PATH") - .reqopt("", "cflags", "flags for the C compiler", "FLAGS") - .reqopt("", "cxxflags", "flags for the CXX compiler", "FLAGS") - .optopt("", "ar", "path to an archiver", "PATH") - .optopt("", "target-linker", "path to a linker for the target", "PATH") - .optopt("", "host-linker", "path to a linker for the host", "PATH") - .reqopt("", "llvm-components", "list of LLVM components built in", "LIST") - .optopt("", "llvm-bin-dir", "Path to LLVM's `bin` directory", "PATH") - .optopt("", "nodejs", "the name of nodejs", "PATH") - .optopt("", "npm", "the name of npm", "PATH") - .optopt("", "remote-test-client", "path to the remote test client", "PATH") - .optopt( - "", - "compare-mode", - "mode describing what file the actual ui output will be compared to", - "COMPARE MODE", - ) - .optflag( - "", - "rustfix-coverage", - "enable this to generate a Rustfix coverage file, which is saved in \ - `.//rustfix_missing_coverage.txt`", - ) - .optflag("", "force-rerun", "rerun tests even if the inputs are unchanged") - .optflag("", "only-modified", "only run tests that result been modified") - .optflag("", "nocapture", "") - .optflag("h", "help", "show this message") - .reqopt("", "channel", "current Rust channel", "CHANNEL") - .optflag("", "git-hash", "run tests which rely on commit version being compiled into the binaries") - .optopt("", "edition", "default Rust edition", "EDITION"); - - let (argv0, args_) = args.split_first().unwrap(); - if args.len() == 1 || args[1] == "-h" || args[1] == "--help" { - let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0); - println!("{}", opts.usage(&message)); - println!(); - panic!() - } - - let matches = &match opts.parse(args_) { - Ok(m) => m, - Err(f) => panic!("{:?}", f), - }; - - if matches.opt_present("h") || matches.opt_present("help") { - let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0); - println!("{}", opts.usage(&message)); - println!(); - panic!() - } - - fn opt_path(m: &getopts::Matches, nm: &str) -> PathBuf { - match m.opt_str(nm) { - Some(s) => PathBuf::from(&s), - None => panic!("no option (=path) found for {}", nm), - } - } - - fn make_absolute(path: PathBuf) -> PathBuf { - if path.is_relative() { env::current_dir().unwrap().join(path) } else { path } - } - - let target = opt_str2(matches.opt_str("target")); - let android_cross_path = opt_path(matches, "android-cross-path"); - let (cdb, cdb_version) = analyze_cdb(matches.opt_str("cdb"), &target); - let (gdb, gdb_version, gdb_native_rust) = - analyze_gdb(matches.opt_str("gdb"), &target, &android_cross_path); - let (lldb_version, lldb_native_rust) = matches - .opt_str("lldb-version") - .as_deref() - .and_then(extract_lldb_version) - .map(|(v, b)| (Some(v), b)) - .unwrap_or((None, false)); - let color = match matches.opt_str("color").as_deref() { - Some("auto") | None => ColorConfig::AutoColor, - Some("always") => ColorConfig::AlwaysColor, - Some("never") => ColorConfig::NeverColor, - Some(x) => panic!("argument for --color must be auto, always, or never, but found `{}`", x), - }; - let llvm_version = - matches.opt_str("llvm-version").as_deref().and_then(header::extract_llvm_version).or_else( - || header::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?), - ); - - let src_base = opt_path(matches, "src-base"); - let run_ignored = matches.opt_present("ignored"); - let mode = matches.opt_str("mode").unwrap().parse().expect("invalid mode"); - let has_tidy = if mode == Mode::Rustdoc { - Command::new("tidy") - .arg("--version") - .stdout(Stdio::null()) - .status() - .map_or(false, |status| status.success()) - } else { - // Avoid spawning an external command when we know tidy won't be used. - false - }; - Config { - bless: matches.opt_present("bless"), - compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")), - run_lib_path: make_absolute(opt_path(matches, "run-lib-path")), - rustc_path: opt_path(matches, "rustc-path"), - rustdoc_path: matches.opt_str("rustdoc-path").map(PathBuf::from), - rust_demangler_path: matches.opt_str("rust-demangler-path").map(PathBuf::from), - python: matches.opt_str("python").unwrap(), - jsondocck_path: matches.opt_str("jsondocck-path"), - jsondoclint_path: matches.opt_str("jsondoclint-path"), - valgrind_path: matches.opt_str("valgrind-path"), - force_valgrind: matches.opt_present("force-valgrind"), - run_clang_based_tests_with: matches.opt_str("run-clang-based-tests-with"), - llvm_filecheck: matches.opt_str("llvm-filecheck").map(PathBuf::from), - llvm_bin_dir: matches.opt_str("llvm-bin-dir").map(PathBuf::from), - src_base, - build_base: opt_path(matches, "build-base"), - sysroot_base: opt_path(matches, "sysroot-base"), - stage_id: matches.opt_str("stage-id").unwrap(), - mode, - suite: matches.opt_str("suite").unwrap(), - debugger: None, - run_ignored, - filters: matches.free.clone(), - skip: matches.opt_strs("skip"), - filter_exact: matches.opt_present("exact"), - force_pass_mode: matches.opt_str("pass").map(|mode| { - mode.parse::() - .unwrap_or_else(|_| panic!("unknown `--pass` option `{}` given", mode)) - }), - run: matches.opt_str("run").and_then(|mode| match mode.as_str() { - "auto" => None, - "always" => Some(true), - "never" => Some(false), - _ => panic!("unknown `--run` option `{}` given", mode), - }), - logfile: matches.opt_str("logfile").map(|s| PathBuf::from(&s)), - runtool: matches.opt_str("runtool"), - host_rustcflags: matches.opt_strs("host-rustcflags"), - target_rustcflags: matches.opt_strs("target-rustcflags"), - optimize_tests: matches.opt_present("optimize-tests"), - target, - host: opt_str2(matches.opt_str("host")), - cdb, - cdb_version, - gdb, - gdb_version, - gdb_native_rust, - lldb_version, - lldb_native_rust, - llvm_version, - system_llvm: matches.opt_present("system-llvm"), - android_cross_path, - adb_path: opt_str2(matches.opt_str("adb-path")), - adb_test_dir: opt_str2(matches.opt_str("adb-test-dir")), - adb_device_status: opt_str2(matches.opt_str("target")).contains("android") - && "(none)" != opt_str2(matches.opt_str("adb-test-dir")) - && !opt_str2(matches.opt_str("adb-test-dir")).is_empty(), - lldb_python_dir: matches.opt_str("lldb-python-dir"), - verbose: matches.opt_present("verbose"), - format: match (matches.opt_present("quiet"), matches.opt_present("json")) { - (true, true) => panic!("--quiet and --json are incompatible"), - (true, false) => test::OutputFormat::Terse, - (false, true) => test::OutputFormat::Json, - (false, false) => test::OutputFormat::Pretty, - }, - only_modified: matches.opt_present("only-modified"), - color, - remote_test_client: matches.opt_str("remote-test-client").map(PathBuf::from), - compare_mode: matches - .opt_str("compare-mode") - .map(|s| s.parse().expect("invalid --compare-mode provided")), - rustfix_coverage: matches.opt_present("rustfix-coverage"), - has_tidy, - channel: matches.opt_str("channel").unwrap(), - git_hash: matches.opt_present("git-hash"), - edition: matches.opt_str("edition"), - - cc: matches.opt_str("cc").unwrap(), - cxx: matches.opt_str("cxx").unwrap(), - cflags: matches.opt_str("cflags").unwrap(), - cxxflags: matches.opt_str("cxxflags").unwrap(), - ar: matches.opt_str("ar").unwrap_or_else(|| String::from("ar")), - target_linker: matches.opt_str("target-linker"), - host_linker: matches.opt_str("host-linker"), - llvm_components: matches.opt_str("llvm-components").unwrap(), - nodejs: matches.opt_str("nodejs"), - npm: matches.opt_str("npm"), - - force_rerun: matches.opt_present("force-rerun"), - - target_cfgs: AtomicLazyCell::new(), - - nocapture: matches.opt_present("nocapture"), - } -} - -pub fn log_config(config: &Config) { - let c = config; - logv(c, "configuration:".to_string()); - logv(c, format!("compile_lib_path: {:?}", config.compile_lib_path)); - logv(c, format!("run_lib_path: {:?}", config.run_lib_path)); - logv(c, format!("rustc_path: {:?}", config.rustc_path.display())); - logv(c, format!("rustdoc_path: {:?}", config.rustdoc_path)); - logv(c, format!("rust_demangler_path: {:?}", config.rust_demangler_path)); - logv(c, format!("src_base: {:?}", config.src_base.display())); - logv(c, format!("build_base: {:?}", config.build_base.display())); - logv(c, format!("stage_id: {}", config.stage_id)); - logv(c, format!("mode: {}", config.mode)); - logv(c, format!("run_ignored: {}", config.run_ignored)); - logv(c, format!("filters: {:?}", config.filters)); - logv(c, format!("skip: {:?}", config.skip)); - logv(c, format!("filter_exact: {}", config.filter_exact)); - logv( - c, - format!("force_pass_mode: {}", opt_str(&config.force_pass_mode.map(|m| format!("{}", m))),), - ); - logv(c, format!("runtool: {}", opt_str(&config.runtool))); - logv(c, format!("host-rustcflags: {:?}", config.host_rustcflags)); - logv(c, format!("target-rustcflags: {:?}", config.target_rustcflags)); - logv(c, format!("target: {}", config.target)); - logv(c, format!("host: {}", config.host)); - logv(c, format!("android-cross-path: {:?}", config.android_cross_path.display())); - logv(c, format!("adb_path: {:?}", config.adb_path)); - logv(c, format!("adb_test_dir: {:?}", config.adb_test_dir)); - logv(c, format!("adb_device_status: {}", config.adb_device_status)); - logv(c, format!("ar: {}", config.ar)); - logv(c, format!("target-linker: {:?}", config.target_linker)); - logv(c, format!("host-linker: {:?}", config.host_linker)); - logv(c, format!("verbose: {}", config.verbose)); - logv(c, format!("format: {:?}", config.format)); - logv(c, "\n".to_string()); -} - -pub fn opt_str(maybestr: &Option) -> &str { - match *maybestr { - None => "(none)", - Some(ref s) => s, - } -} - -pub fn opt_str2(maybestr: Option) -> String { - match maybestr { - None => "(none)".to_owned(), - Some(s) => s, - } -} - -pub fn run_tests(config: Arc) { - // If we want to collect rustfix coverage information, - // we first make sure that the coverage file does not exist. - // It will be created later on. - if config.rustfix_coverage { - let mut coverage_file_path = config.build_base.clone(); - coverage_file_path.push("rustfix_missing_coverage.txt"); - if coverage_file_path.exists() { - if let Err(e) = fs::remove_file(&coverage_file_path) { - panic!("Could not delete {} due to {}", coverage_file_path.display(), e) - } - } - } - - // sadly osx needs some file descriptor limits raised for running tests in - // parallel (especially when we have lots and lots of child processes). - // For context, see #8904 - unsafe { - raise_fd_limit::raise_fd_limit(); - } - // Prevent issue #21352 UAC blocking .exe containing 'patch' etc. on Windows - // If #11207 is resolved (adding manifest to .exe) this becomes unnecessary - env::set_var("__COMPAT_LAYER", "RunAsInvoker"); - - // Let tests know which target they're running as - env::set_var("TARGET", &config.target); - - let opts = test_opts(&config); - - let mut configs = Vec::new(); - if let Mode::DebugInfo = config.mode { - // Debugging emscripten code doesn't make sense today - if !config.target.contains("emscripten") { - configs.extend(configure_cdb(&config)); - configs.extend(configure_gdb(&config)); - configs.extend(configure_lldb(&config)); - } - } else { - configs.push(config.clone()); - }; - - let mut tests = Vec::new(); - for c in configs { - let mut found_paths = BTreeSet::new(); - make_tests(c, &mut tests, &mut found_paths); - check_overlapping_tests(&found_paths); - } - - tests.sort_by(|a, b| a.desc.name.as_slice().cmp(&b.desc.name.as_slice())); - - let res = test::run_tests_console(&opts, tests); - match res { - Ok(true) => {} - Ok(false) => { - // We want to report that the tests failed, but we also want to give - // some indication of just what tests we were running. Especially on - // CI, where there can be cross-compiled tests for a lot of - // architectures, without this critical information it can be quite - // easy to miss which tests failed, and as such fail to reproduce - // the failure locally. - - println!( - "Some tests failed in compiletest suite={}{} mode={} host={} target={}", - config.suite, - config - .compare_mode - .as_ref() - .map(|c| format!(" compare_mode={:?}", c)) - .unwrap_or_default(), - config.mode, - config.host, - config.target - ); - - std::process::exit(1); - } - Err(e) => { - // We don't know if tests passed or not, but if there was an error - // during testing we don't want to just succeed (we may not have - // tested something), so fail. - // - // This should realistically "never" happen, so don't try to make - // this a pretty error message. - panic!("I/O failure during tests: {:?}", e); - } - } -} - -fn configure_cdb(config: &Config) -> Option> { - config.cdb.as_ref()?; - - Some(Arc::new(Config { debugger: Some(Debugger::Cdb), ..config.clone() })) -} - -fn configure_gdb(config: &Config) -> Option> { - config.gdb_version?; - - if config.matches_env("msvc") { - return None; - } - - if config.remote_test_client.is_some() && !config.target.contains("android") { - println!( - "WARNING: debuginfo tests are not available when \ - testing with remote" - ); - return None; - } - - if config.target.contains("android") { - println!( - "{} debug-info test uses tcp 5039 port.\ - please reserve it", - config.target - ); - - // android debug-info test uses remote debugger so, we test 1 thread - // at once as they're all sharing the same TCP port to communicate - // over. - // - // we should figure out how to lift this restriction! (run them all - // on different ports allocated dynamically). - env::set_var("RUST_TEST_THREADS", "1"); - } - - Some(Arc::new(Config { debugger: Some(Debugger::Gdb), ..config.clone() })) -} - -fn configure_lldb(config: &Config) -> Option> { - config.lldb_python_dir.as_ref()?; - - if let Some(350) = config.lldb_version { - println!( - "WARNING: The used version of LLDB (350) has a \ - known issue that breaks debuginfo tests. See \ - issue #32520 for more information. Skipping all \ - LLDB-based tests!", - ); - return None; - } - - Some(Arc::new(Config { debugger: Some(Debugger::Lldb), ..config.clone() })) -} - -pub fn test_opts(config: &Config) -> test::TestOpts { - if env::var("RUST_TEST_NOCAPTURE").is_ok() { - eprintln!( - "WARNING: RUST_TEST_NOCAPTURE is no longer used. \ - Use the `--nocapture` flag instead." - ); - } - - test::TestOpts { - exclude_should_panic: false, - filters: config.filters.clone(), - filter_exact: config.filter_exact, - run_ignored: if config.run_ignored { test::RunIgnored::Yes } else { test::RunIgnored::No }, - format: config.format, - logfile: config.logfile.clone(), - run_tests: true, - bench_benchmarks: true, - nocapture: config.nocapture, - color: config.color, - shuffle: false, - shuffle_seed: None, - test_threads: None, - skip: config.skip.clone(), - list: false, - options: test::Options::new(), - time_options: None, - force_run_in_process: false, - fail_fast: std::env::var_os("RUSTC_TEST_FAIL_FAST").is_some(), - } -} - -pub fn make_tests( - config: Arc, - tests: &mut Vec, - found_paths: &mut BTreeSet, -) { - debug!("making tests from {:?}", config.src_base.display()); - let inputs = common_inputs_stamp(&config); - let modified_tests = modified_tests(&config, &config.src_base).unwrap_or_else(|err| { - panic!("modified_tests got error from dir: {}, error: {}", config.src_base.display(), err) - }); - - let cache = HeadersCache::load(&config); - let mut poisoned = false; - collect_tests_from_dir( - config.clone(), - &cache, - &config.src_base, - &PathBuf::new(), - &inputs, - tests, - found_paths, - &modified_tests, - &mut poisoned, - ) - .unwrap_or_else(|_| panic!("Could not read tests from {}", config.src_base.display())); - - if poisoned { - eprintln!(); - panic!("there are errors in tests"); - } -} - -/// Returns a stamp constructed from input files common to all test cases. -fn common_inputs_stamp(config: &Config) -> Stamp { - let rust_src_dir = config.find_rust_src_root().expect("Could not find Rust source root"); - - let mut stamp = Stamp::from_path(&config.rustc_path); - - // Relevant pretty printer files - let pretty_printer_files = [ - "src/etc/rust_types.py", - "src/etc/gdb_load_rust_pretty_printers.py", - "src/etc/gdb_lookup.py", - "src/etc/gdb_providers.py", - "src/etc/lldb_batchmode.py", - "src/etc/lldb_lookup.py", - "src/etc/lldb_providers.py", - ]; - for file in &pretty_printer_files { - let path = rust_src_dir.join(file); - stamp.add_path(&path); - } - - stamp.add_dir(&rust_src_dir.join("src/etc/natvis")); - - stamp.add_dir(&config.run_lib_path); - - if let Some(ref rustdoc_path) = config.rustdoc_path { - stamp.add_path(&rustdoc_path); - stamp.add_path(&rust_src_dir.join("src/etc/htmldocck.py")); - } - - // Compiletest itself. - stamp.add_dir(&rust_src_dir.join("src/tools/compiletest/")); - - stamp -} - -fn modified_tests(config: &Config, dir: &Path) -> Result, String> { - if !config.only_modified { - return Ok(vec![]); - } - let files = - get_git_modified_files(Some(dir), &vec!["rs", "stderr", "fixed"])?.unwrap_or(vec![]); - // Add new test cases to the list, it will be convenient in daily development. - let untracked_files = get_git_untracked_files(None)?.unwrap_or(vec![]); - - let all_paths = [&files[..], &untracked_files[..]].concat(); - let full_paths = { - let mut full_paths: Vec = all_paths - .into_iter() - .map(|f| PathBuf::from(f).with_extension("").with_extension("rs")) - .filter_map(|f| if Path::new(&f).exists() { f.canonicalize().ok() } else { None }) - .collect(); - full_paths.dedup(); - full_paths.sort_unstable(); - full_paths - }; - Ok(full_paths) -} - -fn collect_tests_from_dir( - config: Arc, - cache: &HeadersCache, - dir: &Path, - relative_dir_path: &Path, - inputs: &Stamp, - tests: &mut Vec, - found_paths: &mut BTreeSet, - modified_tests: &Vec, - poisoned: &mut bool, -) -> io::Result<()> { - // Ignore directories that contain a file named `compiletest-ignore-dir`. - if dir.join("compiletest-ignore-dir").exists() { - return Ok(()); - } - - if config.mode == Mode::RunMake && dir.join("Makefile").exists() { - let paths = TestPaths { - file: dir.to_path_buf(), - relative_dir: relative_dir_path.parent().unwrap().to_path_buf(), - }; - tests.extend(make_test(config, cache, &paths, inputs, poisoned)); - return Ok(()); - } - - // If we find a test foo/bar.rs, we have to build the - // output directory `$build/foo` so we can write - // `$build/foo/bar` into it. We do this *now* in this - // sequential loop because otherwise, if we do it in the - // tests themselves, they race for the privilege of - // creating the directories and sometimes fail randomly. - let build_dir = output_relative_path(&config, relative_dir_path); - fs::create_dir_all(&build_dir).unwrap(); - - // Add each `.rs` file as a test, and recurse further on any - // subdirectories we find, except for `aux` directories. - for file in fs::read_dir(dir)? { - let file = file?; - let file_path = file.path(); - let file_name = file.file_name(); - if is_test(&file_name) && (!config.only_modified || modified_tests.contains(&file_path)) { - debug!("found test file: {:?}", file_path.display()); - let rel_test_path = relative_dir_path.join(file_path.file_stem().unwrap()); - found_paths.insert(rel_test_path); - let paths = - TestPaths { file: file_path, relative_dir: relative_dir_path.to_path_buf() }; - - tests.extend(make_test(config.clone(), cache, &paths, inputs, poisoned)) - } else if file_path.is_dir() { - let relative_file_path = relative_dir_path.join(file.file_name()); - if &file_name != "auxiliary" { - debug!("found directory: {:?}", file_path.display()); - collect_tests_from_dir( - config.clone(), - cache, - &file_path, - &relative_file_path, - inputs, - tests, - found_paths, - modified_tests, - poisoned, - )?; - } - } else { - debug!("found other file/directory: {:?}", file_path.display()); - } - } - Ok(()) -} - -/// Returns true if `file_name` looks like a proper test file name. -pub fn is_test(file_name: &OsString) -> bool { - let file_name = file_name.to_str().unwrap(); - - if !file_name.ends_with(".rs") { - return false; - } - - // `.`, `#`, and `~` are common temp-file prefixes. - let invalid_prefixes = &[".", "#", "~"]; - !invalid_prefixes.iter().any(|p| file_name.starts_with(p)) -} - -fn make_test( - config: Arc, - cache: &HeadersCache, - testpaths: &TestPaths, - inputs: &Stamp, - poisoned: &mut bool, -) -> Vec { - let test_path = if config.mode == Mode::RunMake { - // Parse directives in the Makefile - testpaths.file.join("Makefile") - } else { - PathBuf::from(&testpaths.file) - }; - let early_props = EarlyProps::from_file(&config, &test_path); - - // Incremental tests are special, they inherently cannot be run in parallel. - // `runtest::run` will be responsible for iterating over revisions. - let revisions = if early_props.revisions.is_empty() || config.mode == Mode::Incremental { - vec![None] - } else { - early_props.revisions.iter().map(Some).collect() - }; - - revisions - .into_iter() - .map(|revision| { - let src_file = - std::fs::File::open(&test_path).expect("open test file to parse ignores"); - let cfg = revision.map(|v| &**v); - let test_name = crate::make_test_name(&config, testpaths, revision); - let mut desc = make_test_description( - &config, cache, test_name, &test_path, src_file, cfg, poisoned, - ); - // Ignore tests that already run and are up to date with respect to inputs. - if !config.force_rerun { - desc.ignore |= is_up_to_date( - &config, - testpaths, - &early_props, - revision.map(|s| s.as_str()), - inputs, - ); - } - test::TestDescAndFn { - desc, - testfn: make_test_closure(config.clone(), testpaths, revision), - } - }) - .collect() -} - -fn stamp(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf { - output_base_dir(config, testpaths, revision).join("stamp") -} - -fn files_related_to_test( - config: &Config, - testpaths: &TestPaths, - props: &EarlyProps, - revision: Option<&str>, -) -> Vec { - let mut related = vec![]; - - if testpaths.file.is_dir() { - // run-make tests use their individual directory - for entry in WalkDir::new(&testpaths.file) { - let path = entry.unwrap().into_path(); - if path.is_file() { - related.push(path); - } - } - } else { - related.push(testpaths.file.clone()); - } - - for aux in &props.aux { - let path = testpaths.file.parent().unwrap().join("auxiliary").join(aux); - related.push(path); - } - - // UI test files. - for extension in UI_EXTENSIONS { - let path = expected_output_path(testpaths, revision, &config.compare_mode, extension); - related.push(path); - } - - related -} - -fn is_up_to_date( - config: &Config, - testpaths: &TestPaths, - props: &EarlyProps, - revision: Option<&str>, - inputs: &Stamp, -) -> bool { - let stamp_name = stamp(config, testpaths, revision); - // Check hash. - let contents = match fs::read_to_string(&stamp_name) { - Ok(f) => f, - Err(ref e) if e.kind() == ErrorKind::InvalidData => panic!("Can't read stamp contents"), - Err(_) => return false, - }; - let expected_hash = runtest::compute_stamp_hash(config); - if contents != expected_hash { - return false; - } - - // Check timestamps. - let mut inputs = inputs.clone(); - for path in files_related_to_test(config, testpaths, props, revision) { - inputs.add_path(&path); - } - - inputs < Stamp::from_path(&stamp_name) -} - -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] -struct Stamp { - time: SystemTime, -} - -impl Stamp { - fn from_path(path: &Path) -> Self { - let mut stamp = Stamp { time: SystemTime::UNIX_EPOCH }; - stamp.add_path(path); - stamp - } - - fn add_path(&mut self, path: &Path) { - let modified = fs::metadata(path) - .and_then(|metadata| metadata.modified()) - .unwrap_or(SystemTime::UNIX_EPOCH); - self.time = self.time.max(modified); - } - - fn add_dir(&mut self, path: &Path) { - for entry in WalkDir::new(path) { - let entry = entry.unwrap(); - if entry.file_type().is_file() { - let modified = entry - .metadata() - .ok() - .and_then(|metadata| metadata.modified().ok()) - .unwrap_or(SystemTime::UNIX_EPOCH); - self.time = self.time.max(modified); - } - } - } -} - -fn make_test_name( - config: &Config, - testpaths: &TestPaths, - revision: Option<&String>, -) -> test::TestName { - // Print the name of the file, relative to the repository root. - // `src_base` looks like `/path/to/rust/tests/ui` - let root_directory = config.src_base.parent().unwrap().parent().unwrap(); - let path = testpaths.file.strip_prefix(root_directory).unwrap(); - let debugger = match config.debugger { - Some(d) => format!("-{}", d), - None => String::new(), - }; - let mode_suffix = match config.compare_mode { - Some(ref mode) => format!(" ({})", mode.to_str()), - None => String::new(), - }; - - test::DynTestName(format!( - "[{}{}{}] {}{}", - config.mode, - debugger, - mode_suffix, - path.display(), - revision.map_or("".to_string(), |rev| format!("#{}", rev)) - )) -} - -fn make_test_closure( - config: Arc, - testpaths: &TestPaths, - revision: Option<&String>, -) -> test::TestFn { - let config = config.clone(); - let testpaths = testpaths.clone(); - let revision = revision.cloned(); - test::DynTestFn(Box::new(move || { - runtest::run(config, &testpaths, revision.as_deref()); - Ok(()) - })) -} - -/// Returns `true` if the given target is an Android target for the -/// purposes of GDB testing. -fn is_android_gdb_target(target: &str) -> bool { - matches!( - &target[..], - "arm-linux-androideabi" | "armv7-linux-androideabi" | "aarch64-linux-android" - ) -} - -/// Returns `true` if the given target is a MSVC target for the purpouses of CDB testing. -fn is_pc_windows_msvc_target(target: &str) -> bool { - target.ends_with("-pc-windows-msvc") -} - -fn find_cdb(target: &str) -> Option { - if !(cfg!(windows) && is_pc_windows_msvc_target(target)) { - return None; - } - - let pf86 = env::var_os("ProgramFiles(x86)").or_else(|| env::var_os("ProgramFiles"))?; - let cdb_arch = if cfg!(target_arch = "x86") { - "x86" - } else if cfg!(target_arch = "x86_64") { - "x64" - } else if cfg!(target_arch = "aarch64") { - "arm64" - } else if cfg!(target_arch = "arm") { - "arm" - } else { - return None; // No compatible CDB.exe in the Windows 10 SDK - }; - - let mut path = PathBuf::new(); - path.push(pf86); - path.push(r"Windows Kits\10\Debuggers"); // We could check 8.1 etc. too? - path.push(cdb_arch); - path.push(r"cdb.exe"); - - if !path.exists() { - return None; - } - - Some(path.into_os_string()) -} - -/// Returns Path to CDB -fn analyze_cdb(cdb: Option, target: &str) -> (Option, Option<[u16; 4]>) { - let cdb = cdb.map(OsString::from).or_else(|| find_cdb(target)); - - let mut version = None; - if let Some(cdb) = cdb.as_ref() { - if let Ok(output) = Command::new(cdb).arg("/version").output() { - if let Some(first_line) = String::from_utf8_lossy(&output.stdout).lines().next() { - version = extract_cdb_version(&first_line); - } - } - } - - (cdb, version) -} - -fn extract_cdb_version(full_version_line: &str) -> Option<[u16; 4]> { - // Example full_version_line: "cdb version 10.0.18362.1" - let version = full_version_line.rsplit(' ').next()?; - let mut components = version.split('.'); - let major: u16 = components.next().unwrap().parse().unwrap(); - let minor: u16 = components.next().unwrap().parse().unwrap(); - let patch: u16 = components.next().unwrap_or("0").parse().unwrap(); - let build: u16 = components.next().unwrap_or("0").parse().unwrap(); - Some([major, minor, patch, build]) -} - -/// Returns (Path to GDB, GDB Version, GDB has Rust Support) -fn analyze_gdb( - gdb: Option, - target: &str, - android_cross_path: &PathBuf, -) -> (Option, Option, bool) { - #[cfg(not(windows))] - const GDB_FALLBACK: &str = "gdb"; - #[cfg(windows)] - const GDB_FALLBACK: &str = "gdb.exe"; - - const MIN_GDB_WITH_RUST: u32 = 7011010; - - let fallback_gdb = || { - if is_android_gdb_target(target) { - let mut gdb_path = match android_cross_path.to_str() { - Some(x) => x.to_owned(), - None => panic!("cannot find android cross path"), - }; - gdb_path.push_str("/bin/gdb"); - gdb_path - } else { - GDB_FALLBACK.to_owned() - } - }; - - let gdb = match gdb { - None => fallback_gdb(), - Some(ref s) if s.is_empty() => fallback_gdb(), // may be empty if configure found no gdb - Some(ref s) => s.to_owned(), - }; - - let mut version_line = None; - if let Ok(output) = Command::new(&gdb).arg("--version").output() { - if let Some(first_line) = String::from_utf8_lossy(&output.stdout).lines().next() { - version_line = Some(first_line.to_string()); - } - } - - let version = match version_line { - Some(line) => extract_gdb_version(&line), - None => return (None, None, false), - }; - - let gdb_native_rust = version.map_or(false, |v| v >= MIN_GDB_WITH_RUST); - - (Some(gdb), version, gdb_native_rust) -} - -fn extract_gdb_version(full_version_line: &str) -> Option { - let full_version_line = full_version_line.trim(); - - // GDB versions look like this: "major.minor.patch?.yyyymmdd?", with both - // of the ? sections being optional - - // We will parse up to 3 digits for each component, ignoring the date - - // We skip text in parentheses. This avoids accidentally parsing - // the openSUSE version, which looks like: - // GNU gdb (GDB; openSUSE Leap 15.0) 8.1 - // This particular form is documented in the GNU coding standards: - // https://www.gnu.org/prep/standards/html_node/_002d_002dversion.html#g_t_002d_002dversion - - let unbracketed_part = full_version_line.split('[').next().unwrap(); - let mut splits = unbracketed_part.trim_end().rsplit(' '); - let version_string = splits.next().unwrap(); - - let mut splits = version_string.split('.'); - let major = splits.next().unwrap(); - let minor = splits.next().unwrap(); - let patch = splits.next(); - - let major: u32 = major.parse().unwrap(); - let (minor, patch): (u32, u32) = match minor.find(not_a_digit) { - None => { - let minor = minor.parse().unwrap(); - let patch: u32 = match patch { - Some(patch) => match patch.find(not_a_digit) { - None => patch.parse().unwrap(), - Some(idx) if idx > 3 => 0, - Some(idx) => patch[..idx].parse().unwrap(), - }, - None => 0, - }; - (minor, patch) - } - // There is no patch version after minor-date (e.g. "4-2012"). - Some(idx) => { - let minor = minor[..idx].parse().unwrap(); - (minor, 0) - } - }; - - Some(((major * 1000) + minor) * 1000 + patch) -} - -/// Returns (LLDB version, LLDB is rust-enabled) -fn extract_lldb_version(full_version_line: &str) -> Option<(u32, bool)> { - // Extract the major LLDB version from the given version string. - // LLDB version strings are different for Apple and non-Apple platforms. - // The Apple variant looks like this: - // - // LLDB-179.5 (older versions) - // lldb-300.2.51 (new versions) - // - // We are only interested in the major version number, so this function - // will return `Some(179)` and `Some(300)` respectively. - // - // Upstream versions look like: - // lldb version 6.0.1 - // - // There doesn't seem to be a way to correlate the Apple version - // with the upstream version, and since the tests were originally - // written against Apple versions, we make a fake Apple version by - // multiplying the first number by 100. This is a hack, but - // normally fine because the only non-Apple version we test is - // rust-enabled. - - let full_version_line = full_version_line.trim(); - - if let Some(apple_ver) = - full_version_line.strip_prefix("LLDB-").or_else(|| full_version_line.strip_prefix("lldb-")) - { - if let Some(idx) = apple_ver.find(not_a_digit) { - let version: u32 = apple_ver[..idx].parse().unwrap(); - return Some((version, full_version_line.contains("rust-enabled"))); - } - } else if let Some(lldb_ver) = full_version_line.strip_prefix("lldb version ") { - if let Some(idx) = lldb_ver.find(not_a_digit) { - let version: u32 = lldb_ver[..idx].parse().ok()?; - return Some((version * 100, full_version_line.contains("rust-enabled"))); - } - } - None -} - -fn not_a_digit(c: char) -> bool { - !c.is_digit(10) -} - -fn check_overlapping_tests(found_paths: &BTreeSet) { - let mut collisions = Vec::new(); - for path in found_paths { - for ancestor in path.ancestors().skip(1) { - if found_paths.contains(ancestor) { - collisions.push((path, ancestor.clone())); - } - } - } - if !collisions.is_empty() { - let collisions: String = collisions - .into_iter() - .map(|(path, check_parent)| format!("test {path:?} clashes with {check_parent:?}\n")) - .collect(); - panic!( - "{collisions}\n\ - Tests cannot have overlapping names. Make sure they use unique prefixes." - ); - } -} From f0c9c1eb19864d95e6348d79c54fa4a412019f3a Mon Sep 17 00:00:00 2001 From: Finn Bear Date: Tue, 16 May 2023 13:39:17 -0700 Subject: [PATCH 04/69] Use an unbounded lifetime in String::leak. --- library/alloc/src/string.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 088139a6907b8..559704d90af01 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1851,7 +1851,7 @@ impl String { } /// Consumes and leaks the `String`, returning a mutable reference to the contents, - /// `&'static mut str`. + /// `&'a mut str`. /// /// This is mainly useful for data that lives for the remainder of /// the program's life. Dropping the returned reference will cause a memory @@ -1874,7 +1874,7 @@ impl String { /// ``` #[unstable(feature = "string_leak", issue = "102929")] #[inline] - pub fn leak(self) -> &'static mut str { + pub fn leak<'a>(self) -> &'a mut str { let slice = self.vec.leak(); unsafe { from_utf8_unchecked_mut(slice) } } From f52db3ecaa47167137cdbe48bd7d56bb5f9c9d3c Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 18 May 2023 08:50:56 +0000 Subject: [PATCH 05/69] Stop confusing specification levels when computing expectations. --- compiler/rustc_lint/src/levels.rs | 10 +++++++--- .../rfc-2383-lint-reason/root-attribute-confusion.rs | 7 +++++++ 2 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 tests/ui/lint/rfc-2383-lint-reason/root-attribute-confusion.rs diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index b92ed11f38a88..8376835f52cfa 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -242,7 +242,9 @@ impl LintLevelsProvider for LintLevelQueryMap<'_> { struct QueryMapExpectationsWrapper<'tcx> { tcx: TyCtxt<'tcx>, + /// HirId of the currently investigated element. cur: HirId, + /// Level map for `cur`. specs: ShallowLintLevelMap, expectations: Vec<(LintExpectationId, LintExpectation)>, unstable_to_stable_ids: FxHashMap, @@ -255,11 +257,11 @@ impl LintLevelsProvider for QueryMapExpectationsWrapper<'_> { self.specs.specs.get(&self.cur.local_id).unwrap_or(&self.empty) } fn insert(&mut self, id: LintId, lvl: LevelAndSource) { - let specs = self.specs.specs.get_mut_or_insert_default(self.cur.local_id); - specs.clear(); - specs.insert(id, lvl); + self.specs.specs.get_mut_or_insert_default(self.cur.local_id).insert(id, lvl); } fn get_lint_level(&self, lint: &'static Lint, _: &Session) -> LevelAndSource { + // We cannot use `tcx.lint_level_at_node` because we want to know in which order the + // attributes have been inserted, in particular whether an `expect` follows a `forbid`. self.specs.lint_level_id_at_node(self.tcx, LintId::of(lint), self.cur) } fn push_expectation(&mut self, id: LintExpectationId, expectation: LintExpectation) { @@ -355,7 +357,9 @@ impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> { impl<'tcx> LintLevelsBuilder<'_, QueryMapExpectationsWrapper<'tcx>> { fn add_id(&mut self, hir_id: HirId) { + // Change both the `HirId` and the associated specs. self.provider.cur = hir_id; + self.provider.specs.specs.clear(); self.add(self.provider.tcx.hir().attrs(hir_id), hir_id == hir::CRATE_HIR_ID, Some(hir_id)); } } diff --git a/tests/ui/lint/rfc-2383-lint-reason/root-attribute-confusion.rs b/tests/ui/lint/rfc-2383-lint-reason/root-attribute-confusion.rs new file mode 100644 index 0000000000000..0cade7fef02fd --- /dev/null +++ b/tests/ui/lint/rfc-2383-lint-reason/root-attribute-confusion.rs @@ -0,0 +1,7 @@ +// check-pass +// compile-flags: -Dunused_attributes + +#![deny(unused_crate_dependencies)] +#![feature(lint_reasons)] + +fn main() {} From c36b2092bbb88604fe5b467be56ccd870307be94 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Sat, 20 May 2023 14:40:11 +0300 Subject: [PATCH 06/69] create new tool rustdoc-gui-test --- Cargo.lock | 9 ++ Cargo.toml | 1 + src/tools/rustdoc-gui-test/Cargo.toml | 9 ++ src/tools/rustdoc-gui-test/src/config.rs | 62 +++++++++ src/tools/rustdoc-gui-test/src/main.rs | 162 +++++++++++++++++++++++ 5 files changed, 243 insertions(+) create mode 100644 src/tools/rustdoc-gui-test/Cargo.toml create mode 100644 src/tools/rustdoc-gui-test/src/config.rs create mode 100644 src/tools/rustdoc-gui-test/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index be95e63eb7698..1da5a5ccb5fa8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4324,6 +4324,15 @@ dependencies = [ "tracing-tree", ] +[[package]] +name = "rustdoc-gui-test" +version = "0.1.0" +dependencies = [ + "compiletest", + "getopts", + "walkdir", +] + [[package]] name = "rustdoc-json-types" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 53331e2869f2e..8eb378afe428a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,7 @@ members = [ "src/tools/generate-copyright", "src/tools/suggest-tests", "src/tools/generate-windows-sys", + "src/tools/rustdoc-gui-test", ] exclude = [ diff --git a/src/tools/rustdoc-gui-test/Cargo.toml b/src/tools/rustdoc-gui-test/Cargo.toml new file mode 100644 index 0000000000000..f0c5b367117e1 --- /dev/null +++ b/src/tools/rustdoc-gui-test/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "rustdoc-gui-test" +version = "0.1.0" +edition = "2021" + +[dependencies] +compiletest = { path = "../compiletest" } +getopts = "0.2" +walkdir = "2" diff --git a/src/tools/rustdoc-gui-test/src/config.rs b/src/tools/rustdoc-gui-test/src/config.rs new file mode 100644 index 0000000000000..dc4c56a5e7abd --- /dev/null +++ b/src/tools/rustdoc-gui-test/src/config.rs @@ -0,0 +1,62 @@ +use getopts::Options; +use std::{env, path::PathBuf}; + +pub(crate) struct Config { + pub(crate) nodejs: PathBuf, + pub(crate) npm: PathBuf, + pub(crate) rust_src: PathBuf, + pub(crate) out_dir: PathBuf, + pub(crate) initial_cargo: PathBuf, + pub(crate) jobs: String, + pub(crate) test_args: Vec, + pub(crate) goml_files: Vec, + pub(crate) rustc: PathBuf, + pub(crate) rustdoc: PathBuf, + pub(crate) verbose: bool, +} + +impl Config { + pub(crate) fn from_args(args: Vec) -> Self { + let mut opts = Options::new(); + opts.reqopt("", "nodejs", "absolute path of nodejs", "PATH") + .reqopt("", "npm", "absolute path of npm", "PATH") + .reqopt("", "out-dir", "output path of doc compilation", "PATH") + .reqopt("", "rust-src", "root source of the rust source", "PATH") + .reqopt( + "", + "initial-cargo", + "path to cargo to use for compiling tests/rustdoc-gui/src/*", + "PATH", + ) + .reqopt("", "jobs", "jobs arg of browser-ui-test", "JOBS") + .optflag("", "verbose", "run tests verbosely, showing all output") + .optmulti("", "test-arg", "args for browser-ui-test", "FLAGS") + .optmulti("", "goml-file", "goml files for testing with browser-ui-test", "LIST"); + + let (argv0, args_) = args.split_first().unwrap(); + if args.len() == 1 || args[1] == "-h" || args[1] == "--help" { + let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0); + println!("{}", opts.usage(&message)); + std::process::exit(1); + } + + let matches = &match opts.parse(args_) { + Ok(m) => m, + Err(f) => panic!("{:?}", f), + }; + + Self { + nodejs: matches.opt_str("nodejs").map(PathBuf::from).expect("nodejs isn't available"), + npm: matches.opt_str("npm").map(PathBuf::from).expect("npm isn't available"), + rust_src: matches.opt_str("rust-src").map(PathBuf::from).unwrap(), + out_dir: matches.opt_str("out-dir").map(PathBuf::from).unwrap(), + initial_cargo: matches.opt_str("initial-cargo").map(PathBuf::from).unwrap(), + jobs: matches.opt_str("jobs").unwrap(), + goml_files: matches.opt_strs("goml-file").iter().map(PathBuf::from).collect(), + test_args: matches.opt_strs("test-arg").iter().map(PathBuf::from).collect(), + rustc: env::var("RUSTC").map(PathBuf::from).unwrap(), + rustdoc: env::var("RUSTDOC").map(PathBuf::from).unwrap(), + verbose: matches.opt_present("verbose"), + } + } +} diff --git a/src/tools/rustdoc-gui-test/src/main.rs b/src/tools/rustdoc-gui-test/src/main.rs new file mode 100644 index 0000000000000..8dc18dfaea2d6 --- /dev/null +++ b/src/tools/rustdoc-gui-test/src/main.rs @@ -0,0 +1,162 @@ +use compiletest::header::TestProps; +use config::Config; +use std::path::{Path, PathBuf}; +use std::process::Command; +use std::sync::Arc; +use std::{env, fs}; + +mod config; + +fn get_browser_ui_test_version_inner(npm: &Path, global: bool) -> Option { + let mut command = Command::new(&npm); + command.arg("list").arg("--parseable").arg("--long").arg("--depth=0"); + if global { + command.arg("--global"); + } + let lines = command + .output() + .map(|output| String::from_utf8_lossy(&output.stdout).into_owned()) + .unwrap_or(String::new()); + lines + .lines() + .find_map(|l| l.split(':').nth(1)?.strip_prefix("browser-ui-test@")) + .map(|v| v.to_owned()) +} + +fn get_browser_ui_test_version(npm: &Path) -> Option { + get_browser_ui_test_version_inner(npm, false) + .or_else(|| get_browser_ui_test_version_inner(npm, true)) +} + +fn compare_browser_ui_test_version(installed_version: &str, src: &Path) { + match fs::read_to_string( + src.join("src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version"), + ) { + Ok(v) => { + if v.trim() != installed_version { + eprintln!( + "⚠️ Installed version of browser-ui-test (`{}`) is different than the \ + one used in the CI (`{}`)", + installed_version, v + ); + eprintln!( + "You can install this version using `npm update browser-ui-test` or by using \ + `npm install browser-ui-test@{}`", + v, + ); + } + } + Err(e) => eprintln!("Couldn't find the CI browser-ui-test version: {:?}", e), + } +} + +fn find_librs>(path: P) -> Option { + for entry in walkdir::WalkDir::new(path) { + let entry = entry.ok()?; + if entry.file_type().is_file() && entry.file_name() == "lib.rs" { + return Some(entry.path().to_path_buf()); + } + } + None +} + +// FIXME: move `bootstrap::util::try_run` into `build_helper` crate +// and use that one instead of creating this function. +fn try_run(cmd: &mut Command, print_cmd_on_fail: bool) -> bool { + let status = match cmd.status() { + Ok(status) => status, + Err(e) => panic!("failed to execute command: {:?}\nerror: {}", cmd, e), + }; + if !status.success() && print_cmd_on_fail { + println!( + "\n\ncommand did not execute successfully: {:?}\n\ + expected success, got: {}\n\n", + cmd, status + ); + } + status.success() +} + +fn main() { + let config = Arc::new(Config::from_args(env::args().collect())); + + // The goal here is to check if the necessary packages are installed, and if not, we + // panic. + match get_browser_ui_test_version(&config.npm) { + Some(version) => { + // We also check the version currently used in CI and emit a warning if it's not the + // same one. + compare_browser_ui_test_version(&version, &config.rust_src); + } + None => { + eprintln!( + r#" +error: rustdoc-gui test suite cannot be run because npm `browser-ui-test` dependency is missing. + +If you want to install the `browser-ui-test` dependency, run `npm install browser-ui-test` +"#, + ); + + panic!("Cannot run rustdoc-gui tests"); + } + } + + let src_path = config.rust_src.join("tests/rustdoc-gui/src"); + for entry in src_path.read_dir().expect("read_dir call failed") { + if let Ok(entry) = entry { + let path = entry.path(); + + if !path.is_dir() { + continue; + } + + let mut cargo = Command::new(&config.initial_cargo); + cargo + .arg("doc") + .arg("--target-dir") + .arg(&config.out_dir) + .env("RUSTC_BOOTSTRAP", "1") + .env("RUSTDOC", &config.rustdoc) + .env("RUSTC", &config.rustc) + .current_dir(path); + + if let Some(librs) = find_librs(entry.path()) { + let compiletest_c = compiletest::common::Config { + edition: None, + mode: compiletest::common::Mode::Rustdoc, + ..Default::default() + }; + + let test_props = TestProps::from_file(&librs, None, &compiletest_c); + + if !test_props.compile_flags.is_empty() { + cargo.env("RUSTDOCFLAGS", test_props.compile_flags.join(" ")); + } + + if let Some(flags) = &test_props.run_flags { + cargo.arg(flags); + } + } + + try_run(&mut cargo, config.verbose); + } + } + + let mut command = Command::new(&config.nodejs); + command + .arg(config.rust_src.join("src/tools/rustdoc-gui/tester.js")) + .arg("--jobs") + .arg(&config.jobs) + .arg("--doc-folder") + .arg(config.out_dir.join("doc")) + .arg("--tests-folder") + .arg(config.rust_src.join("tests/rustdoc-gui")); + + for file in &config.goml_files { + command.arg("--file").arg(file); + } + + command.args(&config.test_args); + + try_run(&mut command, config.verbose); +} From 6a347322a9dcb44967020da98c3f9e9e22f38e17 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Sat, 20 May 2023 14:40:46 +0300 Subject: [PATCH 07/69] derive `Default` trait for `compiletest::common::Config` --- library/test/src/options.rs | 6 ++++-- src/tools/compiletest/src/common.rs | 8 +++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/library/test/src/options.rs b/library/test/src/options.rs index 75ec0b616e193..3eaad59474a12 100644 --- a/library/test/src/options.rs +++ b/library/test/src/options.rs @@ -16,19 +16,21 @@ pub enum ShouldPanic { } /// Whether should console output be colored or not -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Default, Debug)] pub enum ColorConfig { + #[default] AutoColor, AlwaysColor, NeverColor, } /// Format of the test results output -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] pub enum OutputFormat { /// Verbose output Pretty, /// Quiet output + #[default] Terse, /// JSON output Json, diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 9059a145b4345..1dd8cf04b25c3 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -69,6 +69,12 @@ string_enum! { } } +impl Default for Mode { + fn default() -> Self { + Mode::Ui + } +} + impl Mode { pub fn disambiguator(self) -> &'static str { // Pretty-printing tests could run concurrently, and if they do, @@ -125,7 +131,7 @@ pub enum PanicStrategy { } /// Configuration for compiletest -#[derive(Debug, Clone)] +#[derive(Debug, Default, Clone)] pub struct Config { /// `true` to overwrite stderr/stdout files instead of complaining about changes in output. pub bless: bool, From 02ea750f0bf5b85c1b11f45c22aa8eccdcfcc57d Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Sat, 20 May 2023 14:41:37 +0300 Subject: [PATCH 08/69] add compiletest headers to rustdoc-gui tests --- tests/rustdoc-gui/source-anchor-scroll.goml | 8 ++++---- tests/rustdoc-gui/src/extend_css/lib.rs | 1 + tests/rustdoc-gui/src/link_to_definition/lib.rs | 1 + tests/rustdoc-gui/src/scrape_examples/src/lib.rs | 1 + 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/rustdoc-gui/source-anchor-scroll.goml b/tests/rustdoc-gui/source-anchor-scroll.goml index 3d88d5619b19b..67f1497e70ce6 100644 --- a/tests/rustdoc-gui/source-anchor-scroll.goml +++ b/tests/rustdoc-gui/source-anchor-scroll.goml @@ -8,13 +8,13 @@ set-window-size: (600, 800) assert-property: ("html", {"scrollTop": "0"}) click: '//a[text() = "barbar"]' -assert-property: ("html", {"scrollTop": "125"}) +assert-property: ("html", {"scrollTop": "149"}) click: '//a[text() = "bar"]' -assert-property: ("html", {"scrollTop": "156"}) +assert-property: ("html", {"scrollTop": "180"}) click: '//a[text() = "sub_fn"]' -assert-property: ("html", {"scrollTop": "53"}) +assert-property: ("html", {"scrollTop": "77"}) // We now check that clicking on lines doesn't change the scroll // Extra information: the "sub_fn" function header is on line 1. click: '//*[@id="6"]' -assert-property: ("html", {"scrollTop": "53"}) +assert-property: ("html", {"scrollTop": "77"}) diff --git a/tests/rustdoc-gui/src/extend_css/lib.rs b/tests/rustdoc-gui/src/extend_css/lib.rs index 3a3babf898405..2308c0932fd0e 100644 --- a/tests/rustdoc-gui/src/extend_css/lib.rs +++ b/tests/rustdoc-gui/src/extend_css/lib.rs @@ -1 +1,2 @@ +// compile-flags: --extend-css extra.css //!
text in red
diff --git a/tests/rustdoc-gui/src/link_to_definition/lib.rs b/tests/rustdoc-gui/src/link_to_definition/lib.rs index 419a9cceec5f3..6fed79aedb890 100644 --- a/tests/rustdoc-gui/src/link_to_definition/lib.rs +++ b/tests/rustdoc-gui/src/link_to_definition/lib.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zunstable-options --generate-link-to-definition pub fn sub_fn() { barbar(); } diff --git a/tests/rustdoc-gui/src/scrape_examples/src/lib.rs b/tests/rustdoc-gui/src/scrape_examples/src/lib.rs index 88b03cf26038d..6666587ad541a 100644 --- a/tests/rustdoc-gui/src/scrape_examples/src/lib.rs +++ b/tests/rustdoc-gui/src/scrape_examples/src/lib.rs @@ -1,3 +1,4 @@ +// run-flags:-Zrustdoc-scrape-examples /// # Examples /// /// ``` From f28a63bdf0f18057f0c4be578eb10c7dcc7929de Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Sat, 20 May 2023 14:42:12 +0300 Subject: [PATCH 09/69] implement and use tools/rustdoc-gui-test in bootstrap --- src/bootstrap/builder.rs | 3 +- src/bootstrap/test.rs | 116 ++++++++++----------------------------- src/bootstrap/tool.rs | 1 + 3 files changed, 31 insertions(+), 89 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 5c37fab547070..1b07f64fb5ea2 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -689,7 +689,8 @@ impl<'a> Builder<'a> { tool::Miri, tool::CargoMiri, llvm::Lld, - llvm::CrtBeginEnd + llvm::CrtBeginEnd, + tool::RustdocGUITest, ), Kind::Check | Kind::Clippy | Kind::Fix => describe!( check::Std, diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 2d600704e025e..8c62b9b3a99bf 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -942,28 +942,6 @@ fn get_browser_ui_test_version(npm: &Path) -> Option { .or_else(|| get_browser_ui_test_version_inner(npm, true)) } -fn compare_browser_ui_test_version(installed_version: &str, src: &Path) { - match fs::read_to_string( - src.join("src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version"), - ) { - Ok(v) => { - if v.trim() != installed_version { - eprintln!( - "⚠️ Installed version of browser-ui-test (`{}`) is different than the \ - one used in the CI (`{}`)", - installed_version, v - ); - eprintln!( - "You can install this version using `npm update browser-ui-test` or by using \ - `npm install browser-ui-test@{}`", - v, - ); - } - } - Err(e) => eprintln!("Couldn't find the CI browser-ui-test version: {:?}", e), - } -} - #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct RustdocGUI { pub target: TargetSelection, @@ -995,79 +973,30 @@ impl Step for RustdocGUI { } fn run(self, builder: &Builder<'_>) { - let nodejs = builder.config.nodejs.as_ref().expect("nodejs isn't available"); - let npm = builder.config.npm.as_ref().expect("npm isn't available"); - builder.ensure(compile::Std::new(self.compiler, self.target)); - // The goal here is to check if the necessary packages are installed, and if not, we - // panic. - match get_browser_ui_test_version(&npm) { - Some(version) => { - // We also check the version currently used in CI and emit a warning if it's not the - // same one. - compare_browser_ui_test_version(&version, &builder.build.src); - } - None => { - eprintln!( - "error: rustdoc-gui test suite cannot be run because npm `browser-ui-test` \ - dependency is missing", - ); - eprintln!( - "If you want to install the `{0}` dependency, run `npm install {0}`", - "browser-ui-test", - ); - panic!("Cannot run rustdoc-gui tests"); - } - } + let mut cmd = builder.tool_cmd(Tool::RustdocGUITest); let out_dir = builder.test_out(self.target).join("rustdoc-gui"); - - // We remove existing folder to be sure there won't be artifacts remaining. builder.clear_if_dirty(&out_dir, &builder.rustdoc(self.compiler)); - let src_path = builder.build.src.join("tests/rustdoc-gui/src"); - // We generate docs for the libraries present in the rustdoc-gui's src folder. - for entry in src_path.read_dir().expect("read_dir call failed") { - if let Ok(entry) = entry { - let path = entry.path(); + if let Some(src) = builder.config.src.to_str() { + cmd.arg("--rust-src").arg(src); + } - if !path.is_dir() { - continue; - } + if let Some(out_dir) = out_dir.to_str() { + cmd.arg("--out-dir").arg(out_dir); + } - let mut cargo = Command::new(&builder.initial_cargo); - cargo - .arg("doc") - .arg("--target-dir") - .arg(&out_dir) - .env("RUSTC_BOOTSTRAP", "1") - .env("RUSTDOC", builder.rustdoc(self.compiler)) - .env("RUSTC", builder.rustc(self.compiler)) - .current_dir(path); - // FIXME: implement a `// compile-flags` command or similar - // instead of hard-coding this test - if entry.file_name() == "link_to_definition" { - cargo.env("RUSTDOCFLAGS", "-Zunstable-options --generate-link-to-definition"); - } else if entry.file_name() == "scrape_examples" { - cargo.arg("-Zrustdoc-scrape-examples"); - } else if entry.file_name() == "extend_css" { - cargo.env("RUSTDOCFLAGS", &format!("--extend-css extra.css")); - } - builder.run(&mut cargo); - } + if let Some(initial_cargo) = builder.config.initial_cargo.to_str() { + cmd.arg("--initial-cargo").arg(initial_cargo); } - // We now run GUI tests. - let mut command = Command::new(&nodejs); - command - .arg(builder.build.src.join("src/tools/rustdoc-gui/tester.js")) - .arg("--jobs") - .arg(&builder.jobs().to_string()) - .arg("--doc-folder") - .arg(out_dir.join("doc")) - .arg("--tests-folder") - .arg(builder.build.src.join("tests/rustdoc-gui")); + cmd.arg("--jobs").arg(builder.jobs().to_string()); + + cmd.env("RUSTDOC", builder.rustdoc(self.compiler)) + .env("RUSTC", builder.rustc(self.compiler)); + for path in &builder.paths { if let Some(p) = util::is_valid_test_suite_arg(path, "tests/rustdoc-gui", builder) { if !p.ends_with(".goml") { @@ -1075,14 +1004,25 @@ impl Step for RustdocGUI { panic!("Cannot run rustdoc-gui tests"); } if let Some(name) = path.file_name().and_then(|f| f.to_str()) { - command.arg("--file").arg(name); + cmd.arg("--goml-file").arg(name); } } } + for test_arg in builder.config.test_args() { - command.arg(test_arg); + cmd.arg("--test-arg").arg(test_arg); } - builder.run(&mut command); + + if let Some(ref nodejs) = builder.config.nodejs { + cmd.arg("--nodejs").arg(nodejs); + } + + if let Some(ref npm) = builder.config.npm { + cmd.arg("--npm").arg(npm); + } + + let _time = util::timeit(&builder); + crate::render_tests::try_run_tests(builder, &mut cmd); } } diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index f13d365e3754d..b3791efaf58cf 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -302,6 +302,7 @@ bootstrap_tool!( GenerateCopyright, "src/tools/generate-copyright", "generate-copyright"; SuggestTests, "src/tools/suggest-tests", "suggest-tests"; GenerateWindowsSys, "src/tools/generate-windows-sys", "generate-windows-sys"; + RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = "test"; ); #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)] From 57c5ac7894cae042678b98f239c412f4710071c2 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 21 May 2023 01:31:17 -0700 Subject: [PATCH 10/69] Tweak the post-order for multi-successor blocks --- compiler/rustc_middle/src/mir/terminator.rs | 2 +- compiler/rustc_middle/src/mir/traversal.rs | 26 +++++++++---------- ...ead-local-static-borrow-outlives-fn.stderr | 2 +- tests/ui/issues/issue-17954.stderr | 2 +- tests/ui/issues/issue-52049.stderr | 4 +-- ...600-expected-return-static-indirect.stderr | 2 +- 6 files changed, 18 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 2c6126cdd29cd..561ef371b0904 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -105,7 +105,7 @@ pub struct Terminator<'tcx> { pub kind: TerminatorKind<'tcx>, } -pub type Successors<'a> = impl Iterator + 'a; +pub type Successors<'a> = impl DoubleEndedIterator + 'a; pub type SuccessorsMut<'a> = iter::Chain, slice::IterMut<'a, BasicBlock>>; diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs index 7d247eeb656c2..99ead14139aec 100644 --- a/compiler/rustc_middle/src/mir/traversal.rs +++ b/compiler/rustc_middle/src/mir/traversal.rs @@ -149,7 +149,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { // B C // | | // | | - // D | + // | D // \ / // \ / // E @@ -159,26 +159,26 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { // // When the first call to `traverse_successor` happens, the following happens: // - // [(B, [D]), // `B` taken from the successors of `A`, pushed to the - // // top of the stack along with the successors of `B` - // (A, [C])] + // [(C, [D]), // `C` taken from the successors of `A`, pushed to the + // // top of the stack along with the successors of `C` + // (A, [B])] // - // [(D, [E]), // `D` taken from successors of `B`, pushed to stack - // (B, []), - // (A, [C])] + // [(D, [E]), // `D` taken from successors of `C`, pushed to stack + // (C, []), + // (A, [B])] // // [(E, []), // `E` taken from successors of `D`, pushed to stack // (D, []), - // (B, []), - // (A, [C])] + // (C, []), + // (A, [B])] // // Now that the top of the stack has no successors we can traverse, each item will - // be popped off during iteration until we get back to `A`. This yields [E, D, B]. + // be popped off during iteration until we get back to `A`. This yields [E, D, C]. // - // When we yield `B` and call `traverse_successor`, we push `C` to the stack, but + // When we yield `C` and call `traverse_successor`, we push `B` to the stack, but // since we've already visited `E`, that child isn't added to the stack. The last - // two iterations yield `C` and finally `A` for a final traversal of [E, D, B, C, A] - while let Some(&mut (_, ref mut iter)) = self.visit_stack.last_mut() && let Some(bb) = iter.next() { + // two iterations yield `B` and finally `A` for a final traversal of [E, D, C, B, A] + while let Some(&mut (_, ref mut iter)) = self.visit_stack.last_mut() && let Some(bb) = iter.next_back() { if self.visited.insert(bb) { if let Some(term) = &self.basic_blocks[bb].terminator { self.visit_stack.push((bb, term.successors())); diff --git a/tests/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.stderr b/tests/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.stderr index 26453b42fa94a..2f397f6b58532 100644 --- a/tests/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.stderr +++ b/tests/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.stderr @@ -4,7 +4,7 @@ error[E0712]: thread-local variable borrowed past end of function LL | assert_static(&FOO); | ^^^^ thread-local variables cannot be borrowed beyond the end of the function LL | } - | - end of enclosing function is here + | - end of enclosing function is here error: aborting due to previous error diff --git a/tests/ui/issues/issue-17954.stderr b/tests/ui/issues/issue-17954.stderr index e08375fee1fe4..3e3706bcb7de9 100644 --- a/tests/ui/issues/issue-17954.stderr +++ b/tests/ui/issues/issue-17954.stderr @@ -5,7 +5,7 @@ LL | let a = &FOO; | ^^^^ thread-local variables cannot be borrowed beyond the end of the function ... LL | } - | - end of enclosing function is here + | - end of enclosing function is here error: aborting due to previous error diff --git a/tests/ui/issues/issue-52049.stderr b/tests/ui/issues/issue-52049.stderr index b25dbd1cb8b12..0812976cf4092 100644 --- a/tests/ui/issues/issue-52049.stderr +++ b/tests/ui/issues/issue-52049.stderr @@ -2,12 +2,10 @@ error[E0716]: temporary value dropped while borrowed --> $DIR/issue-52049.rs:6:10 | LL | foo(&unpromotable(5u32)); - | -----^^^^^^^^^^^^^^^^^^- + | -----^^^^^^^^^^^^^^^^^^-- temporary value is freed at the end of this statement | | | | | creates a temporary value which is freed while still in use | argument requires that borrow lasts for `'static` -LL | } - | - temporary value is freed at the end of this statement error: aborting due to previous error diff --git a/tests/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr b/tests/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr index 3602de8dd9577..598f142419137 100644 --- a/tests/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr +++ b/tests/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr @@ -10,7 +10,7 @@ LL | let read = &refcell as &RefCell; | -------- cast requires that `foo` is borrowed for `'static` ... LL | } - | - `foo` dropped here while still borrowed + | - `foo` dropped here while still borrowed error: lifetime may not live long enough --> $DIR/issue-90600-expected-return-static-indirect.rs:9:16 From 977ac5b4dd48aab9c41d380a3fb141d9c120ad29 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 21 May 2023 17:38:34 -0700 Subject: [PATCH 11/69] MIR: opt-in normalization of `BasicBlock` and `Local` numbering --- compiler/rustc_mir_transform/src/lib.rs | 5 + compiler/rustc_mir_transform/src/prettify.rs | 134 +++++++++++++++++++ 2 files changed, 139 insertions(+) create mode 100644 compiler/rustc_mir_transform/src/prettify.rs diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 65864dc016f4f..54c138b6fbd4c 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -3,6 +3,7 @@ #![deny(rustc::diagnostic_outside_of_impl)] #![feature(box_patterns)] #![feature(drain_filter)] +#![feature(is_sorted)] #![feature(let_chains)] #![feature(map_try_insert)] #![feature(min_specialization)] @@ -84,6 +85,7 @@ mod match_branches; mod multiple_return_terminators; mod normalize_array_len; mod nrvo; +mod prettify; mod ref_prop; mod remove_noop_landing_pads; mod remove_storage_markers; @@ -581,6 +583,9 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &large_enums::EnumSizeOpt { discrepancy: 128 }, // Some cleanup necessary at least for LLVM and potentially other codegen backends. &add_call_guards::CriticalCallEdges, + // Cleanup for human readability, off by default. + &prettify::ReorderBasicBlocks, + &prettify::ReorderLocals, // Dump the end result for testing and debugging purposes. &dump_mir::Marker("PreCodegen"), ], diff --git a/compiler/rustc_mir_transform/src/prettify.rs b/compiler/rustc_mir_transform/src/prettify.rs new file mode 100644 index 0000000000000..d3637405edc84 --- /dev/null +++ b/compiler/rustc_mir_transform/src/prettify.rs @@ -0,0 +1,134 @@ +//! These two passes provide no value to the compiler, so are off at every level. +//! +//! However, they can be enabled on the command line +//! (`-Zmir-enable-passes=+ReorderBasicBlocks,+ReorderLocals`) +//! to make the MIR easier to read for humans. + +use crate::MirPass; +use rustc_index::{bit_set::BitSet, IndexSlice, IndexVec}; +use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; +use rustc_session::Session; + +pub struct ReorderBasicBlocks; + +impl<'tcx> MirPass<'tcx> for ReorderBasicBlocks { + fn is_enabled(&self, _session: &Session) -> bool { + false + } + + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let rpo: IndexVec = + body.basic_blocks.postorder().iter().copied().rev().collect(); + if rpo.iter().is_sorted() { + return; + } + + let mut updater = BasicBlockUpdater { map: rpo.invert_bijective_mapping(), tcx }; + debug_assert_eq!(updater.map[START_BLOCK], START_BLOCK); + updater.visit_body(body); + + permute(body.basic_blocks.as_mut(), &updater.map); + } +} + +pub struct ReorderLocals; + +impl<'tcx> MirPass<'tcx> for ReorderLocals { + fn is_enabled(&self, _session: &Session) -> bool { + false + } + + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let mut finder = + LocalFinder { map: IndexVec::new(), seen: BitSet::new_empty(body.local_decls.len()) }; + + // We can't reorder the return place or the arguments + for i in 0..=body.arg_count { + finder.track(Local::from_usize(i)); + } + + for (bb, bbd) in body.basic_blocks.iter_enumerated() { + finder.visit_basic_block_data(bb, bbd); + } + + // track everything in case there are some locals that we never saw, + // such as in non-block things like debug info or in non-uses. + for local in body.local_decls.indices() { + finder.track(local); + } + + if finder.map.iter().is_sorted() { + return; + } + + let mut updater = LocalUpdater { map: finder.map.invert_bijective_mapping(), tcx }; + debug_assert_eq!(updater.map[RETURN_PLACE], RETURN_PLACE); + updater.visit_body_preserves_cfg(body); + + permute(&mut body.local_decls, &updater.map); + } +} + +fn permute(data: &mut IndexVec, map: &IndexSlice) { + // FIXME: It would be nice to have a less-awkward way to apply permutations, + // but I don't know one that exists. `sort_by_cached_key` has logic for it + // internally, but not in a way that we're allowed to use here. + let mut enumerated: Vec<_> = std::mem::take(data).into_iter_enumerated().collect(); + enumerated.sort_by_key(|p| map[p.0]); + *data = enumerated.into_iter().map(|p| p.1).collect(); +} + +struct BasicBlockUpdater<'tcx> { + map: IndexVec, + tcx: TyCtxt<'tcx>, +} + +impl<'tcx> MutVisitor<'tcx> for BasicBlockUpdater<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, _location: Location) { + for succ in terminator.successors_mut() { + *succ = self.map[*succ]; + } + } +} + +struct LocalFinder { + map: IndexVec, + seen: BitSet, +} + +impl LocalFinder { + fn track(&mut self, l: Local) { + if self.seen.insert(l) { + self.map.push(l); + } + } +} + +impl<'tcx> Visitor<'tcx> for LocalFinder { + fn visit_local(&mut self, l: Local, context: PlaceContext, _location: Location) { + if context.is_use() { + self.track(l); + } + } +} + +struct LocalUpdater<'tcx> { + pub map: IndexVec, + pub tcx: TyCtxt<'tcx>, +} + +impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_local(&mut self, l: &mut Local, _: PlaceContext, _: Location) { + *l = self.map[*l]; + } +} From 05bf42bfa9f616652be4fb11142c6bec0c85db96 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 21 May 2023 10:58:32 -0700 Subject: [PATCH 12/69] PR feedback: better comments and debug asserts --- compiler/rustc_mir_transform/src/prettify.rs | 22 +++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_mir_transform/src/prettify.rs b/compiler/rustc_mir_transform/src/prettify.rs index d3637405edc84..6f46974ea0053 100644 --- a/compiler/rustc_mir_transform/src/prettify.rs +++ b/compiler/rustc_mir_transform/src/prettify.rs @@ -11,6 +11,10 @@ use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; use rustc_session::Session; +/// Rearranges the basic blocks into a *reverse post-order*. +/// +/// Thus after this pass, all the successors of a block are later than it in the +/// `IndexVec`, unless that successor is a back-edge (such as from a loop). pub struct ReorderBasicBlocks; impl<'tcx> MirPass<'tcx> for ReorderBasicBlocks { @@ -33,6 +37,12 @@ impl<'tcx> MirPass<'tcx> for ReorderBasicBlocks { } } +/// Rearranges the locals into *use* order. +/// +/// Thus after this pass, a local with a smaller [`Location`] where it was first +/// assigned or referenced will have a smaller number. +/// +/// (Does not reorder arguments nor the [`RETURN_PLACE`].) pub struct ReorderLocals; impl<'tcx> MirPass<'tcx> for ReorderLocals { @@ -45,8 +55,8 @@ impl<'tcx> MirPass<'tcx> for ReorderLocals { LocalFinder { map: IndexVec::new(), seen: BitSet::new_empty(body.local_decls.len()) }; // We can't reorder the return place or the arguments - for i in 0..=body.arg_count { - finder.track(Local::from_usize(i)); + for local in (0..=body.arg_count).map(Local::from_usize) { + finder.track(local); } for (bb, bbd) in body.basic_blocks.iter_enumerated() { @@ -64,7 +74,11 @@ impl<'tcx> MirPass<'tcx> for ReorderLocals { } let mut updater = LocalUpdater { map: finder.map.invert_bijective_mapping(), tcx }; - debug_assert_eq!(updater.map[RETURN_PLACE], RETURN_PLACE); + + for local in (0..=body.arg_count).map(Local::from_usize) { + debug_assert_eq!(updater.map[local], local); + } + updater.visit_body_preserves_cfg(body); permute(&mut body.local_decls, &updater.map); @@ -112,6 +126,8 @@ impl LocalFinder { impl<'tcx> Visitor<'tcx> for LocalFinder { fn visit_local(&mut self, l: Local, context: PlaceContext, _location: Location) { + // Exclude non-uses to keep `StorageLive` from controlling where we put + // a `Local`, since it might not actually be assigned until much later. if context.is_use() { self.track(l); } From d69725d5d5173e6c6fc20873f306cbd66fa963e7 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 21 May 2023 11:44:37 -0700 Subject: [PATCH 13/69] Normalize block and local orders in mir-opt tests Since this only affects `PreCodegen MIR, and it would be nice for that to be resilient to permutations of things that don't affect the actual semantic behaviours. --- src/tools/compiletest/src/runtest.rs | 5 +- .../string.foo.PreCodegen.after.mir | 62 ++--- tests/mir-opt/inline/cycle.g.Inline.diff | 16 +- tests/mir-opt/inline/cycle.main.Inline.diff | 16 +- ...line_closure_captures.foo.Inline.after.mir | 24 +- .../inline/inline_diverging.h.Inline.diff | 38 +-- .../inline/inline_generator.main.Inline.diff | 32 +-- .../inline/issue_106141.outer.Inline.diff | 18 +- ..._shl_unsigned_smaller.PreCodegen.after.mir | 128 ++++----- ...ed_shr_signed_smaller.PreCodegen.after.mir | 128 ++++----- ...cked.unwrap_unchecked.PreCodegen.after.mir | 20 +- .../mir-opt/issue_101973.inner.ConstProp.diff | 16 +- ...ue_59352.num_to_digit.PreCodegen.after.mir | 62 ++--- ...witch_targets.ub_if_b.PreCodegen.after.mir | 8 +- ...nge_iter.forward_loop.PreCodegen.after.mir | 68 ++--- ...e_iter.inclusive_loop.PreCodegen.after.mir | 68 ++--- ...mple_option_map.ezmap.PreCodegen.after.mir | 40 +-- ...x.slice_get_mut_usize.PreCodegen.after.mir | 74 +++--- ...t_unchecked_mut_range.PreCodegen.after.mir | 132 ++++----- ...ice_iter.forward_loop.PreCodegen.after.mir | 210 +++++++-------- ...ice_iter.reverse_loop.PreCodegen.after.mir | 250 +++++++++--------- .../try_identity.new.PreCodegen.after.mir | 48 ++-- .../try_identity.old.PreCodegen.after.mir | 18 +- .../tls_access.main.PreCodegen.after.mir | 16 +- ...le_storage.while_loop.PreCodegen.after.mir | 8 +- 25 files changed, 754 insertions(+), 751 deletions(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 5bc4d16426551..a799d93ce25c7 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2045,7 +2045,10 @@ impl<'test> TestCx<'test> { if let Some(pass) = &self.props.mir_unit_test { rustc.args(&["-Zmir-opt-level=0", &format!("-Zmir-enable-passes=+{}", pass)]); } else { - rustc.arg("-Zmir-opt-level=4"); + rustc.args(&[ + "-Zmir-opt-level=4", + "-Zmir-enable-passes=+ReorderBasicBlocks,+ReorderLocals", + ]); } let mir_dump_dir = self.get_mir_dump_dir(); diff --git a/tests/mir-opt/deref-patterns/string.foo.PreCodegen.after.mir b/tests/mir-opt/deref-patterns/string.foo.PreCodegen.after.mir index 97826ed19a252..bcdb12011bcd5 100644 --- a/tests/mir-opt/deref-patterns/string.foo.PreCodegen.after.mir +++ b/tests/mir-opt/deref-patterns/string.foo.PreCodegen.after.mir @@ -3,41 +3,33 @@ fn foo(_1: Option) -> i32 { debug s => _1; // in scope 0 at $DIR/string.rs:+0:12: +0:13 let mut _0: i32; // return place in scope 0 at $DIR/string.rs:+0:34: +0:37 - let mut _2: &std::string::String; // in scope 0 at $DIR/string.rs:+2:14: +2:17 - let mut _3: &str; // in scope 0 at $DIR/string.rs:+2:14: +2:17 - let mut _4: bool; // in scope 0 at $DIR/string.rs:+2:14: +2:17 - let mut _5: isize; // in scope 0 at $DIR/string.rs:+2:9: +2:18 - let _6: std::option::Option; // in scope 0 at $DIR/string.rs:+3:9: +3:10 - let mut _7: bool; // in scope 0 at $DIR/string.rs:+5:1: +5:2 + let mut _2: bool; // in scope 0 at $DIR/string.rs:+5:1: +5:2 + let mut _3: isize; // in scope 0 at $DIR/string.rs:+2:9: +2:18 + let mut _4: &std::string::String; // in scope 0 at $DIR/string.rs:+2:14: +2:17 + let mut _5: &str; // in scope 0 at $DIR/string.rs:+2:14: +2:17 + let mut _6: bool; // in scope 0 at $DIR/string.rs:+2:14: +2:17 + let _7: std::option::Option; // in scope 0 at $DIR/string.rs:+3:9: +3:10 scope 1 { - debug s => _6; // in scope 1 at $DIR/string.rs:+3:9: +3:10 + debug s => _7; // in scope 1 at $DIR/string.rs:+3:9: +3:10 } bb0: { - _7 = const false; // scope 0 at $DIR/string.rs:+1:11: +1:12 - _7 = const true; // scope 0 at $DIR/string.rs:+1:11: +1:12 - _5 = discriminant(_1); // scope 0 at $DIR/string.rs:+1:11: +1:12 - switchInt(move _5) -> [1: bb2, otherwise: bb1]; // scope 0 at $DIR/string.rs:+1:5: +1:12 + _2 = const false; // scope 0 at $DIR/string.rs:+1:11: +1:12 + _2 = const true; // scope 0 at $DIR/string.rs:+1:11: +1:12 + _3 = discriminant(_1); // scope 0 at $DIR/string.rs:+1:11: +1:12 + switchInt(move _3) -> [1: bb1, otherwise: bb5]; // scope 0 at $DIR/string.rs:+1:5: +1:12 } bb1: { - StorageLive(_6); // scope 0 at $DIR/string.rs:+3:9: +3:10 - _7 = const false; // scope 0 at $DIR/string.rs:+3:9: +3:10 - _6 = move _1; // scope 0 at $DIR/string.rs:+3:9: +3:10 - _0 = const 4321_i32; // scope 1 at $DIR/string.rs:+3:14: +3:18 - drop(_6) -> [return: bb6, unwind unreachable]; // scope 0 at $DIR/string.rs:+3:17: +3:18 - } - - bb2: { - _2 = &((_1 as Some).0: std::string::String); // scope 0 at $DIR/string.rs:+2:14: +2:17 - _3 = ::deref(move _2) -> [return: bb3, unwind unreachable]; // scope 0 at $DIR/string.rs:+2:14: +2:17 + _4 = &((_1 as Some).0: std::string::String); // scope 0 at $DIR/string.rs:+2:14: +2:17 + _5 = ::deref(move _4) -> [return: bb2, unwind unreachable]; // scope 0 at $DIR/string.rs:+2:14: +2:17 // mir::Constant // + span: $DIR/string.rs:9:14: 9:17 // + literal: Const { ty: for<'a> fn(&'a String) -> &'a ::Target {::deref}, val: Value() } } - bb3: { - _4 = ::eq(_3, const "a") -> [return: bb4, unwind unreachable]; // scope 0 at $DIR/string.rs:+2:14: +2:17 + bb2: { + _6 = ::eq(_5, const "a") -> [return: bb3, unwind unreachable]; // scope 0 at $DIR/string.rs:+2:14: +2:17 // mir::Constant // + span: $DIR/string.rs:9:14: 9:17 // + literal: Const { ty: for<'a, 'b> fn(&'a str, &'b str) -> bool {::eq}, val: Value() } @@ -46,29 +38,37 @@ fn foo(_1: Option) -> i32 { // + literal: Const { ty: &str, val: Value(Slice(..)) } } + bb3: { + switchInt(move _6) -> [0: bb5, otherwise: bb4]; // scope 0 at $DIR/string.rs:+2:14: +2:17 + } + bb4: { - switchInt(move _4) -> [0: bb1, otherwise: bb5]; // scope 0 at $DIR/string.rs:+2:14: +2:17 + _0 = const 1234_i32; // scope 0 at $DIR/string.rs:+2:22: +2:26 + goto -> bb7; // scope 0 at $DIR/string.rs:+2:22: +2:26 } bb5: { - _0 = const 1234_i32; // scope 0 at $DIR/string.rs:+2:22: +2:26 - goto -> bb9; // scope 0 at $DIR/string.rs:+2:22: +2:26 + StorageLive(_7); // scope 0 at $DIR/string.rs:+3:9: +3:10 + _2 = const false; // scope 0 at $DIR/string.rs:+3:9: +3:10 + _7 = move _1; // scope 0 at $DIR/string.rs:+3:9: +3:10 + _0 = const 4321_i32; // scope 1 at $DIR/string.rs:+3:14: +3:18 + drop(_7) -> [return: bb6, unwind unreachable]; // scope 0 at $DIR/string.rs:+3:17: +3:18 } bb6: { - StorageDead(_6); // scope 0 at $DIR/string.rs:+3:17: +3:18 - goto -> bb9; // scope 0 at $DIR/string.rs:+3:17: +3:18 + StorageDead(_7); // scope 0 at $DIR/string.rs:+3:17: +3:18 + goto -> bb7; // scope 0 at $DIR/string.rs:+3:17: +3:18 } bb7: { - return; // scope 0 at $DIR/string.rs:+5:2: +5:2 + switchInt(_2) -> [0: bb9, otherwise: bb8]; // scope 0 at $DIR/string.rs:+5:1: +5:2 } bb8: { - drop(_1) -> [return: bb7, unwind unreachable]; // scope 0 at $DIR/string.rs:+5:1: +5:2 + drop(_1) -> [return: bb9, unwind unreachable]; // scope 0 at $DIR/string.rs:+5:1: +5:2 } bb9: { - switchInt(_7) -> [0: bb7, otherwise: bb8]; // scope 0 at $DIR/string.rs:+5:1: +5:2 + return; // scope 0 at $DIR/string.rs:+5:2: +5:2 } } diff --git a/tests/mir-opt/inline/cycle.g.Inline.diff b/tests/mir-opt/inline/cycle.g.Inline.diff index 1e6e30f9e9bef..53bf14a0ab6e9 100644 --- a/tests/mir-opt/inline/cycle.g.Inline.diff +++ b/tests/mir-opt/inline/cycle.g.Inline.diff @@ -8,8 +8,8 @@ + let mut _5: (); // in scope 0 at $DIR/cycle.rs:6:5: 6:8 + scope 1 (inlined f::) { // at $DIR/cycle.rs:12:5: 12:12 + debug g => _2; // in scope 1 at $DIR/cycle.rs:5:6: 5:7 -+ let _3: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8 -+ let mut _4: &fn() {main}; // in scope 1 at $DIR/cycle.rs:6:5: 6:6 ++ let mut _3: &fn() {main}; // in scope 1 at $DIR/cycle.rs:6:5: 6:6 ++ let _4: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8 + scope 2 (inlined >::call - shim(fn() {main})) { // at $DIR/cycle.rs:6:5: 6:8 + } + } @@ -25,16 +25,16 @@ - // mir::Constant // + span: $DIR/cycle.rs:12:7: 12:11 // + literal: Const { ty: fn() {main}, val: Value() } -+ StorageLive(_3); // scope 0 at $DIR/cycle.rs:+1:5: +1:12 -+ StorageLive(_4); // scope 1 at $DIR/cycle.rs:6:5: 6:6 -+ _4 = &_2; // scope 1 at $DIR/cycle.rs:6:5: 6:6 ++ StorageLive(_4); // scope 0 at $DIR/cycle.rs:+1:5: +1:12 ++ StorageLive(_3); // scope 1 at $DIR/cycle.rs:6:5: 6:6 ++ _3 = &_2; // scope 1 at $DIR/cycle.rs:6:5: 6:6 + StorageLive(_5); // scope 1 at $DIR/cycle.rs:6:5: 6:8 + _5 = const (); // scope 1 at $DIR/cycle.rs:6:5: 6:8 -+ _3 = move (*_4)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL ++ _4 = move (*_3)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL } bb1: { -+ StorageDead(_3); // scope 0 at $DIR/cycle.rs:+1:5: +1:12 ++ StorageDead(_4); // scope 0 at $DIR/cycle.rs:+1:5: +1:12 + StorageDead(_2); // scope 0 at $DIR/cycle.rs:+1:5: +1:12 StorageDead(_1); // scope 0 at $DIR/cycle.rs:+1:12: +1:13 _0 = const (); // scope 0 at $DIR/cycle.rs:+0:8: +2:2 @@ -51,7 +51,7 @@ + + bb4: { + StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:5: 6:8 -+ StorageDead(_4); // scope 1 at $DIR/cycle.rs:6:7: 6:8 ++ StorageDead(_3); // scope 1 at $DIR/cycle.rs:6:7: 6:8 + drop(_2) -> bb1; // scope 1 at $DIR/cycle.rs:7:1: 7:2 } } diff --git a/tests/mir-opt/inline/cycle.main.Inline.diff b/tests/mir-opt/inline/cycle.main.Inline.diff index 315634945e432..fdf6337a9bee6 100644 --- a/tests/mir-opt/inline/cycle.main.Inline.diff +++ b/tests/mir-opt/inline/cycle.main.Inline.diff @@ -8,8 +8,8 @@ + let mut _5: (); // in scope 0 at $DIR/cycle.rs:6:5: 6:8 + scope 1 (inlined f::) { // at $DIR/cycle.rs:17:5: 17:9 + debug g => _2; // in scope 1 at $DIR/cycle.rs:5:6: 5:7 -+ let _3: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8 -+ let mut _4: &fn() {g}; // in scope 1 at $DIR/cycle.rs:6:5: 6:6 ++ let mut _3: &fn() {g}; // in scope 1 at $DIR/cycle.rs:6:5: 6:6 ++ let _4: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8 + scope 2 (inlined >::call - shim(fn() {g})) { // at $DIR/cycle.rs:6:5: 6:8 + } + } @@ -25,16 +25,16 @@ - // mir::Constant // + span: $DIR/cycle.rs:17:7: 17:8 // + literal: Const { ty: fn() {g}, val: Value() } -+ StorageLive(_3); // scope 0 at $DIR/cycle.rs:+1:5: +1:9 -+ StorageLive(_4); // scope 1 at $DIR/cycle.rs:6:5: 6:6 -+ _4 = &_2; // scope 1 at $DIR/cycle.rs:6:5: 6:6 ++ StorageLive(_4); // scope 0 at $DIR/cycle.rs:+1:5: +1:9 ++ StorageLive(_3); // scope 1 at $DIR/cycle.rs:6:5: 6:6 ++ _3 = &_2; // scope 1 at $DIR/cycle.rs:6:5: 6:6 + StorageLive(_5); // scope 1 at $DIR/cycle.rs:6:5: 6:8 + _5 = const (); // scope 1 at $DIR/cycle.rs:6:5: 6:8 -+ _3 = move (*_4)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL ++ _4 = move (*_3)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL } bb1: { -+ StorageDead(_3); // scope 0 at $DIR/cycle.rs:+1:5: +1:9 ++ StorageDead(_4); // scope 0 at $DIR/cycle.rs:+1:5: +1:9 + StorageDead(_2); // scope 0 at $DIR/cycle.rs:+1:5: +1:9 StorageDead(_1); // scope 0 at $DIR/cycle.rs:+1:9: +1:10 _0 = const (); // scope 0 at $DIR/cycle.rs:+0:11: +2:2 @@ -51,7 +51,7 @@ + + bb4: { + StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:5: 6:8 -+ StorageDead(_4); // scope 1 at $DIR/cycle.rs:6:7: 6:8 ++ StorageDead(_3); // scope 1 at $DIR/cycle.rs:6:7: 6:8 + drop(_2) -> bb1; // scope 1 at $DIR/cycle.rs:7:1: 7:2 } } diff --git a/tests/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir b/tests/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir index b36711f82f40e..33bf3b73b2372 100644 --- a/tests/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir +++ b/tests/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir @@ -17,10 +17,10 @@ fn foo(_1: T, _2: i32) -> (i32, T) { debug _q => _9; // in scope 2 at $DIR/inline_closure_captures.rs:+1:14: +1:16 debug q => (*((*_6).0: &i32)); // in scope 2 at $DIR/inline_closure_captures.rs:+0:23: +0:24 debug t => (*((*_6).1: &T)); // in scope 2 at $DIR/inline_closure_captures.rs:+0:17: +0:18 - let mut _10: i32; // in scope 2 at $DIR/inline_closure_captures.rs:+1:19: +1:20 - let mut _11: T; // in scope 2 at $DIR/inline_closure_captures.rs:+1:22: +1:23 - let mut _12: &i32; // in scope 2 at $DIR/inline_closure_captures.rs:+1:13: +1:24 - let mut _13: &T; // in scope 2 at $DIR/inline_closure_captures.rs:+1:13: +1:24 + let mut _10: &i32; // in scope 2 at $DIR/inline_closure_captures.rs:+1:13: +1:24 + let mut _11: i32; // in scope 2 at $DIR/inline_closure_captures.rs:+1:19: +1:20 + let mut _12: &T; // in scope 2 at $DIR/inline_closure_captures.rs:+1:13: +1:24 + let mut _13: T; // in scope 2 at $DIR/inline_closure_captures.rs:+1:22: +1:23 } } @@ -49,15 +49,15 @@ fn foo(_1: T, _2: i32) -> (i32, T) { _7 = (move _8,); // scope 1 at $DIR/inline_closure_captures.rs:+2:5: +2:9 StorageLive(_9); // scope 1 at $DIR/inline_closure_captures.rs:+2:5: +2:9 _9 = move (_7.0: i32); // scope 1 at $DIR/inline_closure_captures.rs:+2:5: +2:9 - StorageLive(_10); // scope 2 at $DIR/inline_closure_captures.rs:+1:19: +1:20 - _12 = deref_copy ((*_6).0: &i32); // scope 2 at $DIR/inline_closure_captures.rs:+1:19: +1:20 - _10 = (*_12); // scope 2 at $DIR/inline_closure_captures.rs:+1:19: +1:20 - StorageLive(_11); // scope 2 at $DIR/inline_closure_captures.rs:+1:22: +1:23 - _13 = deref_copy ((*_6).1: &T); // scope 2 at $DIR/inline_closure_captures.rs:+1:22: +1:23 - _11 = (*_13); // scope 2 at $DIR/inline_closure_captures.rs:+1:22: +1:23 - _0 = (move _10, move _11); // scope 2 at $DIR/inline_closure_captures.rs:+1:18: +1:24 + StorageLive(_11); // scope 2 at $DIR/inline_closure_captures.rs:+1:19: +1:20 + _10 = deref_copy ((*_6).0: &i32); // scope 2 at $DIR/inline_closure_captures.rs:+1:19: +1:20 + _11 = (*_10); // scope 2 at $DIR/inline_closure_captures.rs:+1:19: +1:20 + StorageLive(_13); // scope 2 at $DIR/inline_closure_captures.rs:+1:22: +1:23 + _12 = deref_copy ((*_6).1: &T); // scope 2 at $DIR/inline_closure_captures.rs:+1:22: +1:23 + _13 = (*_12); // scope 2 at $DIR/inline_closure_captures.rs:+1:22: +1:23 + _0 = (move _11, move _13); // scope 2 at $DIR/inline_closure_captures.rs:+1:18: +1:24 + StorageDead(_13); // scope 2 at $DIR/inline_closure_captures.rs:+1:23: +1:24 StorageDead(_11); // scope 2 at $DIR/inline_closure_captures.rs:+1:23: +1:24 - StorageDead(_10); // scope 2 at $DIR/inline_closure_captures.rs:+1:23: +1:24 StorageDead(_9); // scope 1 at $DIR/inline_closure_captures.rs:+2:5: +2:9 StorageDead(_8); // scope 1 at $DIR/inline_closure_captures.rs:+2:8: +2:9 StorageDead(_7); // scope 1 at $DIR/inline_closure_captures.rs:+2:8: +2:9 diff --git a/tests/mir-opt/inline/inline_diverging.h.Inline.diff b/tests/mir-opt/inline/inline_diverging.h.Inline.diff index d501b6ca8d2c6..255451e867030 100644 --- a/tests/mir-opt/inline/inline_diverging.h.Inline.diff +++ b/tests/mir-opt/inline/inline_diverging.h.Inline.diff @@ -8,15 +8,15 @@ + let mut _8: (); // in scope 0 at $DIR/inline_diverging.rs:27:13: 27:16 + scope 1 (inlined call_twice:: ! {sleep}>) { // at $DIR/inline_diverging.rs:22:5: 22:22 + debug f => _2; // in scope 1 at $DIR/inline_diverging.rs:26:36: 26:37 -+ let _3: !; // in scope 1 at $DIR/inline_diverging.rs:27:9: 27:10 -+ let mut _4: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline_diverging.rs:27:13: 27:14 ++ let mut _3: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline_diverging.rs:27:13: 27:14 ++ let _4: !; // in scope 1 at $DIR/inline_diverging.rs:27:9: 27:10 + let mut _5: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline_diverging.rs:28:13: 28:14 -+ let mut _6: !; // in scope 1 at $DIR/inline_diverging.rs:29:6: 29:7 -+ let mut _7: !; // in scope 1 at $DIR/inline_diverging.rs:29:9: 29:10 ++ let mut _6: !; // in scope 1 at $DIR/inline_diverging.rs:29:9: 29:10 ++ let mut _7: !; // in scope 1 at $DIR/inline_diverging.rs:29:6: 29:7 + scope 2 { -+ debug a => _3; // in scope 2 at $DIR/inline_diverging.rs:27:9: 27:10 ++ debug a => _4; // in scope 2 at $DIR/inline_diverging.rs:27:9: 27:10 + scope 3 { -+ debug b => _7; // in scope 3 at $DIR/inline_diverging.rs:28:9: 28:10 ++ debug b => _6; // in scope 3 at $DIR/inline_diverging.rs:28:9: 28:10 + } + } + scope 4 (inlined ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline_diverging.rs:27:13: 27:16 @@ -34,22 +34,22 @@ - // mir::Constant // + span: $DIR/inline_diverging.rs:22:16: 22:21 // + literal: Const { ty: fn() -> ! {sleep}, val: Value() } -+ StorageLive(_7); // scope 0 at $DIR/inline_diverging.rs:+1:5: +1:22 -+ StorageLive(_3); // scope 1 at $DIR/inline_diverging.rs:27:9: 27:10 -+ StorageLive(_4); // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14 -+ _4 = &_2; // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14 ++ StorageLive(_6); // scope 0 at $DIR/inline_diverging.rs:+1:5: +1:22 ++ StorageLive(_4); // scope 1 at $DIR/inline_diverging.rs:27:9: 27:10 ++ StorageLive(_3); // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14 ++ _3 = &_2; // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14 + StorageLive(_8); // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16 + _8 = const (); // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16 -+ _3 = move (*_4)() -> [return: bb6, unwind: bb4]; // scope 4 at $SRC_DIR/core/src/ops/function.rs:LL:COL ++ _4 = move (*_3)() -> [return: bb6, unwind: bb4]; // scope 4 at $SRC_DIR/core/src/ops/function.rs:LL:COL + } + + bb1: { + StorageDead(_5); // scope 2 at $DIR/inline_diverging.rs:28:15: 28:16 -+ StorageLive(_6); // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7 -+ _6 = move _3; // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7 -+ _1 = (move _6, move _7); // scope 3 at $DIR/inline_diverging.rs:29:5: 29:11 -+ StorageDead(_6); // scope 3 at $DIR/inline_diverging.rs:29:10: 29:11 -+ StorageDead(_3); // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2 ++ StorageLive(_7); // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7 ++ _7 = move _4; // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7 ++ _1 = (move _7, move _6); // scope 3 at $DIR/inline_diverging.rs:29:5: 29:11 ++ StorageDead(_7); // scope 3 at $DIR/inline_diverging.rs:29:10: 29:11 ++ StorageDead(_4); // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2 + drop(_2) -> bb2; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2 + } + @@ -58,7 +58,7 @@ + } + + bb3 (cleanup): { -+ drop(_3) -> [return: bb4, unwind terminate]; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2 ++ drop(_4) -> [return: bb4, unwind terminate]; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2 + } + + bb4 (cleanup): { @@ -71,10 +71,10 @@ + + bb6: { + StorageDead(_8); // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16 -+ StorageDead(_4); // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16 ++ StorageDead(_3); // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16 + StorageLive(_5); // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14 + _5 = &_2; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14 -+ _7 = ! {sleep} as Fn<()>>::call(move _5, const ()) -> [return: bb1, unwind: bb3]; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16 ++ _6 = ! {sleep} as Fn<()>>::call(move _5, const ()) -> [return: bb1, unwind: bb3]; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16 + // mir::Constant + // + span: $DIR/inline_diverging.rs:28:13: 28:14 + // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() -> ! {sleep}, ()) -> ! {sleep} as FnOnce<()>>::Output { ! {sleep} as Fn<()>>::call}, val: Value() } diff --git a/tests/mir-opt/inline/inline_generator.main.Inline.diff b/tests/mir-opt/inline/inline_generator.main.Inline.diff index c3ca2d7d42c2b..0dcae1e4d45f9 100644 --- a/tests/mir-opt/inline/inline_generator.main.Inline.diff +++ b/tests/mir-opt/inline/inline_generator.main.Inline.diff @@ -23,9 +23,9 @@ + } + scope 6 (inlined g::{closure#0}) { // at $DIR/inline_generator.rs:9:33: 9:46 + debug a => _5; // in scope 6 at $DIR/inline_generator.rs:15:6: 15:7 -+ let mut _6: i32; // in scope 6 at $DIR/inline_generator.rs:15:17: 15:39 ++ let mut _6: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]; // in scope 6 at $DIR/inline_generator.rs:15:5: 15:41 + let mut _7: u32; // in scope 6 at $DIR/inline_generator.rs:15:5: 15:41 -+ let mut _8: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]; // in scope 6 at $DIR/inline_generator.rs:15:5: 15:41 ++ let mut _8: i32; // in scope 6 at $DIR/inline_generator.rs:15:17: 15:39 + let mut _9: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]; // in scope 6 at $DIR/inline_generator.rs:15:5: 15:41 + let mut _10: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]; // in scope 6 at $DIR/inline_generator.rs:15:5: 15:41 + } @@ -70,9 +70,9 @@ - // + literal: Const { ty: for<'a> fn(Pin<&'a mut [generator@$DIR/inline_generator.rs:15:5: 15:8]>, bool) -> GeneratorState<<[generator@$DIR/inline_generator.rs:15:5: 15:8] as Generator>::Yield, <[generator@$DIR/inline_generator.rs:15:5: 15:8] as Generator>::Return> {<[generator@$DIR/inline_generator.rs:15:5: 15:8] as Generator>::resume}, val: Value() } + StorageLive(_5); // scope 0 at $DIR/inline_generator.rs:+1:33: +1:46 + _5 = const false; // scope 0 at $DIR/inline_generator.rs:+1:33: +1:46 -+ _8 = deref_copy (_2.0: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline_generator.rs:15:5: 15:41 -+ _7 = discriminant((*_8)); // scope 6 at $DIR/inline_generator.rs:15:5: 15:41 -+ switchInt(move _7) -> [0: bb3, 1: bb8, 3: bb7, otherwise: bb9]; // scope 6 at $DIR/inline_generator.rs:15:5: 15:41 ++ _6 = deref_copy (_2.0: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline_generator.rs:15:5: 15:41 ++ _7 = discriminant((*_6)); // scope 6 at $DIR/inline_generator.rs:15:5: 15:41 ++ switchInt(move _7) -> [0: bb3, 1: bb7, 3: bb8, otherwise: bb9]; // scope 6 at $DIR/inline_generator.rs:15:5: 15:41 } - bb3: { @@ -91,40 +91,40 @@ + } + + bb3: { -+ StorageLive(_6); // scope 6 at $DIR/inline_generator.rs:15:17: 15:39 -+ switchInt(_5) -> [0: bb5, otherwise: bb4]; // scope 6 at $DIR/inline_generator.rs:15:20: 15:21 ++ StorageLive(_8); // scope 6 at $DIR/inline_generator.rs:15:17: 15:39 ++ switchInt(_5) -> [0: bb4, otherwise: bb5]; // scope 6 at $DIR/inline_generator.rs:15:20: 15:21 + } + + bb4: { -+ _6 = const 7_i32; // scope 6 at $DIR/inline_generator.rs:15:24: 15:25 ++ _8 = const 13_i32; // scope 6 at $DIR/inline_generator.rs:15:35: 15:37 + goto -> bb6; // scope 6 at $DIR/inline_generator.rs:15:17: 15:39 + } + + bb5: { -+ _6 = const 13_i32; // scope 6 at $DIR/inline_generator.rs:15:35: 15:37 ++ _8 = const 7_i32; // scope 6 at $DIR/inline_generator.rs:15:24: 15:25 + goto -> bb6; // scope 6 at $DIR/inline_generator.rs:15:17: 15:39 + } + + bb6: { -+ _1 = GeneratorState::::Yielded(move _6); // scope 6 at $DIR/inline_generator.rs:15:11: 15:39 ++ _1 = GeneratorState::::Yielded(move _8); // scope 6 at $DIR/inline_generator.rs:15:11: 15:39 + _9 = deref_copy (_2.0: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline_generator.rs:15:11: 15:39 + discriminant((*_9)) = 3; // scope 6 at $DIR/inline_generator.rs:15:11: 15:39 + goto -> bb1; // scope 0 at $DIR/inline_generator.rs:15:11: 15:39 + } + + bb7: { -+ StorageLive(_6); // scope 6 at $DIR/inline_generator.rs:15:5: 15:41 -+ StorageDead(_6); // scope 6 at $DIR/inline_generator.rs:15:38: 15:39 ++ assert(const false, "generator resumed after completion") -> [success: bb7, unwind: bb2]; // scope 6 at $DIR/inline_generator.rs:15:5: 15:41 ++ } ++ ++ bb8: { ++ StorageLive(_8); // scope 6 at $DIR/inline_generator.rs:15:5: 15:41 ++ StorageDead(_8); // scope 6 at $DIR/inline_generator.rs:15:38: 15:39 + _1 = GeneratorState::::Complete(_5); // scope 6 at $DIR/inline_generator.rs:15:41: 15:41 + _10 = deref_copy (_2.0: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline_generator.rs:15:41: 15:41 + discriminant((*_10)) = 1; // scope 6 at $DIR/inline_generator.rs:15:41: 15:41 + goto -> bb1; // scope 0 at $DIR/inline_generator.rs:15:41: 15:41 + } + -+ bb8: { -+ assert(const false, "generator resumed after completion") -> [success: bb8, unwind: bb2]; // scope 6 at $DIR/inline_generator.rs:15:5: 15:41 -+ } -+ + bb9: { + unreachable; // scope 6 at $DIR/inline_generator.rs:15:5: 15:41 } diff --git a/tests/mir-opt/inline/issue_106141.outer.Inline.diff b/tests/mir-opt/inline/issue_106141.outer.Inline.diff index 3aebfb69e0ae1..5fed54f83a788 100644 --- a/tests/mir-opt/inline/issue_106141.outer.Inline.diff +++ b/tests/mir-opt/inline/issue_106141.outer.Inline.diff @@ -4,9 +4,9 @@ fn outer() -> usize { let mut _0: usize; // return place in scope 0 at $DIR/issue_106141.rs:+0:19: +0:24 + scope 1 (inlined inner) { // at $DIR/issue_106141.rs:3:5: 3:12 -+ let mut _1: bool; // in scope 1 at $DIR/issue_106141.rs:14:8: 14:21 ++ let mut _1: &[bool; 1]; // in scope 1 at $DIR/issue_106141.rs:12:18: 12:25 + let mut _2: bool; // in scope 1 at $DIR/issue_106141.rs:14:8: 14:21 -+ let mut _3: &[bool; 1]; // in scope 1 at $DIR/issue_106141.rs:12:18: 12:25 ++ let mut _3: bool; // in scope 1 at $DIR/issue_106141.rs:14:8: 14:21 + scope 2 { + debug buffer => const _; // in scope 2 at $DIR/issue_106141.rs:12:9: 12:15 + scope 3 { @@ -17,8 +17,8 @@ bb0: { - _0 = inner() -> bb1; // scope 0 at $DIR/issue_106141.rs:+1:5: +1:12 -+ StorageLive(_3); // scope 0 at $DIR/issue_106141.rs:+1:5: +1:12 -+ _3 = const _; // scope 1 at $DIR/issue_106141.rs:12:18: 12:25 ++ StorageLive(_1); // scope 0 at $DIR/issue_106141.rs:+1:5: +1:12 ++ _1 = const _; // scope 1 at $DIR/issue_106141.rs:12:18: 12:25 // mir::Constant - // + span: $DIR/issue_106141.rs:3:5: 3:10 - // + literal: Const { ty: fn() -> usize {inner}, val: Value() } @@ -31,14 +31,14 @@ } bb1: { -+ StorageLive(_1); // scope 3 at $DIR/issue_106141.rs:14:8: 14:21 ++ StorageLive(_3); // scope 3 at $DIR/issue_106141.rs:14:8: 14:21 + _2 = Lt(_0, const 1_usize); // scope 3 at $DIR/issue_106141.rs:14:8: 14:21 + assert(move _2, "index out of bounds: the length is {} but the index is {}", const 1_usize, _0) -> bb2; // scope 3 at $DIR/issue_106141.rs:14:8: 14:21 + } + + bb2: { -+ _1 = (*_3)[_0]; // scope 3 at $DIR/issue_106141.rs:14:8: 14:21 -+ switchInt(move _1) -> [0: bb3, otherwise: bb4]; // scope 3 at $DIR/issue_106141.rs:14:8: 14:21 ++ _3 = (*_1)[_0]; // scope 3 at $DIR/issue_106141.rs:14:8: 14:21 ++ switchInt(move _3) -> [0: bb3, otherwise: bb4]; // scope 3 at $DIR/issue_106141.rs:14:8: 14:21 + } + + bb3: { @@ -47,8 +47,8 @@ + } + + bb4: { -+ StorageDead(_1); // scope 3 at $DIR/issue_106141.rs:18:5: 18:6 -+ StorageDead(_3); // scope 0 at $DIR/issue_106141.rs:+1:5: +1:12 ++ StorageDead(_3); // scope 3 at $DIR/issue_106141.rs:18:5: 18:6 ++ StorageDead(_1); // scope 0 at $DIR/issue_106141.rs:+1:5: +1:12 return; // scope 0 at $DIR/issue_106141.rs:+2:2: +2:2 } } diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.mir index 3c175ed1504f6..f4b2416eaab11 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.mir +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.mir @@ -7,38 +7,38 @@ fn unchecked_shl_unsigned_smaller(_1: u16, _2: u32) -> u16 { scope 1 (inlined core::num::::unchecked_shl) { // at $DIR/unchecked_shifts.rs:11:7: 11:23 debug self => _1; // in scope 1 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL debug rhs => _2; // in scope 1 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL - let mut _3: u16; // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL - let mut _4: (u32,); // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL - let mut _5: u32; // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL + let mut _3: (u32,); // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL + let mut _4: u32; // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL + let mut _13: u16; // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL scope 2 { scope 3 (inlined core::num::::unchecked_shl::conv) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL - debug x => _5; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL - let mut _6: std::option::Option; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL - let mut _7: std::result::Result; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL + debug x => _4; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL + let mut _8: std::result::Result; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL + let mut _11: std::option::Option; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL scope 4 { scope 5 (inlined >::try_into) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL - debug self => _5; // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL + debug self => _4; // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL scope 6 (inlined convert::num:: for u16>::try_from) { // at $SRC_DIR/core/src/convert/mod.rs:LL:COL - debug u => _5; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - let mut _8: bool; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - let mut _9: u32; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - let mut _10: u16; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + debug u => _4; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + let mut _5: u32; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + let mut _6: bool; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + let mut _7: u16; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL } } scope 7 (inlined Result::::ok) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL - debug self => _7; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _11: isize; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - let _12: u16; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + debug self => _8; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + let mut _9: isize; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + let _10: u16; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL scope 8 { - debug x => _12; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL + debug x => _10; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL } } scope 9 (inlined #[track_caller] Option::::unwrap_unchecked) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL - debug self => _6; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL - let mut _13: &std::option::Option; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL - let mut _14: isize; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + debug self => _11; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + let mut _12: isize; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + let mut _14: &std::option::Option; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL scope 10 { - debug val => _3; // in scope 10 at $SRC_DIR/core/src/option.rs:LL:COL + debug val => _13; // in scope 10 at $SRC_DIR/core/src/option.rs:LL:COL } scope 11 { scope 13 (inlined unreachable_unchecked) { // at $SRC_DIR/core/src/option.rs:LL:COL @@ -49,7 +49,7 @@ fn unchecked_shl_unsigned_smaller(_1: u16, _2: u32) -> u16 { } } scope 12 (inlined Option::::is_some) { // at $SRC_DIR/core/src/option.rs:LL:COL - debug self => _13; // in scope 12 at $SRC_DIR/core/src/option.rs:LL:COL + debug self => _14; // in scope 12 at $SRC_DIR/core/src/option.rs:LL:COL } } } @@ -58,81 +58,81 @@ fn unchecked_shl_unsigned_smaller(_1: u16, _2: u32) -> u16 { } bb0: { + StorageLive(_13); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL StorageLive(_3); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL + _3 = (_2,); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL StorageLive(_4); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL - _4 = (_2,); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageLive(_5); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL - _5 = move (_4.0: u32); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageLive(_6); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageLive(_7); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageLive(_8); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - StorageLive(_9); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - _9 = const 65535_u32; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - _8 = Gt(_5, move _9); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - StorageDead(_9); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - switchInt(move _8) -> [0: bb3, otherwise: bb2]; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + _4 = move (_3.0: u32); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageLive(_11); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageLive(_8); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageLive(_6); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + StorageLive(_5); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + _5 = const 65535_u32; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + _6 = Gt(_4, move _5); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + StorageDead(_5); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + switchInt(move _6) -> [0: bb1, otherwise: bb2]; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL } bb1: { - StorageDead(_3); // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL - return; // scope 0 at $DIR/unchecked_shifts.rs:+2:2: +2:2 + StorageLive(_7); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + _7 = _4 as u16 (IntToInt); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + _8 = Result::::Ok(move _7); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + StorageDead(_7); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + goto -> bb3; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL } bb2: { - _7 = Result::::Err(const TryFromIntError(())); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + _8 = Result::::Err(const TryFromIntError(())); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL // mir::Constant // + span: no-location // + literal: Const { ty: TryFromIntError, val: Value() } - goto -> bb4; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + goto -> bb3; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL } bb3: { - StorageLive(_10); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - _10 = _5 as u16 (IntToInt); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - _7 = Result::::Ok(move _10); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - StorageDead(_10); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - goto -> bb4; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + StorageDead(_6); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + StorageLive(_10); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + _9 = discriminant(_8); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + switchInt(move _9) -> [0: bb4, 1: bb5, otherwise: bb9]; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL } bb4: { - StorageDead(_8); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - StorageLive(_12); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL - _11 = discriminant(_7); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - switchInt(move _11) -> [0: bb7, 1: bb5, otherwise: bb6]; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + _10 = move ((_8 as Ok).0: u16); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + _11 = Option::::Some(move _10); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL + goto -> bb6; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL } bb5: { - _6 = Option::::None; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - goto -> bb8; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + _11 = Option::::None; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + goto -> bb6; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL } bb6: { - unreachable; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + StorageDead(_10); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageDead(_8); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageLive(_14); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + _12 = discriminant(_11); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + switchInt(move _12) -> [1: bb7, otherwise: bb9]; // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL } bb7: { - _12 = move ((_7 as Ok).0: u16); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - _6 = Option::::Some(move _12); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - goto -> bb8; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + _13 = move ((_11 as Some).0: u16); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + StorageDead(_14); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageDead(_11); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageDead(_4); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageDead(_3); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL + _0 = unchecked_shl::(_1, move _13) -> [return: bb8, unwind unreachable]; // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL + // mir::Constant + // + span: $SRC_DIR/core/src/num/uint_macros.rs:LL:COL + // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u16, u16) -> u16 {unchecked_shl::}, val: Value() } } bb8: { - StorageDead(_12); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageDead(_7); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageLive(_13); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL - _14 = discriminant(_6); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL - switchInt(move _14) -> [1: bb9, otherwise: bb6]; // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + StorageDead(_13); // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL + return; // scope 0 at $DIR/unchecked_shifts.rs:+2:2: +2:2 } bb9: { - _3 = move ((_6 as Some).0: u16); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL - StorageDead(_13); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageDead(_6); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageDead(_5); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageDead(_4); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL - _0 = unchecked_shl::(_1, move _3) -> [return: bb1, unwind unreachable]; // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL - // mir::Constant - // + span: $SRC_DIR/core/src/num/uint_macros.rs:LL:COL - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u16, u16) -> u16 {unchecked_shl::}, val: Value() } + unreachable; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL } } diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.mir index 724b3c56723a3..67f0fe8932f41 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.mir +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.mir @@ -7,38 +7,38 @@ fn unchecked_shr_signed_smaller(_1: i16, _2: u32) -> i16 { scope 1 (inlined core::num::::unchecked_shr) { // at $DIR/unchecked_shifts.rs:17:7: 17:23 debug self => _1; // in scope 1 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL debug rhs => _2; // in scope 1 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL - let mut _3: i16; // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL - let mut _4: (u32,); // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL - let mut _5: u32; // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL + let mut _3: (u32,); // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL + let mut _4: u32; // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL + let mut _13: i16; // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL scope 2 { scope 3 (inlined core::num::::unchecked_shr::conv) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL - debug x => _5; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL - let mut _6: std::option::Option; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL - let mut _7: std::result::Result; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL + debug x => _4; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL + let mut _8: std::result::Result; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL + let mut _11: std::option::Option; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL scope 4 { scope 5 (inlined >::try_into) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL - debug self => _5; // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL + debug self => _4; // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL scope 6 (inlined convert::num:: for i16>::try_from) { // at $SRC_DIR/core/src/convert/mod.rs:LL:COL - debug u => _5; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - let mut _8: bool; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - let mut _9: u32; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - let mut _10: i16; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + debug u => _4; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + let mut _5: u32; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + let mut _6: bool; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + let mut _7: i16; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL } } scope 7 (inlined Result::::ok) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL - debug self => _7; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _11: isize; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - let _12: i16; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + debug self => _8; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + let mut _9: isize; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + let _10: i16; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL scope 8 { - debug x => _12; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL + debug x => _10; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL } } scope 9 (inlined #[track_caller] Option::::unwrap_unchecked) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL - debug self => _6; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL - let mut _13: &std::option::Option; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL - let mut _14: isize; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + debug self => _11; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + let mut _12: isize; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + let mut _14: &std::option::Option; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL scope 10 { - debug val => _3; // in scope 10 at $SRC_DIR/core/src/option.rs:LL:COL + debug val => _13; // in scope 10 at $SRC_DIR/core/src/option.rs:LL:COL } scope 11 { scope 13 (inlined unreachable_unchecked) { // at $SRC_DIR/core/src/option.rs:LL:COL @@ -49,7 +49,7 @@ fn unchecked_shr_signed_smaller(_1: i16, _2: u32) -> i16 { } } scope 12 (inlined Option::::is_some) { // at $SRC_DIR/core/src/option.rs:LL:COL - debug self => _13; // in scope 12 at $SRC_DIR/core/src/option.rs:LL:COL + debug self => _14; // in scope 12 at $SRC_DIR/core/src/option.rs:LL:COL } } } @@ -58,81 +58,81 @@ fn unchecked_shr_signed_smaller(_1: i16, _2: u32) -> i16 { } bb0: { + StorageLive(_13); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL StorageLive(_3); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL + _3 = (_2,); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL StorageLive(_4); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL - _4 = (_2,); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageLive(_5); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL - _5 = move (_4.0: u32); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageLive(_6); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageLive(_7); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageLive(_8); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - StorageLive(_9); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - _9 = const 32767_u32; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - _8 = Gt(_5, move _9); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - StorageDead(_9); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - switchInt(move _8) -> [0: bb3, otherwise: bb2]; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + _4 = move (_3.0: u32); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageLive(_11); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageLive(_8); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageLive(_6); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + StorageLive(_5); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + _5 = const 32767_u32; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + _6 = Gt(_4, move _5); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + StorageDead(_5); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + switchInt(move _6) -> [0: bb1, otherwise: bb2]; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL } bb1: { - StorageDead(_3); // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL - return; // scope 0 at $DIR/unchecked_shifts.rs:+2:2: +2:2 + StorageLive(_7); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + _7 = _4 as i16 (IntToInt); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + _8 = Result::::Ok(move _7); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + StorageDead(_7); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + goto -> bb3; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL } bb2: { - _7 = Result::::Err(const TryFromIntError(())); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + _8 = Result::::Err(const TryFromIntError(())); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL // mir::Constant // + span: no-location // + literal: Const { ty: TryFromIntError, val: Value() } - goto -> bb4; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + goto -> bb3; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL } bb3: { - StorageLive(_10); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - _10 = _5 as i16 (IntToInt); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - _7 = Result::::Ok(move _10); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - StorageDead(_10); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - goto -> bb4; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + StorageDead(_6); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + StorageLive(_10); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + _9 = discriminant(_8); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + switchInt(move _9) -> [0: bb4, 1: bb5, otherwise: bb9]; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL } bb4: { - StorageDead(_8); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL - StorageLive(_12); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL - _11 = discriminant(_7); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - switchInt(move _11) -> [0: bb7, 1: bb5, otherwise: bb6]; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + _10 = move ((_8 as Ok).0: i16); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + _11 = Option::::Some(move _10); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL + goto -> bb6; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL } bb5: { - _6 = Option::::None; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - goto -> bb8; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + _11 = Option::::None; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + goto -> bb6; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL } bb6: { - unreachable; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + StorageDead(_10); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageDead(_8); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageLive(_14); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + _12 = discriminant(_11); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + switchInt(move _12) -> [1: bb7, otherwise: bb9]; // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL } bb7: { - _12 = move ((_7 as Ok).0: i16); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - _6 = Option::::Some(move _12); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - goto -> bb8; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + _13 = move ((_11 as Some).0: i16); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + StorageDead(_14); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageDead(_11); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageDead(_4); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageDead(_3); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL + _0 = unchecked_shr::(_1, move _13) -> [return: bb8, unwind unreachable]; // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL + // mir::Constant + // + span: $SRC_DIR/core/src/num/int_macros.rs:LL:COL + // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(i16, i16) -> i16 {unchecked_shr::}, val: Value() } } bb8: { - StorageDead(_12); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageDead(_7); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageLive(_13); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL - _14 = discriminant(_6); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL - switchInt(move _14) -> [1: bb9, otherwise: bb6]; // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + StorageDead(_13); // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL + return; // scope 0 at $DIR/unchecked_shifts.rs:+2:2: +2:2 } bb9: { - _3 = move ((_6 as Some).0: i16); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL - StorageDead(_13); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageDead(_6); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageDead(_5); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL - StorageDead(_4); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL - _0 = unchecked_shr::(_1, move _3) -> [return: bb1, unwind unreachable]; // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL - // mir::Constant - // + span: $SRC_DIR/core/src/num/int_macros.rs:LL:COL - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(i16, i16) -> i16 {unchecked_shr::}, val: Value() } + unreachable; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL } } diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.mir b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.mir index c5e2469fc27c6..601d83702f435 100644 --- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.mir +++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.mir @@ -5,8 +5,8 @@ fn unwrap_unchecked(_1: Option) -> T { let mut _0: T; // return place in scope 0 at $DIR/unwrap_unchecked.rs:+0:54: +0:55 scope 1 (inlined #[track_caller] Option::::unwrap_unchecked) { // at $DIR/unwrap_unchecked.rs:10:9: 10:27 debug self => _1; // in scope 1 at $SRC_DIR/core/src/option.rs:LL:COL - let mut _2: &std::option::Option; // in scope 1 at $SRC_DIR/core/src/option.rs:LL:COL - let mut _3: isize; // in scope 1 at $SRC_DIR/core/src/option.rs:LL:COL + let mut _2: isize; // in scope 1 at $SRC_DIR/core/src/option.rs:LL:COL + let mut _3: &std::option::Option; // in scope 1 at $SRC_DIR/core/src/option.rs:LL:COL scope 2 { debug val => _0; // in scope 2 at $SRC_DIR/core/src/option.rs:LL:COL } @@ -19,23 +19,23 @@ fn unwrap_unchecked(_1: Option) -> T { } } scope 4 (inlined Option::::is_some) { // at $SRC_DIR/core/src/option.rs:LL:COL - debug self => _2; // in scope 4 at $SRC_DIR/core/src/option.rs:LL:COL + debug self => _3; // in scope 4 at $SRC_DIR/core/src/option.rs:LL:COL } } bb0: { - StorageLive(_2); // scope 0 at $DIR/unwrap_unchecked.rs:+1:9: +1:27 - _3 = discriminant(_1); // scope 1 at $SRC_DIR/core/src/option.rs:LL:COL - switchInt(move _3) -> [1: bb2, otherwise: bb1]; // scope 1 at $SRC_DIR/core/src/option.rs:LL:COL + StorageLive(_3); // scope 0 at $DIR/unwrap_unchecked.rs:+1:9: +1:27 + _2 = discriminant(_1); // scope 1 at $SRC_DIR/core/src/option.rs:LL:COL + switchInt(move _2) -> [1: bb1, otherwise: bb2]; // scope 1 at $SRC_DIR/core/src/option.rs:LL:COL } bb1: { - unreachable; // scope 6 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + _0 = move ((_1 as Some).0: T); // scope 1 at $SRC_DIR/core/src/option.rs:LL:COL + StorageDead(_3); // scope 0 at $DIR/unwrap_unchecked.rs:+1:9: +1:27 + return; // scope 0 at $DIR/unwrap_unchecked.rs:+2:2: +2:2 } bb2: { - _0 = move ((_1 as Some).0: T); // scope 1 at $SRC_DIR/core/src/option.rs:LL:COL - StorageDead(_2); // scope 0 at $DIR/unwrap_unchecked.rs:+1:9: +1:27 - return; // scope 0 at $DIR/unwrap_unchecked.rs:+2:2: +2:2 + unreachable; // scope 6 at $SRC_DIR/core/src/intrinsics.rs:LL:COL } } diff --git a/tests/mir-opt/issue_101973.inner.ConstProp.diff b/tests/mir-opt/issue_101973.inner.ConstProp.diff index d048b9e65130f..2f68f65c87492 100644 --- a/tests/mir-opt/issue_101973.inner.ConstProp.diff +++ b/tests/mir-opt/issue_101973.inner.ConstProp.diff @@ -18,8 +18,8 @@ let mut _13: bool; // in scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 scope 1 (inlined imm8) { // at $DIR/issue_101973.rs:15:5: 15:17 debug x => _1; // in scope 1 at $DIR/issue_101973.rs:6:13: 6:14 - let mut _14: u32; // in scope 1 at $DIR/issue_101973.rs:8:12: 8:27 - let mut _15: u32; // in scope 1 at $DIR/issue_101973.rs:8:12: 8:20 + let mut _14: u32; // in scope 1 at $DIR/issue_101973.rs:8:12: 8:20 + let mut _15: u32; // in scope 1 at $DIR/issue_101973.rs:8:12: 8:27 scope 2 { debug out => _4; // in scope 2 at $DIR/issue_101973.rs:7:9: 7:16 } @@ -33,13 +33,13 @@ StorageLive(_2); // scope 0 at $DIR/issue_101973.rs:+1:5: +1:65 StorageLive(_3); // scope 0 at $DIR/issue_101973.rs:+1:5: +1:58 StorageLive(_4); // scope 0 at $DIR/issue_101973.rs:+1:5: +1:17 - StorageLive(_14); // scope 2 at $DIR/issue_101973.rs:8:12: 8:27 - StorageLive(_15); // scope 2 at $DIR/issue_101973.rs:8:12: 8:20 - _15 = Shr(_1, const 0_i32); // scope 2 at $DIR/issue_101973.rs:8:12: 8:20 - _14 = BitAnd(move _15, const 255_u32); // scope 2 at $DIR/issue_101973.rs:8:12: 8:27 - StorageDead(_15); // scope 2 at $DIR/issue_101973.rs:8:26: 8:27 - _4 = BitOr(const 0_u32, move _14); // scope 2 at $DIR/issue_101973.rs:8:5: 8:27 + StorageLive(_15); // scope 2 at $DIR/issue_101973.rs:8:12: 8:27 + StorageLive(_14); // scope 2 at $DIR/issue_101973.rs:8:12: 8:20 + _14 = Shr(_1, const 0_i32); // scope 2 at $DIR/issue_101973.rs:8:12: 8:20 + _15 = BitAnd(move _14, const 255_u32); // scope 2 at $DIR/issue_101973.rs:8:12: 8:27 StorageDead(_14); // scope 2 at $DIR/issue_101973.rs:8:26: 8:27 + _4 = BitOr(const 0_u32, move _15); // scope 2 at $DIR/issue_101973.rs:8:5: 8:27 + StorageDead(_15); // scope 2 at $DIR/issue_101973.rs:8:26: 8:27 StorageLive(_6); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 StorageLive(_7); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:52 StorageLive(_8); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir index 9f955b4717bc3..fac4b8a2d25e0 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir @@ -3,19 +3,19 @@ fn num_to_digit(_1: char) -> u32 { debug num => _1; // in scope 0 at $DIR/issue_59352.rs:+0:21: +0:24 let mut _0: u32; // return place in scope 0 at $DIR/issue_59352.rs:+0:35: +0:38 - let mut _2: std::option::Option; // in scope 0 at $DIR/issue_59352.rs:+2:26: +2:41 + let mut _5: std::option::Option; // in scope 0 at $DIR/issue_59352.rs:+2:26: +2:41 scope 1 (inlined char::methods::::is_digit) { // at $DIR/issue_59352.rs:15:12: 15:23 debug self => _1; // in scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL debug radix => const 8_u32; // in scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL + let _2: std::option::Option; // in scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL let mut _3: &std::option::Option; // in scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL - let _4: std::option::Option; // in scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL scope 2 (inlined Option::::is_some) { // at $SRC_DIR/core/src/char/methods.rs:LL:COL debug self => _3; // in scope 2 at $SRC_DIR/core/src/option.rs:LL:COL - let mut _5: isize; // in scope 2 at $SRC_DIR/core/src/option.rs:LL:COL + let mut _4: isize; // in scope 2 at $SRC_DIR/core/src/option.rs:LL:COL } } scope 3 (inlined #[track_caller] Option::::unwrap) { // at $DIR/issue_59352.rs:15:42: 15:50 - debug self => _2; // in scope 3 at $SRC_DIR/core/src/option.rs:LL:COL + debug self => _5; // in scope 3 at $SRC_DIR/core/src/option.rs:LL:COL let mut _6: isize; // in scope 3 at $SRC_DIR/core/src/option.rs:LL:COL let mut _7: !; // in scope 3 at $SRC_DIR/core/src/option.rs:LL:COL scope 4 { @@ -25,44 +25,35 @@ fn num_to_digit(_1: char) -> u32 { bb0: { StorageLive(_3); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL - StorageLive(_4); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL - _4 = char::methods::::to_digit(_1, const 8_u32) -> bb5; // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL + StorageLive(_2); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL + _2 = char::methods::::to_digit(_1, const 8_u32) -> bb1; // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/char/methods.rs:LL:COL // + literal: Const { ty: fn(char, u32) -> Option {char::methods::::to_digit}, val: Value() } } bb1: { - StorageLive(_2); // scope 0 at $DIR/issue_59352.rs:+2:26: +2:41 - _2 = char::methods::::to_digit(_1, const 8_u32) -> bb2; // scope 0 at $DIR/issue_59352.rs:+2:26: +2:41 - // mir::Constant - // + span: $DIR/issue_59352.rs:15:30: 15:38 - // + literal: Const { ty: fn(char, u32) -> Option {char::methods::::to_digit}, val: Value() } + _3 = &_2; // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL + _4 = discriminant((*_3)); // scope 2 at $SRC_DIR/core/src/option.rs:LL:COL + StorageDead(_3); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL + StorageDead(_2); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL + switchInt(move _4) -> [1: bb2, otherwise: bb7]; // scope 0 at $DIR/issue_59352.rs:+2:8: +2:23 } bb2: { - _6 = discriminant(_2); // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL - switchInt(move _6) -> [0: bb6, 1: bb8, otherwise: bb7]; // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL + StorageLive(_5); // scope 0 at $DIR/issue_59352.rs:+2:26: +2:41 + _5 = char::methods::::to_digit(_1, const 8_u32) -> bb3; // scope 0 at $DIR/issue_59352.rs:+2:26: +2:41 + // mir::Constant + // + span: $DIR/issue_59352.rs:15:30: 15:38 + // + literal: Const { ty: fn(char, u32) -> Option {char::methods::::to_digit}, val: Value() } } bb3: { - _0 = const 0_u32; // scope 0 at $DIR/issue_59352.rs:+2:60: +2:61 - goto -> bb4; // scope 0 at $DIR/issue_59352.rs:+2:5: +2:63 + _6 = discriminant(_5); // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL + switchInt(move _6) -> [0: bb4, 1: bb5, otherwise: bb6]; // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL } bb4: { - return; // scope 0 at $DIR/issue_59352.rs:+3:2: +3:2 - } - - bb5: { - _3 = &_4; // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL - _5 = discriminant((*_3)); // scope 2 at $SRC_DIR/core/src/option.rs:LL:COL - StorageDead(_3); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL - StorageDead(_4); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL - switchInt(move _5) -> [1: bb1, otherwise: bb3]; // scope 0 at $DIR/issue_59352.rs:+2:8: +2:23 - } - - bb6: { _7 = core::panicking::panic(const "called `Option::unwrap()` on a `None` value"); // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/option.rs:LL:COL @@ -72,13 +63,22 @@ fn num_to_digit(_1: char) -> u32 { // + literal: Const { ty: &str, val: Value(Slice(..)) } } - bb7: { + bb5: { + _0 = move ((_5 as Some).0: u32); // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL + StorageDead(_5); // scope 0 at $DIR/issue_59352.rs:+2:49: +2:50 + goto -> bb8; // scope 0 at $DIR/issue_59352.rs:+2:5: +2:63 + } + + bb6: { unreachable; // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL } + bb7: { + _0 = const 0_u32; // scope 0 at $DIR/issue_59352.rs:+2:60: +2:61 + goto -> bb8; // scope 0 at $DIR/issue_59352.rs:+2:5: +2:63 + } + bb8: { - _0 = move ((_2 as Some).0: u32); // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL - StorageDead(_2); // scope 0 at $DIR/issue_59352.rs:+2:49: +2:50 - goto -> bb4; // scope 0 at $DIR/issue_59352.rs:+2:5: +2:63 + return; // scope 0 at $DIR/issue_59352.rs:+3:2: +3:2 } } diff --git a/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir index 0e885cf94fdbd..6b805166ba29c 100644 --- a/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir @@ -13,15 +13,15 @@ fn ub_if_b(_1: Thing) -> Thing { bb0: { _2 = discriminant(_1); // scope 0 at $DIR/duplicate_switch_targets.rs:+1:11: +1:12 - switchInt(move _2) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/duplicate_switch_targets.rs:+1:5: +1:12 + switchInt(move _2) -> [0: bb1, otherwise: bb2]; // scope 0 at $DIR/duplicate_switch_targets.rs:+1:5: +1:12 } bb1: { - unreachable; // scope 2 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + _0 = move _1; // scope 0 at $DIR/duplicate_switch_targets.rs:+2:21: +2:22 + return; // scope 0 at $DIR/duplicate_switch_targets.rs:+5:2: +5:2 } bb2: { - _0 = move _1; // scope 0 at $DIR/duplicate_switch_targets.rs:+2:21: +2:22 - return; // scope 0 at $DIR/duplicate_switch_targets.rs:+5:2: +5:2 + unreachable; // scope 2 at $SRC_DIR/core/src/intrinsics.rs:LL:COL } } diff --git a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.mir index 343a4a5a6f3a1..9856cdd5688ba 100644 --- a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.mir @@ -7,20 +7,20 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { let mut _0: (); // return place in scope 0 at $DIR/range_iter.rs:+0:60: +0:60 let mut _4: std::ops::Range; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:24 let mut _5: std::ops::Range; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:24 - let _6: (); // in scope 0 at $DIR/range_iter.rs:+1:14: +1:24 + let mut _6: &mut std::ops::Range; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:24 let mut _7: std::option::Option; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:24 - let mut _8: &mut std::ops::Range; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:24 - let mut _9: isize; // in scope 0 at $DIR/range_iter.rs:+1:5: +3:6 - let mut _11: &impl Fn(u32); // in scope 0 at $DIR/range_iter.rs:+2:9: +2:10 - let mut _12: (u32,); // in scope 0 at $DIR/range_iter.rs:+2:9: +2:13 + let mut _8: isize; // in scope 0 at $DIR/range_iter.rs:+1:5: +3:6 + let mut _10: &impl Fn(u32); // in scope 0 at $DIR/range_iter.rs:+2:9: +2:10 + let mut _11: (u32,); // in scope 0 at $DIR/range_iter.rs:+2:9: +2:13 + let _12: (); // in scope 0 at $DIR/range_iter.rs:+1:14: +1:24 scope 1 { debug iter => _5; // in scope 1 at $DIR/range_iter.rs:+1:14: +1:24 - let _10: u32; // in scope 1 at $DIR/range_iter.rs:+1:9: +1:10 + let _9: u32; // in scope 1 at $DIR/range_iter.rs:+1:9: +1:10 scope 2 { - debug x => _10; // in scope 2 at $DIR/range_iter.rs:+1:9: +1:10 + debug x => _9; // in scope 2 at $DIR/range_iter.rs:+1:9: +1:10 } scope 4 (inlined iter::range::>::next) { // at $DIR/range_iter.rs:21:14: 21:24 - debug self => _8; // in scope 4 at $SRC_DIR/core/src/iter/range.rs:LL:COL + debug self => _6; // in scope 4 at $SRC_DIR/core/src/iter/range.rs:LL:COL } } scope 3 (inlined as IntoIterator>::into_iter) { // at $DIR/range_iter.rs:21:14: 21:24 @@ -36,56 +36,56 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { bb1: { StorageLive(_7); // scope 1 at $DIR/range_iter.rs:+1:14: +1:24 - _8 = &mut _5; // scope 1 at $DIR/range_iter.rs:+1:14: +1:24 - _7 = as iter::range::RangeIteratorImpl>::spec_next(_8) -> [return: bb9, unwind: bb7]; // scope 4 at $SRC_DIR/core/src/iter/range.rs:LL:COL + _6 = &mut _5; // scope 1 at $DIR/range_iter.rs:+1:14: +1:24 + _7 = as iter::range::RangeIteratorImpl>::spec_next(_6) -> [return: bb2, unwind: bb8]; // scope 4 at $SRC_DIR/core/src/iter/range.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/iter/range.rs:LL:COL // + literal: Const { ty: for<'a> fn(&'a mut std::ops::Range) -> Option< as iter::range::RangeIteratorImpl>::Item> { as iter::range::RangeIteratorImpl>::spec_next}, val: Value() } } bb2: { - _10 = ((_7 as Some).0: u32); // scope 1 at $DIR/range_iter.rs:+1:9: +1:10 - StorageLive(_11); // scope 2 at $DIR/range_iter.rs:+2:9: +2:10 - _11 = &_3; // scope 2 at $DIR/range_iter.rs:+2:9: +2:10 - StorageLive(_12); // scope 2 at $DIR/range_iter.rs:+2:9: +2:13 - _12 = (_10,); // scope 2 at $DIR/range_iter.rs:+2:9: +2:13 - _6 = >::call(move _11, move _12) -> [return: bb5, unwind: bb7]; // scope 2 at $DIR/range_iter.rs:+2:9: +2:13 - // mir::Constant - // + span: $DIR/range_iter.rs:22:9: 22:10 - // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a impl Fn(u32), (u32,)) -> >::Output {>::call}, val: Value() } + _8 = discriminant(_7); // scope 1 at $DIR/range_iter.rs:+1:14: +1:24 + switchInt(move _8) -> [0: bb3, 1: bb5, otherwise: bb7]; // scope 1 at $DIR/range_iter.rs:+1:14: +1:24 } bb3: { - unreachable; // scope 1 at $DIR/range_iter.rs:+1:14: +1:24 + StorageDead(_7); // scope 1 at $DIR/range_iter.rs:+3:5: +3:6 + StorageDead(_5); // scope 0 at $DIR/range_iter.rs:+3:5: +3:6 + drop(_3) -> bb4; // scope 0 at $DIR/range_iter.rs:+4:1: +4:2 } bb4: { - StorageDead(_7); // scope 1 at $DIR/range_iter.rs:+3:5: +3:6 - StorageDead(_5); // scope 0 at $DIR/range_iter.rs:+3:5: +3:6 - drop(_3) -> bb6; // scope 0 at $DIR/range_iter.rs:+4:1: +4:2 + return; // scope 0 at $DIR/range_iter.rs:+4:2: +4:2 } bb5: { - StorageDead(_12); // scope 2 at $DIR/range_iter.rs:+2:12: +2:13 - StorageDead(_11); // scope 2 at $DIR/range_iter.rs:+2:12: +2:13 - StorageDead(_7); // scope 1 at $DIR/range_iter.rs:+3:5: +3:6 - goto -> bb1; // scope 1 at $DIR/range_iter.rs:+1:5: +3:6 + _9 = ((_7 as Some).0: u32); // scope 1 at $DIR/range_iter.rs:+1:9: +1:10 + StorageLive(_10); // scope 2 at $DIR/range_iter.rs:+2:9: +2:10 + _10 = &_3; // scope 2 at $DIR/range_iter.rs:+2:9: +2:10 + StorageLive(_11); // scope 2 at $DIR/range_iter.rs:+2:9: +2:13 + _11 = (_9,); // scope 2 at $DIR/range_iter.rs:+2:9: +2:13 + _12 = >::call(move _10, move _11) -> [return: bb6, unwind: bb8]; // scope 2 at $DIR/range_iter.rs:+2:9: +2:13 + // mir::Constant + // + span: $DIR/range_iter.rs:22:9: 22:10 + // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a impl Fn(u32), (u32,)) -> >::Output {>::call}, val: Value() } } bb6: { - return; // scope 0 at $DIR/range_iter.rs:+4:2: +4:2 + StorageDead(_11); // scope 2 at $DIR/range_iter.rs:+2:12: +2:13 + StorageDead(_10); // scope 2 at $DIR/range_iter.rs:+2:12: +2:13 + StorageDead(_7); // scope 1 at $DIR/range_iter.rs:+3:5: +3:6 + goto -> bb1; // scope 1 at $DIR/range_iter.rs:+1:5: +3:6 } - bb7 (cleanup): { - drop(_3) -> [return: bb8, unwind terminate]; // scope 0 at $DIR/range_iter.rs:+4:1: +4:2 + bb7: { + unreachable; // scope 1 at $DIR/range_iter.rs:+1:14: +1:24 } bb8 (cleanup): { - resume; // scope 0 at $DIR/range_iter.rs:+0:1: +4:2 + drop(_3) -> [return: bb9, unwind terminate]; // scope 0 at $DIR/range_iter.rs:+4:1: +4:2 } - bb9: { - _9 = discriminant(_7); // scope 1 at $DIR/range_iter.rs:+1:14: +1:24 - switchInt(move _9) -> [0: bb4, 1: bb2, otherwise: bb3]; // scope 1 at $DIR/range_iter.rs:+1:14: +1:24 + bb9 (cleanup): { + resume; // scope 0 at $DIR/range_iter.rs:+0:1: +4:2 } } diff --git a/tests/mir-opt/pre-codegen/range_iter.inclusive_loop.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/range_iter.inclusive_loop.PreCodegen.after.mir index f45eabba252ee..a187d650a7772 100644 --- a/tests/mir-opt/pre-codegen/range_iter.inclusive_loop.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/range_iter.inclusive_loop.PreCodegen.after.mir @@ -7,20 +7,20 @@ fn inclusive_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { let mut _0: (); // return place in scope 0 at $DIR/range_iter.rs:+0:62: +0:62 let mut _4: std::ops::RangeInclusive; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:25 let mut _5: std::ops::RangeInclusive; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:25 - let _6: (); // in scope 0 at $DIR/range_iter.rs:+1:14: +1:25 + let mut _6: &mut std::ops::RangeInclusive; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:25 let mut _7: std::option::Option; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:25 - let mut _8: &mut std::ops::RangeInclusive; // in scope 0 at $DIR/range_iter.rs:+1:14: +1:25 - let mut _9: isize; // in scope 0 at $DIR/range_iter.rs:+1:5: +3:6 - let mut _11: &impl Fn(u32); // in scope 0 at $DIR/range_iter.rs:+2:9: +2:10 - let mut _12: (u32,); // in scope 0 at $DIR/range_iter.rs:+2:9: +2:13 + let mut _8: isize; // in scope 0 at $DIR/range_iter.rs:+1:5: +3:6 + let mut _10: &impl Fn(u32); // in scope 0 at $DIR/range_iter.rs:+2:9: +2:10 + let mut _11: (u32,); // in scope 0 at $DIR/range_iter.rs:+2:9: +2:13 + let _12: (); // in scope 0 at $DIR/range_iter.rs:+1:14: +1:25 scope 1 { debug iter => _5; // in scope 1 at $DIR/range_iter.rs:+1:14: +1:25 - let _10: u32; // in scope 1 at $DIR/range_iter.rs:+1:9: +1:10 + let _9: u32; // in scope 1 at $DIR/range_iter.rs:+1:9: +1:10 scope 2 { - debug x => _10; // in scope 2 at $DIR/range_iter.rs:+1:9: +1:10 + debug x => _9; // in scope 2 at $DIR/range_iter.rs:+1:9: +1:10 } scope 5 (inlined iter::range::>::next) { // at $DIR/range_iter.rs:28:14: 28:25 - debug self => _8; // in scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + debug self => _6; // in scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL } } scope 3 (inlined RangeInclusive::::new) { // at $DIR/range_iter.rs:28:14: 28:25 @@ -40,56 +40,56 @@ fn inclusive_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { bb1: { StorageLive(_7); // scope 1 at $DIR/range_iter.rs:+1:14: +1:25 - _8 = &mut _5; // scope 1 at $DIR/range_iter.rs:+1:14: +1:25 - _7 = as iter::range::RangeInclusiveIteratorImpl>::spec_next(_8) -> [return: bb9, unwind: bb7]; // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + _6 = &mut _5; // scope 1 at $DIR/range_iter.rs:+1:14: +1:25 + _7 = as iter::range::RangeInclusiveIteratorImpl>::spec_next(_6) -> [return: bb2, unwind: bb8]; // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/iter/range.rs:LL:COL // + literal: Const { ty: for<'a> fn(&'a mut RangeInclusive) -> Option< as iter::range::RangeInclusiveIteratorImpl>::Item> { as iter::range::RangeInclusiveIteratorImpl>::spec_next}, val: Value() } } bb2: { - _10 = ((_7 as Some).0: u32); // scope 1 at $DIR/range_iter.rs:+1:9: +1:10 - StorageLive(_11); // scope 2 at $DIR/range_iter.rs:+2:9: +2:10 - _11 = &_3; // scope 2 at $DIR/range_iter.rs:+2:9: +2:10 - StorageLive(_12); // scope 2 at $DIR/range_iter.rs:+2:9: +2:13 - _12 = (_10,); // scope 2 at $DIR/range_iter.rs:+2:9: +2:13 - _6 = >::call(move _11, move _12) -> [return: bb5, unwind: bb7]; // scope 2 at $DIR/range_iter.rs:+2:9: +2:13 - // mir::Constant - // + span: $DIR/range_iter.rs:29:9: 29:10 - // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a impl Fn(u32), (u32,)) -> >::Output {>::call}, val: Value() } + _8 = discriminant(_7); // scope 1 at $DIR/range_iter.rs:+1:14: +1:25 + switchInt(move _8) -> [0: bb3, 1: bb5, otherwise: bb7]; // scope 1 at $DIR/range_iter.rs:+1:14: +1:25 } bb3: { - unreachable; // scope 1 at $DIR/range_iter.rs:+1:14: +1:25 + StorageDead(_7); // scope 1 at $DIR/range_iter.rs:+3:5: +3:6 + StorageDead(_5); // scope 0 at $DIR/range_iter.rs:+3:5: +3:6 + drop(_3) -> bb4; // scope 0 at $DIR/range_iter.rs:+4:1: +4:2 } bb4: { - StorageDead(_7); // scope 1 at $DIR/range_iter.rs:+3:5: +3:6 - StorageDead(_5); // scope 0 at $DIR/range_iter.rs:+3:5: +3:6 - drop(_3) -> bb6; // scope 0 at $DIR/range_iter.rs:+4:1: +4:2 + return; // scope 0 at $DIR/range_iter.rs:+4:2: +4:2 } bb5: { - StorageDead(_12); // scope 2 at $DIR/range_iter.rs:+2:12: +2:13 - StorageDead(_11); // scope 2 at $DIR/range_iter.rs:+2:12: +2:13 - StorageDead(_7); // scope 1 at $DIR/range_iter.rs:+3:5: +3:6 - goto -> bb1; // scope 1 at $DIR/range_iter.rs:+1:5: +3:6 + _9 = ((_7 as Some).0: u32); // scope 1 at $DIR/range_iter.rs:+1:9: +1:10 + StorageLive(_10); // scope 2 at $DIR/range_iter.rs:+2:9: +2:10 + _10 = &_3; // scope 2 at $DIR/range_iter.rs:+2:9: +2:10 + StorageLive(_11); // scope 2 at $DIR/range_iter.rs:+2:9: +2:13 + _11 = (_9,); // scope 2 at $DIR/range_iter.rs:+2:9: +2:13 + _12 = >::call(move _10, move _11) -> [return: bb6, unwind: bb8]; // scope 2 at $DIR/range_iter.rs:+2:9: +2:13 + // mir::Constant + // + span: $DIR/range_iter.rs:29:9: 29:10 + // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a impl Fn(u32), (u32,)) -> >::Output {>::call}, val: Value() } } bb6: { - return; // scope 0 at $DIR/range_iter.rs:+4:2: +4:2 + StorageDead(_11); // scope 2 at $DIR/range_iter.rs:+2:12: +2:13 + StorageDead(_10); // scope 2 at $DIR/range_iter.rs:+2:12: +2:13 + StorageDead(_7); // scope 1 at $DIR/range_iter.rs:+3:5: +3:6 + goto -> bb1; // scope 1 at $DIR/range_iter.rs:+1:5: +3:6 } - bb7 (cleanup): { - drop(_3) -> [return: bb8, unwind terminate]; // scope 0 at $DIR/range_iter.rs:+4:1: +4:2 + bb7: { + unreachable; // scope 1 at $DIR/range_iter.rs:+1:14: +1:25 } bb8 (cleanup): { - resume; // scope 0 at $DIR/range_iter.rs:+0:1: +4:2 + drop(_3) -> [return: bb9, unwind terminate]; // scope 0 at $DIR/range_iter.rs:+4:1: +4:2 } - bb9: { - _9 = discriminant(_7); // scope 1 at $DIR/range_iter.rs:+1:14: +1:25 - switchInt(move _9) -> [0: bb4, 1: bb2, otherwise: bb3]; // scope 1 at $DIR/range_iter.rs:+1:14: +1:25 + bb9 (cleanup): { + resume; // scope 0 at $DIR/range_iter.rs:+0:1: +4:2 } } diff --git a/tests/mir-opt/pre-codegen/simple_option_map.ezmap.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/simple_option_map.ezmap.PreCodegen.after.mir index 986ab35886f76..089b0c23e2ce7 100644 --- a/tests/mir-opt/pre-codegen/simple_option_map.ezmap.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/simple_option_map.ezmap.PreCodegen.after.mir @@ -3,18 +3,18 @@ fn ezmap(_1: Option) -> Option { debug x => _1; // in scope 0 at $DIR/simple_option_map.rs:+0:14: +0:15 let mut _0: std::option::Option; // return place in scope 0 at $DIR/simple_option_map.rs:+0:33: +0:44 - let mut _6: i32; // in scope 0 at $DIR/simple_option_map.rs:11:25: 11:29 + let mut _5: i32; // in scope 0 at $DIR/simple_option_map.rs:11:25: 11:29 scope 1 (inlined map::) { // at $DIR/simple_option_map.rs:18:5: 18:22 debug slf => _1; // in scope 1 at $DIR/simple_option_map.rs:6:17: 6:20 debug f => const ZeroSized: [closure@$DIR/simple_option_map.rs:18:12: 18:15]; // in scope 1 at $DIR/simple_option_map.rs:6:33: 6:34 let mut _2: isize; // in scope 1 at $DIR/simple_option_map.rs:11:9: 11:16 let _3: i32; // in scope 1 at $DIR/simple_option_map.rs:11:14: 11:15 - let mut _4: i32; // in scope 1 at $DIR/simple_option_map.rs:11:25: 11:29 - let mut _5: (i32,); // in scope 1 at $DIR/simple_option_map.rs:11:25: 11:29 + let mut _4: (i32,); // in scope 1 at $DIR/simple_option_map.rs:11:25: 11:29 + let mut _6: i32; // in scope 1 at $DIR/simple_option_map.rs:11:25: 11:29 scope 2 { debug x => _3; // in scope 2 at $DIR/simple_option_map.rs:11:14: 11:15 scope 3 (inlined ezmap::{closure#0}) { // at $DIR/simple_option_map.rs:11:25: 11:29 - debug n => _6; // in scope 3 at $DIR/simple_option_map.rs:+1:13: +1:14 + debug n => _5; // in scope 3 at $DIR/simple_option_map.rs:+1:13: +1:14 } } } @@ -22,35 +22,35 @@ fn ezmap(_1: Option) -> Option { bb0: { StorageLive(_3); // scope 0 at $DIR/simple_option_map.rs:+1:5: +1:22 _2 = discriminant(_1); // scope 1 at $DIR/simple_option_map.rs:10:11: 10:14 - switchInt(move _2) -> [0: bb1, 1: bb3, otherwise: bb2]; // scope 1 at $DIR/simple_option_map.rs:10:5: 10:14 + switchInt(move _2) -> [0: bb1, 1: bb2, otherwise: bb4]; // scope 1 at $DIR/simple_option_map.rs:10:5: 10:14 } bb1: { _0 = Option::::None; // scope 1 at $DIR/simple_option_map.rs:12:17: 12:21 - goto -> bb4; // scope 1 at $DIR/simple_option_map.rs:12:17: 12:21 + goto -> bb3; // scope 1 at $DIR/simple_option_map.rs:12:17: 12:21 } bb2: { - unreachable; // scope 1 at $DIR/simple_option_map.rs:10:11: 10:14 - } - - bb3: { _3 = ((_1 as Some).0: i32); // scope 1 at $DIR/simple_option_map.rs:11:14: 11:15 + StorageLive(_6); // scope 2 at $DIR/simple_option_map.rs:11:25: 11:29 StorageLive(_4); // scope 2 at $DIR/simple_option_map.rs:11:25: 11:29 + _4 = (move _3,); // scope 2 at $DIR/simple_option_map.rs:11:25: 11:29 StorageLive(_5); // scope 2 at $DIR/simple_option_map.rs:11:25: 11:29 - _5 = (move _3,); // scope 2 at $DIR/simple_option_map.rs:11:25: 11:29 - StorageLive(_6); // scope 2 at $DIR/simple_option_map.rs:11:25: 11:29 - _6 = move (_5.0: i32); // scope 2 at $DIR/simple_option_map.rs:11:25: 11:29 - _4 = Add(_6, const 1_i32); // scope 3 at $DIR/simple_option_map.rs:+1:16: +1:21 - StorageDead(_6); // scope 2 at $DIR/simple_option_map.rs:11:25: 11:29 - StorageDead(_5); // scope 2 at $DIR/simple_option_map.rs:11:28: 11:29 - _0 = Option::::Some(move _4); // scope 2 at $DIR/simple_option_map.rs:11:20: 11:30 - StorageDead(_4); // scope 2 at $DIR/simple_option_map.rs:11:29: 11:30 - goto -> bb4; // scope 1 at $DIR/simple_option_map.rs:14:1: 14:2 + _5 = move (_4.0: i32); // scope 2 at $DIR/simple_option_map.rs:11:25: 11:29 + _6 = Add(_5, const 1_i32); // scope 3 at $DIR/simple_option_map.rs:+1:16: +1:21 + StorageDead(_5); // scope 2 at $DIR/simple_option_map.rs:11:25: 11:29 + StorageDead(_4); // scope 2 at $DIR/simple_option_map.rs:11:28: 11:29 + _0 = Option::::Some(move _6); // scope 2 at $DIR/simple_option_map.rs:11:20: 11:30 + StorageDead(_6); // scope 2 at $DIR/simple_option_map.rs:11:29: 11:30 + goto -> bb3; // scope 1 at $DIR/simple_option_map.rs:14:1: 14:2 } - bb4: { + bb3: { StorageDead(_3); // scope 0 at $DIR/simple_option_map.rs:+1:5: +1:22 return; // scope 0 at $DIR/simple_option_map.rs:+2:2: +2:2 } + + bb4: { + unreachable; // scope 1 at $DIR/simple_option_map.rs:10:11: 10:14 + } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.mir index 715a1e3fcd479..b05d44f4d60ab 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.mir @@ -10,17 +10,17 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> { scope 2 (inlined >::get_mut) { // at $SRC_DIR/core/src/slice/mod.rs:LL:COL debug self => _2; // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL debug slice => _1; // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL - let mut _3: bool; // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL + let mut _3: &[u32]; // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL let mut _4: usize; // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL - let mut _5: &[u32]; // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL - let mut _6: &mut u32; // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL - let mut _7: *mut u32; // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL - let mut _8: *mut [u32]; // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL + let mut _5: bool; // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL + let mut _6: *mut [u32]; // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL + let mut _8: *mut u32; // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL + let mut _9: &mut u32; // in scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL scope 3 { scope 4 (inlined >::get_unchecked_mut) { // at $SRC_DIR/core/src/slice/index.rs:LL:COL debug self => _2; // in scope 4 at $SRC_DIR/core/src/slice/index.rs:LL:COL - debug slice => _8; // in scope 4 at $SRC_DIR/core/src/slice/index.rs:LL:COL - let mut _9: *mut u32; // in scope 4 at $SRC_DIR/core/src/slice/index.rs:LL:COL + debug slice => _6; // in scope 4 at $SRC_DIR/core/src/slice/index.rs:LL:COL + let mut _7: *mut u32; // in scope 4 at $SRC_DIR/core/src/slice/index.rs:LL:COL let mut _10: usize; // in scope 4 at $SRC_DIR/core/src/intrinsics.rs:LL:COL let mut _11: *mut [u32]; // in scope 4 at $SRC_DIR/core/src/intrinsics.rs:LL:COL scope 5 { @@ -40,10 +40,10 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> { } } scope 11 (inlined ptr::mut_ptr::::as_mut_ptr) { // at $SRC_DIR/core/src/slice/index.rs:LL:COL - debug self => _8; // in scope 11 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + debug self => _6; // in scope 11 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL } scope 12 (inlined ptr::mut_ptr::::add) { // at $SRC_DIR/core/src/slice/index.rs:LL:COL - debug self => _9; // in scope 12 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + debug self => _7; // in scope 12 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL debug count => _2; // in scope 12 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL scope 13 { } @@ -56,50 +56,50 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> { } bb0: { - StorageLive(_6); // scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageLive(_3); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL - StorageLive(_4); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageLive(_9); // scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL StorageLive(_5); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _5 = &(*_1); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _4 = Len((*_5)); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL - StorageDead(_5); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _3 = Lt(_2, move _4); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageLive(_4); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageLive(_3); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _3 = &(*_1); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _4 = Len((*_3)); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageDead(_3); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _5 = Lt(_2, move _4); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL StorageDead(_4); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL - switchInt(move _3) -> [0: bb2, otherwise: bb1]; // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL + switchInt(move _5) -> [0: bb1, otherwise: bb2]; // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL } bb1: { - StorageLive(_7); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _0 = const Option::<&mut u32>::None; // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL + // mir::Constant + // + span: no-location + // + literal: Const { ty: Option<&mut u32>, val: Value(Scalar(0x0000000000000000)) } + goto -> bb3; // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL + } + + bb2: { StorageLive(_8); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _8 = &raw mut (*_1); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageLive(_6); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _6 = &raw mut (*_1); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL StorageLive(_10); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL StorageLive(_11); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL StorageLive(_12); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL - StorageLive(_9); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _9 = _8 as *mut u32 (PtrToPtr); // scope 11 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - _7 = Offset(_9, _2); // scope 13 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - StorageDead(_9); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageLive(_7); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _7 = _6 as *mut u32 (PtrToPtr); // scope 11 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + _8 = Offset(_7, _2); // scope 13 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + StorageDead(_7); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL StorageDead(_12); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL StorageDead(_11); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL StorageDead(_10); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL - StorageDead(_8); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _6 = &mut (*_7); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _0 = Option::<&mut u32>::Some(_6); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL - StorageDead(_7); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL - goto -> bb3; // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL - } - - bb2: { - _0 = const Option::<&mut u32>::None; // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL - // mir::Constant - // + span: no-location - // + literal: Const { ty: Option<&mut u32>, val: Value(Scalar(0x0000000000000000)) } + StorageDead(_6); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _9 = &mut (*_8); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _0 = Option::<&mut u32>::Some(_9); // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageDead(_8); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL goto -> bb3; // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL } bb3: { - StorageDead(_3); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL - StorageDead(_6); // scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageDead(_5); // scope 2 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageDead(_9); // scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL return; // scope 0 at $DIR/slice_index.rs:+2:2: +2:2 } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.mir index 7a10b929ebd09..6d9ec5d9a27f5 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.mir @@ -8,61 +8,61 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> debug self => _1; // in scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL debug index => _2; // in scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL let mut _3: *mut [u32]; // in scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - let mut _4: *mut [u32]; // in scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + let mut _15: *mut [u32]; // in scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL scope 2 { scope 3 (inlined as SliceIndex<[u32]>>::get_unchecked_mut) { // at $SRC_DIR/core/src/slice/mod.rs:LL:COL debug self => _2; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL - debug slice => _4; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL - let _5: std::ops::Range; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL - let mut _7: usize; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL + debug slice => _3; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL + let mut _4: usize; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL + let mut _5: usize; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL + let mut _7: *mut u32; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL let mut _8: usize; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL let mut _9: *mut u32; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL - let mut _10: *mut u32; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL - let mut _11: usize; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL - let mut _12: usize; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL - let mut _13: std::ops::Range; // in scope 3 at $SRC_DIR/core/src/intrinsics.rs:LL:COL - let mut _14: *mut [u32]; // in scope 3 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + let mut _10: usize; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL + let _16: std::ops::Range; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL + let mut _17: std::ops::Range; // in scope 3 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + let mut _18: *mut [u32]; // in scope 3 at $SRC_DIR/core/src/intrinsics.rs:LL:COL scope 4 { - debug this => _5; // in scope 4 at $SRC_DIR/core/src/slice/index.rs:LL:COL + debug this => _16; // in scope 4 at $SRC_DIR/core/src/slice/index.rs:LL:COL scope 5 { let _6: usize; // in scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL scope 6 { debug new_len => _6; // in scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL scope 11 (inlined ptr::mut_ptr::::as_mut_ptr) { // at $SRC_DIR/core/src/slice/index.rs:LL:COL - debug self => _4; // in scope 11 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + debug self => _3; // in scope 11 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL } scope 12 (inlined ptr::mut_ptr::::add) { // at $SRC_DIR/core/src/slice/index.rs:LL:COL - debug self => _10; // in scope 12 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - debug count => _11; // in scope 12 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + debug self => _7; // in scope 12 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + debug count => _8; // in scope 12 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL scope 13 { } } scope 14 (inlined slice_from_raw_parts_mut::) { // at $SRC_DIR/core/src/slice/index.rs:LL:COL debug data => _9; // in scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - debug len => _12; // in scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - let mut _16: *mut (); // in scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + debug len => _10; // in scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _11: *mut (); // in scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL scope 15 (inlined ptr::mut_ptr::::cast::<()>) { // at $SRC_DIR/core/src/ptr/mod.rs:LL:COL debug self => _9; // in scope 15 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL } scope 16 (inlined std::ptr::from_raw_parts_mut::<[u32]>) { // at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - debug data_address => _16; // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - debug metadata => _12; // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - let mut _17: std::ptr::metadata::PtrRepr<[u32]>; // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - let mut _18: std::ptr::metadata::PtrComponents<[u32]>; // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - let mut _19: *const (); // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + debug data_address => _11; // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + debug metadata => _10; // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + let mut _12: *const (); // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + let mut _13: std::ptr::metadata::PtrComponents<[u32]>; // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + let mut _14: std::ptr::metadata::PtrRepr<[u32]>; // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL scope 17 { } } } } scope 7 (inlined as SliceIndex<[T]>>::get_unchecked_mut::runtime::) { // at $SRC_DIR/core/src/intrinsics.rs:LL:COL - debug this => _13; // in scope 7 at $SRC_DIR/core/src/intrinsics.rs:LL:COL - debug slice => _14; // in scope 7 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + debug this => _17; // in scope 7 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + debug slice => _18; // in scope 7 at $SRC_DIR/core/src/intrinsics.rs:LL:COL scope 8 (inlined ptr::mut_ptr::::len) { // at $SRC_DIR/core/src/slice/index.rs:LL:COL - debug self => _14; // in scope 8 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - let mut _15: *const [u32]; // in scope 8 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + debug self => _18; // in scope 8 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + let mut _19: *const [u32]; // in scope 8 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL scope 9 (inlined std::ptr::metadata::<[u32]>) { // at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - debug ptr => _15; // in scope 9 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + debug ptr => _19; // in scope 9 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL scope 10 { } } @@ -75,60 +75,60 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> } bb0: { - StorageLive(_3); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageLive(_4); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - _4 = &raw mut (*_1); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageLive(_5); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageLive(_13); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageLive(_14); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL StorageLive(_15); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageLive(_3); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + _3 = &raw mut (*_1); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageLive(_16); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageLive(_17); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageLive(_18); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageLive(_19); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL StorageLive(_6); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL - StorageLive(_7); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _7 = (_2.1: usize); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL - StorageLive(_8); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _8 = (_2.0: usize); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _6 = unchecked_sub::(move _7, move _8) -> [return: bb1, unwind unreachable]; // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageLive(_4); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _4 = (_2.1: usize); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageLive(_5); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _5 = (_2.0: usize); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _6 = unchecked_sub::(move _4, move _5) -> [return: bb1, unwind unreachable]; // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/slice/index.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize, usize) -> usize {unchecked_sub::}, val: Value() } } bb1: { - StorageDead(_8); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL - StorageDead(_7); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageDead(_5); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageDead(_4); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL StorageLive(_9); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageLive(_7); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _7 = _3 as *mut u32 (PtrToPtr); // scope 11 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + StorageLive(_8); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _8 = (_2.0: usize); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _9 = Offset(_7, _8); // scope 13 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + StorageDead(_8); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageDead(_7); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL StorageLive(_10); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _10 = _4 as *mut u32 (PtrToPtr); // scope 11 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - StorageLive(_11); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _11 = (_2.0: usize); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _9 = Offset(_10, _11); // scope 13 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - StorageDead(_11); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _10 = _6; // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageLive(_11); // scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + _11 = _9 as *mut () (PtrToPtr); // scope 15 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + StorageLive(_14); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + StorageLive(_13); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + StorageLive(_12); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + _12 = _11 as *const () (Pointer(MutToConstPointer)); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + _13 = ptr::metadata::PtrComponents::<[u32]> { data_address: move _12, metadata: _10 }; // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + StorageDead(_12); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + _14 = ptr::metadata::PtrRepr::<[u32]> { const_ptr: move _13 }; // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + StorageDead(_13); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + _15 = (_14.1: *mut [u32]); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + StorageDead(_14); // scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + StorageDead(_11); // scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL StorageDead(_10); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL - StorageLive(_12); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _12 = _6; // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL - StorageLive(_16); // scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - _16 = _9 as *mut () (PtrToPtr); // scope 15 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - StorageLive(_17); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - StorageLive(_18); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - StorageLive(_19); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - _19 = _16 as *const () (Pointer(MutToConstPointer)); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - _18 = ptr::metadata::PtrComponents::<[u32]> { data_address: move _19, metadata: _12 }; // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - StorageDead(_19); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - _17 = ptr::metadata::PtrRepr::<[u32]> { const_ptr: move _18 }; // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - StorageDead(_18); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - _3 = (_17.1: *mut [u32]); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - StorageDead(_17); // scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - StorageDead(_16); // scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - StorageDead(_12); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL StorageDead(_9); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL StorageDead(_6); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL - StorageDead(_15); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageDead(_14); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageDead(_13); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageDead(_5); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageDead(_4); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - _0 = &mut (*_3); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageDead(_3); // scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageDead(_19); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageDead(_18); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageDead(_17); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageDead(_16); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageDead(_3); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + _0 = &mut (*_15); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageDead(_15); // scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL return; // scope 0 at $DIR/slice_index.rs:+2:2: +2:2 } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.mir index 0da7e5536ae07..0cf1d68d18a2e 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.mir @@ -4,41 +4,41 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { debug slice => _1; // in scope 0 at $DIR/slice_iter.rs:+0:28: +0:33 debug f => _2; // in scope 0 at $DIR/slice_iter.rs:+0:44: +0:45 let mut _0: (); // return place in scope 0 at $DIR/slice_iter.rs:+0:60: +0:60 - let mut _3: std::slice::Iter<'_, T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 - let mut _4: std::slice::Iter<'_, T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 - let _5: (); // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 - let mut _6: std::option::Option<&T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 - let mut _7: &mut std::slice::Iter<'_, T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 - let mut _8: isize; // in scope 0 at $DIR/slice_iter.rs:+1:5: +3:6 - let mut _10: &impl Fn(&T); // in scope 0 at $DIR/slice_iter.rs:+2:9: +2:10 - let mut _11: (&T,); // in scope 0 at $DIR/slice_iter.rs:+2:9: +2:13 + let mut _13: std::slice::Iter<'_, T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 + let mut _14: std::slice::Iter<'_, T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 + let mut _15: &mut std::slice::Iter<'_, T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 + let mut _16: std::option::Option<&T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 + let mut _17: isize; // in scope 0 at $DIR/slice_iter.rs:+1:5: +3:6 + let mut _19: &impl Fn(&T); // in scope 0 at $DIR/slice_iter.rs:+2:9: +2:10 + let mut _20: (&T,); // in scope 0 at $DIR/slice_iter.rs:+2:9: +2:13 + let _21: (); // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 scope 1 { - debug iter => _4; // in scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 - let _9: &T; // in scope 1 at $DIR/slice_iter.rs:+1:9: +1:10 + debug iter => _14; // in scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 + let _18: &T; // in scope 1 at $DIR/slice_iter.rs:+1:9: +1:10 scope 2 { - debug x => _9; // in scope 2 at $DIR/slice_iter.rs:+1:9: +1:10 + debug x => _18; // in scope 2 at $DIR/slice_iter.rs:+1:9: +1:10 } } scope 3 (inlined core::slice::::iter) { // at $DIR/slice_iter.rs:28:20: 28:26 debug self => _1; // in scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL scope 4 (inlined std::slice::Iter::<'_, T>::new) { // at $SRC_DIR/core/src/slice/mod.rs:LL:COL debug slice => _1; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - let _12: *const T; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - let mut _14: bool; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - let mut _15: usize; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - let mut _16: usize; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - let mut _17: std::ptr::NonNull; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - let mut _18: *mut T; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - let mut _19: *const T; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let _4: *const T; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _5: bool; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _6: usize; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _8: usize; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _9: *mut T; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _11: std::ptr::NonNull; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _12: *const T; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL scope 5 { - debug ptr => _12; // in scope 5 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + debug ptr => _4; // in scope 5 at $SRC_DIR/core/src/slice/iter.rs:LL:COL scope 6 { - let _13: *const T; // in scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let _7: *const T; // in scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL scope 7 { - debug end => _13; // in scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + debug end => _7; // in scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL scope 13 (inlined NonNull::::new_unchecked) { // at $SRC_DIR/core/src/slice/iter.rs:LL:COL - debug ptr => _18; // in scope 13 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL - let mut _21: *const T; // in scope 13 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL + debug ptr => _9; // in scope 13 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL + let mut _10: *const T; // in scope 13 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL let mut _22: *mut T; // in scope 13 at $SRC_DIR/core/src/intrinsics.rs:LL:COL scope 14 { scope 15 (inlined NonNull::::new_unchecked::runtime::) { // at $SRC_DIR/core/src/intrinsics.rs:LL:COL @@ -65,13 +65,13 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } } scope 9 (inlined invalid::) { // at $SRC_DIR/core/src/slice/iter.rs:LL:COL - debug addr => _15; // in scope 9 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + debug addr => _8; // in scope 9 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL scope 10 { } } scope 11 (inlined ptr::const_ptr::::add) { // at $SRC_DIR/core/src/slice/iter.rs:LL:COL - debug self => _12; // in scope 11 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL - debug count => _16; // in scope 11 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + debug self => _4; // in scope 11 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + debug count => _6; // in scope 11 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL scope 12 { } } @@ -79,125 +79,125 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } scope 8 (inlined core::slice::::as_ptr) { // at $SRC_DIR/core/src/slice/iter.rs:LL:COL debug self => _1; // in scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - let mut _20: *const [T]; // in scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + let mut _3: *const [T]; // in scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL } } } scope 22 (inlined as IntoIterator>::into_iter) { // at $DIR/slice_iter.rs:28:14: 28:26 - debug self => _3; // in scope 22 at $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + debug self => _13; // in scope 22 at $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL } bb0: { - StorageLive(_12); // scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageLive(_20); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - _20 = &raw const (*_1); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - _12 = move _20 as *const T (PtrToPtr); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageDead(_20); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageLive(_13); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageLive(_14); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _14 = const _; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - switchInt(move _14) -> [0: bb11, otherwise: bb10]; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_4); // scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageLive(_3); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + _3 = &raw const (*_1); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + _4 = move _3 as *const T (PtrToPtr); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageDead(_3); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageLive(_7); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_5); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _5 = const _; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + switchInt(move _5) -> [0: bb1, otherwise: bb2]; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL } bb1: { - StorageLive(_6); // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 - _7 = &mut _4; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 - _6 = as Iterator>::next(_7) -> [return: bb2, unwind: bb8]; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 - // mir::Constant - // + span: $DIR/slice_iter.rs:28:14: 28:26 - // + literal: Const { ty: for<'a> fn(&'a mut std::slice::Iter<'_, T>) -> Option< as Iterator>::Item> { as Iterator>::next}, val: Value() } + StorageLive(_6); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _6 = Len((*_1)); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _7 = Offset(_4, _6); // scope 12 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + StorageDead(_6); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + goto -> bb3; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL } bb2: { - _8 = discriminant(_6); // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 - switchInt(move _8) -> [0: bb5, 1: bb3, otherwise: bb4]; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 + StorageLive(_8); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _8 = Len((*_1)); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _7 = _8 as *const T (Transmute); // scope 10 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + StorageDead(_8); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + goto -> bb3; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL } bb3: { - _9 = ((_6 as Some).0: &T); // scope 1 at $DIR/slice_iter.rs:+1:9: +1:10 - StorageLive(_10); // scope 2 at $DIR/slice_iter.rs:+2:9: +2:10 - _10 = &_2; // scope 2 at $DIR/slice_iter.rs:+2:9: +2:10 - StorageLive(_11); // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13 - _11 = (_9,); // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13 - _5 = >::call(move _10, move _11) -> [return: bb6, unwind: bb8]; // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13 + StorageDead(_5); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_11); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_9); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _9 = _4 as *mut T (PtrToPtr); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_10); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_22); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_23); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _10 = _9 as *const T (Pointer(MutToConstPointer)); // scope 14 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL + _11 = NonNull:: { pointer: _10 }; // scope 14 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL + StorageDead(_23); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_22); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_10); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_9); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_12); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _12 = _7; // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _13 = std::slice::Iter::<'_, T> { ptr: move _11, end: move _12, _marker: const ZeroSized: PhantomData<&T> }; // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL // mir::Constant - // + span: $DIR/slice_iter.rs:29:9: 29:10 - // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a impl Fn(&T), (&T,)) -> >::Output {>::call}, val: Value() } + // + span: no-location + // + literal: Const { ty: PhantomData<&T>, val: Value() } + // adt + // + user_ty: UserType(1) + StorageDead(_12); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_11); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_7); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_4); // scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageLive(_14); // scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 + _14 = move _13; // scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 + goto -> bb4; // scope 1 at $DIR/slice_iter.rs:+1:5: +3:6 } bb4: { - unreachable; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 + StorageLive(_16); // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 + _15 = &mut _14; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 + _16 = as Iterator>::next(_15) -> [return: bb5, unwind: bb11]; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 + // mir::Constant + // + span: $DIR/slice_iter.rs:28:14: 28:26 + // + literal: Const { ty: for<'a> fn(&'a mut std::slice::Iter<'_, T>) -> Option< as Iterator>::Item> { as Iterator>::next}, val: Value() } } bb5: { - StorageDead(_6); // scope 1 at $DIR/slice_iter.rs:+3:5: +3:6 - StorageDead(_4); // scope 0 at $DIR/slice_iter.rs:+3:5: +3:6 - drop(_2) -> bb7; // scope 0 at $DIR/slice_iter.rs:+4:1: +4:2 + _17 = discriminant(_16); // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 + switchInt(move _17) -> [0: bb6, 1: bb8, otherwise: bb10]; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 } bb6: { - StorageDead(_11); // scope 2 at $DIR/slice_iter.rs:+2:12: +2:13 - StorageDead(_10); // scope 2 at $DIR/slice_iter.rs:+2:12: +2:13 - StorageDead(_6); // scope 1 at $DIR/slice_iter.rs:+3:5: +3:6 - goto -> bb1; // scope 1 at $DIR/slice_iter.rs:+1:5: +3:6 + StorageDead(_16); // scope 1 at $DIR/slice_iter.rs:+3:5: +3:6 + StorageDead(_14); // scope 0 at $DIR/slice_iter.rs:+3:5: +3:6 + drop(_2) -> bb7; // scope 0 at $DIR/slice_iter.rs:+4:1: +4:2 } bb7: { return; // scope 0 at $DIR/slice_iter.rs:+4:2: +4:2 } - bb8 (cleanup): { - drop(_2) -> [return: bb9, unwind terminate]; // scope 0 at $DIR/slice_iter.rs:+4:1: +4:2 + bb8: { + _18 = ((_16 as Some).0: &T); // scope 1 at $DIR/slice_iter.rs:+1:9: +1:10 + StorageLive(_19); // scope 2 at $DIR/slice_iter.rs:+2:9: +2:10 + _19 = &_2; // scope 2 at $DIR/slice_iter.rs:+2:9: +2:10 + StorageLive(_20); // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13 + _20 = (_18,); // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13 + _21 = >::call(move _19, move _20) -> [return: bb9, unwind: bb11]; // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13 + // mir::Constant + // + span: $DIR/slice_iter.rs:29:9: 29:10 + // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a impl Fn(&T), (&T,)) -> >::Output {>::call}, val: Value() } } - bb9 (cleanup): { - resume; // scope 0 at $DIR/slice_iter.rs:+0:1: +4:2 + bb9: { + StorageDead(_20); // scope 2 at $DIR/slice_iter.rs:+2:12: +2:13 + StorageDead(_19); // scope 2 at $DIR/slice_iter.rs:+2:12: +2:13 + StorageDead(_16); // scope 1 at $DIR/slice_iter.rs:+3:5: +3:6 + goto -> bb4; // scope 1 at $DIR/slice_iter.rs:+1:5: +3:6 } bb10: { - StorageLive(_15); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _15 = Len((*_1)); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _13 = _15 as *const T (Transmute); // scope 10 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - StorageDead(_15); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - goto -> bb12; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + unreachable; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 } - bb11: { - StorageLive(_16); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _16 = Len((*_1)); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _13 = Offset(_12, _16); // scope 12 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL - StorageDead(_16); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - goto -> bb12; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + bb11 (cleanup): { + drop(_2) -> [return: bb12, unwind terminate]; // scope 0 at $DIR/slice_iter.rs:+4:1: +4:2 } - bb12: { - StorageDead(_14); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageLive(_17); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageLive(_18); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _18 = _12 as *mut T (PtrToPtr); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageLive(_21); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageLive(_22); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageLive(_23); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _21 = _18 as *const T (Pointer(MutToConstPointer)); // scope 14 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL - _17 = NonNull:: { pointer: _21 }; // scope 14 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL - StorageDead(_23); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageDead(_22); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageDead(_21); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageDead(_18); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageLive(_19); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _19 = _13; // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _3 = std::slice::Iter::<'_, T> { ptr: move _17, end: move _19, _marker: const ZeroSized: PhantomData<&T> }; // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - // mir::Constant - // + span: no-location - // + literal: Const { ty: PhantomData<&T>, val: Value() } - // adt - // + user_ty: UserType(1) - StorageDead(_19); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageDead(_17); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageDead(_13); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageDead(_12); // scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageLive(_4); // scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 - _4 = move _3; // scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 - goto -> bb1; // scope 1 at $DIR/slice_iter.rs:+1:5: +3:6 + bb12 (cleanup): { + resume; // scope 0 at $DIR/slice_iter.rs:+0:1: +4:2 } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.mir index 45b41b54c8b66..4fde50c6fe43a 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.mir @@ -4,61 +4,61 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { debug slice => _1; // in scope 0 at $DIR/slice_iter.rs:+0:28: +0:33 debug f => _2; // in scope 0 at $DIR/slice_iter.rs:+0:44: +0:45 let mut _0: (); // return place in scope 0 at $DIR/slice_iter.rs:+0:60: +0:60 - let mut _3: std::iter::Rev>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:32 - let mut _4: std::slice::Iter<'_, T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 - let mut _5: std::iter::Rev>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:32 - let _6: (); // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:32 - let mut _7: std::option::Option<&T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:32 - let mut _8: &mut std::iter::Rev>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:32 - let mut _9: isize; // in scope 0 at $DIR/slice_iter.rs:+1:5: +3:6 - let mut _11: &impl Fn(&T); // in scope 0 at $DIR/slice_iter.rs:+2:9: +2:10 - let mut _12: (&T,); // in scope 0 at $DIR/slice_iter.rs:+2:9: +2:13 + let mut _13: std::slice::Iter<'_, T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 + let mut _14: std::iter::Rev>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:32 + let mut _15: std::iter::Rev>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:32 + let mut _16: &mut std::iter::Rev>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:32 + let mut _18: std::option::Option<&T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:32 + let mut _19: isize; // in scope 0 at $DIR/slice_iter.rs:+1:5: +3:6 + let mut _21: &impl Fn(&T); // in scope 0 at $DIR/slice_iter.rs:+2:9: +2:10 + let mut _22: (&T,); // in scope 0 at $DIR/slice_iter.rs:+2:9: +2:13 + let _23: (); // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:32 scope 1 { - debug iter => _5; // in scope 1 at $DIR/slice_iter.rs:+1:14: +1:32 - let _10: &T; // in scope 1 at $DIR/slice_iter.rs:+1:9: +1:10 + debug iter => _15; // in scope 1 at $DIR/slice_iter.rs:+1:14: +1:32 + let _20: &T; // in scope 1 at $DIR/slice_iter.rs:+1:9: +1:10 scope 2 { - debug x => _10; // in scope 2 at $DIR/slice_iter.rs:+1:9: +1:10 + debug x => _20; // in scope 2 at $DIR/slice_iter.rs:+1:9: +1:10 } scope 25 (inlined > as Iterator>::next) { // at $DIR/slice_iter.rs:35:14: 35:32 - debug self => _8; // in scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL - let mut _25: &mut std::slice::Iter<'_, T>; // in scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL + debug self => _16; // in scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL + let mut _17: &mut std::slice::Iter<'_, T>; // in scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL } } scope 3 (inlined core::slice::::iter) { // at $DIR/slice_iter.rs:35:20: 35:26 debug self => _1; // in scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL scope 4 (inlined std::slice::Iter::<'_, T>::new) { // at $SRC_DIR/core/src/slice/mod.rs:LL:COL debug slice => _1; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - let _13: *const T; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - let mut _15: bool; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - let mut _16: usize; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - let mut _17: usize; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - let mut _18: std::ptr::NonNull; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - let mut _19: *mut T; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - let mut _20: *const T; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let _4: *const T; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _5: bool; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _6: usize; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _8: usize; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _9: *mut T; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _11: std::ptr::NonNull; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _12: *const T; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL scope 5 { - debug ptr => _13; // in scope 5 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + debug ptr => _4; // in scope 5 at $SRC_DIR/core/src/slice/iter.rs:LL:COL scope 6 { - let _14: *const T; // in scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let _7: *const T; // in scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL scope 7 { - debug end => _14; // in scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + debug end => _7; // in scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL scope 13 (inlined NonNull::::new_unchecked) { // at $SRC_DIR/core/src/slice/iter.rs:LL:COL - debug ptr => _19; // in scope 13 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL - let mut _22: *const T; // in scope 13 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL - let mut _23: *mut T; // in scope 13 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + debug ptr => _9; // in scope 13 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL + let mut _10: *const T; // in scope 13 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL + let mut _24: *mut T; // in scope 13 at $SRC_DIR/core/src/intrinsics.rs:LL:COL scope 14 { scope 15 (inlined NonNull::::new_unchecked::runtime::) { // at $SRC_DIR/core/src/intrinsics.rs:LL:COL - debug ptr => _23; // in scope 15 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + debug ptr => _24; // in scope 15 at $SRC_DIR/core/src/intrinsics.rs:LL:COL scope 16 (inlined ptr::mut_ptr::::is_null) { // at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL - debug self => _23; // in scope 16 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - let mut _24: *mut u8; // in scope 16 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + debug self => _24; // in scope 16 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + let mut _25: *mut u8; // in scope 16 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL scope 17 { scope 18 (inlined ptr::mut_ptr::::is_null::runtime_impl) { // at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - debug ptr => _24; // in scope 18 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + debug ptr => _25; // in scope 18 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL scope 19 (inlined ptr::mut_ptr::::addr) { // at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - debug self => _24; // in scope 19 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + debug self => _25; // in scope 19 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL scope 20 { scope 21 (inlined ptr::mut_ptr::::cast::<()>) { // at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - debug self => _24; // in scope 21 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + debug self => _25; // in scope 21 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL } } } @@ -70,13 +70,13 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } } scope 9 (inlined invalid::) { // at $SRC_DIR/core/src/slice/iter.rs:LL:COL - debug addr => _16; // in scope 9 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + debug addr => _8; // in scope 9 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL scope 10 { } } scope 11 (inlined ptr::const_ptr::::add) { // at $SRC_DIR/core/src/slice/iter.rs:LL:COL - debug self => _13; // in scope 11 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL - debug count => _17; // in scope 11 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + debug self => _4; // in scope 11 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + debug count => _6; // in scope 11 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL scope 12 { } } @@ -84,137 +84,137 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } scope 8 (inlined core::slice::::as_ptr) { // at $SRC_DIR/core/src/slice/iter.rs:LL:COL debug self => _1; // in scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - let mut _21: *const [T]; // in scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + let mut _3: *const [T]; // in scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL } } } scope 22 (inlined as Iterator>::rev) { // at $DIR/slice_iter.rs:35:27: 35:32 - debug self => _4; // in scope 22 at $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL + debug self => _13; // in scope 22 at $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL scope 23 (inlined Rev::>::new) { // at $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL - debug iter => _4; // in scope 23 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL + debug iter => _13; // in scope 23 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL } } scope 24 (inlined > as IntoIterator>::into_iter) { // at $DIR/slice_iter.rs:35:14: 35:32 - debug self => _3; // in scope 24 at $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + debug self => _14; // in scope 24 at $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL } bb0: { - StorageLive(_4); // scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 - StorageLive(_13); // scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageLive(_21); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - _21 = &raw const (*_1); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - _13 = move _21 as *const T (PtrToPtr); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageDead(_21); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageLive(_14); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageLive(_15); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _15 = const _; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - switchInt(move _15) -> [0: bb10, otherwise: bb9]; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_13); // scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 + StorageLive(_4); // scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageLive(_3); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + _3 = &raw const (*_1); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + _4 = move _3 as *const T (PtrToPtr); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageDead(_3); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageLive(_7); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_5); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _5 = const _; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + switchInt(move _5) -> [0: bb1, otherwise: bb2]; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL } bb1: { - StorageLive(_7); // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32 - _8 = &mut _5; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32 - StorageLive(_25); // scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL - _25 = &mut ((*_8).0: std::slice::Iter<'_, T>); // scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL - _7 = as DoubleEndedIterator>::next_back(move _25) -> [return: bb12, unwind: bb7]; // scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL - // mir::Constant - // + span: $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL - // + literal: Const { ty: for<'a> fn(&'a mut std::slice::Iter<'_, T>) -> Option< as Iterator>::Item> { as DoubleEndedIterator>::next_back}, val: Value() } + StorageLive(_6); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _6 = Len((*_1)); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _7 = Offset(_4, _6); // scope 12 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + StorageDead(_6); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + goto -> bb3; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL } bb2: { - _10 = ((_7 as Some).0: &T); // scope 1 at $DIR/slice_iter.rs:+1:9: +1:10 - StorageLive(_11); // scope 2 at $DIR/slice_iter.rs:+2:9: +2:10 - _11 = &_2; // scope 2 at $DIR/slice_iter.rs:+2:9: +2:10 - StorageLive(_12); // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13 - _12 = (_10,); // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13 - _6 = >::call(move _11, move _12) -> [return: bb5, unwind: bb7]; // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13 - // mir::Constant - // + span: $DIR/slice_iter.rs:36:9: 36:10 - // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a impl Fn(&T), (&T,)) -> >::Output {>::call}, val: Value() } + StorageLive(_8); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _8 = Len((*_1)); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _7 = _8 as *const T (Transmute); // scope 10 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + StorageDead(_8); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + goto -> bb3; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL } bb3: { - unreachable; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32 + StorageDead(_5); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_11); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_9); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _9 = _4 as *mut T (PtrToPtr); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_10); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_24); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_25); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _10 = _9 as *const T (Pointer(MutToConstPointer)); // scope 14 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL + _11 = NonNull:: { pointer: _10 }; // scope 14 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL + StorageDead(_25); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_24); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_10); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_9); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_12); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _12 = _7; // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _13 = std::slice::Iter::<'_, T> { ptr: move _11, end: move _12, _marker: const ZeroSized: PhantomData<&T> }; // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + // mir::Constant + // + span: no-location + // + literal: Const { ty: PhantomData<&T>, val: Value() } + // adt + // + user_ty: UserType(1) + StorageDead(_12); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_11); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_7); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_4); // scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + _14 = Rev::> { iter: move _13 }; // scope 23 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL + StorageDead(_13); // scope 0 at $DIR/slice_iter.rs:+1:31: +1:32 + StorageLive(_15); // scope 0 at $DIR/slice_iter.rs:+1:14: +1:32 + _15 = move _14; // scope 0 at $DIR/slice_iter.rs:+1:14: +1:32 + goto -> bb4; // scope 1 at $DIR/slice_iter.rs:+1:5: +3:6 } bb4: { - StorageDead(_7); // scope 1 at $DIR/slice_iter.rs:+3:5: +3:6 - StorageDead(_5); // scope 0 at $DIR/slice_iter.rs:+3:5: +3:6 - drop(_2) -> bb6; // scope 0 at $DIR/slice_iter.rs:+4:1: +4:2 + StorageLive(_18); // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32 + _16 = &mut _15; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32 + StorageLive(_17); // scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL + _17 = &mut ((*_16).0: std::slice::Iter<'_, T>); // scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL + _18 = as DoubleEndedIterator>::next_back(move _17) -> [return: bb5, unwind: bb11]; // scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL + // mir::Constant + // + span: $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL + // + literal: Const { ty: for<'a> fn(&'a mut std::slice::Iter<'_, T>) -> Option< as Iterator>::Item> { as DoubleEndedIterator>::next_back}, val: Value() } } bb5: { - StorageDead(_12); // scope 2 at $DIR/slice_iter.rs:+2:12: +2:13 - StorageDead(_11); // scope 2 at $DIR/slice_iter.rs:+2:12: +2:13 - StorageDead(_7); // scope 1 at $DIR/slice_iter.rs:+3:5: +3:6 - goto -> bb1; // scope 1 at $DIR/slice_iter.rs:+1:5: +3:6 + StorageDead(_17); // scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL + _19 = discriminant(_18); // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32 + switchInt(move _19) -> [0: bb6, 1: bb8, otherwise: bb10]; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32 } bb6: { - return; // scope 0 at $DIR/slice_iter.rs:+4:2: +4:2 + StorageDead(_18); // scope 1 at $DIR/slice_iter.rs:+3:5: +3:6 + StorageDead(_15); // scope 0 at $DIR/slice_iter.rs:+3:5: +3:6 + drop(_2) -> bb7; // scope 0 at $DIR/slice_iter.rs:+4:1: +4:2 } - bb7 (cleanup): { - drop(_2) -> [return: bb8, unwind terminate]; // scope 0 at $DIR/slice_iter.rs:+4:1: +4:2 + bb7: { + return; // scope 0 at $DIR/slice_iter.rs:+4:2: +4:2 } - bb8 (cleanup): { - resume; // scope 0 at $DIR/slice_iter.rs:+0:1: +4:2 + bb8: { + _20 = ((_18 as Some).0: &T); // scope 1 at $DIR/slice_iter.rs:+1:9: +1:10 + StorageLive(_21); // scope 2 at $DIR/slice_iter.rs:+2:9: +2:10 + _21 = &_2; // scope 2 at $DIR/slice_iter.rs:+2:9: +2:10 + StorageLive(_22); // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13 + _22 = (_20,); // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13 + _23 = >::call(move _21, move _22) -> [return: bb9, unwind: bb11]; // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13 + // mir::Constant + // + span: $DIR/slice_iter.rs:36:9: 36:10 + // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a impl Fn(&T), (&T,)) -> >::Output {>::call}, val: Value() } } bb9: { - StorageLive(_16); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _16 = Len((*_1)); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _14 = _16 as *const T (Transmute); // scope 10 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - StorageDead(_16); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - goto -> bb11; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_22); // scope 2 at $DIR/slice_iter.rs:+2:12: +2:13 + StorageDead(_21); // scope 2 at $DIR/slice_iter.rs:+2:12: +2:13 + StorageDead(_18); // scope 1 at $DIR/slice_iter.rs:+3:5: +3:6 + goto -> bb4; // scope 1 at $DIR/slice_iter.rs:+1:5: +3:6 } bb10: { - StorageLive(_17); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _17 = Len((*_1)); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _14 = Offset(_13, _17); // scope 12 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL - StorageDead(_17); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - goto -> bb11; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + unreachable; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32 } - bb11: { - StorageDead(_15); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageLive(_18); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageLive(_19); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _19 = _13 as *mut T (PtrToPtr); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageLive(_22); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageLive(_23); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageLive(_24); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _22 = _19 as *const T (Pointer(MutToConstPointer)); // scope 14 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL - _18 = NonNull:: { pointer: _22 }; // scope 14 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL - StorageDead(_24); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageDead(_23); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageDead(_22); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageDead(_19); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageLive(_20); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _20 = _14; // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - _4 = std::slice::Iter::<'_, T> { ptr: move _18, end: move _20, _marker: const ZeroSized: PhantomData<&T> }; // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - // mir::Constant - // + span: no-location - // + literal: Const { ty: PhantomData<&T>, val: Value() } - // adt - // + user_ty: UserType(1) - StorageDead(_20); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageDead(_18); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageDead(_14); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL - StorageDead(_13); // scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - _3 = Rev::> { iter: move _4 }; // scope 23 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL - StorageDead(_4); // scope 0 at $DIR/slice_iter.rs:+1:31: +1:32 - StorageLive(_5); // scope 0 at $DIR/slice_iter.rs:+1:14: +1:32 - _5 = move _3; // scope 0 at $DIR/slice_iter.rs:+1:14: +1:32 - goto -> bb1; // scope 1 at $DIR/slice_iter.rs:+1:5: +3:6 + bb11 (cleanup): { + drop(_2) -> [return: bb12, unwind terminate]; // scope 0 at $DIR/slice_iter.rs:+4:1: +4:2 } - bb12: { - StorageDead(_25); // scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL - _9 = discriminant(_7); // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32 - switchInt(move _9) -> [0: bb4, 1: bb2, otherwise: bb3]; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32 + bb12 (cleanup): { + resume; // scope 0 at $DIR/slice_iter.rs:+0:1: +4:2 } } diff --git a/tests/mir-opt/pre-codegen/try_identity.new.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/try_identity.new.PreCodegen.after.mir index 53971b4cffcd6..c3f8745b4220f 100644 --- a/tests/mir-opt/pre-codegen/try_identity.new.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/try_identity.new.PreCodegen.after.mir @@ -3,15 +3,15 @@ fn new(_1: Result) -> Result { debug x => _1; // in scope 0 at $DIR/try_identity.rs:+0:14: +0:15 let mut _0: std::result::Result; // return place in scope 0 at $DIR/try_identity.rs:+0:34: +0:46 - let mut _2: std::ops::ControlFlow; // in scope 0 at $DIR/try_identity.rs:+2:15: +7:10 - let mut _3: isize; // in scope 0 at $DIR/try_identity.rs:+4:17: +4:22 - let _4: T; // in scope 0 at $DIR/try_identity.rs:+4:20: +4:21 + let mut _2: isize; // in scope 0 at $DIR/try_identity.rs:+4:17: +4:22 + let _3: T; // in scope 0 at $DIR/try_identity.rs:+4:20: +4:21 + let mut _4: std::ops::ControlFlow; // in scope 0 at $DIR/try_identity.rs:+2:15: +7:10 let _5: E; // in scope 0 at $DIR/try_identity.rs:+5:21: +5:22 let mut _6: isize; // in scope 0 at $DIR/try_identity.rs:+8:13: +8:37 let _7: T; // in scope 0 at $DIR/try_identity.rs:+8:35: +8:36 let _8: E; // in scope 0 at $DIR/try_identity.rs:+9:32: +9:33 scope 1 { - debug v => _4; // in scope 1 at $DIR/try_identity.rs:+4:20: +4:21 + debug v => _3; // in scope 1 at $DIR/try_identity.rs:+4:20: +4:21 } scope 2 { debug e => _5; // in scope 2 at $DIR/try_identity.rs:+5:21: +5:22 @@ -24,47 +24,47 @@ fn new(_1: Result) -> Result { } bb0: { - StorageLive(_2); // scope 0 at $DIR/try_identity.rs:+2:15: +7:10 - _3 = discriminant(_1); // scope 0 at $DIR/try_identity.rs:+3:19: +3:20 - switchInt(move _3) -> [0: bb3, 1: bb1, otherwise: bb2]; // scope 0 at $DIR/try_identity.rs:+3:13: +3:20 + StorageLive(_4); // scope 0 at $DIR/try_identity.rs:+2:15: +7:10 + _2 = discriminant(_1); // scope 0 at $DIR/try_identity.rs:+3:19: +3:20 + switchInt(move _2) -> [0: bb1, 1: bb2, otherwise: bb7]; // scope 0 at $DIR/try_identity.rs:+3:13: +3:20 } bb1: { - _5 = move ((_1 as Err).0: E); // scope 0 at $DIR/try_identity.rs:+5:21: +5:22 - _2 = ControlFlow::::Break(move _5); // scope 2 at $DIR/try_identity.rs:+5:27: +5:48 - goto -> bb4; // scope 0 at $DIR/try_identity.rs:+5:47: +5:48 + _3 = move ((_1 as Ok).0: T); // scope 0 at $DIR/try_identity.rs:+4:20: +4:21 + _4 = ControlFlow::::Continue(move _3); // scope 1 at $DIR/try_identity.rs:+4:26: +4:50 + goto -> bb3; // scope 0 at $DIR/try_identity.rs:+4:49: +4:50 } bb2: { - unreachable; // scope 0 at $DIR/try_identity.rs:+3:19: +3:20 + _5 = move ((_1 as Err).0: E); // scope 0 at $DIR/try_identity.rs:+5:21: +5:22 + _4 = ControlFlow::::Break(move _5); // scope 2 at $DIR/try_identity.rs:+5:27: +5:48 + goto -> bb3; // scope 0 at $DIR/try_identity.rs:+5:47: +5:48 } bb3: { - _4 = move ((_1 as Ok).0: T); // scope 0 at $DIR/try_identity.rs:+4:20: +4:21 - _2 = ControlFlow::::Continue(move _4); // scope 1 at $DIR/try_identity.rs:+4:26: +4:50 - goto -> bb4; // scope 0 at $DIR/try_identity.rs:+4:49: +4:50 + _6 = discriminant(_4); // scope 0 at $DIR/try_identity.rs:+2:15: +7:10 + switchInt(move _6) -> [0: bb4, 1: bb5, otherwise: bb7]; // scope 0 at $DIR/try_identity.rs:+2:9: +7:10 } bb4: { - _6 = discriminant(_2); // scope 0 at $DIR/try_identity.rs:+2:15: +7:10 - switchInt(move _6) -> [0: bb6, 1: bb5, otherwise: bb2]; // scope 0 at $DIR/try_identity.rs:+2:9: +7:10 + _7 = move ((_4 as Continue).0: T); // scope 0 at $DIR/try_identity.rs:+8:35: +8:36 + _0 = Result::::Ok(move _7); // scope 0 at $DIR/try_identity.rs:+1:5: +11:6 + StorageDead(_4); // scope 0 at $DIR/try_identity.rs:+12:1: +12:2 + goto -> bb6; // scope 0 at $DIR/try_identity.rs:+12:1: +12:2 } bb5: { - _8 = move ((_2 as Break).0: E); // scope 0 at $DIR/try_identity.rs:+9:32: +9:33 + _8 = move ((_4 as Break).0: E); // scope 0 at $DIR/try_identity.rs:+9:32: +9:33 _0 = Result::::Err(move _8); // scope 4 at $DIR/try_identity.rs:+9:45: +9:51 - StorageDead(_2); // scope 0 at $DIR/try_identity.rs:+12:1: +12:2 - goto -> bb7; // scope 0 at $DIR/try_identity.rs:+12:1: +12:2 + StorageDead(_4); // scope 0 at $DIR/try_identity.rs:+12:1: +12:2 + goto -> bb6; // scope 0 at $DIR/try_identity.rs:+12:1: +12:2 } bb6: { - _7 = move ((_2 as Continue).0: T); // scope 0 at $DIR/try_identity.rs:+8:35: +8:36 - _0 = Result::::Ok(move _7); // scope 0 at $DIR/try_identity.rs:+1:5: +11:6 - StorageDead(_2); // scope 0 at $DIR/try_identity.rs:+12:1: +12:2 - goto -> bb7; // scope 0 at $DIR/try_identity.rs:+12:1: +12:2 + return; // scope 0 at $DIR/try_identity.rs:+12:2: +12:2 } bb7: { - return; // scope 0 at $DIR/try_identity.rs:+12:2: +12:2 + unreachable; // scope 0 at $DIR/try_identity.rs:+3:19: +3:20 } } diff --git a/tests/mir-opt/pre-codegen/try_identity.old.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/try_identity.old.PreCodegen.after.mir index e217d19947fdc..0487c6c3994a2 100644 --- a/tests/mir-opt/pre-codegen/try_identity.old.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/try_identity.old.PreCodegen.after.mir @@ -15,26 +15,26 @@ fn old(_1: Result) -> Result { bb0: { _2 = discriminant(_1); // scope 0 at $DIR/try_identity.rs:+2:15: +2:16 - switchInt(move _2) -> [0: bb3, 1: bb1, otherwise: bb2]; // scope 0 at $DIR/try_identity.rs:+2:9: +2:16 + switchInt(move _2) -> [0: bb1, 1: bb2, otherwise: bb4]; // scope 0 at $DIR/try_identity.rs:+2:9: +2:16 } bb1: { - _4 = move ((_1 as Err).0: E); // scope 0 at $DIR/try_identity.rs:+4:17: +4:18 - _0 = Result::::Err(move _4); // scope 2 at $DIR/try_identity.rs:+4:30: +4:36 - goto -> bb4; // scope 0 at $DIR/try_identity.rs:+7:1: +7:2 + _3 = move ((_1 as Ok).0: T); // scope 0 at $DIR/try_identity.rs:+3:16: +3:17 + _0 = Result::::Ok(move _3); // scope 0 at $DIR/try_identity.rs:+1:5: +6:6 + goto -> bb3; // scope 0 at $DIR/try_identity.rs:+7:1: +7:2 } bb2: { - unreachable; // scope 0 at $DIR/try_identity.rs:+2:15: +2:16 + _4 = move ((_1 as Err).0: E); // scope 0 at $DIR/try_identity.rs:+4:17: +4:18 + _0 = Result::::Err(move _4); // scope 2 at $DIR/try_identity.rs:+4:30: +4:36 + goto -> bb3; // scope 0 at $DIR/try_identity.rs:+7:1: +7:2 } bb3: { - _3 = move ((_1 as Ok).0: T); // scope 0 at $DIR/try_identity.rs:+3:16: +3:17 - _0 = Result::::Ok(move _3); // scope 0 at $DIR/try_identity.rs:+1:5: +6:6 - goto -> bb4; // scope 0 at $DIR/try_identity.rs:+7:1: +7:2 + return; // scope 0 at $DIR/try_identity.rs:+7:2: +7:2 } bb4: { - return; // scope 0 at $DIR/try_identity.rs:+7:2: +7:2 + unreachable; // scope 0 at $DIR/try_identity.rs:+2:15: +2:16 } } diff --git a/tests/mir-opt/tls_access.main.PreCodegen.after.mir b/tests/mir-opt/tls_access.main.PreCodegen.after.mir index 09453b8ba9c3a..03618ae28149c 100644 --- a/tests/mir-opt/tls_access.main.PreCodegen.after.mir +++ b/tests/mir-opt/tls_access.main.PreCodegen.after.mir @@ -2,27 +2,27 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/tls_access.rs:+0:11: +0:11 - let _2: *mut u8; // in scope 0 at $DIR/tls_access.rs:+2:18: +2:21 + let _1: *mut u8; // in scope 0 at $DIR/tls_access.rs:+2:18: +2:21 let mut _3: *mut u8; // in scope 0 at $DIR/tls_access.rs:+3:9: +3:12 scope 1 { - let _1: &u8; // in scope 1 at $DIR/tls_access.rs:+2:13: +2:14 + let _2: &u8; // in scope 1 at $DIR/tls_access.rs:+2:13: +2:14 scope 2 { - debug a => _1; // in scope 2 at $DIR/tls_access.rs:+2:13: +2:14 + debug a => _2; // in scope 2 at $DIR/tls_access.rs:+2:13: +2:14 } } bb0: { - StorageLive(_1); // scope 1 at $DIR/tls_access.rs:+2:13: +2:14 - StorageLive(_2); // scope 1 at $DIR/tls_access.rs:+2:18: +2:21 - _2 = &/*tls*/ mut FOO; // scope 1 at $DIR/tls_access.rs:+2:18: +2:21 - _1 = &(*_2); // scope 1 at $DIR/tls_access.rs:+2:17: +2:21 + StorageLive(_2); // scope 1 at $DIR/tls_access.rs:+2:13: +2:14 + StorageLive(_1); // scope 1 at $DIR/tls_access.rs:+2:18: +2:21 + _1 = &/*tls*/ mut FOO; // scope 1 at $DIR/tls_access.rs:+2:18: +2:21 + _2 = &(*_1); // scope 1 at $DIR/tls_access.rs:+2:17: +2:21 StorageLive(_3); // scope 2 at $DIR/tls_access.rs:+3:9: +3:12 _3 = &/*tls*/ mut FOO; // scope 2 at $DIR/tls_access.rs:+3:9: +3:12 (*_3) = const 42_u8; // scope 2 at $DIR/tls_access.rs:+3:9: +3:17 StorageDead(_3); // scope 2 at $DIR/tls_access.rs:+3:17: +3:18 _0 = const (); // scope 1 at $DIR/tls_access.rs:+1:5: +4:6 - StorageDead(_2); // scope 1 at $DIR/tls_access.rs:+4:5: +4:6 StorageDead(_1); // scope 1 at $DIR/tls_access.rs:+4:5: +4:6 + StorageDead(_2); // scope 1 at $DIR/tls_access.rs:+4:5: +4:6 return; // scope 0 at $DIR/tls_access.rs:+5:2: +5:2 } } diff --git a/tests/mir-opt/while_storage.while_loop.PreCodegen.after.mir b/tests/mir-opt/while_storage.while_loop.PreCodegen.after.mir index 811789a60c3eb..8922eda07acfc 100644 --- a/tests/mir-opt/while_storage.while_loop.PreCodegen.after.mir +++ b/tests/mir-opt/while_storage.while_loop.PreCodegen.after.mir @@ -31,18 +31,18 @@ fn while_loop(_1: bool) -> () { } bb4: { - switchInt(move _3) -> [0: bb6, otherwise: bb5]; // scope 0 at $DIR/while_storage.rs:+2:12: +2:23 + switchInt(move _3) -> [0: bb5, otherwise: bb6]; // scope 0 at $DIR/while_storage.rs:+2:12: +2:23 } bb5: { StorageDead(_3); // scope 0 at $DIR/while_storage.rs:+4:9: +4:10 - goto -> bb7; // scope 0 at no-location + StorageDead(_2); // scope 0 at $DIR/while_storage.rs:+5:5: +5:6 + goto -> bb1; // scope 0 at $DIR/while_storage.rs:+1:5: +5:6 } bb6: { StorageDead(_3); // scope 0 at $DIR/while_storage.rs:+4:9: +4:10 - StorageDead(_2); // scope 0 at $DIR/while_storage.rs:+5:5: +5:6 - goto -> bb1; // scope 0 at $DIR/while_storage.rs:+1:5: +5:6 + goto -> bb7; // scope 0 at no-location } bb7: { From 8e399275add92283b50eca873213250e2009cdf7 Mon Sep 17 00:00:00 2001 From: sladynnunes Date: Wed, 24 May 2023 17:11:26 -0700 Subject: [PATCH 14/69] Migrate item_static to Askama --- src/librustdoc/html/render/print_item.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 4cc81e860f09a..57b88479641b8 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1541,7 +1541,7 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean write!(w, "{}", document_type_layout(cx, def_id)); } -fn item_static(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) { +fn item_static(w: &mut impl Write, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) { wrap_item(w, |w| { render_attributes_in_code(w, it, cx.tcx()); write!( From 462a96c9e902e8ec7b2fddfbe9429f27eb0030d0 Mon Sep 17 00:00:00 2001 From: Caio Date: Wed, 24 May 2023 21:15:50 -0300 Subject: [PATCH 15/69] [RFC-2011] Expand more expressions --- .../src/assert/context.rs | 16 ++-- library/core/src/macros/mod.rs | 2 +- .../all-expr-kinds.rs | 85 +++---------------- .../all-not-available-cases.rs | 2 +- ...errors-does-not-create-unnecessary-code.rs | 2 +- ...ptures-does-not-create-unnecessary-code.rs | 2 +- .../feature-gate-generic_assert.rs | 2 +- ...onsuming-methods-have-optimized-codegen.rs | 2 +- ...ming-methods-have-optimized-codegen.stdout | 2 +- 9 files changed, 29 insertions(+), 86 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index ea830a0ce60df..b619e80e15f3c 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -233,10 +233,19 @@ impl<'cx, 'a> Context<'cx, 'a> { ExprKind::Cast(local_expr, _) => { self.manage_cond_expr(local_expr); } + ExprKind::If(local_expr, _, _) => { + self.manage_cond_expr(local_expr); + } ExprKind::Index(prefix, suffix) => { self.manage_cond_expr(prefix); self.manage_cond_expr(suffix); } + ExprKind::Let(_, local_expr, _) => { + self.manage_cond_expr(local_expr); + } + ExprKind::Match(local_expr, _) => { + self.manage_cond_expr(local_expr); + } ExprKind::MethodCall(call) => { for arg in &mut call.args { self.manage_cond_expr(arg); @@ -295,17 +304,14 @@ impl<'cx, 'a> Context<'cx, 'a> { | ExprKind::Continue(_) | ExprKind::Err | ExprKind::Field(_, _) - | ExprKind::FormatArgs(_) | ExprKind::ForLoop(_, _, _, _) - | ExprKind::If(_, _, _) + | ExprKind::FormatArgs(_) | ExprKind::IncludedBytes(..) | ExprKind::InlineAsm(_) - | ExprKind::OffsetOf(_, _) - | ExprKind::Let(_, _, _) | ExprKind::Lit(_) | ExprKind::Loop(_, _, _) | ExprKind::MacCall(_) - | ExprKind::Match(_, _) + | ExprKind::OffsetOf(_, _) | ExprKind::Path(_, _) | ExprKind::Ret(_) | ExprKind::Try(_) diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index b24882ddb179f..c4134dbcd2507 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1427,7 +1427,7 @@ pub(crate) mod builtin { #[rustc_builtin_macro] #[macro_export] #[rustc_diagnostic_item = "assert_macro"] - #[allow_internal_unstable(core_panic, edition_panic)] + #[allow_internal_unstable(core_panic, edition_panic, generic_assert_internals)] macro_rules! assert { ($cond:expr $(,)?) => {{ /* compiler built-in */ }}; ($cond:expr, $($arg:tt)+) => {{ /* compiler built-in */ }}; diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs index e88e24482ccc8..b1db05afd080b 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs @@ -5,7 +5,7 @@ // needs-unwind Asserting on contents of error message #![allow(path_statements, unused_allocation)] -#![feature(core_intrinsics, generic_assert, generic_assert_internals)] +#![feature(core_intrinsics, generic_assert)] macro_rules! test { ( @@ -51,6 +51,7 @@ macro_rules! tests { const FOO: Foo = Foo { bar: 1 }; + #[derive(Clone, Copy, Debug, PartialEq)] struct Foo { bar: i32 @@ -83,9 +84,18 @@ fn main() { // cast [ elem as i32 == 3 ] => "Assertion failed: elem as i32 == 3\nWith captures:\n elem = 1\n" + // if + [ if elem == 3 { true } else { false } ] => "Assertion failed: if elem == 3 { true } else { false }\nWith captures:\n elem = 1\n" + // index [ [1i32, 1][elem as usize] == 3 ] => "Assertion failed: [1i32, 1][elem as usize] == 3\nWith captures:\n elem = 1\n" + // let + [ if let 3 = elem { true } else { false } ] => "Assertion failed: if let 3 = elem { true } else { false }\nWith captures:\n elem = 1\n" + + // match + [ match elem { 3 => true, _ => false, } ] => "Assertion failed: match elem { 3 => true, _ => false, }\nWith captures:\n elem = 1\n" + // method call [ FOO.add(elem, elem) == 3 ] => "Assertion failed: FOO.add(elem, elem) == 3\nWith captures:\n elem = 1\n" @@ -107,77 +117,4 @@ fn main() { // unary [ -elem == -3 ] => "Assertion failed: -elem == -3\nWith captures:\n elem = 1\n" ); - - // ***** Disallowed ***** - - tests!( - let mut elem = 1i32; - - // assign - [ { let local = elem; local } == 3 ] => "Assertion failed: { let local = elem; local } == 3" - - // assign op - [ { elem += 1; elem } == 3 ] => "Assertion failed: { elem += 1; elem } == 3" - - // async - [ { let _ = async { elem }; elem } == 3 ] => "Assertion failed: { let _ = async { elem }; elem } == 3" - - // await - - // block - [ { elem } == 3 ] => "Assertion failed: { elem } == 3" - - // break - [ loop { break elem; } == 3 ] => "Assertion failed: loop { break elem; } == 3" - - // closure - [(|| elem)() == 3 ] => "Assertion failed: (|| elem)() == 3" - - // const block - - // continue - - // err - - // field - [ FOO.bar == 3 ] => "Assertion failed: FOO.bar == 3" - - // for loop - [ { for _ in 0..elem { elem; } elem } == 3 ] => "Assertion failed: { for _ in 0..elem { elem; } elem } == 3" - - // if - [ if true { elem } else { elem } == 3 ] => "Assertion failed: if true { elem } else { elem } == 3" - - // inline asm - - // let - [ if let true = true { elem } else { elem } == 3 ] => "Assertion failed: if let true = true { elem } else { elem } == 3" - - // lit - - // loop - [ loop { elem; break elem; } == 3 ] => "Assertion failed: loop { elem; break elem; } == 3" - - // mac call - - // match - [ match elem { _ => elem } == 3 ] => "Assertion failed: (match elem { _ => elem, }) == 3" - - // ret - [ (|| { return elem; })() == 3 ] => "Assertion failed: (|| { return elem; })() == 3" - - // try - [ (|| { Some(Some(elem)?) })() == Some(3) ] => "Assertion failed: (|| { Some(Some(elem)?) })() == Some(3)" - - // try block - - // underscore - - // while - [ { while false { elem; break; } elem } == 3 ] => "Assertion failed: { while false { elem; break; } elem } == 3" - - // yeet - - // yield - ); } diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/all-not-available-cases.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/all-not-available-cases.rs index d46f396ee2970..fcf4f367d0428 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/all-not-available-cases.rs +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/all-not-available-cases.rs @@ -4,7 +4,7 @@ // run-pass // needs-unwind Asserting on contents of error message -#![feature(core_intrinsics, generic_assert, generic_assert_internals)] +#![feature(core_intrinsics, generic_assert)] extern crate common; diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs index 6a1435f792bf4..c8408d16fbb0d 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs @@ -1,7 +1,7 @@ // compile-flags: --test // run-pass -#![feature(core_intrinsics, generic_assert, generic_assert_internals)] +#![feature(core_intrinsics, generic_assert)] #[should_panic(expected = "Custom user message")] #[test] diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs index 1f5a29ab524f2..0e3c14a5770ea 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs @@ -3,7 +3,7 @@ // run-pass // needs-unwind Asserting on contents of error message -#![feature(core_intrinsics, generic_assert, generic_assert_internals)] +#![feature(core_intrinsics, generic_assert)] extern crate common; diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs index 01860adaac250..0d2518dc25317 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs @@ -2,7 +2,7 @@ // ignore-tidy-linelength // run-pass -#![feature(core_intrinsics, generic_assert, generic_assert_internals)] +#![feature(core_intrinsics, generic_assert)] use std::fmt::{Debug, Formatter}; diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs index 5ec84b08ff808..57b79a56b7bfb 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs @@ -1,7 +1,7 @@ // check-pass // compile-flags: -Z unpretty=expanded -#![feature(core_intrinsics, generic_assert, generic_assert_internals)] +#![feature(core_intrinsics, generic_assert)] fn arbitrary_consuming_method_for_demonstration_purposes() { let elem = 1i32; diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout index b69b5bc3b53f2..66321bc35f01c 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout @@ -3,7 +3,7 @@ // check-pass // compile-flags: -Z unpretty=expanded -#![feature(core_intrinsics, generic_assert, generic_assert_internals)] +#![feature(core_intrinsics, generic_assert)] #[prelude_import] use ::std::prelude::rust_2015::*; #[macro_use] From ba5a3968b8ecd578247f94c6a62bfa8652cc2ef8 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Wed, 24 May 2023 23:44:57 -0700 Subject: [PATCH 16/69] Stabilize `BuildHasher::hash_one` --- library/alloc/src/vec/mod.rs | 1 - library/core/src/array/mod.rs | 1 - library/core/src/hash/mod.rs | 4 +--- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 82f30a26d41c5..47661a3d38429 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2662,7 +2662,6 @@ impl Clone for Vec { /// as required by the `core::borrow::Borrow` implementation. /// /// ``` -/// #![feature(build_hasher_simple_hash_one)] /// use std::hash::BuildHasher; /// /// let b = std::collections::hash_map::RandomState::new(); diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index bdb4c975909e0..70f4bf2a7ed8e 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -291,7 +291,6 @@ impl<'a, T, const N: usize> TryFrom<&'a mut [T]> for &'a mut [T; N] { /// as required by the `Borrow` implementation. /// /// ``` -/// #![feature(build_hasher_simple_hash_one)] /// use std::hash::BuildHasher; /// /// let b = std::collections::hash_map::RandomState::new(); diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs index a73b5b610a4ad..ca7c0772de86e 100644 --- a/library/core/src/hash/mod.rs +++ b/library/core/src/hash/mod.rs @@ -674,8 +674,6 @@ pub trait BuildHasher { /// # Example /// /// ``` - /// #![feature(build_hasher_simple_hash_one)] - /// /// use std::cmp::{max, min}; /// use std::hash::{BuildHasher, Hash, Hasher}; /// struct OrderAmbivalentPair(T, T); @@ -697,7 +695,7 @@ pub trait BuildHasher { /// bh.hash_one(&OrderAmbivalentPair(2, 10)) /// ); /// ``` - #[unstable(feature = "build_hasher_simple_hash_one", issue = "86161")] + #[stable(feature = "build_hasher_simple_hash_one", since = "CURRENT_RUSTC_VERSION")] fn hash_one(&self, x: T) -> u64 where Self: Sized, From 3c9b07643a11fe4049826a45382b08a6eaf722fd Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Thu, 25 May 2023 09:39:19 +0200 Subject: [PATCH 17/69] include test suite metadata in build metrics --- src/bootstrap/metrics.rs | 77 ++++++++++++++++++++++++++++------------ src/bootstrap/test.rs | 49 +++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 22 deletions(-) diff --git a/src/bootstrap/metrics.rs b/src/bootstrap/metrics.rs index e19d56ccd6adc..b119cf2bc953a 100644 --- a/src/bootstrap/metrics.rs +++ b/src/bootstrap/metrics.rs @@ -57,7 +57,7 @@ impl BuildMetrics { duration_excluding_children_sec: Duration::ZERO, children: Vec::new(), - tests: Vec::new(), + test_suites: Vec::new(), }); } @@ -84,6 +84,17 @@ impl BuildMetrics { } } + pub(crate) fn begin_test_suite(&self, metadata: TestSuiteMetadata, builder: &Builder<'_>) { + // Do not record dry runs, as they'd be duplicates of the actual steps. + if builder.config.dry_run() { + return; + } + + let mut state = self.state.borrow_mut(); + let step = state.running_steps.last_mut().unwrap(); + step.test_suites.push(TestSuite { metadata, tests: Vec::new() }); + } + pub(crate) fn record_test(&self, name: &str, outcome: TestOutcome, builder: &Builder<'_>) { // Do not record dry runs, as they'd be duplicates of the actual steps. if builder.config.dry_run() { @@ -91,12 +102,15 @@ impl BuildMetrics { } let mut state = self.state.borrow_mut(); - state - .running_steps - .last_mut() - .unwrap() - .tests - .push(Test { name: name.to_string(), outcome }); + let step = state.running_steps.last_mut().unwrap(); + + if let Some(test_suite) = step.test_suites.last_mut() { + test_suite.tests.push(Test { name: name.to_string(), outcome }); + } else { + panic!( + "metrics.record_test() called without calling metrics.record_test_suite() first" + ); + } } fn collect_stats(&self, state: &mut MetricsState) { @@ -159,11 +173,7 @@ impl BuildMetrics { fn prepare_json_step(&self, step: StepMetrics) -> JsonNode { let mut children = Vec::new(); children.extend(step.children.into_iter().map(|child| self.prepare_json_step(child))); - children.extend( - step.tests - .into_iter() - .map(|test| JsonNode::Test { name: test.name, outcome: test.outcome }), - ); + children.extend(step.test_suites.into_iter().map(|suite| JsonNode::TestSuite(suite))); JsonNode::RustbuildStep { type_: step.type_, @@ -198,12 +208,7 @@ struct StepMetrics { duration_excluding_children_sec: Duration, children: Vec, - tests: Vec, -} - -struct Test { - name: String, - outcome: TestOutcome, + test_suites: Vec, } #[derive(Serialize, Deserialize)] @@ -237,13 +242,41 @@ enum JsonNode { children: Vec, }, - Test { - name: String, - #[serde(flatten)] - outcome: TestOutcome, + TestSuite(TestSuite), +} + +#[derive(Serialize, Deserialize)] +struct TestSuite { + metadata: TestSuiteMetadata, + tests: Vec, +} + +#[derive(Serialize, Deserialize)] +#[serde(tag = "kind", rename_all = "snake_case")] +pub(crate) enum TestSuiteMetadata { + Crate { + crates: Vec, + target: String, + host: String, + stage: u32, + }, + Compiletest { + suite: String, + mode: String, + compare_mode: Option, + target: String, + host: String, + stage: u32, }, } +#[derive(Serialize, Deserialize)] +pub(crate) struct Test { + name: String, + #[serde(flatten)] + outcome: TestOutcome, +} + #[derive(Serialize, Deserialize)] #[serde(tag = "outcome", rename_all = "snake_case")] pub(crate) enum TestOutcome { diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 2b72d6c48eb75..f64b5f965237e 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -317,6 +317,17 @@ impl Step for Cargo { cargo.env("CARGO_TEST_DISABLE_NIGHTLY", "1"); cargo.env("PATH", &path_for_cargo(builder, compiler)); + #[cfg(feature = "build-metrics")] + builder.metrics.begin_test_suite( + crate::metrics::TestSuiteMetadata::Crate { + crates: vec!["cargo".into()], + target: self.host.triple.to_string(), + host: self.host.triple.to_string(), + stage: self.stage, + }, + builder, + ); + let _time = util::timeit(&builder); add_flags_and_try_run_tests(builder, &mut cargo); } @@ -1759,6 +1770,19 @@ note: if you're sure you want to do this, please open an issue as to why. In the builder.ci_env.force_coloring_in_ci(&mut cmd); + #[cfg(feature = "build-metrics")] + builder.metrics.begin_test_suite( + crate::metrics::TestSuiteMetadata::Compiletest { + suite: suite.into(), + mode: mode.into(), + compare_mode: None, + target: self.target.triple.to_string(), + host: self.compiler.host.triple.to_string(), + stage: self.compiler.stage, + }, + builder, + ); + builder.info(&format!( "Check compiletest suite={} mode={} ({} -> {})", suite, mode, &compiler.host, target @@ -1768,6 +1792,20 @@ note: if you're sure you want to do this, please open an issue as to why. In the if let Some(compare_mode) = compare_mode { cmd.arg("--compare-mode").arg(compare_mode); + + #[cfg(feature = "build-metrics")] + builder.metrics.begin_test_suite( + crate::metrics::TestSuiteMetadata::Compiletest { + suite: suite.into(), + mode: mode.into(), + compare_mode: Some(compare_mode.into()), + target: self.target.triple.to_string(), + host: self.compiler.host.triple.to_string(), + stage: self.compiler.stage, + }, + builder, + ); + builder.info(&format!( "Check compiletest suite={} mode={} compare_mode={} ({} -> {})", suite, mode, compare_mode, &compiler.host, target @@ -2094,6 +2132,17 @@ fn run_cargo_test( let mut cargo = prepare_cargo_test(cargo, libtest_args, crates, primary_crate, compiler, target, builder); let _time = util::timeit(&builder); + + #[cfg(feature = "build-metrics")] + builder.metrics.begin_test_suite( + crate::metrics::TestSuiteMetadata::Crate { + crates: crates.iter().map(|c| c.to_string()).collect(), + target: target.triple.to_string(), + host: compiler.host.triple.to_string(), + stage: compiler.stage, + }, + builder, + ); add_flags_and_try_run_tests(builder, &mut cargo) } From 0553f71b1b27bd75102284711c84aede3001943b Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Thu, 25 May 2023 09:49:01 +0200 Subject: [PATCH 18/69] introduce build metrics version numbers to handle breaking changes --- src/bootstrap/metrics.rs | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/metrics.rs b/src/bootstrap/metrics.rs index b119cf2bc953a..9f68eea9a5ebe 100644 --- a/src/bootstrap/metrics.rs +++ b/src/bootstrap/metrics.rs @@ -14,6 +14,13 @@ use std::io::BufWriter; use std::time::{Duration, Instant, SystemTime}; use sysinfo::{CpuExt, System, SystemExt}; +// Update this number whenever a breaking change is made to the build metrics. +// +// Versions: +// 0: initial version +// 1: replaced JsonNode::Test with JsonNode::TestSuite +const CURRENT_METADATA_VERSION: usize = 1; + pub(crate) struct BuildMetrics { state: RefCell, } @@ -145,7 +152,20 @@ impl BuildMetrics { // Some of our CI builds consist of multiple independent CI invocations. Ensure all the // previous invocations are still present in the resulting file. let mut invocations = match std::fs::read(&dest) { - Ok(contents) => t!(serde_json::from_slice::(&contents)).invocations, + Ok(contents) => { + // We first parse just the metadata_version field to have the check succeed even if + // the rest of the contents are not valid anymore. + let version: OnlyMetadataVersion = t!(serde_json::from_slice(&contents)); + if version.metadata_version == CURRENT_METADATA_VERSION { + t!(serde_json::from_slice::(&contents)).invocations + } else { + println!( + "warning: overriding existing build/metrics.json, as it's not \ + compatible with build metrics format version {CURRENT_METADATA_VERSION}." + ); + Vec::new() + } + } Err(err) => { if err.kind() != std::io::ErrorKind::NotFound { panic!("failed to open existing metrics file at {}: {err}", dest.display()); @@ -163,7 +183,8 @@ impl BuildMetrics { children: steps.into_iter().map(|step| self.prepare_json_step(step)).collect(), }); - let json = JsonRoot { system_stats, invocations }; + let json = + JsonRoot { metadata_version: CURRENT_METADATA_VERSION, system_stats, invocations }; t!(std::fs::create_dir_all(dest.parent().unwrap())); let mut file = BufWriter::new(t!(File::create(&dest))); @@ -214,6 +235,8 @@ struct StepMetrics { #[derive(Serialize, Deserialize)] #[serde(rename_all = "snake_case")] struct JsonRoot { + #[serde(default)] // For version 0 the field was not present. + metadata_version: usize, system_stats: JsonInvocationSystemStats, invocations: Vec, } @@ -299,3 +322,9 @@ struct JsonInvocationSystemStats { struct JsonStepSystemStats { cpu_utilization_percent: f64, } + +#[derive(Deserialize)] +struct OnlyMetadataVersion { + #[serde(default)] // For version 0 the field was not present. + metadata_version: usize, +} From fbdc5118d55c05a7dfa1017c3f3ec2c1c9370d6e Mon Sep 17 00:00:00 2001 From: Nicky Lim Date: Thu, 25 May 2023 20:31:56 +0800 Subject: [PATCH 19/69] Add `ItemTemplate` trait --- src/librustdoc/html/render/print_item.rs | 95 +++++++++++-------- src/librustdoc/html/templates/item_union.html | 8 +- 2 files changed, 61 insertions(+), 42 deletions(-) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 4cc81e860f09a..b944dc7b26040 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -9,6 +9,8 @@ use rustc_middle::middle::stability; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Symbol}; +use std::borrow::Borrow; +use std::cell::{RefCell, RefMut}; use std::cmp::Ordering; use std::fmt; use std::rc::Rc; @@ -216,6 +218,53 @@ fn toggle_close(mut w: impl fmt::Write) { w.write_str("").unwrap(); } +trait ItemTemplate<'a, 'cx: 'a>: askama::Template + fmt::Display { + fn item_and_mut_cx(&self) -> (&'a clean::Item, RefMut<'_, &'a mut Context<'cx>>); +} + +fn item_template_document<'a: 'b, 'b, 'cx: 'a>( + templ: &'b impl ItemTemplate<'a, 'cx>, +) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { + display_fn(move |f| { + let (item, mut cx) = templ.item_and_mut_cx(); + let v = document(*cx, item, None, HeadingOffset::H2); + write!(f, "{v}") + }) +} + +fn item_template_document_type_layout<'a: 'b, 'b, 'cx: 'a>( + templ: &'b impl ItemTemplate<'a, 'cx>, +) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { + display_fn(move |f| { + let (item, cx) = templ.item_and_mut_cx(); + let def_id = item.item_id.expect_def_id(); + let v = document_type_layout(*cx, def_id); + write!(f, "{v}") + }) +} + +fn item_template_render_attributes_in_pre<'a: 'b, 'b, 'cx: 'a>( + templ: &'b impl ItemTemplate<'a, 'cx>, +) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { + display_fn(move |f| { + let (item, cx) = templ.item_and_mut_cx(); + let tcx = cx.tcx(); + let v = render_attributes_in_pre(item, "", tcx); + write!(f, "{v}") + }) +} + +fn item_template_render_assoc_items<'a: 'b, 'b, 'cx: 'a>( + templ: &'b impl ItemTemplate<'a, 'cx>, +) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { + display_fn(move |f| { + let (item, mut cx) = templ.item_and_mut_cx(); + let def_id = item.item_id.expect_def_id(); + let v = render_assoc_items(*cx, item, def_id, AssocItemRender::All); + write!(f, "{v}") + }) +} + fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: &[clean::Item]) { write!(w, "{}", document(cx, item, None, HeadingOffset::H2)); @@ -1131,32 +1180,18 @@ fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean: #[derive(Template)] #[template(path = "item_union.html")] struct ItemUnion<'a, 'cx> { - cx: std::cell::RefCell<&'a mut Context<'cx>>, + cx: RefCell<&'a mut Context<'cx>>, it: &'a clean::Item, s: &'a clean::Union, } - impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> { - fn render_assoc_items<'b>( - &'b self, - ) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { - display_fn(move |f| { - let def_id = self.it.item_id.expect_def_id(); - let mut cx = self.cx.borrow_mut(); - let v = render_assoc_items(*cx, self.it, def_id, AssocItemRender::All); - write!(f, "{v}") - }) - } - fn document_type_layout<'b>( - &'b self, - ) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { - display_fn(move |f| { - let def_id = self.it.item_id.expect_def_id(); - let cx = self.cx.borrow_mut(); - let v = document_type_layout(*cx, def_id); - write!(f, "{v}") - }) + impl<'a, 'cx: 'a> ItemTemplate<'a, 'cx> for ItemUnion<'a, 'cx> { + fn item_and_mut_cx(&self) -> (&'a clean::Item, RefMut<'_, &'a mut Context<'cx>>) { + (self.it, self.cx.borrow_mut()) } + } + + impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> { fn render_union<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { display_fn(move |f| { let cx = self.cx.borrow_mut(); @@ -1164,22 +1199,6 @@ fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean: write!(f, "{v}") }) } - fn render_attributes_in_pre<'b>( - &'b self, - ) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { - display_fn(move |f| { - let tcx = self.cx.borrow().tcx(); - let v = render_attributes_in_pre(self.it, "", tcx); - write!(f, "{v}") - }) - } - fn document<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { - display_fn(move |f| { - let mut cx = self.cx.borrow_mut(); - let v = document(*cx, self.it, None, HeadingOffset::H2); - write!(f, "{v}") - }) - } fn document_field<'b>( &'b self, field: &'a clean::Item, @@ -1219,7 +1238,7 @@ fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean: } } - ItemUnion { cx: std::cell::RefCell::new(cx), it, s }.render_into(w).unwrap(); + ItemUnion { cx: RefCell::new(cx), it, s }.render_into(w).unwrap(); } fn print_tuple_struct_fields<'a, 'cx: 'a>( diff --git a/src/librustdoc/html/templates/item_union.html b/src/librustdoc/html/templates/item_union.html index a01457971c178..c219670051332 100644 --- a/src/librustdoc/html/templates/item_union.html +++ b/src/librustdoc/html/templates/item_union.html @@ -1,8 +1,8 @@

-    {{ self.render_attributes_in_pre() | safe }}
+    {{ self::item_template_render_attributes_in_pre(self.borrow()) | safe }}
     {{ self.render_union() | safe }}
 
-{{ self.document() | safe }} +{{ self::item_template_document(self.borrow()) | safe }} {% if self.fields_iter().peek().is_some() %}

Fields§ @@ -19,5 +19,5 @@

{{ self.document_field(field) | safe }} {% endfor %} {% endif %} -{{ self.render_assoc_items() | safe }} -{{ self.document_type_layout() | safe }} +{{ self::item_template_render_assoc_items(self.borrow()) | safe }} +{{ self::item_template_document_type_layout(self.borrow()) | safe }} From 844c1cc5fec38f691a2ffb53ef3366f25cf7b02b Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 25 May 2023 17:30:23 +0000 Subject: [PATCH 20/69] Remove DesugaringKind::Replace. --- .../src/diagnostics/conflict_errors.rs | 28 ------------------- .../src/diagnostics/mutability_errors.rs | 7 +---- compiler/rustc_borrowck/src/invalidation.rs | 6 ++-- compiler/rustc_borrowck/src/lib.rs | 19 +++++++++++-- compiler/rustc_codegen_cranelift/src/base.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/block.rs | 2 +- .../src/interpret/terminator.rs | 2 +- compiler/rustc_middle/src/mir/syntax.rs | 6 +++- compiler/rustc_middle/src/mir/visit.rs | 1 + .../src/build/custom/parse/instruction.rs | 1 + .../src/build/expr/as_rvalue.rs | 1 + compiler/rustc_mir_build/src/build/scope.rs | 8 +++--- .../rustc_mir_dataflow/src/elaborate_drops.rs | 10 +++++-- .../src/framework/direction.rs | 2 +- .../src/add_moves_for_packed_drops.rs | 9 ++++-- .../src/elaborate_drops.rs | 9 ++---- compiler/rustc_mir_transform/src/generator.rs | 6 +++- compiler/rustc_mir_transform/src/inline.rs | 6 ++-- compiler/rustc_mir_transform/src/shim.rs | 3 ++ compiler/rustc_smir/src/rustc_smir/mod.rs | 2 +- compiler/rustc_span/src/hygiene.rs | 2 -- .../borrowck/borrowck-vec-pattern-nesting.rs | 2 -- .../borrowck-vec-pattern-nesting.stderr | 18 ++++++------ tests/ui/borrowck/issue-45199.rs | 3 -- tests/ui/borrowck/issue-45199.stderr | 4 +-- .../liveness-assign-imm-local-with-drop.rs | 1 - 26 files changed, 78 insertions(+), 82 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 04b8174079acc..15d73ed732f50 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1635,34 +1635,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { }) } - /// Reports StorageDeadOrDrop of `place` conflicts with `borrow`. - /// - /// Depending on the origin of the StorageDeadOrDrop, this may be - /// reported as either a drop or an illegal mutation of a borrowed value. - /// The latter is preferred when the this is a drop triggered by a - /// reassignment, as it's more user friendly to report a problem with the - /// explicit assignment than the implicit drop. - #[instrument(level = "debug", skip(self))] - pub(crate) fn report_storage_dead_or_drop_of_borrowed( - &mut self, - location: Location, - place_span: (Place<'tcx>, Span), - borrow: &BorrowData<'tcx>, - ) { - // It's sufficient to check the last desugaring as Replace is the last - // one to be applied. - if let Some(DesugaringKind::Replace) = place_span.1.desugaring_kind() { - self.report_illegal_mutation_of_borrowed(location, place_span, borrow) - } else { - self.report_borrowed_value_does_not_live_long_enough( - location, - borrow, - place_span, - Some(WriteKind::StorageDeadOrDrop), - ) - } - } - /// This means that some data referenced by `borrow` needs to live /// past the point where the StorageDeadOrDrop of `place` occurs. /// This is usually interpreted as meaning that `place` has too diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 4bde372c847dd..d0e17bf5a0848 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -641,13 +641,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let Some(hir::Node::Item(item)) = node else { return; }; let hir::ItemKind::Fn(.., body_id) = item.kind else { return; }; let body = self.infcx.tcx.hir().body(body_id); - let mut assign_span = span; - // Drop desugaring is done at MIR build so it's not in the HIR - if let Some(DesugaringKind::Replace) = span.desugaring_kind() { - assign_span.remove_mark(); - } - let mut v = V { assign_span, err, ty, suggested: false }; + let mut v = V { assign_span: span, err, ty, suggested: false }; v.visit_body(body); if !v.suggested { err.help(format!( diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs index 036391d074da8..b2ff25ecb96f4 100644 --- a/compiler/rustc_borrowck/src/invalidation.rs +++ b/compiler/rustc_borrowck/src/invalidation.rs @@ -112,11 +112,13 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { TerminatorKind::SwitchInt { discr, targets: _ } => { self.consume_operand(location, discr); } - TerminatorKind::Drop { place: drop_place, target: _, unwind: _ } => { + TerminatorKind::Drop { place: drop_place, target: _, unwind: _, replace } => { + let write_kind = + if *replace { WriteKind::Replace } else { WriteKind::StorageDeadOrDrop }; self.access_place( location, *drop_place, - (AccessDepth::Drop, Write(WriteKind::StorageDeadOrDrop)), + (AccessDepth::Drop, Write(write_kind)), LocalMutationIsAllowed::Yes, ); } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 9277a262f9789..a53ea100c2242 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -685,17 +685,19 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx TerminatorKind::SwitchInt { discr, targets: _ } => { self.consume_operand(loc, (discr, span), flow_state); } - TerminatorKind::Drop { place, target: _, unwind: _ } => { + TerminatorKind::Drop { place, target: _, unwind: _, replace } => { debug!( "visit_terminator_drop \ loc: {:?} term: {:?} place: {:?} span: {:?}", loc, term, place, span ); + let write_kind = + if *replace { WriteKind::Replace } else { WriteKind::StorageDeadOrDrop }; self.access_place( loc, (*place, span), - (AccessDepth::Drop, Write(WriteKind::StorageDeadOrDrop)), + (AccessDepth::Drop, Write(write_kind)), LocalMutationIsAllowed::Yes, flow_state, ); @@ -885,6 +887,7 @@ enum ReadKind { #[derive(Copy, Clone, PartialEq, Eq, Debug)] enum WriteKind { StorageDeadOrDrop, + Replace, MutableBorrow(BorrowKind), Mutate, Move, @@ -1132,13 +1135,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { this.buffer_error(err); } WriteKind::StorageDeadOrDrop => this - .report_storage_dead_or_drop_of_borrowed(location, place_span, borrow), + .report_borrowed_value_does_not_live_long_enough( + location, + borrow, + place_span, + Some(WriteKind::StorageDeadOrDrop), + ), WriteKind::Mutate => { this.report_illegal_mutation_of_borrowed(location, place_span, borrow) } WriteKind::Move => { this.report_move_out_while_borrowed(location, place_span, borrow) } + WriteKind::Replace => { + this.report_illegal_mutation_of_borrowed(location, place_span, borrow) + } } Control::Break } @@ -1982,12 +1993,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Reservation( WriteKind::Move + | WriteKind::Replace | WriteKind::StorageDeadOrDrop | WriteKind::MutableBorrow(BorrowKind::Shared) | WriteKind::MutableBorrow(BorrowKind::Shallow), ) | Write( WriteKind::Move + | WriteKind::Replace | WriteKind::StorageDeadOrDrop | WriteKind::MutableBorrow(BorrowKind::Shared) | WriteKind::MutableBorrow(BorrowKind::Shallow), diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 9c6a0fae327cf..fcfa0b862d4b5 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -473,7 +473,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { | TerminatorKind::GeneratorDrop => { bug!("shouldn't exist at codegen {:?}", bb_data.terminator()); } - TerminatorKind::Drop { place, target, unwind: _ } => { + TerminatorKind::Drop { place, target, unwind: _, replace: _ } => { let drop_place = codegen_place(fx, *place); crate::abi::codegen_drop(fx, source_info, drop_place); diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 1f5f5b69d4dc8..4084342370152 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1256,7 +1256,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { MergingSucc::False } - mir::TerminatorKind::Drop { place, target, unwind } => { + mir::TerminatorKind::Drop { place, target, unwind, replace: _ } => { self.codegen_drop_terminator(helper, bx, place, target, unwind, mergeable_succ()) } diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index df3879200101b..586e8f063eeef 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -114,7 +114,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } - Drop { place, target, unwind } => { + Drop { place, target, unwind, replace: _ } => { let frame = self.frame(); let ty = place.ty(&frame.body.local_decls, *self.tcx).ty; let ty = self.subst_from_frame_and_normalize_erasing_regions(frame, ty)?; diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 21faf1958e911..6d6d71bc87b14 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -603,7 +603,11 @@ pub enum TerminatorKind<'tcx> { /// > The drop glue is executed if, among all statements executed within this `Body`, an assignment to /// > the place or one of its "parents" occurred more recently than a move out of it. This does not /// > consider indirect assignments. - Drop { place: Place<'tcx>, target: BasicBlock, unwind: UnwindAction }, + /// + /// The `replace` flag indicates whether this terminator was created as part of an assignment. + /// This should only be used for diagnostic purposes, and does not have any operational + /// meaning. + Drop { place: Place<'tcx>, target: BasicBlock, unwind: UnwindAction, replace: bool }, /// Roughly speaking, evaluates the `func` operand and the arguments, and starts execution of /// the referred to function. The operand types must match the argument types of the function. diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 596dd80bf4874..942654b30749c 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -504,6 +504,7 @@ macro_rules! make_mir_visitor { place, target: _, unwind: _, + replace: _, } => { self.visit_place( place, 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 b74422708ce5c..ebf830cb9c1f6 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -57,6 +57,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { place: self.parse_place(args[0])?, target: self.parse_block(args[1])?, unwind: UnwindAction::Continue, + replace: false, }) }, @call("mir_call", args) => { diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index bcab4c0d24b5f..3742d640e3b58 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -725,6 +725,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { place: to_drop, target: success, unwind: UnwindAction::Continue, + replace: false, }, ); this.diverge_from(block); diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index 7331f8ecaa965..7c0fbc6f81c94 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -91,7 +91,7 @@ use rustc_middle::middle::region; use rustc_middle::mir::*; use rustc_middle::thir::{Expr, LintLevel}; -use rustc_span::{DesugaringKind, Span, DUMMY_SP}; +use rustc_span::{Span, DUMMY_SP}; #[derive(Debug)] pub struct Scopes<'tcx> { @@ -371,6 +371,7 @@ impl DropTree { // The caller will handle this if needed. unwind: UnwindAction::Terminate, place: drop_data.0.local.into(), + replace: false, }; cfg.terminate(block, drop_data.0.source_info, terminator); } @@ -1128,9 +1129,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { place: Place<'tcx>, value: Rvalue<'tcx>, ) -> BlockAnd<()> { - let span = self.tcx.with_stable_hashing_context(|hcx| { - span.mark_with_reason(None, DesugaringKind::Replace, self.tcx.sess.edition(), hcx) - }); let source_info = self.source_info(span); // create the new block for the assignment @@ -1148,6 +1146,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { place, target: assign, unwind: UnwindAction::Cleanup(assign_unwind), + replace: true, }, ); self.diverge_from(block); @@ -1261,6 +1260,7 @@ fn build_scope_drops<'tcx>( place: local.into(), target: next, unwind: UnwindAction::Continue, + replace: false, }, ); block = next; diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index 18895072c3b96..d615c83d62191 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -237,6 +237,7 @@ where place: self.place, target: self.succ, unwind: self.unwind.into_action(), + replace: false, }, ); } @@ -719,6 +720,7 @@ where place: tcx.mk_place_deref(ptr), target: loop_block, unwind: unwind.into_action(), + replace: false, }, ); @@ -963,8 +965,12 @@ where } fn drop_block(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock { - let block = - TerminatorKind::Drop { place: self.place, target, unwind: unwind.into_action() }; + let block = TerminatorKind::Drop { + place: self.place, + target, + unwind: unwind.into_action(), + replace: false, + }; self.new_block(unwind, block) } diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index c8fe1af6674c8..ba328e78040a5 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -479,7 +479,7 @@ impl Direction for Forward { Goto { target } => propagate(target, exit_state), Assert { target, unwind, expected: _, msg: _, cond: _ } - | Drop { target, unwind, place: _ } + | Drop { target, unwind, place: _, replace: _ } | FalseUnwind { real_target: target, unwind } => { if let UnwindAction::Cleanup(unwind) = unwind { propagate(unwind, exit_state); diff --git a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs index b29ffcc70f93f..ef2a0c790e945 100644 --- a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs +++ b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs @@ -80,7 +80,7 @@ fn add_move_for_packed_drop<'tcx>( is_cleanup: bool, ) { debug!("add_move_for_packed_drop({:?} @ {:?})", terminator, loc); - let TerminatorKind::Drop { ref place, target, unwind } = terminator.kind else { + let TerminatorKind::Drop { ref place, target, unwind, replace } = terminator.kind else { unreachable!(); }; @@ -98,6 +98,11 @@ fn add_move_for_packed_drop<'tcx>( patch.add_assign(loc, Place::from(temp), Rvalue::Use(Operand::Move(*place))); patch.patch_terminator( loc.block, - TerminatorKind::Drop { place: Place::from(temp), target: storage_dead_block, unwind }, + TerminatorKind::Drop { + place: Place::from(temp), + target: storage_dead_block, + unwind, + replace, + }, ); } diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index 98e7a519c2013..fda0e1023f7c5 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -14,7 +14,7 @@ use rustc_mir_dataflow::un_derefer::UnDerefer; use rustc_mir_dataflow::MoveDataParamEnv; use rustc_mir_dataflow::{on_all_children_bits, on_all_drop_children_bits}; use rustc_mir_dataflow::{Analysis, ResultsCursor}; -use rustc_span::{DesugaringKind, Span}; +use rustc_span::Span; use rustc_target::abi::{FieldIdx, VariantIdx}; use std::fmt; @@ -401,7 +401,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let terminator = data.terminator(); match terminator.kind { - TerminatorKind::Drop { mut place, target, unwind } => { + TerminatorKind::Drop { mut place, target, unwind, replace } => { if let Some(new_place) = self.un_derefer.derefer(place.as_ref(), self.body) { place = new_place; } @@ -434,10 +434,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { ) } LookupResult::Parent(..) => { - if !matches!( - terminator.source_info.span.desugaring_kind(), - Some(DesugaringKind::Replace), - ) { + if !replace { self.tcx.sess.delay_span_bug( terminator.source_info.span, format!("drop of untracked value {:?}", bb), diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index 891e446942e01..89567ed0ab882 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -1045,7 +1045,10 @@ fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { for (block, block_data) in body.basic_blocks.iter_enumerated() { let (target, unwind, source_info) = match block_data.terminator() { - Terminator { source_info, kind: TerminatorKind::Drop { place, target, unwind } } => { + Terminator { + source_info, + kind: TerminatorKind::Drop { place, target, unwind, replace: _ }, + } => { if let Some(local) = place.as_local() { if local == SELF_ARG { (target, unwind, source_info) @@ -1304,6 +1307,7 @@ fn insert_clean_drop(body: &mut Body<'_>) -> BasicBlock { place: Place::from(SELF_ARG), target: return_block, unwind: UnwindAction::Continue, + replace: false, }; let source_info = SourceInfo::outermost(body.span); diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 6c2e22a70b943..6c5e182ed06f9 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -450,7 +450,7 @@ impl<'tcx> Inliner<'tcx> { checker.visit_basic_block_data(bb, blk); let term = blk.terminator(); - if let TerminatorKind::Drop { ref place, target, unwind } = term.kind { + if let TerminatorKind::Drop { ref place, target, unwind, replace: _ } = term.kind { work_list.push(target); // If the place doesn't actually need dropping, treat it like a regular goto. @@ -458,8 +458,8 @@ impl<'tcx> Inliner<'tcx> { .callee .subst_mir(self.tcx, ty::EarlyBinder(&place.ty(callee_body, tcx).ty)); if ty.needs_drop(tcx, self.param_env) && let UnwindAction::Cleanup(unwind) = unwind { - work_list.push(unwind); - } + work_list.push(unwind); + } } else if callee_attrs.instruction_set != self.codegen_fn_attrs.instruction_set && matches!(term.kind, TerminatorKind::InlineAsm { .. }) { diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 7c47d8814db83..0eb27c23105f5 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -544,6 +544,7 @@ impl<'tcx> CloneShimBuilder<'tcx> { place: dest_field, target: unwind, unwind: UnwindAction::Terminate, + replace: false, }, true, ); @@ -800,6 +801,7 @@ fn build_call_shim<'tcx>( place: rcvr_place(), target: BasicBlock::new(2), unwind: UnwindAction::Continue, + replace: false, }, false, ); @@ -815,6 +817,7 @@ fn build_call_shim<'tcx>( place: rcvr_place(), target: BasicBlock::new(4), unwind: UnwindAction::Terminate, + replace: false, }, true, ); diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 6af43f5d3f358..5572108f49567 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -309,7 +309,7 @@ fn rustc_terminator_to_terminator( Terminate => Terminator::Abort, Return => Terminator::Return, Unreachable => Terminator::Unreachable, - Drop { place, target, unwind } => Terminator::Drop { + Drop { place, target, unwind, replace: _ } => Terminator::Drop { place: rustc_place_to_place(place), target: target.as_usize(), unwind: rustc_unwind_to_unwind(unwind), diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index c669b64dd2c81..70ddac086850d 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -1151,7 +1151,6 @@ pub enum DesugaringKind { Await, ForLoop, WhileLoop, - Replace, } impl DesugaringKind { @@ -1167,7 +1166,6 @@ impl DesugaringKind { DesugaringKind::OpaqueTy => "`impl Trait`", DesugaringKind::ForLoop => "`for` loop", DesugaringKind::WhileLoop => "`while` loop", - DesugaringKind::Replace => "drop and replace", } } } diff --git a/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs b/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs index 127a3f5b2dc97..1bda7a4971375 100644 --- a/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs +++ b/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs @@ -8,7 +8,6 @@ fn a() { //~^ NOTE `vec[_]` is borrowed here vec[0] = Box::new(4); //~ ERROR cannot assign //~^ NOTE `vec[_]` is assigned to here - //~| NOTE in this expansion of desugaring of drop and replace _a.use_ref(); //~^ NOTE borrow later used here } @@ -23,7 +22,6 @@ fn b() { //~^ `vec[_]` is borrowed here vec[0] = Box::new(4); //~ ERROR cannot assign //~^ NOTE `vec[_]` is assigned to here - //~| NOTE in this expansion of desugaring of drop and replace _b.use_ref(); //~^ NOTE borrow later used here } diff --git a/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr b/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr index 5e1251b059093..70b9e4f4433b3 100644 --- a/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr +++ b/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr @@ -6,24 +6,24 @@ LL | [box ref _a, _, _] => { LL | LL | vec[0] = Box::new(4); | ^^^^^^ `vec[_]` is assigned to here but it was already borrowed -... +LL | LL | _a.use_ref(); | ------------ borrow later used here error[E0506]: cannot assign to `vec[_]` because it is borrowed - --> $DIR/borrowck-vec-pattern-nesting.rs:24:13 + --> $DIR/borrowck-vec-pattern-nesting.rs:23:13 | LL | &mut [ref _b @ ..] => { | ------ `vec[_]` is borrowed here LL | LL | vec[0] = Box::new(4); | ^^^^^^ `vec[_]` is assigned to here but it was already borrowed -... +LL | LL | _b.use_ref(); | ------------ borrow later used here error[E0508]: cannot move out of type `[Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:36:11 + --> $DIR/borrowck-vec-pattern-nesting.rs:34:11 | LL | match vec { | ^^^ cannot move out of here @@ -41,7 +41,7 @@ LL + [_a, | error[E0508]: cannot move out of type `[Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:48:13 + --> $DIR/borrowck-vec-pattern-nesting.rs:46:13 | LL | let a = vec[0]; | ^^^^^^ @@ -55,7 +55,7 @@ LL | let a = &vec[0]; | + error[E0508]: cannot move out of type `[Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:57:11 + --> $DIR/borrowck-vec-pattern-nesting.rs:55:11 | LL | match vec { | ^^^ cannot move out of here @@ -73,7 +73,7 @@ LL + [ | error[E0508]: cannot move out of type `[Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:67:13 + --> $DIR/borrowck-vec-pattern-nesting.rs:65:13 | LL | let a = vec[0]; | ^^^^^^ @@ -87,7 +87,7 @@ LL | let a = &vec[0]; | + error[E0508]: cannot move out of type `[Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:76:11 + --> $DIR/borrowck-vec-pattern-nesting.rs:74:11 | LL | match vec { | ^^^ cannot move out of here @@ -106,7 +106,7 @@ LL + [_a, _b, _c] => {} | error[E0508]: cannot move out of type `[Box]`, a non-copy slice - --> $DIR/borrowck-vec-pattern-nesting.rs:87:13 + --> $DIR/borrowck-vec-pattern-nesting.rs:85:13 | LL | let a = vec[0]; | ^^^^^^ diff --git a/tests/ui/borrowck/issue-45199.rs b/tests/ui/borrowck/issue-45199.rs index 6a6b25541f396..ded46e56e3451 100644 --- a/tests/ui/borrowck/issue-45199.rs +++ b/tests/ui/borrowck/issue-45199.rs @@ -5,7 +5,6 @@ fn test_drop_replace() { b = Box::new(1); //~ NOTE first assignment b = Box::new(2); //~ ERROR cannot assign twice to immutable variable `b` //~| NOTE cannot assign twice to immutable - //~| NOTE in this expansion of desugaring of drop and replace } fn test_call() { @@ -14,14 +13,12 @@ fn test_call() { //~| SUGGESTION mut b b = Box::new(2); //~ ERROR cannot assign twice to immutable variable `b` //~| NOTE cannot assign twice to immutable - //~| NOTE in this expansion of desugaring of drop and replace } fn test_args(b: Box) { //~ HELP consider making this binding mutable //~| SUGGESTION mut b b = Box::new(2); //~ ERROR cannot assign to immutable argument `b` //~| NOTE cannot assign to immutable argument - //~| NOTE in this expansion of desugaring of drop and replace } fn main() {} diff --git a/tests/ui/borrowck/issue-45199.stderr b/tests/ui/borrowck/issue-45199.stderr index 163f2370ba010..47aa30908270d 100644 --- a/tests/ui/borrowck/issue-45199.stderr +++ b/tests/ui/borrowck/issue-45199.stderr @@ -10,7 +10,7 @@ LL | b = Box::new(2); | ^ cannot assign twice to immutable variable error[E0384]: cannot assign twice to immutable variable `b` - --> $DIR/issue-45199.rs:15:5 + --> $DIR/issue-45199.rs:14:5 | LL | let b = Box::new(1); | - @@ -22,7 +22,7 @@ LL | b = Box::new(2); | ^ cannot assign twice to immutable variable error[E0384]: cannot assign to immutable argument `b` - --> $DIR/issue-45199.rs:22:5 + --> $DIR/issue-45199.rs:20:5 | LL | fn test_args(b: Box) { | - help: consider making this binding mutable: `mut b` diff --git a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.rs b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.rs index 293fdca1cc91b..c9b16e43910e8 100644 --- a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.rs +++ b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.rs @@ -5,7 +5,6 @@ fn test() { drop(b); b = Box::new(2); //~ ERROR cannot assign twice to immutable variable `b` //~| NOTE cannot assign twice to immutable - //~| NOTE in this expansion of desugaring of drop and replace drop(b); } From f2bdaf1a4d38c06521bf9004c5b54ea97d29d6d4 Mon Sep 17 00:00:00 2001 From: raldone01 Date: Fri, 3 Feb 2023 21:26:14 +0100 Subject: [PATCH 21/69] Remove structural match from `TypeId`. --- library/core/src/any.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/library/core/src/any.rs b/library/core/src/any.rs index d1c1ae6526b6e..7969f4055dd2b 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -662,12 +662,20 @@ impl dyn Any + Send + Sync { /// While `TypeId` implements `Hash`, `PartialOrd`, and `Ord`, it is worth /// noting that the hashes and ordering will vary between Rust releases. Beware /// of relying on them inside of your code! -#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Copy, Debug, Hash, Eq, PartialOrd, Ord)] #[stable(feature = "rust1", since = "1.0.0")] pub struct TypeId { t: u64, } +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq for TypeId { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.t == other.t + } +} + impl TypeId { /// Returns the `TypeId` of the type this generic function has been /// instantiated with. From e1b8fad66430abd03e611bb18425e085945c7c40 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Thu, 25 May 2023 18:24:27 -0400 Subject: [PATCH 22/69] Add #[inline] to array TryFrom impls --- library/core/src/array/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index bdb4c975909e0..e3885d485b77a 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -204,6 +204,7 @@ where { type Error = TryFromSliceError; + #[inline] fn try_from(slice: &[T]) -> Result<[T; N], TryFromSliceError> { <&Self>::try_from(slice).map(|r| *r) } @@ -228,6 +229,7 @@ where { type Error = TryFromSliceError; + #[inline] fn try_from(slice: &mut [T]) -> Result<[T; N], TryFromSliceError> { ::try_from(&*slice) } @@ -249,6 +251,7 @@ where impl<'a, T, const N: usize> TryFrom<&'a [T]> for &'a [T; N] { type Error = TryFromSliceError; + #[inline] fn try_from(slice: &'a [T]) -> Result<&'a [T; N], TryFromSliceError> { if slice.len() == N { let ptr = slice.as_ptr() as *const [T; N]; @@ -276,6 +279,7 @@ impl<'a, T, const N: usize> TryFrom<&'a [T]> for &'a [T; N] { impl<'a, T, const N: usize> TryFrom<&'a mut [T]> for &'a mut [T; N] { type Error = TryFromSliceError; + #[inline] fn try_from(slice: &'a mut [T]) -> Result<&'a mut [T; N], TryFromSliceError> { if slice.len() == N { let ptr = slice.as_mut_ptr() as *mut [T; N]; From ea327915d8d2311b03e50c12fd2e9e6aa86f0077 Mon Sep 17 00:00:00 2001 From: Markus Everling Date: Fri, 26 May 2023 01:28:41 +0000 Subject: [PATCH 23/69] Update current implementation comments for `select_nth_unstable` --- library/core/src/slice/mod.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index bd1b16e8d73ed..1f19555522974 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -3005,8 +3005,9 @@ impl [T] { /// /// # Current implementation /// - /// The current algorithm is based on the quickselect portion of the same quicksort algorithm - /// used for [`sort_unstable`]. + /// The current algorithm is an introselect implementation based on Pattern Defeating Quicksort, which is also + /// the basis for [`sort_unstable`]. The fallback algorithm is Median of Medians using Tukey's Ninther for + /// pivot selection, which guarantees linear runtime for all inputs. /// /// [`sort_unstable`]: slice::sort_unstable /// @@ -3056,8 +3057,9 @@ impl [T] { /// /// # Current implementation /// - /// The current algorithm is based on the quickselect portion of the same quicksort algorithm - /// used for [`sort_unstable`]. + /// The current algorithm is an introselect implementation based on Pattern Defeating Quicksort, which is also + /// the basis for [`sort_unstable`]. The fallback algorithm is Median of Medians using Tukey's Ninther for + /// pivot selection, which guarantees linear runtime for all inputs. /// /// [`sort_unstable`]: slice::sort_unstable /// From b084c525d34ef72618b96f469e47b5fae6105b8c Mon Sep 17 00:00:00 2001 From: jyn Date: Thu, 25 May 2023 21:43:13 -0500 Subject: [PATCH 24/69] Generate docs for bootstrap itself This verifies the intra-doc links are correct, and hopefully makes things easier for new contributors. --- src/bootstrap/builder.rs | 3 ++- src/bootstrap/doc.rs | 5 ++++- src/bootstrap/download.rs | 2 +- src/bootstrap/lib.rs | 4 ++++ src/bootstrap/util.rs | 2 +- 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index cf7c6596c0238..f9de87c3f0dae 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -264,7 +264,7 @@ impl PathSet { /// A convenience wrapper for Steps which know they have no aliases and all their sets contain only a single path. /// - /// This can be used with [`ShouldRun::krate`], [`ShouldRun::path`], or [`ShouldRun::alias`]. + /// This can be used with [`ShouldRun::crate_or_deps`], [`ShouldRun::path`], or [`ShouldRun::alias`]. #[track_caller] pub fn assert_single_path(&self) -> &TaskPath { match self { @@ -787,6 +787,7 @@ impl<'a> Builder<'a> { doc::EditionGuide, doc::StyleGuide, doc::Tidy, + doc::Bootstrap, ), Kind::Dist => describe!( dist::Docs, diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 8f5d9bb66e103..b52c3b68cc4ff 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -839,6 +839,8 @@ macro_rules! tool_doc { )+ cargo.rustdocflag("--document-private-items"); + // Since we always pass --document-private-items, there's no need to warn about linking to private items. + cargo.rustdocflag("-Arustdoc::private-intra-doc-links"); cargo.rustdocflag("--enable-index-page"); cargo.rustdocflag("--show-type-layout"); cargo.rustdocflag("--generate-link-to-definition"); @@ -882,7 +884,8 @@ tool_doc!( // "cargo-credential-wincred", ] ); -tool_doc!(Tidy, "tidy", "src/tools/tidy", ["tidy"]); +tool_doc!(Tidy, "tidy", "src/tools/tidy", rustc_tool = false, ["tidy"]); +tool_doc!(Bootstrap, "bootstrap", "src/bootstrap", rustc_tool = false, ["bootstrap"]); #[derive(Ord, PartialOrd, Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct ErrorIndex { diff --git a/src/bootstrap/download.rs b/src/bootstrap/download.rs index 25df5b2573b96..c7969d2a2c7be 100644 --- a/src/bootstrap/download.rs +++ b/src/bootstrap/download.rs @@ -123,7 +123,7 @@ impl Config { /// This is only required on NixOS and uses the PatchELF utility to /// change the interpreter/RPATH of ELF executables. /// - /// Please see https://nixos.org/patchelf.html for more information + /// Please see for more information fn fix_bin_or_dylib(&self, fname: &Path) { assert_eq!(SHOULD_FIX_BINS_AND_DYLIBS.get(), Some(&true)); println!("attempting to patch {}", fname.display()); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 6ee50ee657399..943f513415a16 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -1011,6 +1011,8 @@ impl Build { } /// Return a `Group` guard for a [`Step`] that is built for each `--stage`. + /// + /// [`Step`]: crate::builder::Step fn msg( &self, action: impl Into, @@ -1035,6 +1037,8 @@ impl Build { } /// Return a `Group` guard for a [`Step`] that is only built once and isn't affected by `--stage`. + /// + /// [`Step`]: crate::builder::Step fn msg_unstaged( &self, action: impl Into, diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 2e1adbf63bb10..9bfdc77e6b6cc 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -488,7 +488,7 @@ fn absolute_windows(path: &std::path::Path) -> std::io::Result /// /// When `clang-cl` is used with instrumentation, we need to add clang's runtime library resource /// directory to the linker flags, otherwise there will be linker errors about the profiler runtime From be44860ab94f9e469d6f02232d3064a1049c47ba Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Fri, 5 May 2023 10:52:02 +0000 Subject: [PATCH 25/69] fix for `Self` not respecting tuple Ctor privacy This fixes #111220 by checking the privacy of tuple constructors using `Self`, so the following code now errors ```rust mod my { pub struct Foo(&'static str); } impl AsRef for my::Foo { fn as_ref(&self) -> &str { let Self(s) = self; // previously compiled, now errors correctly s } } ``` --- compiler/rustc_hir_typeck/messages.ftl | 2 + compiler/rustc_hir_typeck/src/errors.rs | 8 ++++ .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 7 +++ ...111220-2-tuple-struct-fields-projection.rs | 33 +++++++++++++ ...20-2-tuple-struct-fields-projection.stderr | 9 ++++ .../issue-111220-tuple-struct-fields.rs | 46 +++++++++++++++++++ .../issue-111220-tuple-struct-fields.stderr | 21 +++++++++ 7 files changed, 126 insertions(+) create mode 100644 tests/ui/privacy/issue-111220-2-tuple-struct-fields-projection.rs create mode 100644 tests/ui/privacy/issue-111220-2-tuple-struct-fields-projection.stderr create mode 100644 tests/ui/privacy/issue-111220-tuple-struct-fields.rs create mode 100644 tests/ui/privacy/issue-111220-tuple-struct-fields.stderr diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 9761b1d3facab..e9bff4eb1fd44 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -25,6 +25,8 @@ hir_typeck_const_select_must_be_fn = this argument must be a function item hir_typeck_convert_to_str = try converting the passed type into a `&str` +hir_typeck_ctor_is_private = tuple struct constructor `{$def}` is private + hir_typeck_expected_default_return_type = expected `()` because of default return type hir_typeck_expected_return_type = expected `{$expected}` because of return type diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 102a313067fd2..e45b8e3d024de 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -319,3 +319,11 @@ pub struct CandidateTraitNote { pub item_name: Ident, pub action_or_ty: String, } + +#[derive(Diagnostic)] +#[diag(hir_typeck_ctor_is_private, code = "E0603")] +pub struct CtorIsPrivate { + #[primary_span] + pub span: Span, + pub def: String, +} diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 2fdcd09b9a2f4..557950338a73b 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1,4 +1,5 @@ use crate::callee::{self, DeferredCallResolution}; +use crate::errors::CtorIsPrivate; use crate::method::{self, MethodCallee, SelfSource}; use crate::rvalue_scopes; use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, RawTy}; @@ -1207,6 +1208,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match ty.normalized.ty_adt_def() { Some(adt_def) if adt_def.has_ctor() => { let (ctor_kind, ctor_def_id) = adt_def.non_enum_variant().ctor.unwrap(); + // Check the visibility of the ctor. + let vis = tcx.visibility(ctor_def_id); + if !vis.is_accessible_from(tcx.parent_module(hir_id).to_def_id(), tcx) { + tcx.sess + .emit_err(CtorIsPrivate { span, def: tcx.def_path_str(adt_def.did()) }); + } let new_res = Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id); let user_substs = Self::user_substs_for_adt(ty); user_self_ty = user_substs.user_self_ty; diff --git a/tests/ui/privacy/issue-111220-2-tuple-struct-fields-projection.rs b/tests/ui/privacy/issue-111220-2-tuple-struct-fields-projection.rs new file mode 100644 index 0000000000000..f413b50277861 --- /dev/null +++ b/tests/ui/privacy/issue-111220-2-tuple-struct-fields-projection.rs @@ -0,0 +1,33 @@ +mod b { + pub struct A(u32); +} + +trait Id { + type Assoc; +} +impl Id for b::A { + type Assoc = b::A; +} +impl Id for u32 { + type Assoc = u32; +} + + +trait Trait { + fn method(&self) + where + T: Id; +} + +impl Trait for ::Assoc { + fn method(&self) + where + T: Id, + { + let Self(a) = self; + //~^ ERROR: tuple struct constructor `A` is private + println!("{a}"); + } +} + +fn main() {} diff --git a/tests/ui/privacy/issue-111220-2-tuple-struct-fields-projection.stderr b/tests/ui/privacy/issue-111220-2-tuple-struct-fields-projection.stderr new file mode 100644 index 0000000000000..231a4da8b5f7f --- /dev/null +++ b/tests/ui/privacy/issue-111220-2-tuple-struct-fields-projection.stderr @@ -0,0 +1,9 @@ +error[E0603]: tuple struct constructor `A` is private + --> $DIR/issue-111220-2-tuple-struct-fields-projection.rs:27:13 + | +LL | let Self(a) = self; + | ^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/privacy/issue-111220-tuple-struct-fields.rs b/tests/ui/privacy/issue-111220-tuple-struct-fields.rs new file mode 100644 index 0000000000000..78d35fd96da3d --- /dev/null +++ b/tests/ui/privacy/issue-111220-tuple-struct-fields.rs @@ -0,0 +1,46 @@ +mod b { + #[derive(Default)] + pub struct A(u32); +} + +impl b::A { + fn inherent_bypass(&self) { + let Self(x) = self; + //~^ ERROR: tuple struct constructor `A` is private + println!("{x}"); + } +} + +pub trait B { + fn f(&self); +} + +impl B for b::A { + fn f(&self) { + let Self(a) = self; + //~^ ERROR: tuple struct constructor `A` is private + println!("{}", a); + } +} + +pub trait Projector { + type P; +} + +impl Projector for () { + type P = b::A; +} + +pub trait Bypass2 { + fn f2(&self); +} + +impl Bypass2 for <() as Projector>::P { + fn f2(&self) { + let Self(a) = self; + //~^ ERROR: tuple struct constructor `A` is private + println!("{}", a); + } +} + +fn main() {} diff --git a/tests/ui/privacy/issue-111220-tuple-struct-fields.stderr b/tests/ui/privacy/issue-111220-tuple-struct-fields.stderr new file mode 100644 index 0000000000000..17a32379cc0a8 --- /dev/null +++ b/tests/ui/privacy/issue-111220-tuple-struct-fields.stderr @@ -0,0 +1,21 @@ +error[E0603]: tuple struct constructor `A` is private + --> $DIR/issue-111220-tuple-struct-fields.rs:8:13 + | +LL | let Self(x) = self; + | ^^^^^^^ + +error[E0603]: tuple struct constructor `A` is private + --> $DIR/issue-111220-tuple-struct-fields.rs:20:13 + | +LL | let Self(a) = self; + | ^^^^^^^ + +error[E0603]: tuple struct constructor `A` is private + --> $DIR/issue-111220-tuple-struct-fields.rs:40:13 + | +LL | let Self(a) = self; + | ^^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0603`. From cb68c051511fe0583ecf3f39147b8537a26c1e1f Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Fri, 26 May 2023 09:47:21 +0200 Subject: [PATCH 26/69] address review feedback --- src/bootstrap/metrics.rs | 8 +++----- src/bootstrap/test.rs | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/bootstrap/metrics.rs b/src/bootstrap/metrics.rs index 9f68eea9a5ebe..8aa821a3afc07 100644 --- a/src/bootstrap/metrics.rs +++ b/src/bootstrap/metrics.rs @@ -114,9 +114,7 @@ impl BuildMetrics { if let Some(test_suite) = step.test_suites.last_mut() { test_suite.tests.push(Test { name: name.to_string(), outcome }); } else { - panic!( - "metrics.record_test() called without calling metrics.record_test_suite() first" - ); + panic!("metrics.record_test() called without calling metrics.begin_test_suite() first"); } } @@ -194,7 +192,7 @@ impl BuildMetrics { fn prepare_json_step(&self, step: StepMetrics) -> JsonNode { let mut children = Vec::new(); children.extend(step.children.into_iter().map(|child| self.prepare_json_step(child))); - children.extend(step.test_suites.into_iter().map(|suite| JsonNode::TestSuite(suite))); + children.extend(step.test_suites.into_iter().map(JsonNode::TestSuite)); JsonNode::RustbuildStep { type_: step.type_, @@ -277,7 +275,7 @@ struct TestSuite { #[derive(Serialize, Deserialize)] #[serde(tag = "kind", rename_all = "snake_case")] pub(crate) enum TestSuiteMetadata { - Crate { + CargoPackage { crates: Vec, target: String, host: String, diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index f64b5f965237e..29edbe5ae417c 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -319,7 +319,7 @@ impl Step for Cargo { #[cfg(feature = "build-metrics")] builder.metrics.begin_test_suite( - crate::metrics::TestSuiteMetadata::Crate { + crate::metrics::TestSuiteMetadata::CargoPackage { crates: vec!["cargo".into()], target: self.host.triple.to_string(), host: self.host.triple.to_string(), @@ -2135,7 +2135,7 @@ fn run_cargo_test( #[cfg(feature = "build-metrics")] builder.metrics.begin_test_suite( - crate::metrics::TestSuiteMetadata::Crate { + crate::metrics::TestSuiteMetadata::CargoPackage { crates: crates.iter().map(|c| c.to_string()).collect(), target: target.triple.to_string(), host: compiler.host.triple.to_string(), From 6827a413c82af4c69b74a5b961b695b854e4ecad Mon Sep 17 00:00:00 2001 From: onestacked Date: Fri, 26 May 2023 09:53:05 +0200 Subject: [PATCH 27/69] Blesses UI tests, add known bug to typeid-equality-by-subtyping --- .../typeid-equality-by-subtyping.rs | 10 ++++++---- .../typeid-equality-by-subtyping.stderr | 11 +++++++++++ tests/ui/consts/const_cmp_type_id.stderr | 2 -- tests/ui/consts/issue-73976-monomorphic.stderr | 1 - 4 files changed, 17 insertions(+), 7 deletions(-) create mode 100644 tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr diff --git a/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.rs b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.rs index 85345d65c4af4..b22cab7c7ffad 100644 --- a/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.rs +++ b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.rs @@ -1,7 +1,7 @@ -// check-pass +// known-bug: #110395 // known-bug: #97156 -#![feature(const_type_id, generic_const_exprs)] +#![feature(const_type_id, const_trait_impl, generic_const_exprs)] #![allow(incomplete_features)] use std::any::TypeId; @@ -26,7 +26,10 @@ impl AssocCt for T { trait WithAssoc { type Assoc; } -impl WithAssoc<()> for T where [(); ::ASSOC]: { +impl WithAssoc<()> for T +where + [(); ::ASSOC]:, +{ type Assoc = [u8; ::ASSOC]; } @@ -38,7 +41,6 @@ where x } - fn unsound(x: >::Assoc) -> >::Assoc where One: WithAssoc, diff --git a/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr new file mode 100644 index 0000000000000..8cbd12654480a --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr @@ -0,0 +1,11 @@ +error: to use a constant of type `TypeId` in a pattern, `TypeId` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/typeid-equality-by-subtyping.rs:18:9 + | +LL | WHAT_A_TYPE => 0, + | ^^^^^^^^^^^ + | + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + +error: aborting due to previous error + diff --git a/tests/ui/consts/const_cmp_type_id.stderr b/tests/ui/consts/const_cmp_type_id.stderr index 319d2b924a88c..dc2c702d885ac 100644 --- a/tests/ui/consts/const_cmp_type_id.stderr +++ b/tests/ui/consts/const_cmp_type_id.stderr @@ -20,7 +20,6 @@ LL | assert!(TypeId::of::() == TypeId::of::()); note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/any.rs:LL:COL = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: can't compare `TypeId` with `TypeId` in const contexts --> $DIR/const_cmp_type_id.rs:9:13 @@ -44,7 +43,6 @@ LL | assert!(TypeId::of::<()>() != TypeId::of::()); note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/any.rs:LL:COL = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: can't compare `TypeId` with `TypeId` in const contexts --> $DIR/const_cmp_type_id.rs:10:22 diff --git a/tests/ui/consts/issue-73976-monomorphic.stderr b/tests/ui/consts/issue-73976-monomorphic.stderr index 95ab78b1b23b3..09661d3f3440d 100644 --- a/tests/ui/consts/issue-73976-monomorphic.stderr +++ b/tests/ui/consts/issue-73976-monomorphic.stderr @@ -20,7 +20,6 @@ LL | GetTypeId::::VALUE == GetTypeId::::VALUE note: impl defined here, but it is not `const` --> $SRC_DIR/core/src/any.rs:LL:COL = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors From 9078fd51d6d16e0689b0ed5022d74aa8d8077191 Mon Sep 17 00:00:00 2001 From: sladynnunes Date: Fri, 26 May 2023 01:19:34 -0700 Subject: [PATCH 28/69] Fix failing CI --- src/librustdoc/html/render/print_item.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 57b88479641b8..02970eb0e9324 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1541,7 +1541,7 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean write!(w, "{}", document_type_layout(cx, def_id)); } -fn item_static(w: &mut impl Write, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) { +fn item_static(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) { wrap_item(w, |w| { render_attributes_in_code(w, it, cx.tcx()); write!( From e7fa993d8980c4a0a199a5018a135e792c051117 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 26 May 2023 10:59:01 +0200 Subject: [PATCH 29/69] do not prefer substs relate during coherence --- compiler/rustc_trait_selection/src/solve/mod.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 26ace28f5fd24..b328c1a6dce8a 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -265,10 +265,18 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { if let Some(merged) = self.try_merge_responses(&candidates) { Ok(merged) - } else if let Ok(subst_relate_response) = subst_relate_response { - Ok(subst_relate_response) } else { - self.flounder(&candidates) + // When relating two aliases and we have ambiguity, we prefer + // relating the generic arguments of the aliases over normalizing + // them. This is necessary for inference during typeck. + // + // As this is incomplete, we must not do so during coherence. + match (self.solver_mode(), subst_relate_response) { + (SolverMode::Normal, Ok(response)) => Ok(response), + (SolverMode::Normal, Err(NoSolution)) | (SolverMode::Coherence, _) => { + self.flounder(&candidates) + } + } } } } From b6b9611190905d75ad2abe3ae3f61835afc4c82c Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 26 May 2023 11:07:20 +0200 Subject: [PATCH 30/69] remove unnecessary `.ok()` calls --- .../rustc_trait_selection/src/solve/mod.rs | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index b328c1a6dce8a..56a254d9c07e1 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -231,13 +231,21 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { let mut candidates = Vec::new(); // LHS normalizes-to RHS - candidates.extend( - evaluate_normalizes_to(self, alias_lhs, rhs, direction, Invert::No).ok(), - ); + candidates.extend(evaluate_normalizes_to( + self, + alias_lhs, + rhs, + direction, + Invert::No, + )); // RHS normalizes-to RHS - candidates.extend( - evaluate_normalizes_to(self, alias_rhs, lhs, direction, Invert::Yes).ok(), - ); + candidates.extend(evaluate_normalizes_to( + self, + alias_rhs, + lhs, + direction, + Invert::Yes, + )); // Relate via substs let subst_relate_response = self.probe(|ecx| { let span = tracing::span!( From df98e3e6ec1aec98b0e25b0f12611d49861a8b9e Mon Sep 17 00:00:00 2001 From: sladynnunes Date: Fri, 26 May 2023 02:22:00 -0700 Subject: [PATCH 31/69] Fixed tests --- src/librustdoc/html/render/print_item.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 02970eb0e9324..6be57676d0744 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1542,10 +1542,12 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean } fn item_static(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) { - wrap_item(w, |w| { - render_attributes_in_code(w, it, cx.tcx()); + + let mut buffer = Buffer::new(); + wrap_item(&mut buffer, |buffer| { + render_attributes_in_code(buffer, it, cx.tcx()); write!( - w, + buffer, "{vis}static {mutability}{name}: {typ}", vis = visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx), mutability = s.mutability.print_with_space(), @@ -1553,7 +1555,10 @@ fn item_static(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item, typ = s.type_.print(cx) ); }); - write!(w, "{}", document(cx, it, None, HeadingOffset::H2)) + + write!(w, "{}", buffer.into_inner()).unwrap(); + + write!(w, "{}", document(cx, it, None, HeadingOffset::H2)).unwrap(); } fn item_foreign_type(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) { From aa67ae2d9d7f12aab30682035fa06067dbe90d2e Mon Sep 17 00:00:00 2001 From: sladynnunes Date: Fri, 26 May 2023 02:28:20 -0700 Subject: [PATCH 32/69] Formatted file correctly --- src/librustdoc/html/render/print_item.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 6be57676d0744..24244e6323a04 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1542,7 +1542,6 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean } fn item_static(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) { - let mut buffer = Buffer::new(); wrap_item(&mut buffer, |buffer| { render_attributes_in_code(buffer, it, cx.tcx()); From 9a86ceb049380a2a684b7bc8fd6c76235f51d9d1 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Thu, 25 May 2023 14:17:56 +0000 Subject: [PATCH 33/69] Improve startup time for bootstrap.py --- src/bootstrap/bootstrap.py | 93 ++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 49 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index f22cdad7df411..057560922bd48 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -226,16 +226,13 @@ def format_build_time(duration): def default_build_triple(verbose): """Build triple as in LLVM""" - # If the user already has a host build triple with an existing `rustc` - # install, use their preference. This fixes most issues with Windows builds - # being detected as GNU instead of MSVC. + # If we're on Windows and have an existing `rustc` toolchain, use `rustc --version --verbose` + # to find our host target triple. This fixes an issue with Windows builds being detected + # as GNU instead of MSVC. + # Otherwise, detect it via `uname` default_encoding = sys.getdefaultencoding() - if sys.platform == 'darwin': - if verbose: - print("not using rustc detection as it is unreliable on macOS", file=sys.stderr) - print("falling back to auto-detect", file=sys.stderr) - else: + if platform_is_win32(): try: version = subprocess.check_output(["rustc", "--version", "--verbose"], stderr=subprocess.DEVNULL) @@ -253,19 +250,17 @@ def default_build_triple(verbose): print("falling back to auto-detect", file=sys.stderr) required = not platform_is_win32() - ostype = require(["uname", "-s"], exit=required) - cputype = require(['uname', '-m'], exit=required) + uname = require(["uname", "-smp"], exit=required) # If we do not have `uname`, assume Windows. - if ostype is None or cputype is None: + if uname is None: return 'x86_64-pc-windows-msvc' - ostype = ostype.decode(default_encoding) - cputype = cputype.decode(default_encoding) + kernel, cputype, processor = uname.decode(default_encoding).split() # The goal here is to come up with the same triple as LLVM would, # at least for the subset of platforms we're willing to target. - ostype_mapper = { + kerneltype_mapper = { 'Darwin': 'apple-darwin', 'DragonFly': 'unknown-dragonfly', 'FreeBSD': 'unknown-freebsd', @@ -275,17 +270,18 @@ def default_build_triple(verbose): } # Consider the direct transformation first and then the special cases - if ostype in ostype_mapper: - ostype = ostype_mapper[ostype] - elif ostype == 'Linux': - os_from_sp = subprocess.check_output( - ['uname', '-o']).strip().decode(default_encoding) - if os_from_sp == 'Android': - ostype = 'linux-android' + if kernel in kerneltype_mapper: + kernel = kerneltype_mapper[kernel] + elif kernel == 'Linux': + # Apple doesn't support `-o` so this can't be used in the combined + # uname invocation above + ostype = require(["uname", "-o"], exit=required).decode(default_encoding) + if ostype == 'Android': + kernel = 'linux-android' else: - ostype = 'unknown-linux-gnu' - elif ostype == 'SunOS': - ostype = 'pc-solaris' + kernel = 'unknown-linux-gnu' + elif kernel == 'SunOS': + kernel = 'pc-solaris' # On Solaris, uname -m will return a machine classification instead # of a cpu type, so uname -p is recommended instead. However, the # output from that option is too generic for our purposes (it will @@ -294,34 +290,34 @@ def default_build_triple(verbose): cputype = require(['isainfo', '-k']).decode(default_encoding) # sparc cpus have sun as a target vendor if 'sparc' in cputype: - ostype = 'sun-solaris' - elif ostype.startswith('MINGW'): + kernel = 'sun-solaris' + elif kernel.startswith('MINGW'): # msys' `uname` does not print gcc configuration, but prints msys # configuration. so we cannot believe `uname -m`: # msys1 is always i686 and msys2 is always x86_64. # instead, msys defines $MSYSTEM which is MINGW32 on i686 and # MINGW64 on x86_64. - ostype = 'pc-windows-gnu' + kernel = 'pc-windows-gnu' cputype = 'i686' if os.environ.get('MSYSTEM') == 'MINGW64': cputype = 'x86_64' - elif ostype.startswith('MSYS'): - ostype = 'pc-windows-gnu' - elif ostype.startswith('CYGWIN_NT'): + elif kernel.startswith('MSYS'): + kernel = 'pc-windows-gnu' + elif kernel.startswith('CYGWIN_NT'): cputype = 'i686' - if ostype.endswith('WOW64'): + if kernel.endswith('WOW64'): cputype = 'x86_64' - ostype = 'pc-windows-gnu' - elif sys.platform == 'win32': + kernel = 'pc-windows-gnu' + elif platform_is_win32(): # Some Windows platforms might have a `uname` command that returns a # non-standard string (e.g. gnuwin32 tools returns `windows32`). In # these cases, fall back to using sys.platform. return 'x86_64-pc-windows-msvc' else: - err = "unknown OS type: {}".format(ostype) + err = "unknown OS type: {}".format(kernel) sys.exit(err) - if cputype in ['powerpc', 'riscv'] and ostype == 'unknown-freebsd': + if cputype in ['powerpc', 'riscv'] and kernel == 'unknown-freebsd': cputype = subprocess.check_output( ['uname', '-p']).strip().decode(default_encoding) cputype_mapper = { @@ -354,24 +350,23 @@ def default_build_triple(verbose): cputype = cputype_mapper[cputype] elif cputype in {'xscale', 'arm'}: cputype = 'arm' - if ostype == 'linux-android': - ostype = 'linux-androideabi' - elif ostype == 'unknown-freebsd': - cputype = subprocess.check_output( - ['uname', '-p']).strip().decode(default_encoding) - ostype = 'unknown-freebsd' + if kernel == 'linux-android': + kernel = 'linux-androideabi' + elif kernel == 'unknown-freebsd': + cputype = processor + kernel = 'unknown-freebsd' elif cputype == 'armv6l': cputype = 'arm' - if ostype == 'linux-android': - ostype = 'linux-androideabi' + if kernel == 'linux-android': + kernel = 'linux-androideabi' else: - ostype += 'eabihf' + kernel += 'eabihf' elif cputype in {'armv7l', 'armv8l'}: cputype = 'armv7' - if ostype == 'linux-android': - ostype = 'linux-androideabi' + if kernel == 'linux-android': + kernel = 'linux-androideabi' else: - ostype += 'eabihf' + kernel += 'eabihf' elif cputype == 'mips': if sys.byteorder == 'big': cputype = 'mips' @@ -387,14 +382,14 @@ def default_build_triple(verbose): else: raise ValueError('unknown byteorder: {}'.format(sys.byteorder)) # only the n64 ABI is supported, indicate it - ostype += 'abi64' + kernel += 'abi64' elif cputype == 'sparc' or cputype == 'sparcv9' or cputype == 'sparc64': pass else: err = "unknown cpu type: {}".format(cputype) sys.exit(err) - return "{}-{}".format(cputype, ostype) + return "{}-{}".format(cputype, kernel) @contextlib.contextmanager From 39f337ab955e7a860530417e4bf02b99aa54a8a0 Mon Sep 17 00:00:00 2001 From: jyn Date: Thu, 25 May 2023 21:58:23 -0500 Subject: [PATCH 34/69] Make errors from `x doc` less verbose before: ``` error: could not document `bootstrap` Caused by: process didn't exit successfully: `/home/jyn/src/rust/build/bootstrap/debug/rustdoc ... --crate-version '1.71.0 (eb9da7bfa 2023-05-25) (a long description goes here)' --document-private-items --enable-index-page --show-type-layout --generate-link-to-definition -Zunstable-options` (exit status: 1) ``` after: ``` error: could not document `bootstrap` Caused by: process didn't exit successfully: `/home/jyn/src/rust/build/bootstrap/debug/rustdoc ... --crate-version '1.71.0 (eb9da7bfa 2023-05-25) (a long description goes here)' --document-private-items --enable-index-page --show-type-layout --generate-link-to-definition -Zunstable-options` (exit status: 1) ``` --- src/bootstrap/builder.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index cf7c6596c0238..c6200cfe262a5 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -1915,10 +1915,10 @@ impl<'a> Builder<'a> { } // For `cargo doc` invocations, make rustdoc print the Rust version into the docs - // This replaces spaces with newlines because RUSTDOCFLAGS does not + // This replaces spaces with tabs because RUSTDOCFLAGS does not // support arguments with regular spaces. Hopefully someday Cargo will // have space support. - let rust_version = self.rust_version().replace(' ', "\n"); + let rust_version = self.rust_version().replace(' ', "\t"); rustdocflags.arg("--crate-version").arg(&rust_version); // Environment variables *required* throughout the build From 7040d4102f0f3915944369e8d25ebf91f6a99640 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Fri, 26 May 2023 15:21:21 +0200 Subject: [PATCH 35/69] rename metadata_version to format_version The new name is more accurate. --- src/bootstrap/metrics.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/bootstrap/metrics.rs b/src/bootstrap/metrics.rs index 8aa821a3afc07..405a88d756878 100644 --- a/src/bootstrap/metrics.rs +++ b/src/bootstrap/metrics.rs @@ -19,7 +19,7 @@ use sysinfo::{CpuExt, System, SystemExt}; // Versions: // 0: initial version // 1: replaced JsonNode::Test with JsonNode::TestSuite -const CURRENT_METADATA_VERSION: usize = 1; +const CURRENT_FORMAT_VERSION: usize = 1; pub(crate) struct BuildMetrics { state: RefCell, @@ -151,15 +151,15 @@ impl BuildMetrics { // previous invocations are still present in the resulting file. let mut invocations = match std::fs::read(&dest) { Ok(contents) => { - // We first parse just the metadata_version field to have the check succeed even if + // We first parse just the format_version field to have the check succeed even if // the rest of the contents are not valid anymore. - let version: OnlyMetadataVersion = t!(serde_json::from_slice(&contents)); - if version.metadata_version == CURRENT_METADATA_VERSION { + let version: OnlyFormatVersion = t!(serde_json::from_slice(&contents)); + if version.format_version == CURRENT_FORMAT_VERSION { t!(serde_json::from_slice::(&contents)).invocations } else { println!( "warning: overriding existing build/metrics.json, as it's not \ - compatible with build metrics format version {CURRENT_METADATA_VERSION}." + compatible with build metrics format version {CURRENT_FORMAT_VERSION}." ); Vec::new() } @@ -181,8 +181,7 @@ impl BuildMetrics { children: steps.into_iter().map(|step| self.prepare_json_step(step)).collect(), }); - let json = - JsonRoot { metadata_version: CURRENT_METADATA_VERSION, system_stats, invocations }; + let json = JsonRoot { format_version: CURRENT_FORMAT_VERSION, system_stats, invocations }; t!(std::fs::create_dir_all(dest.parent().unwrap())); let mut file = BufWriter::new(t!(File::create(&dest))); @@ -234,7 +233,7 @@ struct StepMetrics { #[serde(rename_all = "snake_case")] struct JsonRoot { #[serde(default)] // For version 0 the field was not present. - metadata_version: usize, + format_version: usize, system_stats: JsonInvocationSystemStats, invocations: Vec, } @@ -322,7 +321,7 @@ struct JsonStepSystemStats { } #[derive(Deserialize)] -struct OnlyMetadataVersion { +struct OnlyFormatVersion { #[serde(default)] // For version 0 the field was not present. - metadata_version: usize, + format_version: usize, } From c5139b9136c25c71f4c5f71335da9aedb8088cbc Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Fri, 26 May 2023 15:25:21 +0200 Subject: [PATCH 36/69] add reasoning for introducing a metrics format version --- src/bootstrap/metrics.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/metrics.rs b/src/bootstrap/metrics.rs index 405a88d756878..5990f33b9bc6c 100644 --- a/src/bootstrap/metrics.rs +++ b/src/bootstrap/metrics.rs @@ -16,9 +16,21 @@ use sysinfo::{CpuExt, System, SystemExt}; // Update this number whenever a breaking change is made to the build metrics. // -// Versions: -// 0: initial version -// 1: replaced JsonNode::Test with JsonNode::TestSuite +// The output format is versioned for two reasons: +// +// - The metadata is intended to be consumed by external tooling, and exposing a format version +// helps the tools determine whether they're compatible with a metrics file. +// +// - If a developer enables build metrics in their local checkout, making a breaking change to the +// metrics format would result in a hard-to-diagnose error message when an existing metrics file +// is not compatible with the new changes. With a format version number, bootstrap can discard +// incompatible metrics files instead of appending metrics to them. +// +// Version changelog: +// +// - v0: initial version +// - v1: replaced JsonNode::Test with JsonNode::TestSuite +// const CURRENT_FORMAT_VERSION: usize = 1; pub(crate) struct BuildMetrics { From c7cec292154873bad0c7a27ce7c8d7ebfc1f320e Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Sat, 20 May 2023 14:42:37 +0300 Subject: [PATCH 37/69] add rustdoc-gui-test tool in triagebot.toml --- triagebot.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index 54c8b2060c526..c20fc5841c68b 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -190,6 +190,7 @@ trigger_files = [ "src/stage0.json", "src/tools/compiletest", "src/tools/tidy", + "src/tools/rustdoc-gui-test", ] [autolabel."T-infra"] @@ -663,3 +664,4 @@ style-team = [ "/src/tools/rustdoc-themes" = ["rustdoc"] "/src/tools/tidy" = ["bootstrap"] "/src/tools/x" = ["bootstrap"] +"/src/tools/rustdoc-gui-test" = ["bootstrap", "@ozkanonur"] From ad77bc8427cb181a4f0e61ba0f85c793139f9512 Mon Sep 17 00:00:00 2001 From: Boxy Date: Fri, 26 May 2023 16:01:23 +0100 Subject: [PATCH 38/69] print const and type errors in braces not square brackets --- compiler/rustc_hir_analysis/src/astconv/mod.rs | 2 +- compiler/rustc_middle/src/ty/print/pretty.rs | 6 +++--- tests/ui/const-generics/transmute-fail.stderr | 8 ++++---- ...closure-sugar-wrong-number-number-type-parameters-1.rs | 2 +- ...ure-sugar-wrong-number-number-type-parameters-1.stderr | 2 +- ...ure-sugar-wrong-number-number-type-parameters-3.stderr | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 5fb06cf94652e..2c60a0624605f 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -1159,7 +1159,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // those that do. self.one_bound_for_assoc_type( || traits::supertraits(tcx, trait_ref), - trait_ref.print_only_trait_path(), + trait_ref.skip_binder().print_only_trait_name(), binding.item_name, path_span, match binding.kind { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index a064174e2616b..d6c88ea96ca43 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -700,7 +700,7 @@ pub trait PrettyPrinter<'tcx>: if verbose { p!(write("{:?}", infer_ty)) } else { p!(write("{}", infer_ty)) } } } - ty::Error(_) => p!("[type error]"), + ty::Error(_) => p!("{{type error}}"), ty::Param(ref param_ty) => p!(print(param_ty)), ty::Bound(debruijn, bound_ty) => match bound_ty.kind { ty::BoundTyKind::Anon => debug_bound_var(&mut self, debruijn, bound_ty.var)?, @@ -1379,8 +1379,8 @@ pub trait PrettyPrinter<'tcx>: }, // FIXME(generic_const_exprs): // write out some legible representation of an abstract const? - ty::ConstKind::Expr(_) => p!("[const expr]"), - ty::ConstKind::Error(_) => p!("[const error]"), + ty::ConstKind::Expr(_) => p!("{{const expr}}"), + ty::ConstKind::Error(_) => p!("{{const error}}"), }; Ok(self) } diff --git a/tests/ui/const-generics/transmute-fail.stderr b/tests/ui/const-generics/transmute-fail.stderr index 41b098135e81e..3d1197afd0f79 100644 --- a/tests/ui/const-generics/transmute-fail.stderr +++ b/tests/ui/const-generics/transmute-fail.stderr @@ -4,8 +4,8 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- LL | std::mem::transmute(v) | ^^^^^^^^^^^^^^^^^^^ | - = note: source type: `[[u32; H+1]; W]` (generic size [const expr]) - = note: target type: `[[u32; W+1]; H]` (generic size [const expr]) + = note: source type: `[[u32; H+1]; W]` (generic size {const expr}) + = note: target type: `[[u32; W+1]; H]` (generic size {const expr}) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/transmute-fail.rs:16:5 @@ -34,8 +34,8 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- LL | std::mem::transmute(v) | ^^^^^^^^^^^^^^^^^^^ | - = note: source type: `[[u32; H]; W]` (generic size [const expr]) - = note: target type: `[u32; W * H * H]` (generic size [const expr]) + = note: source type: `[[u32; H]; W]` (generic size {const expr}) + = note: target type: `[u32; W * H * H]` (generic size {const expr}) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/transmute-fail.rs:30:5 diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs index a6c86311b3772..e7f7fdc513bb7 100644 --- a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs @@ -2,7 +2,7 @@ trait One { fn foo(&self) -> A; } -fn foo(_: &dyn One()) //~ ERROR associated type `Output` not found for `One<()>` +fn foo(_: &dyn One()) //~ ERROR associated type `Output` not found for `One` {} fn main() { } diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.stderr index 59e7bc8c832d6..e4772478bd910 100644 --- a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.stderr +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-1.stderr @@ -1,4 +1,4 @@ -error[E0220]: associated type `Output` not found for `One<()>` +error[E0220]: associated type `Output` not found for `One` --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs:5:16 | LL | fn foo(_: &dyn One()) diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr index 5d7fe3fa533c2..eb18b121957c4 100644 --- a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr @@ -12,7 +12,7 @@ note: trait defined here, with 3 generic parameters: `A`, `B`, `C` LL | trait Three { fn dummy(&self) -> (A,B,C); } | ^^^^^ - - - -error[E0220]: associated type `Output` not found for `Three<(), [type error], [type error]>` +error[E0220]: associated type `Output` not found for `Three` --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs:5:16 | LL | fn foo(_: &dyn Three()) From 3802ba0f6a88355396a4b27b922f6f6b494dbd32 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 26 May 2023 17:31:11 +0200 Subject: [PATCH 39/69] Fix re-export of doc hidden macro not showing up --- src/librustdoc/clean/mod.rs | 3 ++- src/librustdoc/visit_ast.rs | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 59a3e63172406..03adc19e359c1 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2592,7 +2592,8 @@ fn clean_use_statement_inner<'tcx>( } else { if inline_attr.is_none() && let Res::Def(DefKind::Mod, did) = path.res - && !did.is_local() && did.is_crate_root() + && !did.is_local() + && did.is_crate_root() { // if we're `pub use`ing an extern crate root, don't inline it unless we // were specifically asked for it diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 8f8dc6b709053..891574eb46647 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -310,6 +310,16 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } let ret = match tcx.hir().get_by_def_id(res_did) { + // Bang macros are handled a bit on their because of how they are handled by the + // compiler. If they have `#[doc(hidden)]` and the re-export doesn't have + // `#[doc(inline)]`, then we don't inline it. + Node::Item(&hir::Item { kind: hir::ItemKind::Macro(_, MacroKind::Bang), .. }) + if !please_inline + && renamed.is_some() + && self.cx.tcx.is_doc_hidden(ori_res_did) => + { + return false; + } Node::Item(&hir::Item { kind: hir::ItemKind::Mod(ref m), .. }) if glob => { let prev = mem::replace(&mut self.inlining, true); for &i in m.item_ids { From c908d1e4decdb0a6db8280a48baa64f8344acab7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 26 May 2023 17:31:54 +0200 Subject: [PATCH 40/69] Update tests for re-exports of doc hidden macros --- tests/rustdoc/reexport-doc-hidden.rs | 3 +-- tests/rustdoc/reexport-hidden-macro.rs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/rustdoc/reexport-doc-hidden.rs b/tests/rustdoc/reexport-doc-hidden.rs index 3ea5fde72f711..d9ed954868e50 100644 --- a/tests/rustdoc/reexport-doc-hidden.rs +++ b/tests/rustdoc/reexport-doc-hidden.rs @@ -21,6 +21,5 @@ macro_rules! foo { () => {}; } -// This is a bug: https://github.com/rust-lang/rust/issues/59368 -// @!has - '//*[@id="reexport.Macro"]/code' 'pub use crate::foo as Macro;' +// @has - '//*[@id="reexport.Macro"]/code' 'pub use crate::foo as Macro;' pub use crate::foo as Macro; diff --git a/tests/rustdoc/reexport-hidden-macro.rs b/tests/rustdoc/reexport-hidden-macro.rs index afcfa979616ec..e498acbab0b52 100644 --- a/tests/rustdoc/reexport-hidden-macro.rs +++ b/tests/rustdoc/reexport-hidden-macro.rs @@ -15,7 +15,7 @@ macro_rules! foo { () => {}; } -/// not displayed +// @has - '//*[@id="reexport.Macro"]/code' 'pub use crate::foo as Macro;' pub use crate::foo as Macro; /// Displayed #[doc(inline)] From b19466abc26d3815f88b84073c4b31a426015ce0 Mon Sep 17 00:00:00 2001 From: asquared31415 <34665709+asquared31415@users.noreply.github.com> Date: Thu, 25 May 2023 14:48:12 -0400 Subject: [PATCH 41/69] improve error message for calling a method on a raw pointer with an unknown pointee, and add some tests --- compiler/rustc_hir_typeck/messages.ftl | 4 +-- compiler/rustc_hir_typeck/src/errors.rs | 4 +-- compiler/rustc_hir_typeck/src/method/probe.rs | 4 +-- .../edition-raw-pointer-method-2018.rs | 2 +- .../edition-raw-pointer-method-2018.stderr | 2 +- .../ui/methods/call_method_unknown_pointee.rs | 28 +++++++++++++++++++ .../call_method_unknown_pointee.stderr | 27 ++++++++++++++++++ 7 files changed, 63 insertions(+), 8 deletions(-) create mode 100644 tests/ui/methods/call_method_unknown_pointee.rs create mode 100644 tests/ui/methods/call_method_unknown_pointee.stderr diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 9761b1d3facab..3768b53698d64 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -59,8 +59,8 @@ hir_typeck_lang_start_incorrect_param = parameter {$param_num} of the `start` la hir_typeck_lang_start_incorrect_ret_ty = the return type of the `start` lang item is incorrect .suggestion = change the type from `{$found_ty}` to `{$expected_ty}` -hir_typeck_method_call_on_unknown_type = - the type of this value must be known to call a method on a raw pointer on it +hir_typeck_method_call_on_unknown_raw_pointee = + cannot call a method on a raw pointer with an unknown pointee type hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}` diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 102a313067fd2..0ceb5074a04f4 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -49,8 +49,8 @@ pub struct StructExprNonExhaustive { } #[derive(Diagnostic)] -#[diag(hir_typeck_method_call_on_unknown_type, code = "E0699")] -pub struct MethodCallOnUnknownType { +#[diag(hir_typeck_method_call_on_unknown_raw_pointee, code = "E0699")] +pub struct MethodCallOnUnknownRawPointee { #[primary_span] pub span: Span, } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index ba21edea30b1c..9f3d35a77dc75 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -3,7 +3,7 @@ use super::CandidateSource; use super::MethodError; use super::NoMatchData; -use crate::errors::MethodCallOnUnknownType; +use crate::errors::MethodCallOnUnknownRawPointee; use crate::FnCtxt; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -438,7 +438,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // so we do a future-compat lint here for the 2015 edition // (see https://github.com/rust-lang/rust/issues/46906) if self.tcx.sess.rust_2018() { - self.tcx.sess.emit_err(MethodCallOnUnknownType { span }); + self.tcx.sess.emit_err(MethodCallOnUnknownRawPointee { span }); } else { self.tcx.struct_span_lint_hir( lint::builtin::TYVAR_BEHIND_RAW_POINTER, diff --git a/tests/ui/editions/edition-raw-pointer-method-2018.rs b/tests/ui/editions/edition-raw-pointer-method-2018.rs index af0b2d6bd4aa6..0bae65a9ae53d 100644 --- a/tests/ui/editions/edition-raw-pointer-method-2018.rs +++ b/tests/ui/editions/edition-raw-pointer-method-2018.rs @@ -7,5 +7,5 @@ fn main() { let x = 0; let y = &x as *const _; let _ = y.is_null(); - //~^ error: the type of this value must be known to call a method on a raw pointer on it [E0699] + //~^ error: cannot call a method on a raw pointer with an unknown pointee type [E0699] } diff --git a/tests/ui/editions/edition-raw-pointer-method-2018.stderr b/tests/ui/editions/edition-raw-pointer-method-2018.stderr index 23452495b4bc6..b9afa0133cac3 100644 --- a/tests/ui/editions/edition-raw-pointer-method-2018.stderr +++ b/tests/ui/editions/edition-raw-pointer-method-2018.stderr @@ -1,4 +1,4 @@ -error[E0699]: the type of this value must be known to call a method on a raw pointer on it +error[E0699]: cannot call a method on a raw pointer with an unknown pointee type --> $DIR/edition-raw-pointer-method-2018.rs:9:15 | LL | let _ = y.is_null(); diff --git a/tests/ui/methods/call_method_unknown_pointee.rs b/tests/ui/methods/call_method_unknown_pointee.rs new file mode 100644 index 0000000000000..fe4275f5367a9 --- /dev/null +++ b/tests/ui/methods/call_method_unknown_pointee.rs @@ -0,0 +1,28 @@ +// edition: 2018 + +// tests that the pointee type of a raw pointer must be known to call methods on it +// see also: `tests/ui/editions/edition-raw-pointer-method-2018.rs` + +fn main() { + let val = 1_u32; + let ptr = &val as *const u32; + unsafe { + let _a: i32 = (ptr as *const _).read(); + //~^ ERROR cannot call a method on a raw pointer with an unknown pointee type [E0699] + let b = ptr as *const _; + let _b: u8 = b.read(); + //~^ ERROR cannot call a method on a raw pointer with an unknown pointee type [E0699] + let _c = (ptr as *const u8).read(); // we know the type here + } + + let mut val = 2_u32; + let ptr = &mut val as *mut u32; + unsafe { + let _a: i32 = (ptr as *mut _).read(); + //~^ ERROR cannot call a method on a raw pointer with an unknown pointee type [E0699] + let b = ptr as *mut _; + b.write(10); + //~^ ERROR cannot call a method on a raw pointer with an unknown pointee type [E0699] + (ptr as *mut i32).write(1000); // we know the type here + } +} diff --git a/tests/ui/methods/call_method_unknown_pointee.stderr b/tests/ui/methods/call_method_unknown_pointee.stderr new file mode 100644 index 0000000000000..84ecf046e7ac2 --- /dev/null +++ b/tests/ui/methods/call_method_unknown_pointee.stderr @@ -0,0 +1,27 @@ +error[E0699]: cannot call a method on a raw pointer with an unknown pointee type + --> $DIR/call_method_unknown_pointee.rs:10:41 + | +LL | let _a: i32 = (ptr as *const _).read(); + | ^^^^ + +error[E0699]: cannot call a method on a raw pointer with an unknown pointee type + --> $DIR/call_method_unknown_pointee.rs:13:24 + | +LL | let _b: u8 = b.read(); + | ^^^^ + +error[E0699]: cannot call a method on a raw pointer with an unknown pointee type + --> $DIR/call_method_unknown_pointee.rs:21:39 + | +LL | let _a: i32 = (ptr as *mut _).read(); + | ^^^^ + +error[E0699]: cannot call a method on a raw pointer with an unknown pointee type + --> $DIR/call_method_unknown_pointee.rs:24:11 + | +LL | b.write(10); + | ^^^^^ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0699`. From d22314e0f5fdb8ed1181dc1a9d1a85eb54b37c73 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Thu, 25 May 2023 16:53:30 -0400 Subject: [PATCH 42/69] Convert html table to markdown --- src/doc/rustc/src/exploit-mitigations.md | 94 +++--------------------- 1 file changed, 12 insertions(+), 82 deletions(-) diff --git a/src/doc/rustc/src/exploit-mitigations.md b/src/doc/rustc/src/exploit-mitigations.md index a82a53248d485..00417b3a72f78 100644 --- a/src/doc/rustc/src/exploit-mitigations.md +++ b/src/doc/rustc/src/exploit-mitigations.md @@ -55,88 +55,18 @@ Table I \ Summary of exploit mitigations supported by the Rust compiler when building programs for the Linux operating system on the AMD64 architecture and equivalent. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Exploit mitigation - Supported and enabled by default - Since -
Position-independent executable - Yes - 0.12.0 (2014-10-09) -
Integer overflow checks - Yes (enabled when debug assertions are enabled, and disabled when debug assertions are disabled) - 1.1.0 (2015-06-25) -
Non-executable memory regions - Yes - 1.8.0 (2016-04-14) -
Stack clashing protection - Yes - 1.20.0 (2017-08-31) -
Read-only relocations and immediate binding - Yes - 1.21.0 (2017-10-12) -
Heap corruption protection - Yes - 1.32.0 (2019-01-17) (via operating system default or specified allocator) -
Stack smashing protection - Yes - Nightly -
Forward-edge control flow protection - Yes - Nightly -
Backward-edge control flow protection (e.g., shadow and safe stack) - No - -
+ +| Exploit mitigation | Supported and enabled by default | Since | +| - | - | - | +| Position-independent executable | Yes | 0.12.0 (2014-10-09) | +| Integer overflow checks | Yes (enabled when debug assertions are enabled, and disabled when debug assertions are disabled) | 1.1.0 (2015-06-25) | +| Non-executable memory regions | Yes | 1.8.0 (2016-04-14) | +| Stack clashing protection | Yes | 1.20.0 (2017-08-31) | +| Read-only relocations and immediate binding | Yes | 1.21.0 (2017-10-12) | +| Heap corruption protection | Yes | 1.32.0 (2019-01-17) (via operating system default or specified allocator) | +| Stack smashing protection | Yes | Nightly | +| Forward-edge control flow protection | Yes | Nightly | +| Backward-edge control flow protection (e.g., shadow and safe stack) | No | | 1\. See From 019d75b44e3f4349495890453d2d154a8f7ba116 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Fri, 19 May 2023 19:30:15 -0400 Subject: [PATCH 43/69] Add SafeStack support to rustc Adds support for LLVM [SafeStack] which provides backward edge control flow protection by separating the stack into two parts: data which is only accessed in provable safe ways is allocated on the normal stack (the "safe stack") and all other data is placed in a separate allocation (the "unsafe stack"). SafeStack support is enabled by passing `-Zsanitizer=safestack`. [SafeStack]: https://clang.llvm.org/docs/SafeStack.html --- compiler/rustc_codegen_llvm/src/attributes.rs | 3 +++ compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 1 + compiler/rustc_codegen_ssa/src/back/link.rs | 3 +++ .../rustc_llvm/llvm-wrapper/LLVMWrapper.h | 1 + .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 2 ++ compiler/rustc_session/src/options.rs | 3 ++- compiler/rustc_target/src/spec/mod.rs | 4 +++ .../src/spec/x86_64_unknown_linux_gnu.rs | 1 + src/bootstrap/llvm.rs | 2 +- src/doc/rustc/src/exploit-mitigations.md | 27 ++++++++++++++----- .../src/compiler-flags/sanitizer.md | 14 +++++++++- src/tools/compiletest/src/header/needs.rs | 7 +++++ src/tools/compiletest/src/util.rs | 2 ++ .../codegen/sanitizer-safestack-attr-check.rs | 11 ++++++++ 14 files changed, 71 insertions(+), 10 deletions(-) create mode 100644 tests/codegen/sanitizer-safestack-attr-check.rs diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 651d644ebb63d..6d00464e0a0b3 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -88,6 +88,9 @@ pub fn sanitize_attrs<'ll>( attrs.push(llvm::AttributeKind::SanitizeMemTag.create_attr(cx.llcx)); } + if enabled.contains(SanitizerSet::SAFESTACK) { + attrs.push(llvm::AttributeKind::SanitizeSafeStack.create_attr(cx.llcx)); + } attrs } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index de93a64c0d6f5..6ef3418cc5f77 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -196,6 +196,7 @@ pub enum AttributeKind { AllocSize = 37, AllocatedPointer = 38, AllocAlign = 39, + SanitizeSafeStack = 40, } /// LLVMIntPredicate diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 8a00c42a0e8bd..5cc234268b016 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1188,6 +1188,9 @@ fn add_sanitizer_libraries(sess: &Session, crate_type: CrateType, linker: &mut d if sanitizer.contains(SanitizerSet::HWADDRESS) { link_sanitizer_runtime(sess, linker, "hwasan"); } + if sanitizer.contains(SanitizerSet::SAFESTACK) { + link_sanitizer_runtime(sess, linker, "safestack"); + } } fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) { diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h index 0589062837866..af6f4d5eaf998 100644 --- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h +++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h @@ -96,6 +96,7 @@ enum LLVMRustAttribute { AllocatedPointer = 38, AllocAlign = 39, #endif + SanitizeSafeStack = 40, }; typedef struct OpaqueRustString *RustStringRef; diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 49acd71b3e106..ea04899ab6872 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -234,6 +234,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) { case AllocAlign: return Attribute::AllocAlign; #endif + case SanitizeSafeStack: + return Attribute::SafeStack; } report_fatal_error("bad AttributeKind"); } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 2c4c4a7a6ce29..007e720823bfa 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -372,7 +372,7 @@ mod desc { pub const parse_opt_panic_strategy: &str = parse_panic_strategy; pub const parse_oom_strategy: &str = "either `panic` or `abort`"; pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`"; - pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `shadow-call-stack`, or `thread`"; + pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, or `thread`"; pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2"; pub const parse_cfguard: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`"; @@ -694,6 +694,7 @@ mod parse { "shadow-call-stack" => SanitizerSet::SHADOWCALLSTACK, "thread" => SanitizerSet::THREAD, "hwaddress" => SanitizerSet::HWADDRESS, + "safestack" => SanitizerSet::SAFESTACK, _ => return false, } } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index ba4b89c9ea10b..62f94209cf04d 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -815,6 +815,7 @@ bitflags::bitflags! { const SHADOWCALLSTACK = 1 << 7; const KCFI = 1 << 8; const KERNELADDRESS = 1 << 9; + const SAFESTACK = 1 << 10; } } @@ -831,6 +832,7 @@ impl SanitizerSet { SanitizerSet::LEAK => "leak", SanitizerSet::MEMORY => "memory", SanitizerSet::MEMTAG => "memtag", + SanitizerSet::SAFESTACK => "safestack", SanitizerSet::SHADOWCALLSTACK => "shadow-call-stack", SanitizerSet::THREAD => "thread", SanitizerSet::HWADDRESS => "hwaddress", @@ -871,6 +873,7 @@ impl IntoIterator for SanitizerSet { SanitizerSet::THREAD, SanitizerSet::HWADDRESS, SanitizerSet::KERNELADDRESS, + SanitizerSet::SAFESTACK, ] .iter() .copied() @@ -2364,6 +2367,7 @@ impl Target { Some("leak") => SanitizerSet::LEAK, Some("memory") => SanitizerSet::MEMORY, Some("memtag") => SanitizerSet::MEMTAG, + Some("safestack") => SanitizerSet::SAFESTACK, Some("shadow-call-stack") => SanitizerSet::SHADOWCALLSTACK, Some("thread") => SanitizerSet::THREAD, Some("hwaddress") => SanitizerSet::HWADDRESS, diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs index 9af1049b87026..deb15c02c6839 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs @@ -11,6 +11,7 @@ pub fn target() -> Target { | SanitizerSet::CFI | SanitizerSet::LEAK | SanitizerSet::MEMORY + | SanitizerSet::SAFESTACK | SanitizerSet::THREAD; base.supports_xray = true; diff --git a/src/bootstrap/llvm.rs b/src/bootstrap/llvm.rs index 040a12f5d10a4..3fd0cca40e522 100644 --- a/src/bootstrap/llvm.rs +++ b/src/bootstrap/llvm.rs @@ -1017,7 +1017,7 @@ fn supported_sanitizers( "x86_64-unknown-illumos" => common_libs("illumos", "x86_64", &["asan"]), "x86_64-pc-solaris" => common_libs("solaris", "x86_64", &["asan"]), "x86_64-unknown-linux-gnu" => { - common_libs("linux", "x86_64", &["asan", "lsan", "msan", "tsan"]) + common_libs("linux", "x86_64", &["asan", "lsan", "msan", "safestack", "tsan"]) } "x86_64-unknown-linux-musl" => { common_libs("linux", "x86_64", &["asan", "lsan", "msan", "tsan"]) diff --git a/src/doc/rustc/src/exploit-mitigations.md b/src/doc/rustc/src/exploit-mitigations.md index 00417b3a72f78..172048704f48d 100644 --- a/src/doc/rustc/src/exploit-mitigations.md +++ b/src/doc/rustc/src/exploit-mitigations.md @@ -66,7 +66,7 @@ equivalent. | Heap corruption protection | Yes | 1.32.0 (2019-01-17) (via operating system default or specified allocator) | | Stack smashing protection | Yes | Nightly | | Forward-edge control flow protection | Yes | Nightly | -| Backward-edge control flow protection (e.g., shadow and safe stack) | No | | +| Backward-edge control flow protection (e.g., shadow and safe stack) | Yes | Nightly | 1\. See @@ -443,20 +443,21 @@ Newer processors provide hardware assistance for backward-edge control flow protection, such as ARM Pointer Authentication, and Intel Shadow Stack as part of Intel CET. -The Rust compiler does not support shadow or safe stack. There is work -currently ongoing to add support for the sanitizers[40], which may or may -not include support for safe stack
7. +The Rust compiler supports shadow stack for aarch64 only +7 +on nightly Rust compilers [43]-[44]. Safe stack is available on nightly +Rust compilers [45]-[46]. ```text $ readelf -s target/release/hello-rust | grep __safestack_init + 1177: 00000000000057b0 444 FUNC GLOBAL DEFAULT 9 __safestack_init ``` Fig. 16. Checking if LLVM SafeStack is enabled for a given binary. The presence of the `__safestack_init` symbol indicates that LLVM SafeStack -is enabled for a given binary. Conversely, the absence of the +is enabled for a given binary (see Fig. 16). Conversely, the absence of the `__safestack_init` symbol indicates that LLVM SafeStack is not enabled for a -given binary (see Fig. 16). +given binary. 7\. The shadow stack implementation for the AMD64 architecture and equivalent in LLVM was removed due to performance and @@ -628,3 +629,15 @@ defaults (unrelated to `READ_IMPLIES_EXEC`). 42. bbjornse. “add codegen option for using LLVM stack smash protection #84197.” GitHub. + +43. ivanloz. “Add support for LLVM ShadowCallStack. #98208.” GitHub. + . + +44. “ShadowCallStack.” The Rust Unstable Book. + [https://doc.rust-lang.org/unstable-book/compiler-flags/sanitizer.html#shadowcallstack](../unstable-book/compiler-flags/sanitizer.html#shadowcallstack). + +45. W. Wiser. “Add support for LLVM SafeStack #112000” GitHub. + + +46. “SafeStack.” The Rust Unstable Book. + [https://doc.rust-lang/org/unstable-book/compiler-flags/sanitizer.html#safestack](../unstable-book/compiler-flags/sanitizer.html#safestack). diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md index aa776daf09db6..49389b28c8fc7 100644 --- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md +++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md @@ -21,7 +21,8 @@ This feature allows for use of one of following sanitizers: * [MemorySanitizer](#memorysanitizer) a detector of uninitialized reads. * [MemTagSanitizer](#memtagsanitizer) fast memory error detector based on Armv8.5-A Memory Tagging Extension. -* [ShadowCallStack](#shadowcallstack) provides backward-edge control flow protection. +* [SafeStack](#safestack) provides backward-edge control flow protection by separating the stack into safe and unsafe regions. +* [ShadowCallStack](#shadowcallstack) provides backward-edge control flow protection (aarch64 only). * [ThreadSanitizer](#threadsanitizer) a fast data race detector. To enable a sanitizer compile with `-Zsanitizer=address`,`-Zsanitizer=cfi`, @@ -712,6 +713,16 @@ To enable this target feature compile with `-C target-feature="+mte"`. See the [LLVM MemTagSanitizer documentation][llvm-memtag] for more details. +# SafeStack + +SafeStack provides backward edge control flow protection by separating the stack into data which is only accessed safely (the safe stack) and all other data (the unsafe stack). + +SafeStack can be enabled with the `-Zsanitizer=safestack` option and is supported on the following targets: + +* `x86_64-unknown-linux-gnu` + +See the [Clang SafeStack documentation][clang-safestack] for more details. + # ShadowCallStack ShadowCallStack provides backward edge control flow protection by storing a function's return address in a separately allocated 'shadow call stack' and loading the return address from that shadow call stack. @@ -828,6 +839,7 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT [clang-kcfi]: https://clang.llvm.org/docs/ControlFlowIntegrity.html#fsanitize-kcfi [clang-lsan]: https://clang.llvm.org/docs/LeakSanitizer.html [clang-msan]: https://clang.llvm.org/docs/MemorySanitizer.html +[clang-safestack]: https://clang.llvm.org/docs/SafeStack.html [clang-scs]: https://clang.llvm.org/docs/ShadowCallStack.html [clang-tsan]: https://clang.llvm.org/docs/ThreadSanitizer.html [linux-kasan]: https://www.kernel.org/doc/html/latest/dev-tools/kasan.html diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs index 4a57c61406ce4..18b3b913a682f 100644 --- a/src/tools/compiletest/src/header/needs.rs +++ b/src/tools/compiletest/src/header/needs.rs @@ -70,6 +70,11 @@ pub(super) fn handle_needs( condition: cache.sanitizer_shadow_call_stack, ignore_reason: "ignored on targets without shadow call stacks", }, + Need { + name: "needs-sanitizer-safestack", + condition: cache.sanitizer_safestack, + ignore_reason: "ignored on targets without SafeStack support", + }, Need { name: "needs-run-enabled", condition: config.run_enabled(), @@ -184,6 +189,7 @@ pub(super) struct CachedNeedsConditions { sanitizer_hwaddress: bool, sanitizer_memtag: bool, sanitizer_shadow_call_stack: bool, + sanitizer_safestack: bool, xray: bool, rust_lld: bool, i686_dlltool: bool, @@ -220,6 +226,7 @@ impl CachedNeedsConditions { sanitizer_hwaddress: util::HWASAN_SUPPORTED_TARGETS.contains(target), sanitizer_memtag: util::MEMTAG_SUPPORTED_TARGETS.contains(target), sanitizer_shadow_call_stack: util::SHADOWCALLSTACK_SUPPORTED_TARGETS.contains(target), + sanitizer_safestack: util::SAFESTACK_SUPPORTED_TARGETS.contains(target), xray: util::XRAY_SUPPORTED_TARGETS.contains(target), // For tests using the `needs-rust-lld` directive (e.g. for `-Zgcc-ld=lld`), we need to find diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index 748240cc94bc6..17bed38b65e88 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -104,6 +104,8 @@ pub const XRAY_SUPPORTED_TARGETS: &[&str] = &[ "x86_64-unknown-openbsd", ]; +pub const SAFESTACK_SUPPORTED_TARGETS: &[&str] = &["x86_64-unknown-linux-gnu"]; + pub fn make_new_path(path: &str) -> String { assert!(cfg!(windows)); // Windows just uses PATH as the library search path, so we have to diff --git a/tests/codegen/sanitizer-safestack-attr-check.rs b/tests/codegen/sanitizer-safestack-attr-check.rs new file mode 100644 index 0000000000000..b73ed00e7308e --- /dev/null +++ b/tests/codegen/sanitizer-safestack-attr-check.rs @@ -0,0 +1,11 @@ +// This tests that the safestack attribute is applied when enabling the safe-stack sanitizer. +// +// needs-sanitizer-safestack +// compile-flags: -Zsanitizer=safestack + +#![crate_type = "lib"] + +// CHECK: ; Function Attrs:{{.*}}safestack +pub fn tagged() {} + +// CHECK: attributes #0 = {{.*}}safestack From 898dfc680f22b0b07eb569384c5e947d2922d0d5 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 26 May 2023 23:53:14 +0200 Subject: [PATCH 44/69] Correctly handle multiple re-exports of bang macros at the same level --- src/librustdoc/visit_ast.rs | 12 +++++-- tests/rustdoc/reexport-hidden-macro.rs | 2 +- tests/rustdoc/reexport-of-doc-hidden.rs | 42 +++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 tests/rustdoc/reexport-of-doc-hidden.rs diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 891574eb46647..eb813af779ef6 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -305,7 +305,12 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { return false; } - if !self.view_item_stack.insert(res_did) { + let is_bang_macro = matches!( + tcx.hir().get_by_def_id(res_did), + Node::Item(&hir::Item { kind: hir::ItemKind::Macro(_, MacroKind::Bang), .. }) + ); + + if !self.view_item_stack.insert(res_did) && !is_bang_macro { return false; } @@ -313,8 +318,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { // Bang macros are handled a bit on their because of how they are handled by the // compiler. If they have `#[doc(hidden)]` and the re-export doesn't have // `#[doc(inline)]`, then we don't inline it. - Node::Item(&hir::Item { kind: hir::ItemKind::Macro(_, MacroKind::Bang), .. }) - if !please_inline + Node::Item(_) + if is_bang_macro + && !please_inline && renamed.is_some() && self.cx.tcx.is_doc_hidden(ori_res_did) => { diff --git a/tests/rustdoc/reexport-hidden-macro.rs b/tests/rustdoc/reexport-hidden-macro.rs index e498acbab0b52..47a21e3946225 100644 --- a/tests/rustdoc/reexport-hidden-macro.rs +++ b/tests/rustdoc/reexport-hidden-macro.rs @@ -5,6 +5,7 @@ // @has 'foo/index.html' // @has - '//*[@id="main-content"]//a[@href="macro.Macro2.html"]' 'Macro2' +// @has - '//*[@id="reexport.Macro"]/code' 'pub use crate::foo as Macro;' // @has 'foo/macro.Macro2.html' // @has - '//*[@class="docblock"]' 'Displayed' @@ -15,7 +16,6 @@ macro_rules! foo { () => {}; } -// @has - '//*[@id="reexport.Macro"]/code' 'pub use crate::foo as Macro;' pub use crate::foo as Macro; /// Displayed #[doc(inline)] diff --git a/tests/rustdoc/reexport-of-doc-hidden.rs b/tests/rustdoc/reexport-of-doc-hidden.rs new file mode 100644 index 0000000000000..b733716c22a3b --- /dev/null +++ b/tests/rustdoc/reexport-of-doc-hidden.rs @@ -0,0 +1,42 @@ +// This test ensures that all re-exports of doc hidden elements are displayed. + +#![crate_name = "foo"] + +#[doc(hidden)] +pub struct Bar; + +#[macro_export] +#[doc(hidden)] +macro_rules! foo { + () => {}; +} + +// @has 'foo/index.html' +// @has - '//*[@id="reexport.Macro"]/code' 'pub use crate::foo as Macro;' +pub use crate::foo as Macro; +// @has - '//*[@id="reexport.Macro2"]/code' 'pub use crate::foo as Macro2;' +pub use crate::foo as Macro2; +// @has - '//*[@id="reexport.Boo"]/code' 'pub use crate::Bar as Boo;' +pub use crate::Bar as Boo; +// @has - '//*[@id="reexport.Boo2"]/code' 'pub use crate::Bar as Boo2;' +pub use crate::Bar as Boo2; + +pub fn fofo() {} + +// @has - '//*[@id="reexport.f1"]/code' 'pub use crate::fofo as f1;' +pub use crate::fofo as f1; +// @has - '//*[@id="reexport.f2"]/code' 'pub use crate::fofo as f2;' +pub use crate::fofo as f2; + +pub mod sub { + // @has 'foo/sub/index.html' + // @has - '//*[@id="reexport.Macro"]/code' 'pub use crate::foo as Macro;' + pub use crate::foo as Macro; + // @has - '//*[@id="reexport.Macro2"]/code' 'pub use crate::foo as Macro2;' + pub use crate::foo as Macro2; + + // @has - '//*[@id="reexport.f1"]/code' 'pub use crate::fofo as f1;' + pub use crate::fofo as f1; + // @has - '//*[@id="reexport.f2"]/code' 'pub use crate::fofo as f2;' + pub use crate::fofo as f2; +} From 1a77d9a54d1fcf8b2a7aa339fb861d642ad4ff5a Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 26 May 2023 17:29:08 -0700 Subject: [PATCH 45/69] rustdoc: get unnormalized link destination for suggestions Fixes #110111 This bug, and the workaround in this commit, is closely linked to [raphlinus/pulldown-cmark#441], getting offsets of link components. In particular, pulldown-cmark doesn't provide the offsets of the contents of a link. To work around this, rustdoc parser parts of a link definition itself. [raphlinus/pulldown-cmark#441]: https://github.com/raphlinus/pulldown-cmark/issues/441 --- src/librustdoc/html/markdown.rs | 120 +++++++- .../passes/collect_intra_doc_links.rs | 174 +++++++---- .../issue-110495-suffix-with-space.stderr | 7 +- tests/rustdoc-ui/intra-doc/weird-syntax.rs | 140 +++++++++ .../rustdoc-ui/intra-doc/weird-syntax.stderr | 272 ++++++++++++++++++ 5 files changed, 639 insertions(+), 74 deletions(-) create mode 100644 tests/rustdoc-ui/intra-doc/weird-syntax.rs create mode 100644 tests/rustdoc-ui/intra-doc/weird-syntax.stderr diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 09e7ed293d473..9bb20022cfd4c 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1237,7 +1237,27 @@ pub(crate) fn plain_text_summary(md: &str, link_names: &[RenderedLink]) -> Strin pub(crate) struct MarkdownLink { pub kind: LinkType, pub link: String, - pub range: Range, + pub range: MarkdownLinkRange, +} + +#[derive(Clone, Debug)] +pub(crate) enum MarkdownLinkRange { + /// Normally, markdown link warnings point only at the destination. + Destination(Range), + /// In some cases, it's not possible to point at the destination. + /// Usually, this happens because backslashes `\\` are used. + /// When that happens, point at the whole link, and don't provide structured suggestions. + WholeLink(Range), +} + +impl MarkdownLinkRange { + /// Extracts the inner range. + pub fn inner_range(&self) -> &Range { + match self { + MarkdownLinkRange::Destination(range) => range, + MarkdownLinkRange::WholeLink(range) => range, + } + } } pub(crate) fn markdown_links( @@ -1257,9 +1277,9 @@ pub(crate) fn markdown_links( if md_start <= s_start && s_end <= md_end { let start = s_start.offset_from(md_start) as usize; let end = s_end.offset_from(md_start) as usize; - start..end + MarkdownLinkRange::Destination(start..end) } else { - fallback + MarkdownLinkRange::WholeLink(fallback) } }; @@ -1267,6 +1287,7 @@ pub(crate) fn markdown_links( // For diagnostics, we want to underline the link's definition but `span` will point at // where the link is used. This is a problem for reference-style links, where the definition // is separate from the usage. + match link { // `Borrowed` variant means the string (the link's destination) may come directly from // the markdown text and we can locate the original link destination. @@ -1275,8 +1296,80 @@ pub(crate) fn markdown_links( CowStr::Borrowed(s) => locate(s, span), // For anything else, we can only use the provided range. - CowStr::Boxed(_) | CowStr::Inlined(_) => span, + CowStr::Boxed(_) | CowStr::Inlined(_) => MarkdownLinkRange::WholeLink(span), + } + }; + + let span_for_offset_backward = |span: Range, open: u8, close: u8| { + let mut open_brace = !0; + let mut close_brace = !0; + for (i, b) in md.as_bytes()[span.clone()].iter().copied().enumerate().rev() { + let i = i + span.start; + if b == close { + close_brace = i; + break; + } + } + if close_brace < span.start || close_brace >= span.end { + return MarkdownLinkRange::WholeLink(span); + } + let mut nesting = 1; + for (i, b) in md.as_bytes()[span.start..close_brace].iter().copied().enumerate().rev() { + let i = i + span.start; + if b == close { + nesting += 1; + } + if b == open { + nesting -= 1; + } + if nesting == 0 { + open_brace = i; + break; + } + } + assert!(open_brace != close_brace); + if open_brace < span.start || open_brace >= span.end { + return MarkdownLinkRange::WholeLink(span); + } + // do not actually include braces in the span + let range = (open_brace + 1)..close_brace; + MarkdownLinkRange::Destination(range.clone()) + }; + + let span_for_offset_forward = |span: Range, open: u8, close: u8| { + let mut open_brace = !0; + let mut close_brace = !0; + for (i, b) in md.as_bytes()[span.clone()].iter().copied().enumerate() { + let i = i + span.start; + if b == open { + open_brace = i; + break; + } + } + if open_brace < span.start || open_brace >= span.end { + return MarkdownLinkRange::WholeLink(span); } + let mut nesting = 0; + for (i, b) in md.as_bytes()[open_brace..span.end].iter().copied().enumerate() { + let i = i + open_brace; + if b == close { + nesting -= 1; + } + if b == open { + nesting += 1; + } + if nesting == 0 { + close_brace = i; + break; + } + } + assert!(open_brace != close_brace); + if open_brace < span.start || open_brace >= span.end { + return MarkdownLinkRange::WholeLink(span); + } + // do not actually include braces in the span + let range = (open_brace + 1)..close_brace; + MarkdownLinkRange::Destination(range.clone()) }; Parser::new_with_broken_link_callback( @@ -1287,11 +1380,20 @@ pub(crate) fn markdown_links( .into_offset_iter() .filter_map(|(event, span)| match event { Event::Start(Tag::Link(link_type, dest, _)) if may_be_doc_link(link_type) => { - preprocess_link(MarkdownLink { - kind: link_type, - range: span_for_link(&dest, span), - link: dest.into_string(), - }) + let range = match link_type { + // Link is pulled from the link itself. + LinkType::ReferenceUnknown | LinkType::ShortcutUnknown => { + span_for_offset_backward(span, b'[', b']') + } + LinkType::CollapsedUnknown => span_for_offset_forward(span, b'[', b']'), + LinkType::Inline => span_for_offset_backward(span, b'(', b')'), + // Link is pulled from elsewhere in the document. + LinkType::Reference | LinkType::Collapsed | LinkType::Shortcut => { + span_for_link(&dest, span) + } + LinkType::Autolink | LinkType::Email => unreachable!(), + }; + preprocess_link(MarkdownLink { kind: link_type, range, link: dest.into_string() }) } _ => None, }) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 9e6894a77dfa0..417bdd58ad45a 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -31,7 +31,7 @@ use std::ops::Range; use crate::clean::{self, utils::find_nearest_parent_module}; use crate::clean::{Crate, Item, ItemLink, PrimitiveType}; use crate::core::DocContext; -use crate::html::markdown::{markdown_links, MarkdownLink}; +use crate::html::markdown::{markdown_links, MarkdownLink, MarkdownLinkRange}; use crate::lint::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS}; use crate::passes::Pass; use crate::visit::DocVisitor; @@ -248,7 +248,7 @@ struct DiagnosticInfo<'a> { item: &'a Item, dox: &'a str, ori_link: &'a str, - link_range: Range, + link_range: MarkdownLinkRange, } struct LinkCollector<'a, 'tcx> { @@ -833,7 +833,7 @@ impl<'a, 'tcx> DocVisitor for LinkCollector<'a, 'tcx> { enum PreprocessingError { /// User error: `[std#x#y]` is not valid MultipleAnchors, - Disambiguator(Range, String), + Disambiguator(MarkdownLinkRange, String), MalformedGenerics(MalformedGenerics, String), } @@ -873,6 +873,7 @@ pub(crate) struct PreprocessedMarkdownLink( /// `link_buffer` is needed for lifetime reasons; it will always be overwritten and the contents ignored. fn preprocess_link( ori_link: &MarkdownLink, + dox: &str, ) -> Option> { // [] is mostly likely not supposed to be a link if ori_link.link.is_empty() { @@ -906,9 +907,15 @@ fn preprocess_link( Err((err_msg, relative_range)) => { // Only report error if we would not have ignored this link. See issue #83859. if !should_ignore_link_with_disambiguators(link) { - let no_backticks_range = range_between_backticks(ori_link); - let disambiguator_range = (no_backticks_range.start + relative_range.start) - ..(no_backticks_range.start + relative_range.end); + let disambiguator_range = match range_between_backticks(&ori_link.range, dox) { + MarkdownLinkRange::Destination(no_backticks_range) => { + MarkdownLinkRange::Destination( + (no_backticks_range.start + relative_range.start) + ..(no_backticks_range.start + relative_range.end), + ) + } + mdlr @ MarkdownLinkRange::WholeLink(_) => mdlr, + }; return Some(Err(PreprocessingError::Disambiguator(disambiguator_range, err_msg))); } else { return None; @@ -947,7 +954,7 @@ fn preprocess_link( fn preprocessed_markdown_links(s: &str) -> Vec { markdown_links(s, |link| { - preprocess_link(&link).map(|pp_link| PreprocessedMarkdownLink(pp_link, link)) + preprocess_link(&link, s).map(|pp_link| PreprocessedMarkdownLink(pp_link, link)) }) } @@ -1060,22 +1067,12 @@ impl LinkCollector<'_, '_> { // valid omission. See https://github.com/rust-lang/rust/pull/80660#discussion_r551585677 // for discussion on the matter. let kind = self.cx.tcx.def_kind(id); - self.verify_disambiguator( - path_str, - ori_link, - kind, - id, - disambiguator, - item, - &diag_info, - )?; + self.verify_disambiguator(path_str, kind, id, disambiguator, item, &diag_info)?; } else { match disambiguator { Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => {} Some(other) => { - self.report_disambiguator_mismatch( - path_str, ori_link, other, res, &diag_info, - ); + self.report_disambiguator_mismatch(path_str, other, res, &diag_info); return None; } } @@ -1096,7 +1093,6 @@ impl LinkCollector<'_, '_> { }; self.verify_disambiguator( path_str, - ori_link, kind_for_dis, id_for_dis, disambiguator, @@ -1118,7 +1114,6 @@ impl LinkCollector<'_, '_> { fn verify_disambiguator( &self, path_str: &str, - ori_link: &MarkdownLink, kind: DefKind, id: DefId, disambiguator: Option, @@ -1142,7 +1137,7 @@ impl LinkCollector<'_, '_> { => {} (actual, Some(Disambiguator::Kind(expected))) if actual == expected => {} (_, Some(specified @ Disambiguator::Kind(_) | specified @ Disambiguator::Primitive)) => { - self.report_disambiguator_mismatch(path_str,ori_link,specified, Res::Def(kind, id),diag_info); + self.report_disambiguator_mismatch(path_str, specified, Res::Def(kind, id), diag_info); return None; } } @@ -1164,14 +1159,13 @@ impl LinkCollector<'_, '_> { fn report_disambiguator_mismatch( &self, path_str: &str, - ori_link: &MarkdownLink, specified: Disambiguator, resolved: Res, diag_info: &DiagnosticInfo<'_>, ) { // The resolved item did not match the disambiguator; give a better error than 'not found' let msg = format!("incompatible link kind for `{}`", path_str); - let callback = |diag: &mut Diagnostic, sp: Option| { + let callback = |diag: &mut Diagnostic, sp: Option, link_range| { let note = format!( "this link resolved to {} {}, which is not {} {}", resolved.article(), @@ -1184,14 +1178,24 @@ impl LinkCollector<'_, '_> { } else { diag.note(note); } - suggest_disambiguator(resolved, diag, path_str, &ori_link.link, sp); + suggest_disambiguator(resolved, diag, path_str, link_range, sp, diag_info); }; report_diagnostic(self.cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, diag_info, callback); } - fn report_rawptr_assoc_feature_gate(&self, dox: &str, ori_link: &Range, item: &Item) { - let span = super::source_span_for_markdown_range(self.cx.tcx, dox, ori_link, &item.attrs) - .unwrap_or_else(|| item.attr_span(self.cx.tcx)); + fn report_rawptr_assoc_feature_gate( + &self, + dox: &str, + ori_link: &MarkdownLinkRange, + item: &Item, + ) { + let span = super::source_span_for_markdown_range( + self.cx.tcx, + dox, + ori_link.inner_range(), + &item.attrs, + ) + .unwrap_or_else(|| item.attr_span(self.cx.tcx)); rustc_session::parse::feature_err( &self.cx.tcx.sess.parse_sess, sym::intra_doc_pointers, @@ -1371,16 +1375,23 @@ impl LinkCollector<'_, '_> { /// [`Foo`] /// ^^^ /// ``` -fn range_between_backticks(ori_link: &MarkdownLink) -> Range { - let after_first_backtick_group = ori_link.link.bytes().position(|b| b != b'`').unwrap_or(0); - let before_second_backtick_group = ori_link - .link +/// +/// This function does nothing if `ori_link.range` is a `MarkdownLinkRange::WholeLink`. +fn range_between_backticks(ori_link_range: &MarkdownLinkRange, dox: &str) -> MarkdownLinkRange { + let range = match ori_link_range { + mdlr @ MarkdownLinkRange::WholeLink(_) => return mdlr.clone(), + MarkdownLinkRange::Destination(inner) => inner.clone(), + }; + let ori_link_text = &dox[range.clone()]; + let after_first_backtick_group = ori_link_text.bytes().position(|b| b != b'`').unwrap_or(0); + let before_second_backtick_group = ori_link_text .bytes() .skip(after_first_backtick_group) .position(|b| b == b'`') - .unwrap_or(ori_link.link.len()); - (ori_link.range.start + after_first_backtick_group) - ..(ori_link.range.start + before_second_backtick_group) + .unwrap_or(ori_link_text.len()); + MarkdownLinkRange::Destination( + (range.start + after_first_backtick_group)..(range.start + before_second_backtick_group), + ) } /// Returns true if we should ignore `link` due to it being unlikely @@ -1530,14 +1541,23 @@ impl Suggestion { sp: rustc_span::Span, ) -> Vec<(rustc_span::Span, String)> { let inner_sp = match ori_link.find('(') { + Some(index) if index != 0 && ori_link.as_bytes()[index - 1] == b'\\' => { + sp.with_hi(sp.lo() + BytePos((index - 1) as _)) + } Some(index) => sp.with_hi(sp.lo() + BytePos(index as _)), None => sp, }; let inner_sp = match ori_link.find('!') { + Some(index) if index != 0 && ori_link.as_bytes()[index - 1] == b'\\' => { + sp.with_hi(sp.lo() + BytePos((index - 1) as _)) + } Some(index) => inner_sp.with_hi(inner_sp.lo() + BytePos(index as _)), None => inner_sp, }; let inner_sp = match ori_link.find('@') { + Some(index) if index != 0 && ori_link.as_bytes()[index - 1] == b'\\' => { + sp.with_hi(sp.lo() + BytePos((index - 1) as _)) + } Some(index) => inner_sp.with_lo(inner_sp.lo() + BytePos(index as u32 + 1)), None => inner_sp, }; @@ -1584,7 +1604,7 @@ fn report_diagnostic( lint: &'static Lint, msg: impl Into + Display, DiagnosticInfo { item, ori_link: _, dox, link_range }: &DiagnosticInfo<'_>, - decorate: impl FnOnce(&mut Diagnostic, Option), + decorate: impl FnOnce(&mut Diagnostic, Option, MarkdownLinkRange), ) { let Some(hir_id) = DocContext::as_local_hir_id(tcx, item.item_id) else { @@ -1596,16 +1616,32 @@ fn report_diagnostic( let sp = item.attr_span(tcx); tcx.struct_span_lint_hir(lint, hir_id, sp, msg, |lint| { - let span = - super::source_span_for_markdown_range(tcx, dox, link_range, &item.attrs).map(|sp| { - if dox.as_bytes().get(link_range.start) == Some(&b'`') - && dox.as_bytes().get(link_range.end - 1) == Some(&b'`') - { - sp.with_lo(sp.lo() + BytePos(1)).with_hi(sp.hi() - BytePos(1)) - } else { - sp - } - }); + let (span, link_range) = match link_range { + MarkdownLinkRange::Destination(md_range) => { + let mut md_range = md_range.clone(); + let sp = super::source_span_for_markdown_range(tcx, dox, &md_range, &item.attrs) + .map(|mut sp| { + while dox.as_bytes().get(md_range.start) == Some(&b' ') + || dox.as_bytes().get(md_range.start) == Some(&b'`') + { + md_range.start += 1; + sp = sp.with_lo(sp.lo() + BytePos(1)); + } + while dox.as_bytes().get(md_range.end - 1) == Some(&b' ') + || dox.as_bytes().get(md_range.end - 1) == Some(&b'`') + { + md_range.end -= 1; + sp = sp.with_hi(sp.hi() - BytePos(1)); + } + sp + }); + (sp, MarkdownLinkRange::Destination(md_range)) + } + MarkdownLinkRange::WholeLink(md_range) => ( + super::source_span_for_markdown_range(tcx, dox, &md_range, &item.attrs), + link_range.clone(), + ), + }; if let Some(sp) = span { lint.set_span(sp); @@ -1614,21 +1650,22 @@ fn report_diagnostic( // ^ ~~~~ // | link_range // last_new_line_offset - let last_new_line_offset = dox[..link_range.start].rfind('\n').map_or(0, |n| n + 1); + let md_range = link_range.inner_range().clone(); + let last_new_line_offset = dox[..md_range.start].rfind('\n').map_or(0, |n| n + 1); let line = dox[last_new_line_offset..].lines().next().unwrap_or(""); - // Print the line containing the `link_range` and manually mark it with '^'s. + // Print the line containing the `md_range` and manually mark it with '^'s. lint.note(format!( "the link appears in this line:\n\n{line}\n\ {indicator: unreachable!("handled above"), ResolutionFailure::WrongNamespace { res, expected_ns } => { - suggest_disambiguator(res, diag, path_str, diag_info.ori_link, sp); + suggest_disambiguator( + res, + diag, + path_str, + link_range.clone(), + sp, + &diag_info, + ); format!( "this link resolves to {}, which is not in the {} namespace", @@ -1882,7 +1926,7 @@ fn anchor_failure( msg: String, anchor_idx: usize, ) { - report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |diag, sp| { + report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |diag, sp, _link_range| { if let Some(mut sp) = sp { if let Some((fragment_offset, _)) = diag_info.ori_link.char_indices().filter(|(_, x)| *x == '#').nth(anchor_idx) @@ -1898,11 +1942,11 @@ fn anchor_failure( fn disambiguator_error( cx: &DocContext<'_>, mut diag_info: DiagnosticInfo<'_>, - disambiguator_range: Range, + disambiguator_range: MarkdownLinkRange, msg: impl Into + Display, ) { diag_info.link_range = disambiguator_range; - report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |diag, _sp| { + report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |diag, _sp, _link_range| { let msg = format!( "see {}/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators", crate::DOC_RUST_LANG_ORG_CHANNEL @@ -1922,7 +1966,7 @@ fn report_malformed_generics( BROKEN_INTRA_DOC_LINKS, format!("unresolved link to `{}`", path_str), &diag_info, - |diag, sp| { + |diag, sp, _link_range| { let note = match err { MalformedGenerics::UnbalancedAngleBrackets => "unbalanced angle brackets", MalformedGenerics::MissingType => "missing type for generic parameters", @@ -1995,7 +2039,7 @@ fn ambiguity_error( } } - report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, diag_info, |diag, sp| { + report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, diag_info, |diag, sp, link_range| { if let Some(sp) = sp { diag.span_label(sp, "ambiguous link"); } else { @@ -2003,7 +2047,7 @@ fn ambiguity_error( } for res in kinds { - suggest_disambiguator(res, diag, path_str, diag_info.ori_link, sp); + suggest_disambiguator(res, diag, path_str, link_range.clone(), sp, diag_info); } }); true @@ -2015,13 +2059,19 @@ fn suggest_disambiguator( res: Res, diag: &mut Diagnostic, path_str: &str, - ori_link: &str, + link_range: MarkdownLinkRange, sp: Option, + diag_info: &DiagnosticInfo<'_>, ) { let suggestion = res.disambiguator_suggestion(); let help = format!("to link to the {}, {}", res.descr(), suggestion.descr()); - if let Some(sp) = sp { + let ori_link = match link_range { + MarkdownLinkRange::Destination(range) => Some(&diag_info.dox[range]), + MarkdownLinkRange::WholeLink(_) => None, + }; + + if let (Some(sp), Some(ori_link)) = (sp, ori_link) { let mut spans = suggestion.as_help_span(path_str, ori_link, sp); if spans.len() > 1 { diag.multipart_suggestion(help, spans, Applicability::MaybeIncorrect); @@ -2047,7 +2097,7 @@ fn privacy_error(cx: &DocContext<'_>, diag_info: &DiagnosticInfo<'_>, path_str: let msg = format!("public documentation for `{}` links to private item `{}`", item_name, path_str); - report_diagnostic(cx.tcx, PRIVATE_INTRA_DOC_LINKS, msg, diag_info, |diag, sp| { + report_diagnostic(cx.tcx, PRIVATE_INTRA_DOC_LINKS, msg, diag_info, |diag, sp, _link_range| { if let Some(sp) = sp { diag.span_label(sp, "this item is private"); } diff --git a/tests/rustdoc-ui/intra-doc/issue-110495-suffix-with-space.stderr b/tests/rustdoc-ui/intra-doc/issue-110495-suffix-with-space.stderr index 8669b0c20865c..6c834fd0a1b61 100644 --- a/tests/rustdoc-ui/intra-doc/issue-110495-suffix-with-space.stderr +++ b/tests/rustdoc-ui/intra-doc/issue-110495-suffix-with-space.stderr @@ -36,7 +36,7 @@ LL | //! [`Clone ()`]. help: to link to the trait, prefix with `trait@` | LL - //! [`Clone ()`]. -LL + //! [`trait@Clone (`]. +LL + //! [`trait@Clone `]. | error: incompatible link kind for `Clone` @@ -47,8 +47,9 @@ LL | //! [`Clone !`]. | help: to link to the derive macro, prefix with `derive@` | -LL | //! [`derive@Clone !`]. - | +++++++ +LL - //! [`Clone !`]. +LL + //! [`derive@Clone `]. + | error: aborting due to 4 previous errors diff --git a/tests/rustdoc-ui/intra-doc/weird-syntax.rs b/tests/rustdoc-ui/intra-doc/weird-syntax.rs new file mode 100644 index 0000000000000..ca18842fb21c5 --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/weird-syntax.rs @@ -0,0 +1,140 @@ +// Many examples are from +// https://github.com/rust-lang/rust/issues/110111#issuecomment-1517800781 +#![deny(rustdoc::broken_intra_doc_links)] + +//! This test case is closely linked to [raphlinus/pulldown-cmark#441], getting offsets of +//! link components. In particular, pulldown-cmark doesn't provide the offsets of the contents +//! of a link. +//! +//! To work around this, rustdoc parses parts of a link definition itself. This is basically a +//! test suite for that link syntax parser. +//! +//! [raphlinus/pulldown-cmark#441]: https://github.com/raphlinus/pulldown-cmark/issues/441 + +use std::clone::Clone; + +// Basic version // + +/// [`struct@Clone`] //~ERROR link +pub struct LinkToCloneWithBackquotes; + +/// [```struct@Clone```] //~ERROR link +pub struct LinkToCloneWithMultipleBackquotes; + +/// [ ` struct@Clone ` ] //~ERROR link +pub struct LinkToCloneWithSpacesAndBackquotes; + +/// [ `Clone ()` ] //~ERROR link +pub struct LinkToCloneWithSpacesBackquotesAndParens; + +/// [`Clone ()` ] //~ERROR link +pub struct LinkToCloneWithSpacesEndBackquotesAndParens; + +/// [ `Clone ()`] //~ERROR link +pub struct LinkToCloneWithSpacesStartBackquotesAndParens; + +/// [```Clone ()```] //~ERROR link +pub struct LinkToCloneWithMultipleBackquotesAndParens; + +/// [```Clone \(\)```] // not URL-shaped enough +pub struct LinkToCloneWithMultipleBackquotesAndEscapedParens; + +/// [ ``` Clone () ``` ] //~ERROR link +pub struct LinkToCloneWithSpacesMultipleBackquotesAndParens; + +/// [ x \] ] // not URL-shaped enough +pub struct LinkWithEscapedCloseBrace; + +/// [ x \[ ] // not URL-shaped enough +pub struct LinkWithEscapedOpenBrace; + +/// [ x \( ] // not URL-shaped enough +pub struct LinkWithEscapedCloseParen; + +/// [ x \) ] // not URL-shaped enough +pub struct LinkWithEscapedOpenParen; + +/// [ Clone \(\) ] // not URL-shaped enough +pub struct LinkWithEscapedParens; + +// [][] version // + +/// [x][ struct@Clone] //~ERROR link +pub struct XLinkToCloneWithStartSpace; + +/// [x][struct@Clone ] //~ERROR link +pub struct XLinkToCloneWithEndSpace; + +/// [x][Clone\(\)] not URL-shaped enough +pub struct XLinkToCloneWithEscapedParens; + +/// [x][`Clone`] not URL-shaped enough +pub struct XLinkToCloneWithBackquotes; + +/// [x][Clone()] //~ERROR link +pub struct XLinkToCloneWithUnescapedParens; + +/// [x][Clone ()] //~ERROR link +pub struct XLinkToCloneWithUnescapedParensAndDoubleSpace; + +/// [x][Clone [] //~ERROR unresolved link to `x` +pub struct XLinkToCloneWithUnmatchedOpenParenAndDoubleSpace; + +/// [x][Clone \[] // not URL-shaped enough +pub struct XLinkToCloneWithUnmatchedEscapedOpenParenAndDoubleSpace; + +/// [x][Clone \]] // not URL-shaped enough +pub struct XLinkToCloneWithUnmatchedEscapedCloseParenAndDoubleSpace; + +// []() version // + +/// [w]( struct@Clone) //~ERROR link +pub struct WLinkToCloneWithStartSpace; + +/// [w](struct@Clone ) //~ERROR link +pub struct WLinkToCloneWithEndSpace; + +/// [w](Clone\(\)) //~ERROR link +pub struct WLinkToCloneWithEscapedParens; + +/// [w](`Clone`) not URL-shaped enough +pub struct WLinkToCloneWithBackquotes; + +/// [w](Clone()) //~ERROR link +pub struct WLinkToCloneWithUnescapedParens; + +/// [w](Clone ()) not URL-shaped enough +pub struct WLinkToCloneWithUnescapedParensAndDoubleSpace; + +/// [w](Clone () //~ERROR unresolved link to `w` +pub struct WLinkToCloneWithUnmatchedOpenParenAndDoubleSpace; + +/// [w](Clone \() //~ERROR unresolved link to `w` +pub struct WLinkToCloneWithUnmatchedEscapedOpenParenAndDoubleSpace; + +/// [w](Clone \)) //~ERROR unresolved link to `w` +pub struct WLinkToCloneWithUnmatchedEscapedCloseParenAndDoubleSpace; + +// References + +/// The [cln][] link here is going to be unresolved, because `Clone()` gets rejected //~ERROR link +/// in Markdown for not being URL-shaped enough. +/// +/// [cln]: Clone() //~ERROR link +pub struct LinkToCloneWithParensInReference; + +/// The [cln][] link here is going to be unresolved, because `struct@Clone` gets //~ERROR link +/// rejected in Markdown for not being URL-shaped enough. +/// +/// [cln]: struct@Clone //~ERROR link +pub struct LinkToCloneWithWrongPrefix; + +/// The [cln][] link here will produce a plain text suggestion //~ERROR link +/// +/// [cln]: Clone\(\) +pub struct LinkToCloneWithEscapedParensInReference; + +/// The [cln][] link here will produce a plain text suggestion //~ERROR link +/// +/// [cln]: struct\@Clone +pub struct LinkToCloneWithEscapedAtsInReference; diff --git a/tests/rustdoc-ui/intra-doc/weird-syntax.stderr b/tests/rustdoc-ui/intra-doc/weird-syntax.stderr new file mode 100644 index 0000000000000..f50feb57fccf2 --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/weird-syntax.stderr @@ -0,0 +1,272 @@ +error: incompatible link kind for `Clone` + --> $DIR/weird-syntax.rs:18:7 + | +LL | /// [`struct@Clone`] + | ^^^^^^^^^^^^ this link resolved to a trait, which is not a struct + | +note: the lint level is defined here + --> $DIR/weird-syntax.rs:3:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: to link to the trait, prefix with `trait@` + | +LL | /// [`trait@Clone`] + | ~~~~~~ + +error: incompatible link kind for `Clone` + --> $DIR/weird-syntax.rs:21:9 + | +LL | /// [```struct@Clone```] + | ^^^^^^^^^^^^ this link resolved to a trait, which is not a struct + | +help: to link to the trait, prefix with `trait@` + | +LL | /// [```trait@Clone```] + | ~~~~~~ + +error: incompatible link kind for `Clone` + --> $DIR/weird-syntax.rs:24:11 + | +LL | /// [ ` struct@Clone ` ] + | ^^^^^^^^^^^^ this link resolved to a trait, which is not a struct + | +help: to link to the trait, prefix with `trait@` + | +LL | /// [ ` trait@Clone ` ] + | ~~~~~~ + +error: unresolved link to `Clone` + --> $DIR/weird-syntax.rs:27:9 + | +LL | /// [ `Clone ()` ] + | ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | +help: to link to the trait, prefix with `trait@` + | +LL - /// [ `Clone ()` ] +LL + /// [ `trait@Clone ` ] + | + +error: unresolved link to `Clone` + --> $DIR/weird-syntax.rs:30:7 + | +LL | /// [`Clone ()` ] + | ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | +help: to link to the trait, prefix with `trait@` + | +LL - /// [`Clone ()` ] +LL + /// [`trait@Clone ` ] + | + +error: unresolved link to `Clone` + --> $DIR/weird-syntax.rs:33:9 + | +LL | /// [ `Clone ()`] + | ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | +help: to link to the trait, prefix with `trait@` + | +LL - /// [ `Clone ()`] +LL + /// [ `trait@Clone `] + | + +error: unresolved link to `Clone` + --> $DIR/weird-syntax.rs:36:9 + | +LL | /// [```Clone ()```] + | ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | +help: to link to the trait, prefix with `trait@` + | +LL - /// [```Clone ()```] +LL + /// [```trait@Clone ```] + | + +error: unresolved link to `Clone` + --> $DIR/weird-syntax.rs:42:13 + | +LL | /// [ ``` Clone () ``` ] + | ^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | +help: to link to the trait, prefix with `trait@` + | +LL - /// [ ``` Clone () ``` ] +LL + /// [ ``` trait@Clone ``` ] + | + +error: incompatible link kind for `Clone` + --> $DIR/weird-syntax.rs:62:10 + | +LL | /// [x][ struct@Clone] + | ^^^^^^^^^^^^ this link resolved to a trait, which is not a struct + | +help: to link to the trait, prefix with `trait@` + | +LL | /// [x][ trait@Clone] + | ~~~~~~ + +error: incompatible link kind for `Clone` + --> $DIR/weird-syntax.rs:65:9 + | +LL | /// [x][struct@Clone ] + | ^^^^^^^^^^^^ this link resolved to a trait, which is not a struct + | +help: to link to the trait, prefix with `trait@` + | +LL | /// [x][trait@Clone ] + | ~~~~~~ + +error: unresolved link to `Clone` + --> $DIR/weird-syntax.rs:74:9 + | +LL | /// [x][Clone()] + | ^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | +help: to link to the trait, prefix with `trait@` + | +LL - /// [x][Clone()] +LL + /// [x][trait@Clone] + | + +error: unresolved link to `Clone` + --> $DIR/weird-syntax.rs:77:9 + | +LL | /// [x][Clone ()] + | ^^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | +help: to link to the trait, prefix with `trait@` + | +LL - /// [x][Clone ()] +LL + /// [x][trait@Clone ] + | + +error: unresolved link to `x` + --> $DIR/weird-syntax.rs:80:6 + | +LL | /// [x][Clone [] + | ^ no item named `x` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: incompatible link kind for `Clone` + --> $DIR/weird-syntax.rs:91:10 + | +LL | /// [w]( struct@Clone) + | ^^^^^^^^^^^^ this link resolved to a trait, which is not a struct + | +help: to link to the trait, prefix with `trait@` + | +LL | /// [w]( trait@Clone) + | ~~~~~~ + +error: incompatible link kind for `Clone` + --> $DIR/weird-syntax.rs:94:9 + | +LL | /// [w](struct@Clone ) + | ^^^^^^^^^^^^ this link resolved to a trait, which is not a struct + | +help: to link to the trait, prefix with `trait@` + | +LL | /// [w](trait@Clone ) + | ~~~~~~ + +error: unresolved link to `Clone` + --> $DIR/weird-syntax.rs:97:9 + | +LL | /// [w](Clone\(\)) + | ^^^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | +help: to link to the trait, prefix with `trait@` + | +LL - /// [w](Clone\(\)) +LL + /// [w](trait@Clone) + | + +error: unresolved link to `Clone` + --> $DIR/weird-syntax.rs:103:9 + | +LL | /// [w](Clone()) + | ^^^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | +help: to link to the trait, prefix with `trait@` + | +LL - /// [w](Clone()) +LL + /// [w](trait@Clone) + | + +error: unresolved link to `w` + --> $DIR/weird-syntax.rs:109:6 + | +LL | /// [w](Clone () + | ^ no item named `w` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unresolved link to `w` + --> $DIR/weird-syntax.rs:112:6 + | +LL | /// [w](Clone \() + | ^ no item named `w` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unresolved link to `w` + --> $DIR/weird-syntax.rs:115:6 + | +LL | /// [w](Clone \)) + | ^ no item named `w` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unresolved link to `cln` + --> $DIR/weird-syntax.rs:120:10 + | +LL | /// The [cln][] link here is going to be unresolved, because `Clone()` gets rejected + | ^^^ no item named `cln` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unresolved link to `cln` + --> $DIR/weird-syntax.rs:123:6 + | +LL | /// [cln]: Clone() + | ^^^ no item named `cln` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unresolved link to `cln` + --> $DIR/weird-syntax.rs:126:10 + | +LL | /// The [cln][] link here is going to be unresolved, because `struct@Clone` gets + | ^^^ no item named `cln` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unresolved link to `cln` + --> $DIR/weird-syntax.rs:129:6 + | +LL | /// [cln]: struct@Clone + | ^^^ no item named `cln` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unresolved link to `Clone` + --> $DIR/weird-syntax.rs:132:9 + | +LL | /// The [cln][] link here will produce a plain text suggestion + | ^^^^^ this link resolves to the trait `Clone`, which is not in the value namespace + | + = help: to link to the trait, prefix with `trait@`: trait@Clone + +error: incompatible link kind for `Clone` + --> $DIR/weird-syntax.rs:137:9 + | +LL | /// The [cln][] link here will produce a plain text suggestion + | ^^^^^ this link resolved to a trait, which is not a struct + | + = help: to link to the trait, prefix with `trait@`: trait@Clone + +error: aborting due to 26 previous errors + From a25aee19575d59709e51b5c214fe49af7090e69d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 25 May 2023 17:48:19 +0000 Subject: [PATCH 46/69] Perform MIR type ops locally in new solver --- .../traits/query/type_op/ascribe_user_type.rs | 8 ++++++ .../src/traits/query/type_op/eq.rs | 10 ++++++++ .../query/type_op/implied_outlives_bounds.rs | 8 ++++++ .../src/traits/query/type_op/mod.rs | 25 ++++++++++++++++++- .../src/traits/query/type_op/normalize.rs | 10 ++++++++ .../src/traits/query/type_op/outlives.rs | 8 ++++++ .../traits/query/type_op/prove_predicate.rs | 16 ++++++++++++ .../src/traits/query/type_op/subtype.rs | 10 ++++++++ 8 files changed, 94 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs index c61f5454ec52e..a2cfdeefd6f30 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs @@ -1,4 +1,5 @@ use crate::infer::canonical::{Canonical, CanonicalQueryResponse}; +use crate::traits::ObligationCtxt; use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; @@ -20,4 +21,11 @@ impl<'tcx> super::QueryTypeOp<'tcx> for AscribeUserType<'tcx> { ) -> Result, NoSolution> { tcx.type_op_ascribe_user_type(canonicalized) } + + fn perform_locally_in_new_solver( + _ocx: &ObligationCtxt<'_, 'tcx>, + _key: ParamEnvAnd<'tcx, Self>, + ) -> Result { + todo!() + } } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs index 40f8ecfd4ce10..f65893088066e 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs @@ -1,5 +1,7 @@ use crate::infer::canonical::{Canonical, CanonicalQueryResponse}; +use crate::traits::ObligationCtxt; use rustc_middle::traits::query::NoSolution; +use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; pub use rustc_middle::traits::query::type_op::Eq; @@ -20,4 +22,12 @@ impl<'tcx> super::QueryTypeOp<'tcx> for Eq<'tcx> { ) -> Result, NoSolution> { tcx.type_op_eq(canonicalized) } + + fn perform_locally_in_new_solver( + ocx: &ObligationCtxt<'_, 'tcx>, + key: ParamEnvAnd<'tcx, Self>, + ) -> Result { + ocx.eq(&ObligationCause::dummy(), key.param_env, key.value.a, key.value.b)?; + Ok(()) + } } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index 26f0d554d3508..9054bafc4a67a 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -1,4 +1,5 @@ use crate::infer::canonical::{Canonical, CanonicalQueryResponse}; +use crate::traits::ObligationCtxt; use rustc_infer::traits::query::OutlivesBound; use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt}; @@ -39,4 +40,11 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ImpliedOutlivesBounds<'tcx> { tcx.implied_outlives_bounds(canonicalized) } + + fn perform_locally_in_new_solver( + _ocx: &ObligationCtxt<'_, 'tcx>, + _key: ParamEnvAnd<'tcx, Self>, + ) -> Result { + todo!() + } } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs index 6423265984804..642fdec2d9ae3 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -2,7 +2,7 @@ use crate::infer::canonical::{ Canonical, CanonicalQueryResponse, OriginalQueryValues, QueryRegionConstraints, }; use crate::infer::{InferCtxt, InferOk}; -use crate::traits::ObligationCause; +use crate::traits::{ObligationCause, ObligationCtxt}; use rustc_errors::ErrorGuaranteed; use rustc_infer::infer::canonical::Certainty; use rustc_infer::traits::PredicateObligations; @@ -23,6 +23,8 @@ pub mod subtype; pub use rustc_middle::traits::query::type_op::*; +use self::custom::scrape_region_constraints; + /// "Type ops" are used in NLL to perform some particular action and /// extract out the resulting region constraints (or an error if it /// cannot be completed). @@ -81,6 +83,17 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable> + 't canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>, ) -> Result, NoSolution>; + /// In the new trait solver, we already do caching in the solver itself, + /// so there's no need to canonicalize and cache via the query system. + /// Additionally, even if we were to canonicalize, we'd still need to + /// make sure to feed it predefined opaque types and the defining anchor + /// and that would require duplicating all of the tcx queries. Instead, + /// just perform these ops locally. + fn perform_locally_in_new_solver( + ocx: &ObligationCtxt<'_, 'tcx>, + key: ParamEnvAnd<'tcx, Self>, + ) -> Result; + fn fully_perform_into( query_key: ParamEnvAnd<'tcx, Self>, infcx: &InferCtxt<'tcx>, @@ -133,6 +146,16 @@ where infcx: &InferCtxt<'tcx>, span: Span, ) -> Result, ErrorGuaranteed> { + if infcx.tcx.trait_solver_next() { + return Ok(scrape_region_constraints( + infcx, + |ocx| QueryTypeOp::perform_locally_in_new_solver(ocx, self), + "query type op", + span, + )? + .0); + } + let mut region_constraints = QueryRegionConstraints::default(); let (output, error_info, mut obligations, _) = Q::fully_perform_into(self, infcx, &mut region_constraints).map_err(|_| { diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs index 776c74fdfae4b..57ca14aa492ff 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs @@ -1,5 +1,7 @@ use crate::infer::canonical::{Canonical, CanonicalQueryResponse}; +use crate::traits::ObligationCtxt; use rustc_middle::traits::query::NoSolution; +use rustc_middle::traits::ObligationCause; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt}; use std::fmt; @@ -22,6 +24,14 @@ where ) -> Result, NoSolution> { T::type_op_method(tcx, canonicalized) } + + fn perform_locally_in_new_solver( + ocx: &ObligationCtxt<'_, 'tcx>, + key: ParamEnvAnd<'tcx, Self>, + ) -> Result { + // FIXME(-Ztrait-solver=next): shouldn't be using old normalizer + Ok(ocx.normalize(&ObligationCause::dummy(), key.param_env, key.value.value)) + } } pub trait Normalizable<'tcx>: fmt::Debug + TypeFoldable> + Lift<'tcx> + Copy { diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs index 7ce09bbdb7af3..8b3a20a88f03e 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs @@ -1,5 +1,6 @@ use crate::infer::canonical::{Canonical, CanonicalQueryResponse}; use crate::traits::query::dropck_outlives::{trivial_dropck_outlives, DropckOutlivesResult}; +use crate::traits::ObligationCtxt; use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt}; @@ -48,4 +49,11 @@ impl<'tcx> super::QueryTypeOp<'tcx> for DropckOutlives<'tcx> { tcx.dropck_outlives(canonicalized) } + + fn perform_locally_in_new_solver( + _ocx: &ObligationCtxt<'_, 'tcx>, + _key: ParamEnvAnd<'tcx, Self>, + ) -> Result { + todo!() + } } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs index 7c02f363960d7..47850bc330dab 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs @@ -1,5 +1,8 @@ use crate::infer::canonical::{Canonical, CanonicalQueryResponse}; +use crate::traits::ObligationCtxt; +use rustc_infer::traits::Obligation; use rustc_middle::traits::query::NoSolution; +use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt}; pub use rustc_middle::traits::query::type_op::ProvePredicate; @@ -36,4 +39,17 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> { ) -> Result, NoSolution> { tcx.type_op_prove_predicate(canonicalized) } + + fn perform_locally_in_new_solver( + ocx: &ObligationCtxt<'_, 'tcx>, + key: ParamEnvAnd<'tcx, Self>, + ) -> Result { + ocx.register_obligation(Obligation::new( + ocx.infcx.tcx, + ObligationCause::dummy(), + key.param_env, + key.value.predicate, + )); + Ok(()) + } } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs index 2f2b931afcff4..10976d5cd7162 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs @@ -1,5 +1,7 @@ use crate::infer::canonical::{Canonical, CanonicalQueryResponse}; +use crate::traits::ObligationCtxt; use rustc_middle::traits::query::NoSolution; +use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; pub use rustc_middle::traits::query::type_op::Subtype; @@ -17,4 +19,12 @@ impl<'tcx> super::QueryTypeOp<'tcx> for Subtype<'tcx> { ) -> Result, NoSolution> { tcx.type_op_subtype(canonicalized) } + + fn perform_locally_in_new_solver( + ocx: &ObligationCtxt<'_, 'tcx>, + key: ParamEnvAnd<'tcx, Self>, + ) -> Result { + ocx.sub(&ObligationCause::dummy(), key.param_env, key.value.sub, key.value.sup)?; + Ok(()) + } } From d7a2fdd4dba976fddfebe4b3be95a327bae39423 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 25 May 2023 18:25:44 +0000 Subject: [PATCH 47/69] Uplift complex type ops back into typeck so we can call them locally --- .../src/type_check/liveness/trace.rs | 2 +- .../src/traits/query/dropck_outlives.rs | 269 +++++++++++++++++- .../traits/query/type_op/ascribe_user_type.rs | 117 +++++++- .../query/type_op/implied_outlives_bounds.rs | 177 +++++++++++- .../src/traits/query/type_op/outlives.rs | 12 +- compiler/rustc_traits/src/dropck_outlives.rs | 266 +---------------- .../src/implied_outlives_bounds.rs | 169 +---------- compiler/rustc_traits/src/lib.rs | 3 +- compiler/rustc_traits/src/type_op.rs | 117 +------- 9 files changed, 574 insertions(+), 558 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index fd94ac86d7dc2..eb02604b9d925 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -3,9 +3,9 @@ use rustc_index::bit_set::HybridBitSet; use rustc_index::interval::IntervalSet; use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location}; +use rustc_middle::traits::query::DropckOutlivesResult; use rustc_middle::ty::{Ty, TyCtxt, TypeVisitable, TypeVisitableExt}; use rustc_span::DUMMY_SP; -use rustc_trait_selection::traits::query::dropck_outlives::DropckOutlivesResult; use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives; use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; use std::rc::Rc; diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index 455b53bfb7d8f..4e4172e7f41ec 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -1,6 +1,11 @@ -use rustc_middle::ty::{self, Ty, TyCtxt}; +use crate::traits::query::normalize::QueryNormalizeExt; +use crate::traits::query::NoSolution; +use crate::traits::{Normalized, ObligationCause, ObligationCtxt}; -pub use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult}; +use rustc_data_structures::fx::FxHashSet; +use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult}; +use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, Ty, TyCtxt}; +use rustc_span::source_map::{Span, DUMMY_SP}; /// This returns true if the type `ty` is "trivial" for /// dropck-outlives -- that is, if it doesn't require any types to @@ -71,3 +76,263 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { | ty::Generator(..) => false, } } + +pub fn compute_dropck_outlives_inner<'tcx>( + ocx: &ObligationCtxt<'_, 'tcx>, + goal: ParamEnvAnd<'tcx, Ty<'tcx>>, +) -> Result, NoSolution> { + let tcx = ocx.infcx.tcx; + let ParamEnvAnd { param_env, value: for_ty } = goal; + + let mut result = DropckOutlivesResult { kinds: vec![], overflows: vec![] }; + + // A stack of types left to process. Each round, we pop + // something from the stack and invoke + // `dtorck_constraint_for_ty_inner`. This may produce new types that + // have to be pushed on the stack. This continues until we have explored + // all the reachable types from the type `for_ty`. + // + // Example: Imagine that we have the following code: + // + // ```rust + // struct A { + // value: B, + // children: Vec, + // } + // + // struct B { + // value: u32 + // } + // + // fn f() { + // let a: A = ...; + // .. + // } // here, `a` is dropped + // ``` + // + // at the point where `a` is dropped, we need to figure out + // which types inside of `a` contain region data that may be + // accessed by any destructors in `a`. We begin by pushing `A` + // onto the stack, as that is the type of `a`. We will then + // invoke `dtorck_constraint_for_ty_inner` which will expand `A` + // into the types of its fields `(B, Vec)`. These will get + // pushed onto the stack. Eventually, expanding `Vec` will + // lead to us trying to push `A` a second time -- to prevent + // infinite recursion, we notice that `A` was already pushed + // once and stop. + let mut ty_stack = vec![(for_ty, 0)]; + + // Set used to detect infinite recursion. + let mut ty_set = FxHashSet::default(); + + let cause = ObligationCause::dummy(); + let mut constraints = DropckConstraint::empty(); + while let Some((ty, depth)) = ty_stack.pop() { + debug!( + "{} kinds, {} overflows, {} ty_stack", + result.kinds.len(), + result.overflows.len(), + ty_stack.len() + ); + dtorck_constraint_for_ty_inner(tcx, DUMMY_SP, for_ty, depth, ty, &mut constraints)?; + + // "outlives" represent types/regions that may be touched + // by a destructor. + result.kinds.append(&mut constraints.outlives); + result.overflows.append(&mut constraints.overflows); + + // If we have even one overflow, we should stop trying to evaluate further -- + // chances are, the subsequent overflows for this evaluation won't provide useful + // information and will just decrease the speed at which we can emit these errors + // (since we'll be printing for just that much longer for the often enormous types + // that result here). + if !result.overflows.is_empty() { + break; + } + + // dtorck types are "types that will get dropped but which + // do not themselves define a destructor", more or less. We have + // to push them onto the stack to be expanded. + for ty in constraints.dtorck_types.drain(..) { + let Normalized { value: ty, obligations } = + ocx.infcx.at(&cause, param_env).query_normalize(ty)?; + ocx.register_obligations(obligations); + + debug!("dropck_outlives: ty from dtorck_types = {:?}", ty); + + match ty.kind() { + // All parameters live for the duration of the + // function. + ty::Param(..) => {} + + // A projection that we couldn't resolve - it + // might have a destructor. + ty::Alias(..) => { + result.kinds.push(ty.into()); + } + + _ => { + if ty_set.insert(ty) { + ty_stack.push((ty, depth + 1)); + } + } + } + } + } + + debug!("dropck_outlives: result = {:#?}", result); + Ok(result) +} + +/// Returns a set of constraints that needs to be satisfied in +/// order for `ty` to be valid for destruction. +pub fn dtorck_constraint_for_ty_inner<'tcx>( + tcx: TyCtxt<'tcx>, + span: Span, + for_ty: Ty<'tcx>, + depth: usize, + ty: Ty<'tcx>, + constraints: &mut DropckConstraint<'tcx>, +) -> Result<(), NoSolution> { + debug!("dtorck_constraint_for_ty_inner({:?}, {:?}, {:?}, {:?})", span, for_ty, depth, ty); + + if !tcx.recursion_limit().value_within_limit(depth) { + constraints.overflows.push(ty); + return Ok(()); + } + + if trivial_dropck_outlives(tcx, ty) { + return Ok(()); + } + + match ty.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Str + | ty::Never + | ty::Foreign(..) + | ty::RawPtr(..) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) => { + // these types never have a destructor + } + + ty::Array(ety, _) | ty::Slice(ety) => { + // single-element containers, behave like their element + rustc_data_structures::stack::ensure_sufficient_stack(|| { + dtorck_constraint_for_ty_inner(tcx, span, for_ty, depth + 1, *ety, constraints) + })?; + } + + ty::Tuple(tys) => rustc_data_structures::stack::ensure_sufficient_stack(|| { + for ty in tys.iter() { + dtorck_constraint_for_ty_inner(tcx, span, for_ty, depth + 1, ty, constraints)?; + } + Ok::<_, NoSolution>(()) + })?, + + ty::Closure(_, substs) => { + if !substs.as_closure().is_valid() { + // By the time this code runs, all type variables ought to + // be fully resolved. + + tcx.sess.delay_span_bug( + span, + format!("upvar_tys for closure not found. Expected capture information for closure {ty}",), + ); + return Err(NoSolution); + } + + rustc_data_structures::stack::ensure_sufficient_stack(|| { + for ty in substs.as_closure().upvar_tys() { + dtorck_constraint_for_ty_inner(tcx, span, for_ty, depth + 1, ty, constraints)?; + } + Ok::<_, NoSolution>(()) + })? + } + + ty::Generator(_, substs, _movability) => { + // rust-lang/rust#49918: types can be constructed, stored + // in the interior, and sit idle when generator yields + // (and is subsequently dropped). + // + // It would be nice to descend into interior of a + // generator to determine what effects dropping it might + // have (by looking at any drop effects associated with + // its interior). + // + // However, the interior's representation uses things like + // GeneratorWitness that explicitly assume they are not + // traversed in such a manner. So instead, we will + // simplify things for now by treating all generators as + // if they were like trait objects, where its upvars must + // all be alive for the generator's (potential) + // destructor. + // + // In particular, skipping over `_interior` is safe + // because any side-effects from dropping `_interior` can + // only take place through references with lifetimes + // derived from lifetimes attached to the upvars and resume + // argument, and we *do* incorporate those here. + + if !substs.as_generator().is_valid() { + // By the time this code runs, all type variables ought to + // be fully resolved. + tcx.sess.delay_span_bug( + span, + format!("upvar_tys for generator not found. Expected capture information for generator {ty}",), + ); + return Err(NoSolution); + } + + constraints.outlives.extend( + substs + .as_generator() + .upvar_tys() + .map(|t| -> ty::subst::GenericArg<'tcx> { t.into() }), + ); + constraints.outlives.push(substs.as_generator().resume_ty().into()); + } + + ty::Adt(def, substs) => { + let DropckConstraint { dtorck_types, outlives, overflows } = + tcx.at(span).adt_dtorck_constraint(def.did())?; + // FIXME: we can try to recursively `dtorck_constraint_on_ty` + // there, but that needs some way to handle cycles. + constraints + .dtorck_types + .extend(dtorck_types.iter().map(|t| EarlyBinder(*t).subst(tcx, substs))); + constraints + .outlives + .extend(outlives.iter().map(|t| EarlyBinder(*t).subst(tcx, substs))); + constraints + .overflows + .extend(overflows.iter().map(|t| EarlyBinder(*t).subst(tcx, substs))); + } + + // Objects must be alive in order for their destructor + // to be called. + ty::Dynamic(..) => { + constraints.outlives.push(ty.into()); + } + + // Types that can't be resolved. Pass them forward. + ty::Alias(..) | ty::Param(..) => { + constraints.dtorck_types.push(ty); + } + + ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => { + // By the time this code runs, all type variables ought to + // be fully resolved. + return Err(NoSolution); + } + } + + Ok(()) +} diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs index a2cfdeefd6f30..01d7a1e7913b5 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs @@ -1,9 +1,13 @@ use crate::infer::canonical::{Canonical, CanonicalQueryResponse}; use crate::traits::ObligationCtxt; +use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; +use rustc_infer::traits::Obligation; use rustc_middle::traits::query::NoSolution; -use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; +use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; +use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, UserSelfTy, UserSubsts, UserType}; pub use rustc_middle::traits::query::type_op::AscribeUserType; +use rustc_span::{Span, DUMMY_SP}; impl<'tcx> super::QueryTypeOp<'tcx> for AscribeUserType<'tcx> { type QueryResponse = (); @@ -23,9 +27,114 @@ impl<'tcx> super::QueryTypeOp<'tcx> for AscribeUserType<'tcx> { } fn perform_locally_in_new_solver( - _ocx: &ObligationCtxt<'_, 'tcx>, - _key: ParamEnvAnd<'tcx, Self>, + ocx: &ObligationCtxt<'_, 'tcx>, + key: ParamEnvAnd<'tcx, Self>, ) -> Result { - todo!() + type_op_ascribe_user_type_with_span(ocx, key, None) } } + +/// The core of the `type_op_ascribe_user_type` query: for diagnostics purposes in NLL HRTB errors, +/// this query can be re-run to better track the span of the obligation cause, and improve the error +/// message. Do not call directly unless you're in that very specific context. +pub fn type_op_ascribe_user_type_with_span<'tcx>( + ocx: &ObligationCtxt<'_, 'tcx>, + key: ParamEnvAnd<'tcx, AscribeUserType<'tcx>>, + span: Option, +) -> Result<(), NoSolution> { + let (param_env, AscribeUserType { mir_ty, user_ty }) = key.into_parts(); + debug!("type_op_ascribe_user_type: mir_ty={:?} user_ty={:?}", mir_ty, user_ty); + let span = span.unwrap_or(DUMMY_SP); + match user_ty { + UserType::Ty(user_ty) => relate_mir_and_user_ty(ocx, param_env, span, mir_ty, user_ty)?, + UserType::TypeOf(def_id, user_substs) => { + relate_mir_and_user_substs(ocx, param_env, span, mir_ty, def_id, user_substs)? + } + }; + Ok(()) +} + +#[instrument(level = "debug", skip(ocx, param_env, span))] +fn relate_mir_and_user_ty<'tcx>( + ocx: &ObligationCtxt<'_, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + span: Span, + mir_ty: Ty<'tcx>, + user_ty: Ty<'tcx>, +) -> Result<(), NoSolution> { + let cause = ObligationCause::dummy_with_span(span); + let user_ty = ocx.normalize(&cause, param_env, user_ty); + ocx.eq(&cause, param_env, mir_ty, user_ty)?; + + // FIXME(#104764): We should check well-formedness before normalization. + let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(user_ty.into())); + ocx.register_obligation(Obligation::new(ocx.infcx.tcx, cause, param_env, predicate)); + Ok(()) +} + +#[instrument(level = "debug", skip(ocx, param_env, span))] +fn relate_mir_and_user_substs<'tcx>( + ocx: &ObligationCtxt<'_, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + span: Span, + mir_ty: Ty<'tcx>, + def_id: DefId, + user_substs: UserSubsts<'tcx>, +) -> Result<(), NoSolution> { + let param_env = param_env.without_const(); + let UserSubsts { user_self_ty, substs } = user_substs; + let tcx = ocx.infcx.tcx; + let cause = ObligationCause::dummy_with_span(span); + + let ty = tcx.type_of(def_id).subst(tcx, substs); + let ty = ocx.normalize(&cause, param_env, ty); + debug!("relate_type_and_user_type: ty of def-id is {:?}", ty); + + ocx.eq(&cause, param_env, mir_ty, ty)?; + + // Prove the predicates coming along with `def_id`. + // + // Also, normalize the `instantiated_predicates` + // because otherwise we wind up with duplicate "type + // outlives" error messages. + let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs); + + debug!(?instantiated_predicates); + for (instantiated_predicate, predicate_span) in instantiated_predicates { + let span = if span == DUMMY_SP { predicate_span } else { span }; + let cause = ObligationCause::new( + span, + CRATE_DEF_ID, + ObligationCauseCode::AscribeUserTypeProvePredicate(predicate_span), + ); + let instantiated_predicate = + ocx.normalize(&cause.clone(), param_env, instantiated_predicate); + + ocx.register_obligation(Obligation::new(tcx, cause, param_env, instantiated_predicate)); + } + + if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty { + let self_ty = ocx.normalize(&cause, param_env, self_ty); + let impl_self_ty = tcx.type_of(impl_def_id).subst(tcx, substs); + let impl_self_ty = ocx.normalize(&cause, param_env, impl_self_ty); + + ocx.eq(&cause, param_env, self_ty, impl_self_ty)?; + let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into())); + ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, predicate)); + } + + // In addition to proving the predicates, we have to + // prove that `ty` is well-formed -- this is because + // the WF of `ty` is predicated on the substs being + // well-formed, and we haven't proven *that*. We don't + // want to prove the WF of types from `substs` directly because they + // haven't been normalized. + // + // FIXME(nmatsakis): Well, perhaps we should normalize + // them? This would only be relevant if some input + // type were ill-formed but did not appear in `ty`, + // which...could happen with normalization... + let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())); + ocx.register_obligation(Obligation::new(tcx, cause, param_env, predicate)); + Ok(()) +} diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index 9054bafc4a67a..9989fc9c479a3 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -1,8 +1,15 @@ -use crate::infer::canonical::{Canonical, CanonicalQueryResponse}; +use crate::traits::query::NoSolution; +use crate::traits::wf; use crate::traits::ObligationCtxt; + +use rustc_infer::infer::canonical::Canonical; +use rustc_infer::infer::outlives::components::{push_outlives_components, Component}; use rustc_infer::traits::query::OutlivesBound; -use rustc_middle::traits::query::NoSolution; -use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt}; +use rustc_middle::infer::canonical::CanonicalQueryResponse; +use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt}; +use rustc_span::def_id::CRATE_DEF_ID; +use rustc_span::source_map::DUMMY_SP; +use smallvec::{smallvec, SmallVec}; #[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct ImpliedOutlivesBounds<'tcx> { @@ -42,9 +49,167 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ImpliedOutlivesBounds<'tcx> { } fn perform_locally_in_new_solver( - _ocx: &ObligationCtxt<'_, 'tcx>, - _key: ParamEnvAnd<'tcx, Self>, + ocx: &ObligationCtxt<'_, 'tcx>, + key: ParamEnvAnd<'tcx, Self>, ) -> Result { - todo!() + compute_implied_outlives_bounds_inner(ocx, key.param_env, key.value.ty) + } +} + +pub fn compute_implied_outlives_bounds_inner<'tcx>( + ocx: &ObligationCtxt<'_, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, +) -> Result>, NoSolution> { + let tcx = ocx.infcx.tcx; + + // Sometimes when we ask what it takes for T: WF, we get back that + // U: WF is required; in that case, we push U onto this stack and + // process it next. Because the resulting predicates aren't always + // guaranteed to be a subset of the original type, so we need to store the + // WF args we've computed in a set. + let mut checked_wf_args = rustc_data_structures::fx::FxHashSet::default(); + let mut wf_args = vec![ty.into()]; + + let mut outlives_bounds: Vec, ty::Region<'tcx>>> = + vec![]; + + while let Some(arg) = wf_args.pop() { + if !checked_wf_args.insert(arg) { + continue; + } + + // Compute the obligations for `arg` to be well-formed. If `arg` is + // an unresolved inference variable, just substituted an empty set + // -- because the return type here is going to be things we *add* + // to the environment, it's always ok for this set to be smaller + // than the ultimate set. (Note: normally there won't be + // unresolved inference variables here anyway, but there might be + // during typeck under some circumstances.) + // + // FIXME(@lcnr): It's not really "always fine", having fewer implied + // bounds can be backward incompatible, e.g. #101951 was caused by + // us not dealing with inference vars in `TypeOutlives` predicates. + let obligations = wf::obligations(ocx.infcx, param_env, CRATE_DEF_ID, 0, arg, DUMMY_SP) + .unwrap_or_default(); + + for obligation in obligations { + debug!(?obligation); + assert!(!obligation.has_escaping_bound_vars()); + + // While these predicates should all be implied by other parts of + // the program, they are still relevant as they may constrain + // inference variables, which is necessary to add the correct + // implied bounds in some cases, mostly when dealing with projections. + // + // Another important point here: we only register `Projection` + // predicates, since otherwise we might register outlives + // predicates containing inference variables, and we don't + // learn anything new from those. + if obligation.predicate.has_non_region_infer() { + match obligation.predicate.kind().skip_binder() { + ty::PredicateKind::Clause(ty::Clause::Projection(..)) + | ty::PredicateKind::AliasRelate(..) => { + ocx.register_obligation(obligation.clone()); + } + _ => {} + } + } + + let pred = match obligation.predicate.kind().no_bound_vars() { + None => continue, + Some(pred) => pred, + }; + match pred { + ty::PredicateKind::Clause(ty::Clause::Trait(..)) + // FIXME(const_generics): Make sure that `<'a, 'b, const N: &'a &'b u32>` is sound + // if we ever support that + | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) + | ty::PredicateKind::Subtype(..) + | ty::PredicateKind::Coerce(..) + | ty::PredicateKind::Clause(ty::Clause::Projection(..)) + | ty::PredicateKind::ClosureKind(..) + | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::ConstEvaluatable(..) + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::Ambiguous + | ty::PredicateKind::AliasRelate(..) + | ty::PredicateKind::TypeWellFormedFromEnv(..) => {} + + // We need to search through *all* WellFormed predicates + ty::PredicateKind::WellFormed(arg) => { + wf_args.push(arg); + } + + // We need to register region relationships + ty::PredicateKind::Clause(ty::Clause::RegionOutlives(ty::OutlivesPredicate( + r_a, + r_b, + ))) => outlives_bounds.push(ty::OutlivesPredicate(r_a.into(), r_b)), + + ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( + ty_a, + r_b, + ))) => outlives_bounds.push(ty::OutlivesPredicate(ty_a.into(), r_b)), + } + } + } + + // This call to `select_all_or_error` is necessary to constrain inference variables, which we + // use further down when computing the implied bounds. + match ocx.select_all_or_error().as_slice() { + [] => (), + _ => return Err(NoSolution), } + + // We lazily compute the outlives components as + // `select_all_or_error` constrains inference variables. + let implied_bounds = outlives_bounds + .into_iter() + .flat_map(|ty::OutlivesPredicate(a, r_b)| match a.unpack() { + ty::GenericArgKind::Lifetime(r_a) => vec![OutlivesBound::RegionSubRegion(r_b, r_a)], + ty::GenericArgKind::Type(ty_a) => { + let ty_a = ocx.infcx.resolve_vars_if_possible(ty_a); + let mut components = smallvec![]; + push_outlives_components(tcx, ty_a, &mut components); + implied_bounds_from_components(r_b, components) + } + ty::GenericArgKind::Const(_) => unreachable!(), + }) + .collect(); + + Ok(implied_bounds) +} + +/// When we have an implied bound that `T: 'a`, we can further break +/// this down to determine what relationships would have to hold for +/// `T: 'a` to hold. We get to assume that the caller has validated +/// those relationships. +fn implied_bounds_from_components<'tcx>( + sub_region: ty::Region<'tcx>, + sup_components: SmallVec<[Component<'tcx>; 4]>, +) -> Vec> { + sup_components + .into_iter() + .filter_map(|component| { + match component { + Component::Region(r) => Some(OutlivesBound::RegionSubRegion(sub_region, r)), + Component::Param(p) => Some(OutlivesBound::RegionSubParam(sub_region, p)), + Component::Alias(p) => Some(OutlivesBound::RegionSubAlias(sub_region, p)), + Component::EscapingAlias(_) => + // If the projection has escaping regions, don't + // try to infer any implied bounds even for its + // free components. This is conservative, because + // the caller will still have to prove that those + // free components outlive `sub_region`. But the + // idea is that the WAY that the caller proves + // that may change in the future and we want to + // give ourselves room to get smarter here. + { + None + } + Component::UnresolvedInferenceVariable(..) => None, + } + }) + .collect() } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs index 8b3a20a88f03e..9889426337476 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs @@ -1,7 +1,9 @@ use crate::infer::canonical::{Canonical, CanonicalQueryResponse}; -use crate::traits::query::dropck_outlives::{trivial_dropck_outlives, DropckOutlivesResult}; +use crate::traits::query::dropck_outlives::{ + compute_dropck_outlives_inner, trivial_dropck_outlives, +}; use crate::traits::ObligationCtxt; -use rustc_middle::traits::query::NoSolution; +use rustc_middle::traits::query::{DropckOutlivesResult, NoSolution}; use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt}; #[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)] @@ -51,9 +53,9 @@ impl<'tcx> super::QueryTypeOp<'tcx> for DropckOutlives<'tcx> { } fn perform_locally_in_new_solver( - _ocx: &ObligationCtxt<'_, 'tcx>, - _key: ParamEnvAnd<'tcx, Self>, + ocx: &ObligationCtxt<'_, 'tcx>, + key: ParamEnvAnd<'tcx, Self>, ) -> Result { - todo!() + compute_dropck_outlives_inner(ocx, key.param_env.and(key.value.dropped_ty)) } } diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs index 83f6c7d07fe78..f35c14eeac801 100644 --- a/compiler/rustc_traits/src/dropck_outlives.rs +++ b/compiler/rustc_traits/src/dropck_outlives.rs @@ -3,17 +3,14 @@ use rustc_hir::def_id::DefId; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::query::Providers; +use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult}; use rustc_middle::ty::InternalSubsts; -use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, Ty, TyCtxt}; -use rustc_span::source_map::{Span, DUMMY_SP}; +use rustc_middle::ty::TyCtxt; use rustc_trait_selection::infer::InferCtxtBuilderExt; -use rustc_trait_selection::traits::query::dropck_outlives::trivial_dropck_outlives; use rustc_trait_selection::traits::query::dropck_outlives::{ - DropckConstraint, DropckOutlivesResult, + compute_dropck_outlives_inner, dtorck_constraint_for_ty_inner, }; -use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; use rustc_trait_selection::traits::query::{CanonicalTyGoal, NoSolution}; -use rustc_trait_selection::traits::{Normalized, ObligationCause}; pub(crate) fn provide(p: &mut Providers) { *p = Providers { dropck_outlives, adt_dtorck_constraint, ..*p }; @@ -26,263 +23,10 @@ fn dropck_outlives<'tcx>( debug!("dropck_outlives(goal={:#?})", canonical_goal); tcx.infer_ctxt().enter_canonical_trait_query(&canonical_goal, |ocx, goal| { - let tcx = ocx.infcx.tcx; - let ParamEnvAnd { param_env, value: for_ty } = goal; - - let mut result = DropckOutlivesResult { kinds: vec![], overflows: vec![] }; - - // A stack of types left to process. Each round, we pop - // something from the stack and invoke - // `dtorck_constraint_for_ty`. This may produce new types that - // have to be pushed on the stack. This continues until we have explored - // all the reachable types from the type `for_ty`. - // - // Example: Imagine that we have the following code: - // - // ```rust - // struct A { - // value: B, - // children: Vec, - // } - // - // struct B { - // value: u32 - // } - // - // fn f() { - // let a: A = ...; - // .. - // } // here, `a` is dropped - // ``` - // - // at the point where `a` is dropped, we need to figure out - // which types inside of `a` contain region data that may be - // accessed by any destructors in `a`. We begin by pushing `A` - // onto the stack, as that is the type of `a`. We will then - // invoke `dtorck_constraint_for_ty` which will expand `A` - // into the types of its fields `(B, Vec)`. These will get - // pushed onto the stack. Eventually, expanding `Vec` will - // lead to us trying to push `A` a second time -- to prevent - // infinite recursion, we notice that `A` was already pushed - // once and stop. - let mut ty_stack = vec![(for_ty, 0)]; - - // Set used to detect infinite recursion. - let mut ty_set = FxHashSet::default(); - - let cause = ObligationCause::dummy(); - let mut constraints = DropckConstraint::empty(); - while let Some((ty, depth)) = ty_stack.pop() { - debug!( - "{} kinds, {} overflows, {} ty_stack", - result.kinds.len(), - result.overflows.len(), - ty_stack.len() - ); - dtorck_constraint_for_ty(tcx, DUMMY_SP, for_ty, depth, ty, &mut constraints)?; - - // "outlives" represent types/regions that may be touched - // by a destructor. - result.kinds.append(&mut constraints.outlives); - result.overflows.append(&mut constraints.overflows); - - // If we have even one overflow, we should stop trying to evaluate further -- - // chances are, the subsequent overflows for this evaluation won't provide useful - // information and will just decrease the speed at which we can emit these errors - // (since we'll be printing for just that much longer for the often enormous types - // that result here). - if !result.overflows.is_empty() { - break; - } - - // dtorck types are "types that will get dropped but which - // do not themselves define a destructor", more or less. We have - // to push them onto the stack to be expanded. - for ty in constraints.dtorck_types.drain(..) { - let Normalized { value: ty, obligations } = - ocx.infcx.at(&cause, param_env).query_normalize(ty)?; - ocx.register_obligations(obligations); - - debug!("dropck_outlives: ty from dtorck_types = {:?}", ty); - - match ty.kind() { - // All parameters live for the duration of the - // function. - ty::Param(..) => {} - - // A projection that we couldn't resolve - it - // might have a destructor. - ty::Alias(..) => { - result.kinds.push(ty.into()); - } - - _ => { - if ty_set.insert(ty) { - ty_stack.push((ty, depth + 1)); - } - } - } - } - } - - debug!("dropck_outlives: result = {:#?}", result); - Ok(result) + compute_dropck_outlives_inner(ocx, goal) }) } -/// Returns a set of constraints that needs to be satisfied in -/// order for `ty` to be valid for destruction. -fn dtorck_constraint_for_ty<'tcx>( - tcx: TyCtxt<'tcx>, - span: Span, - for_ty: Ty<'tcx>, - depth: usize, - ty: Ty<'tcx>, - constraints: &mut DropckConstraint<'tcx>, -) -> Result<(), NoSolution> { - debug!("dtorck_constraint_for_ty({:?}, {:?}, {:?}, {:?})", span, for_ty, depth, ty); - - if !tcx.recursion_limit().value_within_limit(depth) { - constraints.overflows.push(ty); - return Ok(()); - } - - if trivial_dropck_outlives(tcx, ty) { - return Ok(()); - } - - match ty.kind() { - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Str - | ty::Never - | ty::Foreign(..) - | ty::RawPtr(..) - | ty::Ref(..) - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::GeneratorWitness(..) - | ty::GeneratorWitnessMIR(..) => { - // these types never have a destructor - } - - ty::Array(ety, _) | ty::Slice(ety) => { - // single-element containers, behave like their element - rustc_data_structures::stack::ensure_sufficient_stack(|| { - dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, *ety, constraints) - })?; - } - - ty::Tuple(tys) => rustc_data_structures::stack::ensure_sufficient_stack(|| { - for ty in tys.iter() { - dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty, constraints)?; - } - Ok::<_, NoSolution>(()) - })?, - - ty::Closure(_, substs) => { - if !substs.as_closure().is_valid() { - // By the time this code runs, all type variables ought to - // be fully resolved. - - tcx.sess.delay_span_bug( - span, - format!("upvar_tys for closure not found. Expected capture information for closure {ty}",), - ); - return Err(NoSolution); - } - - rustc_data_structures::stack::ensure_sufficient_stack(|| { - for ty in substs.as_closure().upvar_tys() { - dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty, constraints)?; - } - Ok::<_, NoSolution>(()) - })? - } - - ty::Generator(_, substs, _movability) => { - // rust-lang/rust#49918: types can be constructed, stored - // in the interior, and sit idle when generator yields - // (and is subsequently dropped). - // - // It would be nice to descend into interior of a - // generator to determine what effects dropping it might - // have (by looking at any drop effects associated with - // its interior). - // - // However, the interior's representation uses things like - // GeneratorWitness that explicitly assume they are not - // traversed in such a manner. So instead, we will - // simplify things for now by treating all generators as - // if they were like trait objects, where its upvars must - // all be alive for the generator's (potential) - // destructor. - // - // In particular, skipping over `_interior` is safe - // because any side-effects from dropping `_interior` can - // only take place through references with lifetimes - // derived from lifetimes attached to the upvars and resume - // argument, and we *do* incorporate those here. - - if !substs.as_generator().is_valid() { - // By the time this code runs, all type variables ought to - // be fully resolved. - tcx.sess.delay_span_bug( - span, - format!("upvar_tys for generator not found. Expected capture information for generator {ty}",), - ); - return Err(NoSolution); - } - - constraints.outlives.extend( - substs - .as_generator() - .upvar_tys() - .map(|t| -> ty::subst::GenericArg<'tcx> { t.into() }), - ); - constraints.outlives.push(substs.as_generator().resume_ty().into()); - } - - ty::Adt(def, substs) => { - let DropckConstraint { dtorck_types, outlives, overflows } = - tcx.at(span).adt_dtorck_constraint(def.did())?; - // FIXME: we can try to recursively `dtorck_constraint_on_ty` - // there, but that needs some way to handle cycles. - constraints - .dtorck_types - .extend(dtorck_types.iter().map(|t| EarlyBinder(*t).subst(tcx, substs))); - constraints - .outlives - .extend(outlives.iter().map(|t| EarlyBinder(*t).subst(tcx, substs))); - constraints - .overflows - .extend(overflows.iter().map(|t| EarlyBinder(*t).subst(tcx, substs))); - } - - // Objects must be alive in order for their destructor - // to be called. - ty::Dynamic(..) => { - constraints.outlives.push(ty.into()); - } - - // Types that can't be resolved. Pass them forward. - ty::Alias(..) | ty::Param(..) => { - constraints.dtorck_types.push(ty); - } - - ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => { - // By the time this code runs, all type variables ought to - // be fully resolved. - return Err(NoSolution); - } - } - - Ok(()) -} - /// Calculates the dtorck constraint for a type. pub(crate) fn adt_dtorck_constraint( tcx: TyCtxt<'_>, @@ -311,7 +55,7 @@ pub(crate) fn adt_dtorck_constraint( let mut result = DropckConstraint::empty(); for field in def.all_fields() { let fty = tcx.type_of(field.did).subst_identity(); - dtorck_constraint_for_ty(tcx, span, fty, 0, fty, &mut result)?; + dtorck_constraint_for_ty_inner(tcx, span, fty, 0, fty, &mut result)?; } result.outlives.extend(tcx.destructor_constraints(def)); dedup_dtorck_constraint(&mut result); diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index 49cbf9efa7493..959838ab348fd 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -3,18 +3,13 @@ //! [`rustc_trait_selection::traits::query::type_op::implied_outlives_bounds`]. use rustc_infer::infer::canonical::{self, Canonical}; -use rustc_infer::infer::outlives::components::{push_outlives_components, Component}; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::query::OutlivesBound; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; -use rustc_span::def_id::CRATE_DEF_ID; -use rustc_span::source_map::DUMMY_SP; +use rustc_middle::ty::TyCtxt; use rustc_trait_selection::infer::InferCtxtBuilderExt; +use rustc_trait_selection::traits::query::type_op::implied_outlives_bounds::compute_implied_outlives_bounds_inner; use rustc_trait_selection::traits::query::{CanonicalTyGoal, NoSolution}; -use rustc_trait_selection::traits::wf; -use rustc_trait_selection::traits::ObligationCtxt; -use smallvec::{smallvec, SmallVec}; pub(crate) fn provide(p: &mut Providers) { *p = Providers { implied_outlives_bounds, ..*p }; @@ -29,164 +24,6 @@ fn implied_outlives_bounds<'tcx>( > { tcx.infer_ctxt().enter_canonical_trait_query(&goal, |ocx, key| { let (param_env, ty) = key.into_parts(); - compute_implied_outlives_bounds(ocx, param_env, ty) + compute_implied_outlives_bounds_inner(ocx, param_env, ty) }) } - -fn compute_implied_outlives_bounds<'tcx>( - ocx: &ObligationCtxt<'_, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, -) -> Result>, NoSolution> { - let tcx = ocx.infcx.tcx; - - // Sometimes when we ask what it takes for T: WF, we get back that - // U: WF is required; in that case, we push U onto this stack and - // process it next. Because the resulting predicates aren't always - // guaranteed to be a subset of the original type, so we need to store the - // WF args we've computed in a set. - let mut checked_wf_args = rustc_data_structures::fx::FxHashSet::default(); - let mut wf_args = vec![ty.into()]; - - let mut outlives_bounds: Vec, ty::Region<'tcx>>> = - vec![]; - - while let Some(arg) = wf_args.pop() { - if !checked_wf_args.insert(arg) { - continue; - } - - // Compute the obligations for `arg` to be well-formed. If `arg` is - // an unresolved inference variable, just substituted an empty set - // -- because the return type here is going to be things we *add* - // to the environment, it's always ok for this set to be smaller - // than the ultimate set. (Note: normally there won't be - // unresolved inference variables here anyway, but there might be - // during typeck under some circumstances.) - // - // FIXME(@lcnr): It's not really "always fine", having fewer implied - // bounds can be backward incompatible, e.g. #101951 was caused by - // us not dealing with inference vars in `TypeOutlives` predicates. - let obligations = wf::obligations(ocx.infcx, param_env, CRATE_DEF_ID, 0, arg, DUMMY_SP) - .unwrap_or_default(); - - for obligation in obligations { - debug!(?obligation); - assert!(!obligation.has_escaping_bound_vars()); - - // While these predicates should all be implied by other parts of - // the program, they are still relevant as they may constrain - // inference variables, which is necessary to add the correct - // implied bounds in some cases, mostly when dealing with projections. - // - // Another important point here: we only register `Projection` - // predicates, since otherwise we might register outlives - // predicates containing inference variables, and we don't - // learn anything new from those. - if obligation.predicate.has_non_region_infer() { - match obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Projection(..)) - | ty::PredicateKind::AliasRelate(..) => { - ocx.register_obligation(obligation.clone()); - } - _ => {} - } - } - - let pred = match obligation.predicate.kind().no_bound_vars() { - None => continue, - Some(pred) => pred, - }; - match pred { - ty::PredicateKind::Clause(ty::Clause::Trait(..)) - // FIXME(const_generics): Make sure that `<'a, 'b, const N: &'a &'b u32>` is sound - // if we ever support that - | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) - | ty::PredicateKind::Subtype(..) - | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::Clause(ty::Clause::Projection(..)) - | ty::PredicateKind::ClosureKind(..) - | ty::PredicateKind::ObjectSafe(..) - | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::Ambiguous - | ty::PredicateKind::AliasRelate(..) - | ty::PredicateKind::TypeWellFormedFromEnv(..) => {} - - // We need to search through *all* WellFormed predicates - ty::PredicateKind::WellFormed(arg) => { - wf_args.push(arg); - } - - // We need to register region relationships - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(ty::OutlivesPredicate( - r_a, - r_b, - ))) => outlives_bounds.push(ty::OutlivesPredicate(r_a.into(), r_b)), - - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( - ty_a, - r_b, - ))) => outlives_bounds.push(ty::OutlivesPredicate(ty_a.into(), r_b)), - } - } - } - - // This call to `select_all_or_error` is necessary to constrain inference variables, which we - // use further down when computing the implied bounds. - match ocx.select_all_or_error().as_slice() { - [] => (), - _ => return Err(NoSolution), - } - - // We lazily compute the outlives components as - // `select_all_or_error` constrains inference variables. - let implied_bounds = outlives_bounds - .into_iter() - .flat_map(|ty::OutlivesPredicate(a, r_b)| match a.unpack() { - ty::GenericArgKind::Lifetime(r_a) => vec![OutlivesBound::RegionSubRegion(r_b, r_a)], - ty::GenericArgKind::Type(ty_a) => { - let ty_a = ocx.infcx.resolve_vars_if_possible(ty_a); - let mut components = smallvec![]; - push_outlives_components(tcx, ty_a, &mut components); - implied_bounds_from_components(r_b, components) - } - ty::GenericArgKind::Const(_) => unreachable!(), - }) - .collect(); - - Ok(implied_bounds) -} - -/// When we have an implied bound that `T: 'a`, we can further break -/// this down to determine what relationships would have to hold for -/// `T: 'a` to hold. We get to assume that the caller has validated -/// those relationships. -fn implied_bounds_from_components<'tcx>( - sub_region: ty::Region<'tcx>, - sup_components: SmallVec<[Component<'tcx>; 4]>, -) -> Vec> { - sup_components - .into_iter() - .filter_map(|component| { - match component { - Component::Region(r) => Some(OutlivesBound::RegionSubRegion(sub_region, r)), - Component::Param(p) => Some(OutlivesBound::RegionSubParam(sub_region, p)), - Component::Alias(p) => Some(OutlivesBound::RegionSubAlias(sub_region, p)), - Component::EscapingAlias(_) => - // If the projection has escaping regions, don't - // try to infer any implied bounds even for its - // free components. This is conservative, because - // the caller will still have to prove that those - // free components outlive `sub_region`. But the - // idea is that the WAY that the caller proves - // that may change in the future and we want to - // give ourselves room to get smarter here. - { - None - } - Component::UnresolvedInferenceVariable(..) => None, - } - }) - .collect() -} diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs index b0f9c57154f1b..907e2d39c518f 100644 --- a/compiler/rustc_traits/src/lib.rs +++ b/compiler/rustc_traits/src/lib.rs @@ -21,7 +21,8 @@ mod normalize_erasing_regions; mod normalize_projection_ty; mod type_op; -pub use type_op::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause}; +pub use rustc_trait_selection::traits::query::type_op::ascribe_user_type::type_op_ascribe_user_type_with_span; +pub use type_op::type_op_prove_predicate_with_cause; use rustc_middle::query::Providers; diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index faf985169deff..9904acb1c0d51 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -1,17 +1,15 @@ -use rustc_hir as hir; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::query::Providers; use rustc_middle::traits::query::NoSolution; -use rustc_middle::traits::{DefiningAnchor, ObligationCauseCode}; -use rustc_middle::ty::{self, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::traits::DefiningAnchor; +use rustc_middle::ty::{FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{ParamEnvAnd, Predicate}; -use rustc_middle::ty::{UserSelfTy, UserSubsts, UserType}; -use rustc_span::def_id::CRATE_DEF_ID; -use rustc_span::{Span, DUMMY_SP}; use rustc_trait_selection::infer::InferCtxtBuilderExt; use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; -use rustc_trait_selection::traits::query::type_op::ascribe_user_type::AscribeUserType; +use rustc_trait_selection::traits::query::type_op::ascribe_user_type::{ + type_op_ascribe_user_type_with_span, AscribeUserType, +}; use rustc_trait_selection::traits::query::type_op::eq::Eq; use rustc_trait_selection::traits::query::type_op::normalize::Normalize; use rustc_trait_selection::traits::query::type_op::prove_predicate::ProvePredicate; @@ -42,111 +40,6 @@ fn type_op_ascribe_user_type<'tcx>( }) } -/// The core of the `type_op_ascribe_user_type` query: for diagnostics purposes in NLL HRTB errors, -/// this query can be re-run to better track the span of the obligation cause, and improve the error -/// message. Do not call directly unless you're in that very specific context. -pub fn type_op_ascribe_user_type_with_span<'tcx>( - ocx: &ObligationCtxt<'_, 'tcx>, - key: ParamEnvAnd<'tcx, AscribeUserType<'tcx>>, - span: Option, -) -> Result<(), NoSolution> { - let (param_env, AscribeUserType { mir_ty, user_ty }) = key.into_parts(); - debug!("type_op_ascribe_user_type: mir_ty={:?} user_ty={:?}", mir_ty, user_ty); - let span = span.unwrap_or(DUMMY_SP); - match user_ty { - UserType::Ty(user_ty) => relate_mir_and_user_ty(ocx, param_env, span, mir_ty, user_ty)?, - UserType::TypeOf(def_id, user_substs) => { - relate_mir_and_user_substs(ocx, param_env, span, mir_ty, def_id, user_substs)? - } - }; - Ok(()) -} - -#[instrument(level = "debug", skip(ocx, param_env, span))] -fn relate_mir_and_user_ty<'tcx>( - ocx: &ObligationCtxt<'_, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - span: Span, - mir_ty: Ty<'tcx>, - user_ty: Ty<'tcx>, -) -> Result<(), NoSolution> { - let cause = ObligationCause::dummy_with_span(span); - let user_ty = ocx.normalize(&cause, param_env, user_ty); - ocx.eq(&cause, param_env, mir_ty, user_ty)?; - - // FIXME(#104764): We should check well-formedness before normalization. - let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(user_ty.into())); - ocx.register_obligation(Obligation::new(ocx.infcx.tcx, cause, param_env, predicate)); - Ok(()) -} - -#[instrument(level = "debug", skip(ocx, param_env, span))] -fn relate_mir_and_user_substs<'tcx>( - ocx: &ObligationCtxt<'_, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - span: Span, - mir_ty: Ty<'tcx>, - def_id: hir::def_id::DefId, - user_substs: UserSubsts<'tcx>, -) -> Result<(), NoSolution> { - let param_env = param_env.without_const(); - let UserSubsts { user_self_ty, substs } = user_substs; - let tcx = ocx.infcx.tcx; - let cause = ObligationCause::dummy_with_span(span); - - let ty = tcx.type_of(def_id).subst(tcx, substs); - let ty = ocx.normalize(&cause, param_env, ty); - debug!("relate_type_and_user_type: ty of def-id is {:?}", ty); - - ocx.eq(&cause, param_env, mir_ty, ty)?; - - // Prove the predicates coming along with `def_id`. - // - // Also, normalize the `instantiated_predicates` - // because otherwise we wind up with duplicate "type - // outlives" error messages. - let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs); - - debug!(?instantiated_predicates); - for (instantiated_predicate, predicate_span) in instantiated_predicates { - let span = if span == DUMMY_SP { predicate_span } else { span }; - let cause = ObligationCause::new( - span, - CRATE_DEF_ID, - ObligationCauseCode::AscribeUserTypeProvePredicate(predicate_span), - ); - let instantiated_predicate = - ocx.normalize(&cause.clone(), param_env, instantiated_predicate); - - ocx.register_obligation(Obligation::new(tcx, cause, param_env, instantiated_predicate)); - } - - if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty { - let self_ty = ocx.normalize(&cause, param_env, self_ty); - let impl_self_ty = tcx.type_of(impl_def_id).subst(tcx, substs); - let impl_self_ty = ocx.normalize(&cause, param_env, impl_self_ty); - - ocx.eq(&cause, param_env, self_ty, impl_self_ty)?; - let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into())); - ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, predicate)); - } - - // In addition to proving the predicates, we have to - // prove that `ty` is well-formed -- this is because - // the WF of `ty` is predicated on the substs being - // well-formed, and we haven't proven *that*. We don't - // want to prove the WF of types from `substs` directly because they - // haven't been normalized. - // - // FIXME(nmatsakis): Well, perhaps we should normalize - // them? This would only be relevant if some input - // type were ill-formed but did not appear in `ty`, - // which...could happen with normalization... - let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())); - ocx.register_obligation(Obligation::new(tcx, cause, param_env, predicate)); - Ok(()) -} - fn type_op_eq<'tcx>( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Eq<'tcx>>>, From c4e8a86d9ee6b83bacadd3983122e56c323fd7b2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 25 May 2023 19:46:52 +0000 Subject: [PATCH 48/69] Don't use outlives type op outside of MIR typeck --- .../src/traits/outlives_bounds.rs | 37 ++++++++++++------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index 0e797a1cb60d5..f8d056e321e65 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -1,9 +1,9 @@ use crate::infer::InferCtxt; -use crate::traits::query::type_op::{self, TypeOp, TypeOpOutput}; use crate::traits::{ObligationCause, ObligationCtxt}; use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::ErrorGuaranteed; use rustc_infer::infer::resolve::OpportunisticRegionResolver; +use rustc_infer::infer::InferOk; +use rustc_middle::infer::canonical::{OriginalQueryValues, QueryRegionConstraints}; use rustc_middle::ty::{self, ParamEnv, Ty, TypeFolder, TypeVisitableExt}; use rustc_span::def_id::LocalDefId; @@ -68,20 +68,29 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> { return vec![]; } - let span = self.tcx.def_span(body_id); - let result: Result<_, ErrorGuaranteed> = param_env - .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty }) - .fully_perform(self, span); - let result = match result { - Ok(r) => r, - Err(_) => { - return vec![]; - } + let mut canonical_var_values = OriginalQueryValues::default(); + let canonical_ty = + self.canonicalize_query_keep_static(param_env.and(ty), &mut canonical_var_values); + let Ok(canonical_result) = self.tcx.implied_outlives_bounds(canonical_ty) else { + return vec![]; + }; + + let mut constraints = QueryRegionConstraints::default(); + let Ok(InferOk { value, obligations }) = self + .instantiate_nll_query_response_and_region_obligations( + &ObligationCause::dummy(), + param_env, + &canonical_var_values, + canonical_result, + &mut constraints, + ) else { + return vec![]; }; + assert_eq!(&obligations, &[]); - let TypeOpOutput { output, constraints, .. } = result; + if !constraints.is_empty() { + let span = self.tcx.def_span(body_id); - if let Some(constraints) = constraints { debug!(?constraints); if !constraints.member_constraints.is_empty() { span_bug!(span, "{:#?}", constraints.member_constraints); @@ -108,7 +117,7 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> { } }; - output + value } fn implied_bounds_tys( From b9606589c4ca72008dc8d769f1a1c2b3578be65f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Tue, 9 May 2023 07:15:46 +0800 Subject: [PATCH 49/69] Add warn-by-default lint for local binding shadowing exported glob re-export item --- compiler/rustc_ast/src/token.rs | 1 + compiler/rustc_lint/src/context.rs | 4 + compiler/rustc_lint_defs/src/builtin.rs | 38 +++++++++ compiler/rustc_lint_defs/src/lib.rs | 10 +++ compiler/rustc_middle/src/ty/mod.rs | 2 +- compiler/rustc_resolve/src/imports.rs | 83 ++++++++++++++----- compiler/rustc_resolve/src/lib.rs | 4 +- .../rustc_trait_selection/src/traits/mod.rs | 2 + tests/ui/imports/issue-55884-2.rs | 1 + tests/ui/imports/issue-55884-2.stderr | 6 +- tests/ui/resolve/hidden_glob_reexports.rs | 52 ++++++++++++ tests/ui/resolve/hidden_glob_reexports.stderr | 31 +++++++ 12 files changed, 207 insertions(+), 27 deletions(-) create mode 100644 tests/ui/resolve/hidden_glob_reexports.rs create mode 100644 tests/ui/resolve/hidden_glob_reexports.stderr diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 7ef39f8026b20..6646fa9446fb1 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -11,6 +11,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; use rustc_macros::HashStable_Generic; use rustc_span::symbol::{kw, sym}; +#[cfg_attr(not(bootstrap), allow(hidden_glob_reexports))] use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{self, edition::Edition, Span, DUMMY_SP}; use std::borrow::Cow; diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 1d0c43e95e085..947530a1b65a9 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -952,6 +952,10 @@ pub trait LintContext: Sized { db.span_label(first_reexport_span, format!("the name `{}` in the {} namespace is first re-exported here", name, namespace)); db.span_label(duplicate_reexport_span, format!("but the name `{}` in the {} namespace is also re-exported here", name, namespace)); } + BuiltinLintDiagnostics::HiddenGlobReexports { name, namespace, glob_reexport_span, private_item_span } => { + db.span_label(glob_reexport_span, format!("the name `{}` in the {} namespace is supposed to be publicly re-exported here", name, namespace)); + db.span_label(private_item_span, "but the private item here shadows it"); + } } // Rewrap `db`, and pass control to the user. decorate(db) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 6e9dc880a7dee..1507087bdd4f3 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3272,6 +3272,43 @@ declare_lint! { "ambiguous glob re-exports", } +declare_lint! { + /// The `hidden_glob_reexports` lint detects cases where glob re-export items are shadowed by + /// private items. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(hidden_glob_reexports)] + /// + /// pub mod upstream { + /// mod inner { pub struct Foo {}; pub struct Bar {}; } + /// pub use self::inner::*; + /// struct Foo {} // private item shadows `inner::Foo` + /// } + /// + /// // mod downstream { + /// // fn test() { + /// // let _ = crate::upstream::Foo; // inaccessible + /// // } + /// // } + /// + /// pub fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This was previously accepted without any errors or warnings but it could silently break a + /// crate's downstream user code. If the `struct Foo` was added, `dep::inner::Foo` would + /// silently become inaccessible and trigger a "`struct `Foo` is private`" visibility error at + /// the downstream use site. + pub HIDDEN_GLOB_REEXPORTS, + Warn, + "name introduced by a private item shadows a name introduced by a public glob re-export", +} + declare_lint_pass! { /// Does nothing as a lint pass, but registers some `Lint`s /// that are used by other parts of the compiler. @@ -3304,6 +3341,7 @@ declare_lint_pass! { FORBIDDEN_LINT_GROUPS, FUNCTION_ITEM_REFERENCES, FUZZY_PROVENANCE_CASTS, + HIDDEN_GLOB_REEXPORTS, ILL_FORMED_ATTRIBUTE_INPUT, ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, IMPLIED_BOUNDS_ENTAILMENT, diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index e27e322db8858..5a5031b791964 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -540,6 +540,16 @@ pub enum BuiltinLintDiagnostics { /// Span where the same name is also re-exported. duplicate_reexport_span: Span, }, + HiddenGlobReexports { + /// The name of the local binding which shadows the glob re-export. + name: String, + /// The namespace for which the shadowing occurred in. + namespace: String, + /// The glob reexport that is shadowed by the local binding. + glob_reexport_span: Span, + /// The local binding that shadows the glob reexport. + private_item_span: Span, + }, } /// Lints that are buffered up early on in the `Session` before the diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index a8d0dca37ff99..96023a68cf6d0 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -53,7 +53,6 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{ExpnId, ExpnKind, Span}; use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx}; pub use rustc_target::abi::{ReprFlags, ReprOptions}; -use rustc_type_ir::WithCachedTypeInfo; pub use subst::*; pub use vtable::*; @@ -145,6 +144,7 @@ mod opaque_types; mod parameterized; mod rvalue_scopes; mod structural_impls; +#[cfg_attr(not(bootstrap), allow(hidden_glob_reexports))] mod sty; mod typeck_results; diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 7c4c05d4b9452..c1bb262c0d407 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -21,7 +21,8 @@ use rustc_middle::metadata::Reexport; use rustc_middle::span_bug; use rustc_middle::ty; use rustc_session::lint::builtin::{ - AMBIGUOUS_GLOB_REEXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE, UNUSED_IMPORTS, + AMBIGUOUS_GLOB_REEXPORTS, HIDDEN_GLOB_REEXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE, + UNUSED_IMPORTS, }; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_span::edit_distance::find_best_match_for_name; @@ -526,31 +527,71 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - pub(crate) fn check_reexport_ambiguities( + pub(crate) fn check_hidden_glob_reexports( &mut self, exported_ambiguities: FxHashSet>>, ) { for module in self.arenas.local_modules().iter() { - module.for_each_child(self, |this, ident, ns, binding| { - if let NameBindingKind::Import { import, .. } = binding.kind - && let Some((amb_binding, _)) = binding.ambiguity - && binding.res() != Res::Err - && exported_ambiguities.contains(&Interned::new_unchecked(binding)) - { - this.lint_buffer.buffer_lint_with_diagnostic( - AMBIGUOUS_GLOB_REEXPORTS, - import.root_id, - import.root_span, - "ambiguous glob re-exports", - BuiltinLintDiagnostics::AmbiguousGlobReexports { - name: ident.to_string(), - namespace: ns.descr().to_string(), - first_reexport_span: import.root_span, - duplicate_reexport_span: amb_binding.span, - }, - ); + for (key, resolution) in self.resolutions(module).borrow().iter() { + let resolution = resolution.borrow(); + + if let Some(binding) = resolution.binding { + if let NameBindingKind::Import { import, .. } = binding.kind + && let Some((amb_binding, _)) = binding.ambiguity + && binding.res() != Res::Err + && exported_ambiguities.contains(&Interned::new_unchecked(binding)) + { + self.lint_buffer.buffer_lint_with_diagnostic( + AMBIGUOUS_GLOB_REEXPORTS, + import.root_id, + import.root_span, + "ambiguous glob re-exports", + BuiltinLintDiagnostics::AmbiguousGlobReexports { + name: key.ident.to_string(), + namespace: key.ns.descr().to_string(), + first_reexport_span: import.root_span, + duplicate_reexport_span: amb_binding.span, + }, + ); + } + + if let Some(glob_binding) = resolution.shadowed_glob { + let binding_id = match binding.kind { + NameBindingKind::Res(res) => { + Some(self.def_id_to_node_id[res.def_id().expect_local()]) + } + NameBindingKind::Module(module) => { + Some(self.def_id_to_node_id[module.def_id().expect_local()]) + } + NameBindingKind::Import { import, .. } => import.id(), + }; + + if binding.res() != Res::Err + && glob_binding.res() != Res::Err + && let NameBindingKind::Import { import: glob_import, .. } = glob_binding.kind + && let Some(binding_id) = binding_id + && let Some(glob_import_id) = glob_import.id() + && let glob_import_def_id = self.local_def_id(glob_import_id) + && self.effective_visibilities.is_exported(glob_import_def_id) + && glob_binding.vis.is_public() + && !binding.vis.is_public() + { + self.lint_buffer.buffer_lint_with_diagnostic( + HIDDEN_GLOB_REEXPORTS, + binding_id, + binding.span, + "private item shadows public glob re-export", + BuiltinLintDiagnostics::HiddenGlobReexports { + name: key.ident.name.to_string(), + namespace: key.ns.descr().to_owned(), + glob_reexport_span: glob_binding.span, + private_item_span: binding.span, + }, + ); + } + } } - }); + } } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 3d2bd8429068e..fd977e8e254a2 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1496,8 +1496,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let exported_ambiguities = self.tcx.sess.time("compute_effective_visibilities", || { EffectiveVisibilitiesVisitor::compute_effective_visibilities(self, krate) }); - self.tcx.sess.time("check_reexport_ambiguities", || { - self.check_reexport_ambiguities(exported_ambiguities) + self.tcx.sess.time("check_hidden_glob_reexports", || { + self.check_hidden_glob_reexports(exported_ambiguities) }); self.tcx.sess.time("finalize_macro_resolutions", || self.finalize_macro_resolutions()); self.tcx.sess.time("late_resolve_crate", || self.late_resolve_crate(krate)); diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index f265230ff772d..a44d8955ab95c 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -14,10 +14,12 @@ mod object_safety; pub mod outlives_bounds; mod project; pub mod query; +#[cfg_attr(not(bootstrap), allow(hidden_glob_reexports))] mod select; mod specialize; mod structural_match; mod structural_normalize; +#[cfg_attr(not(bootstrap), allow(hidden_glob_reexports))] mod util; mod vtable; pub mod wf; diff --git a/tests/ui/imports/issue-55884-2.rs b/tests/ui/imports/issue-55884-2.rs index 75bb4206f97d6..6f8d0cf8ae2a2 100644 --- a/tests/ui/imports/issue-55884-2.rs +++ b/tests/ui/imports/issue-55884-2.rs @@ -6,6 +6,7 @@ mod parser { pub use options::*; // Private single import shadows public glob import, but arrives too late for initial // resolution of `use parser::ParseOptions` because it depends on that resolution itself. + #[allow(hidden_glob_reexports)] use ParseOptions; } diff --git a/tests/ui/imports/issue-55884-2.stderr b/tests/ui/imports/issue-55884-2.stderr index 5adbc4b66d133..67d4114149a4b 100644 --- a/tests/ui/imports/issue-55884-2.stderr +++ b/tests/ui/imports/issue-55884-2.stderr @@ -1,16 +1,16 @@ error[E0603]: struct import `ParseOptions` is private - --> $DIR/issue-55884-2.rs:12:17 + --> $DIR/issue-55884-2.rs:13:17 | LL | pub use parser::ParseOptions; | ^^^^^^^^^^^^ private struct import | note: the struct import `ParseOptions` is defined here... - --> $DIR/issue-55884-2.rs:9:9 + --> $DIR/issue-55884-2.rs:10:9 | LL | use ParseOptions; | ^^^^^^^^^^^^ note: ...and refers to the struct import `ParseOptions` which is defined here... - --> $DIR/issue-55884-2.rs:12:9 + --> $DIR/issue-55884-2.rs:13:9 | LL | pub use parser::ParseOptions; | ^^^^^^^^^^^^^^^^^^^^ consider importing it directly diff --git a/tests/ui/resolve/hidden_glob_reexports.rs b/tests/ui/resolve/hidden_glob_reexports.rs new file mode 100644 index 0000000000000..361243fcd7bdf --- /dev/null +++ b/tests/ui/resolve/hidden_glob_reexports.rs @@ -0,0 +1,52 @@ +// check-pass + +pub mod upstream_a { + mod inner { + pub struct Foo {} + pub struct Bar {} + } + + pub use self::inner::*; + + struct Foo; + //~^ WARN private item shadows public glob re-export +} + +pub mod upstream_b { + mod inner { + pub struct Foo {} + pub struct Qux {} + } + + mod other { + pub struct Foo; + } + + pub use self::inner::*; + + use self::other::Foo; + //~^ WARN private item shadows public glob re-export +} + +pub mod upstream_c { + mod no_def_id { + #![allow(non_camel_case_types)] + pub struct u8; + pub struct World; + } + + pub use self::no_def_id::*; + + use std::primitive::u8; + //~^ WARN private item shadows public glob re-export +} + +// Downstream crate +// mod downstream { +// fn proof() { +// let _ = crate::upstream_a::Foo; +// let _ = crate::upstream_b::Foo; +// } +// } + +pub fn main() {} diff --git a/tests/ui/resolve/hidden_glob_reexports.stderr b/tests/ui/resolve/hidden_glob_reexports.stderr new file mode 100644 index 0000000000000..ddf7bcda827a8 --- /dev/null +++ b/tests/ui/resolve/hidden_glob_reexports.stderr @@ -0,0 +1,31 @@ +warning: private item shadows public glob re-export + --> $DIR/hidden_glob_reexports.rs:11:5 + | +LL | pub use self::inner::*; + | -------------- the name `Foo` in the type namespace is supposed to be publicly re-exported here +LL | +LL | struct Foo; + | ^^^^^^^^^^^ but the private item here shadows it + | + = note: `#[warn(hidden_glob_reexports)]` on by default + +warning: private item shadows public glob re-export + --> $DIR/hidden_glob_reexports.rs:27:9 + | +LL | pub use self::inner::*; + | -------------- the name `Foo` in the type namespace is supposed to be publicly re-exported here +LL | +LL | use self::other::Foo; + | ^^^^^^^^^^^^^^^^ but the private item here shadows it + +warning: private item shadows public glob re-export + --> $DIR/hidden_glob_reexports.rs:40:9 + | +LL | pub use self::no_def_id::*; + | ------------------ the name `u8` in the type namespace is supposed to be publicly re-exported here +LL | +LL | use std::primitive::u8; + | ^^^^^^^^^^^^^^^^^^ but the private item here shadows it + +warning: 3 warnings emitted + From b7db3de8d523145e2530619421eef2d10e116e96 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 27 May 2023 14:46:54 +0200 Subject: [PATCH 50/69] Clean up usage of `cx.tcx` when `tcx` is already set into a variable --- src/librustdoc/clean/inline.rs | 4 +-- src/librustdoc/clean/utils.rs | 2 +- src/librustdoc/formats/cache.rs | 2 +- src/librustdoc/html/render/print_item.rs | 17 +++++----- src/librustdoc/html/render/type_layout.rs | 4 +-- .../passes/collect_intra_doc_links.rs | 4 +-- src/librustdoc/passes/collect_trait_impls.rs | 34 +++++++++---------- .../passes/lint/unescaped_backticks.rs | 2 +- src/librustdoc/visit_ast.rs | 13 ++++--- 9 files changed, 39 insertions(+), 43 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index c852f9cca2bfd..7dc08b3b1ffa6 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -355,9 +355,9 @@ pub(crate) fn build_impl( return; } - let _prof_timer = cx.tcx.sess.prof.generic_activity("build_impl"); - let tcx = cx.tcx; + let _prof_timer = tcx.sess.prof.generic_activity("build_impl"); + let associated_trait = tcx.impl_trait_ref(did).map(ty::EarlyBinder::skip_binder); // Only inline impl if the implemented trait is diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 17aa6b38e389c..366f93952963f 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -193,7 +193,7 @@ pub(crate) fn build_deref_target_impls( }; if let Some(prim) = target.primitive_type() { - let _prof_timer = cx.tcx.sess.prof.generic_activity("build_primitive_inherent_impls"); + let _prof_timer = tcx.sess.prof.generic_activity("build_primitive_inherent_impls"); for did in prim.impls(tcx).filter(|did| !did.is_local()) { inline::build_impl(cx, did, None, ret); } diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index c0730e90740eb..297e70a4b2f2a 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -147,7 +147,7 @@ impl Cache { // Cache where all our extern crates are located // FIXME: this part is specific to HTML so it'd be nice to remove it from the common code - for &crate_num in cx.tcx.crates(()) { + for &crate_num in tcx.crates(()) { let e = ExternalCrate { crate_num }; let name = e.name(tcx); diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 4cc81e860f09a..dd23abf0e2c9b 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -356,18 +356,18 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: clean::ImportItem(ref import) => { let stab_tags = if let Some(import_def_id) = import.source.did { - let ast_attrs = cx.tcx().get_attrs_unchecked(import_def_id); + let ast_attrs = tcx.get_attrs_unchecked(import_def_id); let import_attrs = Box::new(clean::Attributes::from_ast(ast_attrs)); // Just need an item with the correct def_id and attrs let import_item = clean::Item { item_id: import_def_id.into(), attrs: import_attrs, - cfg: ast_attrs.cfg(cx.tcx(), &cx.cache().hidden_cfg), + cfg: ast_attrs.cfg(tcx, &cx.cache().hidden_cfg), ..myitem.clone() }; - let stab_tags = Some(extra_info_tags(&import_item, item, cx.tcx()).to_string()); + let stab_tags = Some(extra_info_tags(&import_item, item, tcx).to_string()); stab_tags } else { None @@ -405,8 +405,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: let unsafety_flag = match *myitem.kind { clean::FunctionItem(_) | clean::ForeignFunctionItem(_) - if myitem.fn_header(cx.tcx()).unwrap().unsafety - == hir::Unsafety::Unsafe => + if myitem.fn_header(tcx).unwrap().unsafety == hir::Unsafety::Unsafe => { "" } @@ -439,7 +438,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: {docs_before}{docs}{docs_after}", name = myitem.name.unwrap(), visibility_emoji = visibility_emoji, - stab_tags = extra_info_tags(myitem, item, cx.tcx()), + stab_tags = extra_info_tags(myitem, item, tcx), class = myitem.type_(), unsafety_flag = unsafety_flag, href = item_path(myitem.type_(), myitem.name.unwrap().as_str()), @@ -886,7 +885,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: write_small_section_header(w, "foreign-impls", "Implementations on Foreign Types", ""); for implementor in foreign { - let provided_methods = implementor.inner_impl().provided_trait_methods(cx.tcx()); + let provided_methods = implementor.inner_impl().provided_trait_methods(tcx); let assoc_link = AssocItemLink::GotoSource(implementor.impl_item.item_id, &provided_methods); render_impl( @@ -919,7 +918,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: } w.write_str(""); - if t.is_auto(cx.tcx()) { + if t.is_auto(tcx) { write_small_section_header( w, "synthetic-implementors", @@ -948,7 +947,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: "
", ); - if t.is_auto(cx.tcx()) { + if t.is_auto(tcx) { write_small_section_header( w, "synthetic-implementors", diff --git a/src/librustdoc/html/render/type_layout.rs b/src/librustdoc/html/render/type_layout.rs index 22aec623335e8..c9b95b1e64599 100644 --- a/src/librustdoc/html/render/type_layout.rs +++ b/src/librustdoc/html/render/type_layout.rs @@ -54,13 +54,13 @@ pub(crate) fn document_type_layout<'a, 'cx: 'a>( } else if let Primitive::Int(i, _) = tag.primitive() { i.size().bytes() } else { - span_bug!(cx.tcx().def_span(ty_def_id), "tag is neither niche nor int") + span_bug!(tcx.def_span(ty_def_id), "tag is neither niche nor int") }; variants .iter_enumerated() .map(|(variant_idx, variant_layout)| { let Adt(adt, _) = type_layout.ty.kind() else { - span_bug!(cx.tcx().def_span(ty_def_id), "not an adt") + span_bug!(tcx.def_span(ty_def_id), "not an adt") }; let name = adt.variant(variant_idx).name; let is_unsized = variant_layout.abi.is_unsized(); diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 9e6894a77dfa0..8ab7e58bf7498 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -723,7 +723,7 @@ fn resolve_associated_trait_item<'a>( .iter() .flat_map(|&(impl_, trait_)| { filter_assoc_items_by_name_and_namespace( - cx.tcx, + tcx, trait_, Ident::with_dummy_span(item_name), ns, @@ -1706,7 +1706,7 @@ fn resolution_failure( if let Ok(v_res) = collector.resolve(start, ns, item_id, module_id) { debug!("found partial_res={:?}", v_res); if !v_res.is_empty() { - *partial_res = Some(full_res(collector.cx.tcx, v_res[0])); + *partial_res = Some(full_res(tcx, v_res[0])); *unresolved = end.into(); break 'outer; } diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 8d204ddb79e39..fbf827cce0984 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -19,9 +19,10 @@ pub(crate) const COLLECT_TRAIT_IMPLS: Pass = Pass { }; pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate { + let tcx = cx.tcx; // We need to check if there are errors before running this pass because it would crash when // we try to get auto and blanket implementations. - if cx.tcx.sess.diagnostic().has_errors_or_lint_errors().is_some() { + if tcx.sess.diagnostic().has_errors_or_lint_errors().is_some() { return krate; } @@ -32,8 +33,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> }); let local_crate = ExternalCrate { crate_num: LOCAL_CRATE }; - let prims: FxHashSet = - local_crate.primitives(cx.tcx).iter().map(|p| p.1).collect(); + let prims: FxHashSet = local_crate.primitives(tcx).iter().map(|p| p.1).collect(); let crate_items = { let mut coll = ItemCollector::new(); @@ -46,9 +46,9 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> // External trait impls. { - let _prof_timer = cx.tcx.sess.prof.generic_activity("build_extern_trait_impls"); - for &cnum in cx.tcx.crates(()) { - for &impl_def_id in cx.tcx.trait_impls_in_crate(cnum) { + let _prof_timer = tcx.sess.prof.generic_activity("build_extern_trait_impls"); + for &cnum in tcx.crates(()) { + for &impl_def_id in tcx.trait_impls_in_crate(cnum) { inline::build_impl(cx, impl_def_id, None, &mut new_items_external); } } @@ -56,14 +56,13 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> // Local trait impls. { - let _prof_timer = cx.tcx.sess.prof.generic_activity("build_local_trait_impls"); + let _prof_timer = tcx.sess.prof.generic_activity("build_local_trait_impls"); let mut attr_buf = Vec::new(); - for &impl_def_id in cx.tcx.trait_impls_in_crate(LOCAL_CRATE) { - let mut parent = Some(cx.tcx.parent(impl_def_id)); + for &impl_def_id in tcx.trait_impls_in_crate(LOCAL_CRATE) { + let mut parent = Some(tcx.parent(impl_def_id)); while let Some(did) = parent { attr_buf.extend( - cx.tcx - .get_attrs(did, sym::doc) + tcx.get_attrs(did, sym::doc) .filter(|attr| { if let Some([attr]) = attr.meta_item_list().as_deref() { attr.has_name(sym::cfg) @@ -73,25 +72,24 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> }) .cloned(), ); - parent = cx.tcx.opt_parent(did); + parent = tcx.opt_parent(did); } inline::build_impl(cx, impl_def_id, Some((&attr_buf, None)), &mut new_items_local); attr_buf.clear(); } } - cx.tcx.sess.prof.generic_activity("build_primitive_trait_impls").run(|| { - for def_id in PrimitiveType::all_impls(cx.tcx) { + tcx.sess.prof.generic_activity("build_primitive_trait_impls").run(|| { + for def_id in PrimitiveType::all_impls(tcx) { // Try to inline primitive impls from other crates. if !def_id.is_local() { inline::build_impl(cx, def_id, None, &mut new_items_external); } } - for (prim, did) in PrimitiveType::primitive_locations(cx.tcx) { + for (prim, did) in PrimitiveType::primitive_locations(tcx) { // Do not calculate blanket impl list for docs that are not going to be rendered. // While the `impl` blocks themselves are only in `libcore`, the module with `doc` // attached is directly included in `libstd` as well. - let tcx = cx.tcx; if did.is_local() { for def_id in prim.impls(tcx).filter(|def_id| { // Avoid including impl blocks with filled-in generics. @@ -157,7 +155,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> // scan through included items ahead of time to splice in Deref targets to the "valid" sets for it in new_items_external.iter().chain(new_items_local.iter()) { if let ImplItem(box Impl { ref for_, ref trait_, ref items, .. }) = *it.kind && - trait_.as_ref().map(|t| t.def_id()) == cx.tcx.lang_items().deref_trait() && + trait_.as_ref().map(|t| t.def_id()) == tcx.lang_items().deref_trait() && cleaner.keep_impl(for_, true) { let target = items @@ -199,7 +197,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> if let ImplItem(box Impl { ref for_, ref trait_, ref kind, .. }) = *it.kind { cleaner.keep_impl( for_, - trait_.as_ref().map(|t| t.def_id()) == cx.tcx.lang_items().deref_trait(), + trait_.as_ref().map(|t| t.def_id()) == tcx.lang_items().deref_trait(), ) || trait_.as_ref().map_or(false, |t| cleaner.keep_impl_with_def_id(t.def_id().into())) || kind.is_blanket() } else { diff --git a/src/librustdoc/passes/lint/unescaped_backticks.rs b/src/librustdoc/passes/lint/unescaped_backticks.rs index 33cef82a60cbb..6feb6537dd7d1 100644 --- a/src/librustdoc/passes/lint/unescaped_backticks.rs +++ b/src/librustdoc/passes/lint/unescaped_backticks.rs @@ -56,7 +56,7 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) { ) .unwrap_or_else(|| item.attr_span(tcx)); - cx.tcx.struct_span_lint_hir(crate::lint::UNESCAPED_BACKTICKS, hir_id, span, "unescaped backtick", |lint| { + tcx.struct_span_lint_hir(crate::lint::UNESCAPED_BACKTICKS, hir_id, span, "unescaped backtick", |lint| { let mut help_emitted = false; match element.prev_code_guess { diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 8f8dc6b709053..1681386ce192e 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -280,9 +280,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { return false; }; - let is_private = - !self.cx.cache.effective_visibilities.is_directly_public(self.cx.tcx, ori_res_did); - let is_hidden = inherits_doc_hidden(self.cx.tcx, res_did, None); + let is_private = !self.cx.cache.effective_visibilities.is_directly_public(tcx, ori_res_did); + let is_hidden = inherits_doc_hidden(tcx, res_did, None); // Only inline if requested or if the item would otherwise be stripped. if (!please_inline && !is_private && !is_hidden) || is_no_inline { @@ -290,7 +289,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } if !please_inline && - let Some(item_def_id) = reexport_chain(self.cx.tcx, def_id, res_did).iter() + let Some(item_def_id) = reexport_chain(tcx, def_id, res_did).iter() .flat_map(|reexport| reexport.id()).map(|id| id.expect_local()) .chain(iter::once(res_did)).nth(1) && item_def_id != def_id && @@ -298,8 +297,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { .cx .cache .effective_visibilities - .is_directly_public(self.cx.tcx, item_def_id.to_def_id()) && - !inherits_doc_hidden(self.cx.tcx, item_def_id, None) + .is_directly_public(tcx, item_def_id.to_def_id()) && + !inherits_doc_hidden(tcx, item_def_id, None) { // The imported item is public and not `doc(hidden)` so no need to inline it. return false; @@ -313,7 +312,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { Node::Item(&hir::Item { kind: hir::ItemKind::Mod(ref m), .. }) if glob => { let prev = mem::replace(&mut self.inlining, true); for &i in m.item_ids { - let i = self.cx.tcx.hir().item(i); + let i = tcx.hir().item(i); self.visit_item_inner(i, None, Some(def_id)); } self.inlining = prev; From ef7f0e697bf4f0b8797527ba54f954e452253463 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 28 Apr 2023 14:05:01 +0100 Subject: [PATCH 51/69] Rework handling of recursive panics --- library/std/src/panicking.rs | 120 ++++++++++++++----------- tests/ui/backtrace.rs | 6 +- tests/ui/panics/nested_panic_caught.rs | 24 +++++ 3 files changed, 96 insertions(+), 54 deletions(-) create mode 100644 tests/ui/panics/nested_panic_caught.rs diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 6d59266b6f838..a6a370409c0e2 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -298,8 +298,18 @@ pub mod panic_count { pub const ALWAYS_ABORT_FLAG: usize = 1 << (usize::BITS - 1); - // Panic count for the current thread. - thread_local! { static LOCAL_PANIC_COUNT: Cell = const { Cell::new(0) } } + /// A reason for forcing an immediate abort on panic. + #[derive(Debug)] + pub enum MustAbort { + AlwaysAbort, + PanicInHook, + } + + // Panic count for the current thread and whether a panic hook is currently + // being executed.. + thread_local! { + static LOCAL_PANIC_COUNT: Cell<(usize, bool)> = const { Cell::new((0, false)) } + } // Sum of panic counts from all threads. The purpose of this is to have // a fast path in `count_is_zero` (which is used by `panicking`). In any particular @@ -328,34 +338,39 @@ pub mod panic_count { // panicking thread consumes at least 2 bytes of address space. static GLOBAL_PANIC_COUNT: AtomicUsize = AtomicUsize::new(0); - // Return the state of the ALWAYS_ABORT_FLAG and number of panics. + // Increases the global and local panic count, and returns whether an + // immediate abort is required. // - // If ALWAYS_ABORT_FLAG is not set, the number is determined on a per-thread - // base (stored in LOCAL_PANIC_COUNT), i.e. it is the amount of recursive calls - // of the calling thread. - // If ALWAYS_ABORT_FLAG is set, the number equals the *global* number of panic - // calls. See above why LOCAL_PANIC_COUNT is not used. - pub fn increase() -> (bool, usize) { + // This also updates thread-local state to keep track of whether a panic + // hook is currently executing. + pub fn increase(run_panic_hook: bool) -> Option { let global_count = GLOBAL_PANIC_COUNT.fetch_add(1, Ordering::Relaxed); - let must_abort = global_count & ALWAYS_ABORT_FLAG != 0; - let panics = if must_abort { - global_count & !ALWAYS_ABORT_FLAG - } else { - LOCAL_PANIC_COUNT.with(|c| { - let next = c.get() + 1; - c.set(next); - next - }) - }; - (must_abort, panics) + if global_count & ALWAYS_ABORT_FLAG != 0 { + return Some(MustAbort::AlwaysAbort); + } + + LOCAL_PANIC_COUNT.with(|c| { + let (count, in_panic_hook) = c.get(); + if in_panic_hook { + return Some(MustAbort::PanicInHook); + } + c.set((count + 1, run_panic_hook)); + None + }) + } + + pub fn finished_panic_hook() { + LOCAL_PANIC_COUNT.with(|c| { + let (count, _) = c.get(); + c.set((count, false)); + }); } pub fn decrease() { GLOBAL_PANIC_COUNT.fetch_sub(1, Ordering::Relaxed); LOCAL_PANIC_COUNT.with(|c| { - let next = c.get() - 1; - c.set(next); - next + let (count, _) = c.get(); + c.set((count - 1, false)); }); } @@ -366,7 +381,7 @@ pub mod panic_count { // Disregards ALWAYS_ABORT_FLAG #[must_use] pub fn get_count() -> usize { - LOCAL_PANIC_COUNT.with(|c| c.get()) + LOCAL_PANIC_COUNT.with(|c| c.get().0) } // Disregards ALWAYS_ABORT_FLAG @@ -394,7 +409,7 @@ pub mod panic_count { #[inline(never)] #[cold] fn is_zero_slow_path() -> bool { - LOCAL_PANIC_COUNT.with(|c| c.get() == 0) + LOCAL_PANIC_COUNT.with(|c| c.get().0 == 0) } } @@ -655,23 +670,22 @@ fn rust_panic_with_hook( location: &Location<'_>, can_unwind: bool, ) -> ! { - let (must_abort, panics) = panic_count::increase(); - - // If this is the third nested call (e.g., panics == 2, this is 0-indexed), - // the panic hook probably triggered the last panic, otherwise the - // double-panic check would have aborted the process. In this case abort the - // process real quickly as we don't want to try calling it again as it'll - // probably just panic again. - if must_abort || panics > 2 { - if panics > 2 { - // Don't try to print the message in this case - // - perhaps that is causing the recursive panics. - rtprintpanic!("thread panicked while processing panic. aborting.\n"); - } else { - // Unfortunately, this does not print a backtrace, because creating - // a `Backtrace` will allocate, which we must to avoid here. - let panicinfo = PanicInfo::internal_constructor(message, location, can_unwind); - rtprintpanic!("{panicinfo}\npanicked after panic::always_abort(), aborting.\n"); + let must_abort = panic_count::increase(true); + + // Check if we need to abort immediately. + if let Some(must_abort) = must_abort { + match must_abort { + panic_count::MustAbort::PanicInHook => { + // Don't try to print the message in this case + // - perhaps that is causing the recursive panics. + rtprintpanic!("thread panicked while processing panic. aborting.\n"); + } + panic_count::MustAbort::AlwaysAbort => { + // Unfortunately, this does not print a backtrace, because creating + // a `Backtrace` will allocate, which we must to avoid here. + let panicinfo = PanicInfo::internal_constructor(message, location, can_unwind); + rtprintpanic!("{panicinfo}\npanicked after panic::always_abort(), aborting.\n"); + } } crate::sys::abort_internal(); } @@ -697,16 +711,16 @@ fn rust_panic_with_hook( }; drop(hook); - if panics > 1 || !can_unwind { - // If a thread panics while it's already unwinding then we - // have limited options. Currently our preference is to - // just abort. In the future we may consider resuming - // unwinding or otherwise exiting the thread cleanly. - if !can_unwind { - rtprintpanic!("thread caused non-unwinding panic. aborting.\n"); - } else { - rtprintpanic!("thread panicked while panicking. aborting.\n"); - } + // Indicate that we have finished executing the panic hook. After this point + // it is fine if there is a panic while executing destructors, as long as it + // it contained within a `catch_unwind`. + panic_count::finished_panic_hook(); + + if !can_unwind { + // If a thread panics while running destructors or tries to unwind + // through a nounwind function (e.g. extern "C") then we cannot continue + // unwinding and have to abort immediately. + rtprintpanic!("thread caused non-unwinding panic. aborting.\n"); crate::sys::abort_internal(); } @@ -716,7 +730,7 @@ fn rust_panic_with_hook( /// This is the entry point for `resume_unwind`. /// It just forwards the payload to the panic runtime. pub fn rust_panic_without_hook(payload: Box) -> ! { - panic_count::increase(); + panic_count::increase(false); struct RewrapBox(Box); diff --git a/tests/ui/backtrace.rs b/tests/ui/backtrace.rs index dd73dd9886a3b..66b378f62d63c 100644 --- a/tests/ui/backtrace.rs +++ b/tests/ui/backtrace.rs @@ -104,13 +104,17 @@ fn runtest(me: &str) { "bad output3: {}", s); // Make sure a stack trace isn't printed too many times + // + // Currently it is printed 3 times ("once", "twice" and "panic in a + // function that cannot unwind") but in the future the last one may be + // removed. let p = template(me).arg("double-fail") .env("RUST_BACKTRACE", "1").spawn().unwrap(); let out = p.wait_with_output().unwrap(); assert!(!out.status.success()); let s = str::from_utf8(&out.stderr).unwrap(); let mut i = 0; - for _ in 0..2 { + for _ in 0..3 { i += s[i + 10..].find("stack backtrace").unwrap() + 10; } assert!(s[i + 10..].find("stack backtrace").is_none(), diff --git a/tests/ui/panics/nested_panic_caught.rs b/tests/ui/panics/nested_panic_caught.rs new file mode 100644 index 0000000000000..d43886e809579 --- /dev/null +++ b/tests/ui/panics/nested_panic_caught.rs @@ -0,0 +1,24 @@ +// run-pass +// needs-unwind + +// Checks that nested panics work correctly. + +use std::panic::catch_unwind; + +fn double() { + struct Double; + + impl Drop for Double { + fn drop(&mut self) { + let _ = catch_unwind(|| panic!("twice")); + } + } + + let _d = Double; + + panic!("once"); +} + +fn main() { + assert!(catch_unwind(|| double()).is_err()); +} From de607f1b5cc99d8ac773205702e184c2461d5e12 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 29 Apr 2023 07:23:54 +0100 Subject: [PATCH 52/69] Add support for nested panics to miri --- src/tools/miri/src/concurrency/thread.rs | 19 ++++++++---- src/tools/miri/src/shims/panic.rs | 5 ++-- .../miri/tests/fail/panic/double_panic.rs | 3 +- .../miri/tests/fail/panic/double_panic.stderr | 29 +++++-------------- .../tests/pass/panic/nested_panic_caught.rs | 25 ++++++++++++++++ .../pass/panic/nested_panic_caught.stderr | 4 +++ 6 files changed, 53 insertions(+), 32 deletions(-) create mode 100644 src/tools/miri/tests/pass/panic/nested_panic_caught.rs create mode 100644 src/tools/miri/tests/pass/panic/nested_panic_caught.stderr diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index d85cac7bcbb58..25c8df43ee26c 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -133,10 +133,15 @@ pub struct Thread<'mir, 'tcx> { /// The join status. join_status: ThreadJoinStatus, - /// The temporary used for storing the argument of - /// the call to `miri_start_panic` (the panic payload) when unwinding. + /// Stack of active panic payloads for the current thread. Used for storing + /// the argument of the call to `miri_start_panic` (the panic payload) when unwinding. /// This is pointer-sized, and matches the `Payload` type in `src/libpanic_unwind/miri.rs`. - pub(crate) panic_payload: Option>, + /// + /// In real unwinding, the payload gets passed as an argument to the landing pad, + /// which then forwards it to 'Resume'. However this argument is implicit in MIR, + /// so we have to store it out-of-band. When there are multiple active unwinds, + /// the innermost one is always caught first, so we can store them as a stack. + pub(crate) panic_payloads: Vec>, /// Last OS error location in memory. It is a 32-bit integer. pub(crate) last_error: Option>, @@ -206,7 +211,7 @@ impl<'mir, 'tcx> Thread<'mir, 'tcx> { stack: Vec::new(), top_user_relevant_frame: None, join_status: ThreadJoinStatus::Joinable, - panic_payload: None, + panic_payloads: Vec::new(), last_error: None, on_stack_empty, } @@ -216,7 +221,7 @@ impl<'mir, 'tcx> Thread<'mir, 'tcx> { impl VisitTags for Thread<'_, '_> { fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { let Thread { - panic_payload, + panic_payloads: panic_payload, last_error, stack, top_user_relevant_frame: _, @@ -226,7 +231,9 @@ impl VisitTags for Thread<'_, '_> { on_stack_empty: _, // we assume the closure captures no GC-relevant state } = self; - panic_payload.visit_tags(visit); + for payload in panic_payload { + payload.visit_tags(visit); + } last_error.visit_tags(visit); for frame in stack { frame.visit_tags(visit) diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs index 18ae01a19f914..7aefdfcb976af 100644 --- a/src/tools/miri/src/shims/panic.rs +++ b/src/tools/miri/src/shims/panic.rs @@ -63,8 +63,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let [payload] = this.check_shim(abi, Abi::Rust, link_name, args)?; let payload = this.read_scalar(payload)?; let thread = this.active_thread_mut(); - assert!(thread.panic_payload.is_none(), "the panic runtime should avoid double-panics"); - thread.panic_payload = Some(payload); + thread.panic_payloads.push(payload); // Jump to the unwind block to begin unwinding. this.unwind_to_block(unwind)?; @@ -146,7 +145,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // The Thread's `panic_payload` holds what was passed to `miri_start_panic`. // This is exactly the second argument we need to pass to `catch_fn`. - let payload = this.active_thread_mut().panic_payload.take().unwrap(); + let payload = this.active_thread_mut().panic_payloads.pop().unwrap(); // Push the `catch_fn` stackframe. let f_instance = this.get_ptr_fn(catch_unwind.catch_fn)?.as_instance()?; diff --git a/src/tools/miri/tests/fail/panic/double_panic.rs b/src/tools/miri/tests/fail/panic/double_panic.rs index 9378adb8609df..adb30714269e8 100644 --- a/src/tools/miri/tests/fail/panic/double_panic.rs +++ b/src/tools/miri/tests/fail/panic/double_panic.rs @@ -1,6 +1,4 @@ -//@error-in-other-file: the program aborted //@normalize-stderr-test: "\| +\^+" -> "| ^" -//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "$1" //@normalize-stderr-test: "\n at [^\n]+" -> "$1" @@ -11,6 +9,7 @@ impl Drop for Foo { } } fn main() { + //~^ERROR: panic in a function that cannot unwind let _foo = Foo; panic!("first"); } diff --git a/src/tools/miri/tests/fail/panic/double_panic.stderr b/src/tools/miri/tests/fail/panic/double_panic.stderr index 77d5fc5d7ceb9..b6ac56f15d4b5 100644 --- a/src/tools/miri/tests/fail/panic/double_panic.stderr +++ b/src/tools/miri/tests/fail/panic/double_panic.stderr @@ -2,30 +2,17 @@ thread 'main' panicked at 'first', $DIR/double_panic.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace thread 'main' panicked at 'second', $DIR/double_panic.rs:LL:CC stack backtrace: -thread panicked while panicking. aborting. -error: abnormal termination: the program aborted execution - --> RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC - | -LL | ABORT(); - | ^ the program aborted execution - | - = note: inside `std::sys::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC - = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC - = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC -note: inside `::drop` +error: abnormal termination: panic in a function that cannot unwind --> $DIR/double_panic.rs:LL:CC | -LL | panic!("second"); - | ^ - = note: inside `std::ptr::drop_in_place:: - shim(Some(Foo))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC -note: inside `main` - --> $DIR/double_panic.rs:LL:CC +LL | / fn main() { +LL | | +LL | | let _foo = Foo; +LL | | panic!("first"); +LL | | } + | |_^ panic in a function that cannot unwind | -LL | } - | ^ - = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: inside `main` at $DIR/double_panic.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/pass/panic/nested_panic_caught.rs b/src/tools/miri/tests/pass/panic/nested_panic_caught.rs new file mode 100644 index 0000000000000..884813150ad2a --- /dev/null +++ b/src/tools/miri/tests/pass/panic/nested_panic_caught.rs @@ -0,0 +1,25 @@ +//@normalize-stderr-test: "\| +\^+" -> "| ^" +//@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "$1" +//@normalize-stderr-test: "\n at [^\n]+" -> "$1" + +// Checks that nested panics work correctly. + +use std::panic::catch_unwind; + +fn double() { + struct Double; + + impl Drop for Double { + fn drop(&mut self) { + let _ = catch_unwind(|| panic!("twice")); + } + } + + let _d = Double; + + panic!("once"); +} + +fn main() { + assert!(catch_unwind(|| double()).is_err()); +} diff --git a/src/tools/miri/tests/pass/panic/nested_panic_caught.stderr b/src/tools/miri/tests/pass/panic/nested_panic_caught.stderr new file mode 100644 index 0000000000000..4e2593242df75 --- /dev/null +++ b/src/tools/miri/tests/pass/panic/nested_panic_caught.stderr @@ -0,0 +1,4 @@ +thread 'main' panicked at 'once', $DIR/nested_panic_caught.rs:LL:CC +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +thread 'main' panicked at 'twice', $DIR/nested_panic_caught.rs:LL:CC +stack backtrace: From 6240d4518930bdf20b44109e55d047eec3221c9a Mon Sep 17 00:00:00 2001 From: dekrain Date: Mon, 13 Mar 2023 18:28:59 +0100 Subject: [PATCH 53/69] Fix ICE caused by at-expanding argument 0 instead of removing it early --- compiler/rustc_driver_impl/src/args.rs | 3 +++ compiler/rustc_driver_impl/src/lib.rs | 13 ++++++++++--- src/librustdoc/config.rs | 1 - src/librustdoc/lib.rs | 12 +++++++++++- 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_driver_impl/src/args.rs b/compiler/rustc_driver_impl/src/args.rs index 42c97cc6a9d74..5ddacc388637b 100644 --- a/compiler/rustc_driver_impl/src/args.rs +++ b/compiler/rustc_driver_impl/src/args.rs @@ -18,6 +18,9 @@ fn arg_expand(arg: String) -> Result, Error> { } } +/// **Note:** This function doesn't interpret argument 0 in any special way. +/// If this function is intended to be used with command line arguments, +/// `argv[0]` must be removed prior to calling it manually. pub fn arg_expand_all(at_args: &[String]) -> Vec { let mut args = Vec::new(); for arg in at_args { diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 555917c8b5e9c..88f3b24bc9864 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -237,6 +237,16 @@ fn run_compiler( Box Box + Send>, >, ) -> interface::Result<()> { + // Throw away the first argument, the name of the binary. + // In case of at_args being empty, as might be the case by + // passing empty argument array to execve under some platforms, + // just use an empty slice. + // + // This situation was possible before due to arg_expand_all being + // called before removing the argument, enabling a crash by calling + // the compiler with @empty_file as argv[0] and no more arguments. + let at_args = at_args.get(1..).unwrap_or_default(); + let args = args::arg_expand_all(at_args); let Some(matches) = handle_options(&args) else { return Ok(()) }; @@ -993,9 +1003,6 @@ pub fn print_flag_list( /// So with all that in mind, the comments below have some more detail about the /// contortions done here to get things to work out correctly. pub fn handle_options(args: &[String]) -> Option { - // Throw away the first argument, the name of the binary - let args = &args[1..]; - if args.is_empty() { // user did not write `-v` nor `-Z unstable-options`, so do not // include that extra information. diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 2c514a0c8267b..22356229d0576 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -321,7 +321,6 @@ impl Options { matches: &getopts::Matches, args: Vec, ) -> Result<(Options, RenderOptions), i32> { - let args = &args[1..]; // Check for unstable options. nightly_options::check_nightly_options(matches, &opts()); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 4fcf0873600ab..da32d429dac17 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -703,13 +703,23 @@ fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>( } fn main_args(at_args: &[String]) -> MainResult { + // Throw away the first argument, the name of the binary. + // In case of at_args being empty, as might be the case by + // passing empty argument array to execve under some platforms, + // just use an empty slice. + // + // This situation was possible before due to arg_expand_all being + // called before removing the argument, enabling a crash by calling + // the compiler with @empty_file as argv[0] and no more arguments. + let at_args = at_args.get(1..).unwrap_or_default(); + let args = rustc_driver::args::arg_expand_all(at_args); let mut options = getopts::Options::new(); for option in opts() { (option.apply)(&mut options); } - let matches = match options.parse(&args[1..]) { + let matches = match options.parse(&args) { Ok(m) => m, Err(err) => { early_error(ErrorOutputType::default(), &err.to_string()); From 89b9b25cfab50a34612c5156309e8682fb65517e Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sat, 29 Apr 2023 21:37:05 -0400 Subject: [PATCH 54/69] 1.70.0 release notes --- RELEASES.md | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 85266a17550ad..fa95df685aaa4 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,139 @@ +Version 1.70.0 (2023-06-01) +========================== + +
+ +Language +-------- +- [Relax ordering rules for `asm!` operands](https://github.com/rust-lang/rust/pull/105798/) +- [Properly allow macro expanded `format_args` invocations to uses captures](https://github.com/rust-lang/rust/pull/106505/) +- [Lint ambiguous glob re-exports](https://github.com/rust-lang/rust/pull/107880/) +- [Perform const and unsafe checking for expressions in `let _ = expr` position.](https://github.com/rust-lang/rust/pull/102256/) + + + +Compiler +-------- +- [Extend -Cdebuginfo with new options and named aliases](https://github.com/rust-lang/rust/pull/109808/) + This provides a smaller version of debuginfo for cases that only need line number information + (`-Cdebuginfo=line-tables-only`), which may eventually become the default for `-Cdebuginfo=1`. +- [Make `unused_allocation` lint against `Box::new` too](https://github.com/rust-lang/rust/pull/104363/) +- [Detect uninhabited types early in const eval](https://github.com/rust-lang/rust/pull/109435/) +- [Switch to LLD as default linker for {arm,thumb}v4t-none-eabi](https://github.com/rust-lang/rust/pull/109721/) +- [Add tier 3 target `loongarch64-unknown-linux-gnu`](https://github.com/rust-lang/rust/pull/96971) +- [Add tier 3 target for `i586-pc-nto-qnx700` (QNX Neutrino RTOS, version 7.0)](https://github.com/rust-lang/rust/pull/109173/), +- [Insert alignment checks for pointer dereferences as debug assertions](https://github.com/rust-lang/rust/pull/98112) + This catches undefined behavior at runtime, and may cause existing code to fail. + +Refer to Rust's [platform support page][platform-support-doc] +for more information on Rust's tiered platform support. + + + +Libraries +--------- +- [Document NonZeroXxx layout guarantees](https://github.com/rust-lang/rust/pull/94786/) +- [Windows: make `Command` prefer non-verbatim paths](https://github.com/rust-lang/rust/pull/96391/) +- [Implement Default for some alloc/core iterators](https://github.com/rust-lang/rust/pull/99929/) +- [Fix handling of trailing bare CR in str::lines](https://github.com/rust-lang/rust/pull/100311/) +- [allow negative numeric literals in `concat!`](https://github.com/rust-lang/rust/pull/106844/) +- [Add documentation about the memory layout of `Cell`](https://github.com/rust-lang/rust/pull/106921/) +- [Use `partial_cmp` to implement tuple `lt`/`le`/`ge`/`gt`](https://github.com/rust-lang/rust/pull/108157/) +- [Stabilize `atomic_as_ptr`](https://github.com/rust-lang/rust/pull/108419/) +- [Stabilize `nonnull_slice_from_raw_parts`](https://github.com/rust-lang/rust/pull/97506/) +- [Partial stabilization of `once_cell`](https://github.com/rust-lang/rust/pull/105587/) +- [Stabilize `nonzero_min_max`](https://github.com/rust-lang/rust/pull/106633/) +- [Flatten/inline format_args!() and (string and int) literal arguments into format_args!()](https://github.com/rust-lang/rust/pull/106824/) +- [Stabilize movbe target feature](https://github.com/rust-lang/rust/pull/107711/) +- [don't splice from files into pipes in io::copy](https://github.com/rust-lang/rust/pull/108283/) +- [Add a builtin unstable `FnPtr` trait that is implemented for all function pointers](https://github.com/rust-lang/rust/pull/108080/) + This extends `Debug`, `Pointer`, `Hash`, `PartialEq`, `Eq`, `PartialOrd`, and `Ord` + implementations for function pointers with all ABIs. + + + +Stabilized APIs +--------------- + +- [`NonZero*::MIN/MAX`](https://doc.rust-lang.org/stable/std/num/struct.NonZeroI8.html#associatedconstant.MIN) +- [`BinaryHeap::retain`](https://doc.rust-lang.org/stable/std/collections/struct.BinaryHeap.html#method.retain) +- [`Default for std::collections::binary_heap::IntoIter`](https://doc.rust-lang.org/stable/std/collections/binary_heap/struct.IntoIter.html) +- [`Default for std::collections::btree_map::{IntoIter, Iter, IterMut}`](https://doc.rust-lang.org/stable/std/collections/btree_map/struct.IntoIter.html) +- [`Default for std::collections::btree_map::{IntoKeys, Keys}`](https://doc.rust-lang.org/stable/std/collections/btree_map/struct.IntoKeys.html) +- [`Default for std::collections::btree_map::{IntoValues, Values}`](https://doc.rust-lang.org/stable/std/collections/btree_map/struct.IntoKeys.html) +- [`Default for std::collections::btree_map::Range`](https://doc.rust-lang.org/stable/std/collections/btree_map/struct.Range.html) +- [`Default for std::collections::btree_set::{IntoIter, Iter}`](https://doc.rust-lang.org/stable/std/collections/btree_set/struct.IntoIter.html) +- [`Default for std::collections::btree_set::Range`](https://doc.rust-lang.org/stable/std/collections/btree_set/struct.Range.html) +- [`Default for std::collections::linked_list::{IntoIter, Iter, IterMut}`](https://doc.rust-lang.org/stable/alloc/collections/linked_list/struct.IntoIter.html) +- [`Default for std::vec::IntoIter`](https://doc.rust-lang.org/stable/alloc/vec/struct.IntoIter.html#impl-Default-for-IntoIter%3CT,+A%3E) +- [`Default for std::iter::Chain`](https://doc.rust-lang.org/stable/std/iter/struct.Chain.html) +- [`Default for std::iter::Cloned`](https://doc.rust-lang.org/stable/std/iter/struct.Cloned.html) +- [`Default for std::iter::Copied`](https://doc.rust-lang.org/stable/std/iter/struct.Copied.html) +- [`Default for std::iter::Enumerate`](https://doc.rust-lang.org/stable/std/iter/struct.Enumerate.html) +- [`Default for std::iter::Flatten`](https://doc.rust-lang.org/stable/std/iter/struct.Flatten.html) +- [`Default for std::iter::Fuse`](https://doc.rust-lang.org/stable/std/iter/struct.Fuse.html) +- [`Default for std::iter::Rev`](https://doc.rust-lang.org/stable/std/iter/struct.Rev.html) +- [`Default for std::slice::Iter`](https://doc.rust-lang.org/stable/std/slice/struct.Iter.html) +- [`Default for std::slice::IterMut`](https://doc.rust-lang.org/stable/std/slice/struct.IterMut.html) +- [`Rc::into_inner`](https://doc.rust-lang.org/stable/alloc/rc/struct.Rc.html#method.into_inner) +- [`Arc::into_inner`](https://doc.rust-lang.org/stable/alloc/sync/struct.Arc.html#method.into_inner) +- [`std::cell::OnceCell`](https://doc.rust-lang.org/stable/std/cell/struct.OnceCell.html) +- [`Option::is_some_and`](https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.is_some_and) +- [`NonNull::slice_from_raw_parts`](https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.slice_from_raw_parts) +- [`Result::is_ok_and`](https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.is_ok_and) +- [`Result::is_err_and`](https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.is_err_and) +- [`std::sync::atomic::Atomic*::as_ptr`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicU8.html#method.as_ptr) +- [`std::io::IsTerminal`](https://doc.rust-lang.org/stable/std/io/trait.IsTerminal.html) +- [`std::os::linux::net::SocketAddrExt`](https://doc.rust-lang.org/stable/std/os/linux/net/trait.SocketAddrExt.html) +- [`std::os::unix::net::UnixDatagram::bind_addr`](https://doc.rust-lang.org/stable/std/os/unix/net/struct.UnixDatagram.html#method.bind_addr) +- [`std::os::unix::net::UnixDatagram::connect_addr`](https://doc.rust-lang.org/stable/std/os/unix/net/struct.UnixDatagram.html#method.connect_addr) +- [`std::os::unix::net::UnixDatagram::send_to_addr`](https://doc.rust-lang.org/stable/std/os/unix/net/struct.UnixDatagram.html#method.send_to_addr) +- [`std::os::unix::net::UnixListener::bind_addr`](https://doc.rust-lang.org/stable/std/os/unix/net/struct.UnixListener.html#method.bind_addr) +- [`std::path::Path::as_mut_os_str`](https://doc.rust-lang.org/stable/std/path/struct.Path.html#method.as_mut_os_str) +- [`std::sync::OnceLock`](https://doc.rust-lang.org/stable/std/sync/struct.OnceLock.html) + + + +Cargo +----- + +- [Add `CARGO_PKG_README`](https://github.com/rust-lang/cargo/pull/11645/) +- [Make `sparse` the default protocol for crates.io](https://github.com/rust-lang/cargo/pull/11791/) +- [Accurately show status when downgrading dependencies](https://github.com/rust-lang/cargo/pull/11839/) +- [Use registry.default for login/logout](https://github.com/rust-lang/cargo/pull/11949/) +- [Stabilize `cargo logout`](https://github.com/rust-lang/cargo/pull/11950/) + + + +Misc +---- + +- [Stabilize rustdoc `--test-run-directory`](https://github.com/rust-lang/rust/pull/103682/) + + + +Compatibility Notes +------------------- + +- [Prevent stable `libtest` from supporting `-Zunstable-options`](https://github.com/rust-lang/rust/pull/109044/) +- [Perform const and unsafe checking for expressions in `let _ = expr` position.](https://github.com/rust-lang/rust/pull/102256/) +- [WebAssembly targets enable `sign-ext` and `mutable-globals` features in codegen](https://github.com/rust-lang/rust/issues/109807) + This may cause incompatibility with older execution environments. +- [Insert alignment checks for pointer dereferences as debug assertions](https://github.com/rust-lang/rust/pull/98112) + This catches undefined behavior at runtime, and may cause existing code to fail. + + + +Internal Changes +---------------- + +These changes do not affect any public interfaces of Rust, but they represent +significant improvements to the performance or internals of rustc and related +tools. + +- [Upgrade to LLVM 16](https://github.com/rust-lang/rust/pull/109474/) +- [Use SipHash-1-3 instead of SipHash-2-4 for StableHasher](https://github.com/rust-lang/rust/pull/107925/) + Version 1.69.0 (2023-04-20) ========================== From 7e04c93493a2f9b4d508e6bbf08227407683d666 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Fri, 26 May 2023 14:47:51 -0400 Subject: [PATCH 55/69] Try enabling MatchBranchSimplification --- .../rustc_mir_transform/src/match_branches.rs | 9 ++++++-- .../src/traits/fulfill.rs | 1 + ...s_fixedpoint.foo.SimplifyLocals-final.diff | 7 ++----- tests/mir-opt/switch_to_self.rs | 21 +++++++++++++++++++ ...o_self.test.MatchBranchSimplification.diff | 19 +++++++++++++++++ 5 files changed, 50 insertions(+), 7 deletions(-) create mode 100644 tests/mir-opt/switch_to_self.rs create mode 100644 tests/mir-opt/switch_to_self.test.MatchBranchSimplification.diff diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs index 59942dc76f9aa..6eb4849827447 100644 --- a/compiler/rustc_mir_transform/src/match_branches.rs +++ b/compiler/rustc_mir_transform/src/match_branches.rs @@ -41,7 +41,7 @@ pub struct MatchBranchSimplification; impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - sess.mir_opt_level() >= 3 + sess.mir_opt_level() >= 1 } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { @@ -62,7 +62,12 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { .. } if targets.iter().len() == 1 => { let (value, target) = targets.iter().next().unwrap(); - if target == targets.otherwise() { + // We require that this block and the two possible target blocks all be + // distinct. + if target == targets.otherwise() + || bb_idx == target + || bb_idx == targets.otherwise() + { continue; } (discr, value, target, targets.otherwise()) diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 2f85c32b5750d..88d2091de0f52 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -116,6 +116,7 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> { } impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { + #[inline] fn register_predicate_obligation( &mut self, infcx: &InferCtxt<'tcx>, diff --git a/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.diff b/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.diff index f908e8dd0c1f8..0b9ca29ceddc9 100644 --- a/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.diff +++ b/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.diff @@ -8,8 +8,6 @@ let mut _3: std::option::Option; // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:51: +1:68 let mut _4: isize; // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:22: +1:26 let mut _5: isize; // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:13: +1:20 -- let mut _7: bool; // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:20 -- let mut _8: u8; // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:13 scope 1 { debug a => _6; // in scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:18: +1:19 let _6: u8; // in scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:18: +1:19 @@ -34,10 +32,9 @@ } bb2: { + StorageLive(_6); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:18: +1:19 _6 = (((_1.0: std::option::Option) as Some).0: u8); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:18: +1:19 -- StorageLive(_7); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:20 -- _7 = Gt(_6, const 42_u8); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:20 -- StorageDead(_7); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+4:9: +4:10 + StorageDead(_6); // scope 0 at $DIR/simplify_locals_fixedpoint.rs:+5:5: +5:6 goto -> bb3; // scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:5: +5:6 } diff --git a/tests/mir-opt/switch_to_self.rs b/tests/mir-opt/switch_to_self.rs new file mode 100644 index 0000000000000..6678e4b3bd2e3 --- /dev/null +++ b/tests/mir-opt/switch_to_self.rs @@ -0,0 +1,21 @@ +// Test that MatchBranchSimplification doesn't ICE on a SwitchInt where +// one of the targets is the block that the SwitchInt terminates. +#![crate_type = "lib"] +#![feature(core_intrinsics, custom_mir)] +use std::intrinsics::mir::*; + +// EMIT_MIR switch_to_self.test.MatchBranchSimplification.diff +#[custom_mir(dialect = "runtime", phase = "post-cleanup")] +pub fn test(x: bool) { + mir!( + { + Goto(bb0) + } + bb0 = { + match x { false => bb0, _ => bb1 } + } + bb1 = { + match x { false => bb0, _ => bb1 } + } + ) +} diff --git a/tests/mir-opt/switch_to_self.test.MatchBranchSimplification.diff b/tests/mir-opt/switch_to_self.test.MatchBranchSimplification.diff new file mode 100644 index 0000000000000..b0a4f9f018848 --- /dev/null +++ b/tests/mir-opt/switch_to_self.test.MatchBranchSimplification.diff @@ -0,0 +1,19 @@ +- // MIR for `test` before MatchBranchSimplification ++ // MIR for `test` after MatchBranchSimplification + + fn test(_1: bool) -> () { + let mut _0: (); // return place in scope 0 at $DIR/switch_to_self.rs:+0:22: +0:22 + + bb0: { + goto -> bb1; // scope 0 at $DIR/switch_to_self.rs:+3:13: +3:22 + } + + bb1: { + switchInt(_1) -> [0: bb1, otherwise: bb2]; // scope 0 at $DIR/switch_to_self.rs:+6:13: +6:47 + } + + bb2: { + switchInt(_1) -> [0: bb1, otherwise: bb2]; // scope 0 at $DIR/switch_to_self.rs:+9:13: +9:47 + } + } + From 78acd5df8e761a4612ab34a00b49924550b55b62 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sat, 27 May 2023 14:23:37 -0400 Subject: [PATCH 56/69] Bump to 1.72.0 --- src/version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version b/src/version index df484cbb1d9f8..0834888f55808 100644 --- a/src/version +++ b/src/version @@ -1 +1 @@ -1.71.0 +1.72.0 From 0809338a139f0f02f79d40a60e752e38f43c5feb Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sat, 27 May 2023 14:47:08 -0400 Subject: [PATCH 57/69] Revert "Rollup merge of #111538 - chenyukang:yukang-fix-110067-version-issue, r=jyn514" This reverts commit 9267843e72c8692f934c2ef5505c8a7496c0f06e, reversing changes made to e52fbff5e8c2de7ba085ef84d7d50500b695d521. This breaks our ability to bump the src/version where we're bootstrapping with an older compiler than usual (according to version number). It's not clear whether the intended use case has a clean solution given this constraint, so reverting for now - we can reland with a fix of some kind implemented. --- src/bootstrap/Cargo.lock | 7 ------- src/bootstrap/Cargo.toml | 1 - src/bootstrap/config.rs | 38 -------------------------------------- src/bootstrap/lib.rs | 1 - 4 files changed, 47 deletions(-) diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index 8f8778efee796..311ac1751606e 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -58,7 +58,6 @@ dependencies = [ "once_cell", "opener", "pretty_assertions", - "semver", "serde", "serde_derive", "serde_json", @@ -646,12 +645,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -[[package]] -name = "semver" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" - [[package]] name = "serde" version = "1.0.160" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 367c6190967c6..70ade776d7da7 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -57,7 +57,6 @@ walkdir = "2" sysinfo = { version = "0.26.0", optional = true } clap = { version = "4.2.4", default-features = false, features = ["std", "usage", "help", "derive", "error-context"] } clap_complete = "4.2.2" -semver = "1.0.17" # Solaris doesn't support flock() and thus fd-lock is not option now [target.'cfg(not(target_os = "solaris"))'.dependencies] diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index e192cda9a9a71..41aca0210f677 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -24,7 +24,6 @@ pub use crate::flags::Subcommand; use crate::flags::{Color, Flags, Warnings}; use crate::util::{exe, output, t}; use once_cell::sync::OnceCell; -use semver::Version; use serde::{Deserialize, Deserializer}; use serde_derive::Deserialize; @@ -1118,7 +1117,6 @@ impl Config { config.download_beta_toolchain(); config.out.join(config.build.triple).join("stage0/bin/rustc") }); - config.initial_cargo = build .cargo .map(|cargo| { @@ -1780,42 +1778,6 @@ impl Config { self.rust_codegen_backends.get(0).cloned() } - pub fn check_build_rustc_version(&self) { - if self.dry_run() { - return; - } - - // check rustc version is same or lower with 1 apart from the building one - let mut cmd = Command::new(&self.initial_rustc); - cmd.arg("--version"); - let rustc_output = output(&mut cmd) - .lines() - .next() - .unwrap() - .split(' ') - .nth(1) - .unwrap() - .split('-') - .next() - .unwrap() - .to_owned(); - let rustc_version = Version::parse(&rustc_output.trim()).unwrap(); - let source_version = - Version::parse(&fs::read_to_string(self.src.join("src/version")).unwrap().trim()) - .unwrap(); - if !(source_version == rustc_version - || (source_version.major == rustc_version.major - && source_version.minor == rustc_version.minor + 1)) - { - let prev_version = format!("{}.{}.x", source_version.major, source_version.minor - 1); - eprintln!( - "Unexpected rustc version: {}, we should use {}/{} to build source with {}", - rustc_version, prev_version, source_version, source_version - ); - crate::detail_exit(1); - } - } - /// Returns the commit to download, or `None` if we shouldn't download CI artifacts. fn download_ci_rustc_commit(&self, download_rustc: Option) -> Option { // If `download-rustc` is not set, default to rebuilding. diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 943f513415a16..fb76dffd07156 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -414,7 +414,6 @@ impl Build { bootstrap_out.display() ) } - config.check_build_rustc_version(); if rust_info.is_from_tarball() && config.description.is_none() { config.description = Some("built from a source tarball".to_owned()); From de4dddf155ca599ca4c888bb4ee29989394c24d6 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 27 May 2023 14:52:14 -0400 Subject: [PATCH 58/69] Add a test for misaligned pointer derefs inside addr_of! --- tests/ui/mir/addrof_alignment.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tests/ui/mir/addrof_alignment.rs diff --git a/tests/ui/mir/addrof_alignment.rs b/tests/ui/mir/addrof_alignment.rs new file mode 100644 index 0000000000000..892638bfb92bd --- /dev/null +++ b/tests/ui/mir/addrof_alignment.rs @@ -0,0 +1,15 @@ +// run-pass +// ignore-wasm32-bare: No panic messages +// compile-flags: -C debug-assertions + +struct Misalignment { + a: u32, +} + +fn main() { + let items: [Misalignment; 2] = [Misalignment { a: 0 }, Misalignment { a: 1 }]; + unsafe { + let ptr: *const Misalignment = items.as_ptr().cast::().add(1).cast::(); + let _ptr = core::ptr::addr_of!((*ptr).a); + } +} From 783b1ce99c86106456329d7fc51c149bc27a282a Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 27 May 2023 14:52:41 -0400 Subject: [PATCH 59/69] Exclude Rvalue::AddressOf for raw pointer deref alignment checks --- compiler/rustc_mir_transform/src/check_alignment.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs index d60184e0ebef6..1fe8ea0789286 100644 --- a/compiler/rustc_mir_transform/src/check_alignment.rs +++ b/compiler/rustc_mir_transform/src/check_alignment.rs @@ -75,6 +75,14 @@ struct PointerFinder<'tcx, 'a> { } impl<'tcx, 'a> Visitor<'tcx> for PointerFinder<'tcx, 'a> { + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { + if let Rvalue::AddressOf(..) = rvalue { + // Ignore dereferences inside of an AddressOf + return; + } + self.super_rvalue(rvalue, location); + } + fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) { if let PlaceContext::NonUse(_) = context { return; From a7329cd66bdd58fce76fd8105911838dae7dc275 Mon Sep 17 00:00:00 2001 From: sladynnunes Date: Fri, 26 May 2023 12:42:32 -0700 Subject: [PATCH 60/69] Migrate to Askama Fix formatting Fix CI --- src/librustdoc/html/render/print_item.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 76c8e0885a0a2..a3d2d3c5cfda3 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1556,21 +1556,23 @@ fn item_static(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean write!(w, "{}", document(cx, it, None, HeadingOffset::H2)) } -fn item_foreign_type(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) { - wrap_item(w, |w| { - w.write_str("extern {\n"); - render_attributes_in_code(w, it, cx.tcx()); +fn item_foreign_type(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item) { + let mut buffer = Buffer::new(); + wrap_item(&mut buffer, |buffer| { + buffer.write_str("extern {\n"); + render_attributes_in_code(buffer, it, cx.tcx()); write!( - w, + buffer, " {}type {};\n}}", visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx), it.name.unwrap(), ); }); - write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); + write!(w, "{}{}", buffer.into_inner(), document(cx, it, None, HeadingOffset::H2)).unwrap(); write!(w, "{}", render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All)) + .unwrap(); } fn item_keyword(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) { From ab7c4b76b321e76c2735e960347a79cf96a7fd18 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sat, 8 Apr 2023 10:12:39 +0000 Subject: [PATCH 61/69] bump `thiserror` to use syn 2.0 --- Cargo.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index efd3d85f43ebd..443e6d09156f0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4981,22 +4981,22 @@ checksum = "aac81b6fd6beb5884b0cf3321b8117e6e5d47ecb6fc89f414cfdcca8b2fe2dd8" [[package]] name = "thiserror" -version = "1.0.38" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.38" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 1.0.102", + "syn 2.0.8", ] [[package]] From 66208820895c3e32ce4bff3b4a4039da4dde1d4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 31 Oct 2020 03:14:32 +0100 Subject: [PATCH 62/69] Use only one shard with a single thread --- compiler/rustc_data_structures/src/sharded.rs | 44 ++++++++++++++----- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_data_structures/src/sharded.rs b/compiler/rustc_data_structures/src/sharded.rs index 7ed70ba1e0fc7..c16b9cbf8b773 100644 --- a/compiler/rustc_data_structures/src/sharded.rs +++ b/compiler/rustc_data_structures/src/sharded.rs @@ -1,4 +1,6 @@ use crate::fx::{FxHashMap, FxHasher}; +#[cfg(parallel_compiler)] +use crate::sync::is_dyn_thread_safe; use crate::sync::{CacheAligned, Lock, LockGuard}; use std::borrow::Borrow; use std::collections::hash_map::RawEntryMut; @@ -18,6 +20,8 @@ pub const SHARDS: usize = 1 << SHARD_BITS; /// An array of cache-line aligned inner locked structures with convenience methods. pub struct Sharded { + #[cfg(parallel_compiler)] + mask: usize, shards: [CacheAligned>; SHARDS], } @@ -31,31 +35,53 @@ impl Default for Sharded { impl Sharded { #[inline] pub fn new(mut value: impl FnMut() -> T) -> Self { - Sharded { shards: [(); SHARDS].map(|()| CacheAligned(Lock::new(value()))) } + Sharded { + #[cfg(parallel_compiler)] + mask: if is_dyn_thread_safe() { SHARDS - 1 } else { 0 }, + shards: [(); SHARDS].map(|()| CacheAligned(Lock::new(value()))), + } + } + + #[inline(always)] + fn mask(&self) -> usize { + #[cfg(parallel_compiler)] + { + self.mask + } + #[cfg(not(parallel_compiler))] + { + 0 + } + } + + #[inline(always)] + fn count(&self) -> usize { + self.mask() + 1 } /// The shard is selected by hashing `val` with `FxHasher`. #[inline] pub fn get_shard_by_value(&self, val: &K) -> &Lock { - if SHARDS == 1 { &self.shards[0].0 } else { self.get_shard_by_hash(make_hash(val)) } + self.get_shard_by_hash(if SHARDS == 1 { 0 } else { make_hash(val) }) } #[inline] pub fn get_shard_by_hash(&self, hash: u64) -> &Lock { - &self.shards[get_shard_index_by_hash(hash)].0 + self.get_shard_by_index(get_shard_hash(hash)) } #[inline] pub fn get_shard_by_index(&self, i: usize) -> &Lock { - &self.shards[i].0 + // SAFETY: The index get ANDed with the mask, ensuring it is always inbounds. + unsafe { &self.shards.get_unchecked(i & self.mask()).0 } } pub fn lock_shards(&self) -> Vec> { - (0..SHARDS).map(|i| self.shards[i].0.lock()).collect() + (0..self.count()).map(|i| self.get_shard_by_index(i).lock()).collect() } pub fn try_lock_shards(&self) -> Option>> { - (0..SHARDS).map(|i| self.shards[i].0.try_lock()).collect() + (0..self.count()).map(|i| self.get_shard_by_index(i).try_lock()).collect() } } @@ -136,11 +162,9 @@ pub fn make_hash(val: &K) -> u64 { /// `hash` can be computed with any hasher, so long as that hasher is used /// consistently for each `Sharded` instance. #[inline] -#[allow(clippy::modulo_one)] -pub fn get_shard_index_by_hash(hash: u64) -> usize { +fn get_shard_hash(hash: u64) -> usize { let hash_len = mem::size_of::(); // Ignore the top 7 bits as hashbrown uses these and get the next SHARD_BITS highest bits. // hashbrown also uses the lowest bits, so we can't use those - let bits = (hash >> (hash_len * 8 - 7 - SHARD_BITS)) as usize; - bits % SHARDS + (hash >> (hash_len * 8 - 7 - SHARD_BITS)) as usize } From 5843858c015614c92515f317ce93796c885ca2cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sun, 28 May 2023 15:47:44 +0200 Subject: [PATCH 63/69] Don't access self.mask with a single shard --- compiler/rustc_data_structures/src/sharded.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_data_structures/src/sharded.rs b/compiler/rustc_data_structures/src/sharded.rs index c16b9cbf8b773..9f5c97ae798e3 100644 --- a/compiler/rustc_data_structures/src/sharded.rs +++ b/compiler/rustc_data_structures/src/sharded.rs @@ -46,7 +46,7 @@ impl Sharded { fn mask(&self) -> usize { #[cfg(parallel_compiler)] { - self.mask + if SHARDS == 1 { 0 } else { self.mask } } #[cfg(not(parallel_compiler))] { From 8abafd085aab9b703711b49d02b66910c8c2d739 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sun, 28 May 2023 15:54:52 +0200 Subject: [PATCH 64/69] Add some comments --- compiler/rustc_data_structures/src/sharded.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/rustc_data_structures/src/sharded.rs b/compiler/rustc_data_structures/src/sharded.rs index 9f5c97ae798e3..40cbf14958e77 100644 --- a/compiler/rustc_data_structures/src/sharded.rs +++ b/compiler/rustc_data_structures/src/sharded.rs @@ -20,6 +20,9 @@ pub const SHARDS: usize = 1 << SHARD_BITS; /// An array of cache-line aligned inner locked structures with convenience methods. pub struct Sharded { + /// This mask is used to ensure that accesses are inbounds of `shards`. + /// When dynamic thread safety is off, this field is set to 0 causing only + /// a single shard to be used for greater cache efficiency. #[cfg(parallel_compiler)] mask: usize, shards: [CacheAligned>; SHARDS], @@ -56,6 +59,7 @@ impl Sharded { #[inline(always)] fn count(&self) -> usize { + // `self.mask` is always one below the used shard count self.mask() + 1 } From 03534ac8b70de1134ce7e91b172cd629048a6c8b Mon Sep 17 00:00:00 2001 From: Kyle Matsuda Date: Fri, 26 May 2023 11:19:35 -0600 Subject: [PATCH 65/69] Replace EarlyBinder(x) with EarlyBinder::new(x) --- compiler/rustc_codegen_cranelift/src/common.rs | 2 +- .../rustc_codegen_llvm/src/debuginfo/create_scope_map.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/mod.rs | 2 +- compiler/rustc_const_eval/src/interpret/eval_context.rs | 2 +- compiler/rustc_hir_analysis/src/astconv/mod.rs | 2 +- .../rustc_hir_analysis/src/check/compare_impl_item.rs | 4 ++-- compiler/rustc_hir_analysis/src/check/dropck.rs | 2 +- compiler/rustc_hir_analysis/src/check/wfcheck.rs | 2 +- compiler/rustc_hir_analysis/src/collect.rs | 4 ++-- compiler/rustc_hir_analysis/src/collect/item_bounds.rs | 4 ++-- compiler/rustc_hir_analysis/src/collect/type_of.rs | 4 ++-- compiler/rustc_hir_analysis/src/outlives/explicit.rs | 2 +- .../rustc_hir_analysis/src/outlives/implicit_infer.rs | 2 +- compiler/rustc_metadata/src/rmeta/decoder.rs | 2 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 2 +- compiler/rustc_middle/src/mir/mod.rs | 2 +- compiler/rustc_middle/src/ty/adt.rs | 2 +- compiler/rustc_middle/src/ty/consts.rs | 2 +- compiler/rustc_middle/src/ty/generics.rs | 4 ++-- .../src/ty/inhabitedness/inhabited_predicate.rs | 4 ++-- compiler/rustc_middle/src/ty/mod.rs | 2 +- compiler/rustc_middle/src/ty/sty.rs | 2 +- compiler/rustc_middle/src/ty/subst.rs | 4 ++++ compiler/rustc_middle/src/ty/util.rs | 2 +- compiler/rustc_middle/src/values.rs | 4 ++-- .../rustc_mir_transform/src/function_item_references.rs | 2 +- compiler/rustc_mir_transform/src/inline.rs | 8 ++++---- compiler/rustc_mir_transform/src/inline/cycle.rs | 2 +- compiler/rustc_mir_transform/src/shim.rs | 2 +- compiler/rustc_monomorphize/src/collector.rs | 2 +- compiler/rustc_monomorphize/src/util.rs | 4 ++-- compiler/rustc_symbol_mangling/src/v0.rs | 2 +- compiler/rustc_trait_selection/src/traits/mod.rs | 2 +- .../rustc_trait_selection/src/traits/object_safety.rs | 2 +- .../src/traits/query/dropck_outlives.rs | 6 +++--- compiler/rustc_ty_utils/src/assoc.rs | 2 +- compiler/rustc_ty_utils/src/consts.rs | 2 +- compiler/rustc_ty_utils/src/layout.rs | 2 +- compiler/rustc_ty_utils/src/needs_drop.rs | 2 +- compiler/rustc_ty_utils/src/ty.rs | 2 +- src/librustdoc/clean/blanket_impl.rs | 2 +- src/tools/clippy/clippy_lints/src/dereference.rs | 2 +- src/tools/clippy/clippy_lints/src/eta_reduction.rs | 2 +- .../clippy/clippy_lints/src/methods/needless_collect.rs | 2 +- .../clippy_lints/src/methods/unnecessary_to_owned.rs | 4 ++-- src/tools/clippy/clippy_utils/src/consts.rs | 2 +- 46 files changed, 63 insertions(+), 59 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index 5eaa988dd0929..70cb6dfd66f27 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -361,7 +361,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { self.instance.subst_mir_and_normalize_erasing_regions( self.tcx, ty::ParamEnv::reveal_all(), - ty::EarlyBinder(value), + ty::EarlyBinder::new(value), ) } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs index 3fff112a02056..6cb9e163b404e 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs @@ -93,7 +93,7 @@ fn make_mir_scope<'ll, 'tcx>( let callee = cx.tcx.subst_and_normalize_erasing_regions( instance.substs, ty::ParamEnv::reveal_all(), - ty::EarlyBinder(callee), + ty::EarlyBinder::new(callee), ); let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty()); cx.dbg_scope_fn(callee, callee_fn_abi, None) diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 1204c99e533e2..51393a5d774dc 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -111,7 +111,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.instance.subst_mir_and_normalize_erasing_regions( self.cx.tcx(), ty::ParamEnv::reveal_all(), - ty::EarlyBinder(value), + ty::EarlyBinder::new(value), ) } } diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 7e94578003ebf..9195ae163bc61 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -497,7 +497,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { .try_subst_mir_and_normalize_erasing_regions( *self.tcx, self.param_env, - ty::EarlyBinder(value), + ty::EarlyBinder::new(value), ) .map_err(|_| err_inval!(TooGeneric)) } diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 2c60a0624605f..284ae0e1e58a2 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -1278,7 +1278,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // params (and trait ref's late bound params). This logic is very similar to // `Predicate::subst_supertrait`, and it's no coincidence why. let shifted_output = tcx.shift_bound_var_indices(num_bound_vars, output); - let subst_output = ty::EarlyBinder(shifted_output).subst(tcx, substs); + let subst_output = ty::EarlyBinder::new(shifted_output).subst(tcx, substs); let bound_vars = tcx.late_bound_vars(binding.hir_id); ty::Binder::bind_with_vars(subst_output, bound_vars) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 8bf1e0e84a4fa..283a9ed3388eb 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -794,14 +794,14 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( }) }); debug!(%ty); - collected_tys.insert(def_id, ty::EarlyBinder(ty)); + collected_tys.insert(def_id, ty::EarlyBinder::new(ty)); } Err(err) => { let reported = tcx.sess.delay_span_bug( return_span, format!("could not fully resolve: {ty} => {err:?}"), ); - collected_tys.insert(def_id, ty::EarlyBinder(tcx.ty_error(reported))); + collected_tys.insert(def_id, ty::EarlyBinder::new(tcx.ty_error(reported))); } } } diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index e0ba255cc069c..eeb69c389cd80 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -128,7 +128,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( // We don't need to normalize this param-env or anything, since we're only // substituting it with free params, so no additional param-env normalization // can occur on top of what has been done in the param_env query itself. - let param_env = ty::EarlyBinder(tcx.param_env(adt_def_id)) + let param_env = ty::EarlyBinder::new(tcx.param_env(adt_def_id)) .subst(tcx, adt_to_impl_substs) .with_constness(tcx.constness(drop_impl_def_id)); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index b403ee96b4229..4c513c4d8cc6a 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1398,7 +1398,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id } let mut param_count = CountParams::default(); let has_region = pred.visit_with(&mut param_count).is_break(); - let substituted_pred = ty::EarlyBinder(pred).subst(tcx, substs); + let substituted_pred = ty::EarlyBinder::new(pred).subst(tcx, substs); // Don't check non-defaulted params, dependent defaults (including lifetimes) // or preds with multiple params. if substituted_pred.has_non_region_param() || param_count.params.len() > 1 || has_region diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index ca0d5509c5768..75d99fee152ea 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1124,7 +1124,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder( @@ -1312,7 +1312,7 @@ fn impl_trait_ref( check_impl_constness(tcx, impl_.constness, ast_trait_ref), ) }) - .map(ty::EarlyBinder) + .map(ty::EarlyBinder::new) } fn check_impl_constness( diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 948b903e509ad..03c8c59402e76 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -86,7 +86,7 @@ pub(super) fn explicit_item_bounds( Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => { let item = tcx.hir().get_by_def_id(opaque_def_id.expect_local()).expect_item(); let opaque_ty = item.expect_opaque_ty(); - return ty::EarlyBinder(opaque_type_bounds( + return ty::EarlyBinder::new(opaque_type_bounds( tcx, opaque_def_id.expect_local(), opaque_ty.bounds, @@ -124,7 +124,7 @@ pub(super) fn explicit_item_bounds( } _ => bug!("item_bounds called on {:?}", def_id), }; - ty::EarlyBinder(bounds) + ty::EarlyBinder::new(bounds) } pub(super) fn item_bounds( diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 8e082d3c5328b..0b57d69658563 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -323,7 +323,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder { - return ty::EarlyBinder(tcx.ty_error_with_message( + return ty::EarlyBinder::new(tcx.ty_error_with_message( DUMMY_SP, "Could not collect return position impl trait in trait tys", )); @@ -497,7 +497,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder( diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs index 357deb07b8f31..d7f11d3fd9d38 100644 --- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs +++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs @@ -68,7 +68,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { } } - ty::EarlyBinder(required_predicates) + ty::EarlyBinder::new(required_predicates) }) } } diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs index 0cd2fc1aa299a..e386b1b7120f3 100644 --- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs +++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs @@ -73,7 +73,7 @@ pub(super) fn infer_predicates( if item_required_predicates.len() > item_predicates_len { predicates_added = true; global_inferred_outlives - .insert(item_did.to_def_id(), ty::EarlyBinder(item_required_predicates)); + .insert(item_did.to_def_id(), ty::EarlyBinder::new(item_required_predicates)); } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index cc4e60cf6ac58..731bbb1edfb70 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -851,7 +851,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } else { tcx.arena.alloc_from_iter(lazy.decode((self, tcx))) }; - ty::EarlyBinder(&*output) + ty::EarlyBinder::new(&*output) } fn get_variant( diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index f067bca4b0b39..e3a0ce373879b 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1727,7 +1727,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { ty::Closure(_, substs) => { let constness = self.tcx.constness(def_id.to_def_id()); self.tables.constness.set_some(def_id.to_def_id().index, constness); - record!(self.tables.fn_sig[def_id.to_def_id()] <- ty::EarlyBinder(substs.as_closure().sig())); + record!(self.tables.fn_sig[def_id.to_def_id()] <- ty::EarlyBinder::new(substs.as_closure().sig())); } _ => bug!("closure that is neither generator nor closure"), diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 5c71910a955d8..34e47de969c17 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -476,7 +476,7 @@ impl<'tcx> Body<'tcx> { /// Returns the return type; it always return first element from `local_decls` array. #[inline] pub fn bound_return_ty(&self) -> ty::EarlyBinder> { - ty::EarlyBinder(self.local_decls[RETURN_PLACE].ty) + ty::EarlyBinder::new(self.local_decls[RETURN_PLACE].ty) } /// Gets the location of the terminator for the given block. diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 7c5c030c2764e..2b99fcad26758 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -573,7 +573,7 @@ impl<'tcx> AdtDef<'tcx> { /// Due to normalization being eager, this applies even if /// the associated type is behind a pointer (e.g., issue #31299). pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> ty::EarlyBinder<&'tcx [Ty<'tcx>]> { - ty::EarlyBinder(tcx.adt_sized_constraint(self.did())) + ty::EarlyBinder::new(tcx.adt_sized_constraint(self.did())) } } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 1a4bd14815f93..5fcbc4a9ed49a 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -254,5 +254,5 @@ pub fn const_param_default(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBind "`const_param_default` expected a generic parameter with a constant" ), }; - ty::EarlyBinder(Const::from_anon_const(tcx, default_def_id)) + ty::EarlyBinder::new(Const::from_anon_const(tcx, default_def_id)) } diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index b0ffe78299de9..b27ee8cbad0fd 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -343,7 +343,7 @@ impl<'tcx> GenericPredicates<'tcx> { substs: SubstsRef<'tcx>, ) -> impl Iterator, Span)> + DoubleEndedIterator + ExactSizeIterator { - EarlyBinder(self.predicates).subst_iter_copied(tcx, substs) + EarlyBinder::new(self.predicates).subst_iter_copied(tcx, substs) } #[instrument(level = "debug", skip(self, tcx))] @@ -358,7 +358,7 @@ impl<'tcx> GenericPredicates<'tcx> { } instantiated .predicates - .extend(self.predicates.iter().map(|(p, _)| EarlyBinder(*p).subst(tcx, substs))); + .extend(self.predicates.iter().map(|(p, _)| EarlyBinder::new(*p).subst(tcx, substs))); instantiated.spans.extend(self.predicates.iter().map(|(_, sp)| *sp)); } diff --git a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs index ac42d6e05100f..b3cc27e3f7838 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs @@ -158,7 +158,7 @@ impl<'tcx> InhabitedPredicate<'tcx> { fn subst_opt(self, tcx: TyCtxt<'tcx>, substs: ty::SubstsRef<'tcx>) -> Option { match self { Self::ConstIsZero(c) => { - let c = ty::EarlyBinder(c).subst(tcx, substs); + let c = ty::EarlyBinder::new(c).subst(tcx, substs); let pred = match c.kind().try_to_target_usize(tcx) { Some(0) => Self::True, Some(1..) => Self::False, @@ -167,7 +167,7 @@ impl<'tcx> InhabitedPredicate<'tcx> { Some(pred) } Self::GenericType(t) => { - Some(ty::EarlyBinder(t).subst(tcx, substs).inhabited_predicate(tcx)) + Some(ty::EarlyBinder::new(t).subst(tcx, substs).inhabited_predicate(tcx)) } Self::And(&[a, b]) => match a.subst_opt(tcx, substs) { None => b.subst_opt(tcx, substs).map(|b| a.and(tcx, b)), diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 96023a68cf6d0..4b2c7e8ef3110 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -764,7 +764,7 @@ impl<'tcx> Predicate<'tcx> { let shifted_pred = tcx.shift_bound_var_indices(trait_bound_vars.len(), bound_pred.skip_binder()); // 2) Self: Bar1<'a, '^0.1> -> T: Bar1<'^0.0, '^0.1> - let new = EarlyBinder(shifted_pred).subst(tcx, trait_ref.skip_binder().substs); + let new = EarlyBinder::new(shifted_pred).subst(tcx, trait_ref.skip_binder().substs); // 3) ['x] + ['b] -> ['x, 'b] let bound_vars = tcx.mk_bound_variable_kinds_from_iter(trait_bound_vars.iter().chain(pred_bound_vars)); diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index e6d51c4ec9770..945ef6aa25195 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -568,7 +568,7 @@ impl<'tcx> GeneratorSubsts<'tcx> { let layout = tcx.generator_layout(def_id).unwrap(); layout.variant_fields.iter().map(move |variant| { variant.iter().map(move |field| { - ty::EarlyBinder(layout.field_tys[*field].ty).subst(tcx, self.substs) + ty::EarlyBinder::new(layout.field_tys[*field].ty).subst(tcx, self.substs) }) }) } diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 43f95635ab00a..43450bda19b20 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -545,6 +545,10 @@ impl<'tcx, T> !TypeFoldable> for ty::EarlyBinder {} impl<'tcx, T> !TypeVisitable> for ty::EarlyBinder {} impl EarlyBinder { + pub fn new(inner: T) -> EarlyBinder { + EarlyBinder(inner) + } + pub fn as_ref(&self) -> EarlyBinder<&T> { EarlyBinder(&self.0) } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index ba05135638e1f..dade50df5d962 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -709,7 +709,7 @@ impl<'tcx> TyCtxt<'tcx> { .as_ref() .map_or_else(|| [].iter(), |l| l.field_tys.iter()) .filter(|decl| !decl.ignore_for_traits) - .map(|decl| ty::EarlyBinder(decl.ty)) + .map(|decl| ty::EarlyBinder::new(decl.ty)) } /// Normalizes all opaque types in the given value, replacing them diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index c62c33d4dfc18..58374f6b3bd78 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -96,13 +96,13 @@ impl<'tcx> Value, DepKind> for Representability { impl<'tcx> Value, DepKind> for ty::EarlyBinder> { fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo]) -> Self { - ty::EarlyBinder(Ty::from_cycle_error(tcx, cycle)) + ty::EarlyBinder::new(Ty::from_cycle_error(tcx, cycle)) } } impl<'tcx> Value, DepKind> for ty::EarlyBinder>> { fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo]) -> Self { - ty::EarlyBinder(ty::Binder::from_cycle_error(tcx, cycle)) + ty::EarlyBinder::new(ty::Binder::from_cycle_error(tcx, cycle)) } } diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs index 5989dbebf2db9..c0458126840da 100644 --- a/compiler/rustc_mir_transform/src/function_item_references.rs +++ b/compiler/rustc_mir_transform/src/function_item_references.rs @@ -83,7 +83,7 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> { // If the inner type matches the type bound by `Pointer` if inner_ty == bound_ty { // Do a substitution using the parameters from the callsite - let subst_ty = EarlyBinder(inner_ty).subst(self.tcx, substs_ref); + let subst_ty = EarlyBinder::new(inner_ty).subst(self.tcx, substs_ref); if let Some((fn_id, fn_substs)) = FunctionItemRefChecker::is_fn_ref(subst_ty) { diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index ca1e209d504b0..e27d48fa8f65a 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -192,7 +192,7 @@ impl<'tcx> Inliner<'tcx> { let Ok(callee_body) = callsite.callee.try_subst_mir_and_normalize_erasing_regions( self.tcx, self.param_env, - ty::EarlyBinder(callee_body.clone()), + ty::EarlyBinder::new(callee_body.clone()), ) else { return Err("failed to normalize callee body"); }; @@ -455,7 +455,7 @@ impl<'tcx> Inliner<'tcx> { // If the place doesn't actually need dropping, treat it like a regular goto. let ty = callsite .callee - .subst_mir(self.tcx, ty::EarlyBinder(&place.ty(callee_body, tcx).ty)); + .subst_mir(self.tcx, ty::EarlyBinder::new(&place.ty(callee_body, tcx).ty)); if ty.needs_drop(tcx, self.param_env) && let UnwindAction::Cleanup(unwind) = unwind { work_list.push(unwind); } @@ -790,7 +790,7 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> { // If the place doesn't actually need dropping, treat it like a regular goto. let ty = self .instance - .subst_mir(tcx, ty::EarlyBinder(&place.ty(self.callee_body, tcx).ty)); + .subst_mir(tcx, ty::EarlyBinder::new(&place.ty(self.callee_body, tcx).ty)); if ty.needs_drop(tcx, self.param_env) { self.cost += CALL_PENALTY; if let UnwindAction::Cleanup(_) = unwind { @@ -801,7 +801,7 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> { } } TerminatorKind::Call { func: Operand::Constant(ref f), unwind, .. } => { - let fn_ty = self.instance.subst_mir(tcx, ty::EarlyBinder(&f.literal.ty())); + let fn_ty = self.instance.subst_mir(tcx, ty::EarlyBinder::new(&f.literal.ty())); self.cost += if let ty::FnDef(def_id, _) = *fn_ty.kind() && tcx.is_intrinsic(def_id) { // Don't give intrinsics the extra penalty for calls INSTR_COST diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index 1ccf06f6153fc..00842e9d66596 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -47,7 +47,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( let Ok(substs) = caller.try_subst_mir_and_normalize_erasing_regions( tcx, param_env, - ty::EarlyBinder(substs), + ty::EarlyBinder::new(substs), ) else { trace!(?caller, ?param_env, ?substs, "cannot normalize, skipping"); continue; diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 0eb27c23105f5..fbe6a274ea19b 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -69,7 +69,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' // of this function. Is this intentional? if let Some(ty::Generator(gen_def_id, substs, _)) = ty.map(Ty::kind) { let body = tcx.optimized_mir(*gen_def_id).generator_drop().unwrap(); - let body = EarlyBinder(body.clone()).subst(tcx, substs); + let body = EarlyBinder::new(body.clone()).subst(tcx, substs); debug!("make_shim({:?}) = {:?}", instance, body); return body; } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 35b154b7b34d1..8874aa7d3ca9b 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -677,7 +677,7 @@ impl<'a, 'tcx> MirNeighborCollector<'a, 'tcx> { self.instance.subst_mir_and_normalize_erasing_regions( self.tcx, ty::ParamEnv::reveal_all(), - ty::EarlyBinder(value), + ty::EarlyBinder::new(value), ) } } diff --git a/compiler/rustc_monomorphize/src/util.rs b/compiler/rustc_monomorphize/src/util.rs index d12bfc6f6bb1d..772f15201536c 100644 --- a/compiler/rustc_monomorphize/src/util.rs +++ b/compiler/rustc_monomorphize/src/util.rs @@ -29,12 +29,12 @@ pub(crate) fn dump_closure_profile<'tcx>(tcx: TyCtxt<'tcx>, closure_instance: In let before_feature_tys = tcx.subst_and_normalize_erasing_regions( closure_instance.substs, param_env, - ty::EarlyBinder(before_feature_tys), + ty::EarlyBinder::new(before_feature_tys), ); let after_feature_tys = tcx.subst_and_normalize_erasing_regions( closure_instance.substs, param_env, - ty::EarlyBinder(after_feature_tys), + ty::EarlyBinder::new(after_feature_tys), ); let new_size = tcx diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 4cccc6398927c..55901bfbde9cf 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -274,7 +274,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { let mut param_env = self.tcx.param_env_reveal_all_normalized(impl_def_id); if !substs.is_empty() { - param_env = EarlyBinder(param_env).subst(self.tcx, substs); + param_env = EarlyBinder::new(param_env).subst(self.tcx, substs); } match &mut impl_trait_ref { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index a44d8955ab95c..0f84032d9ef6d 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -487,7 +487,7 @@ fn is_impossible_method(tcx: TyCtxt<'_>, (impl_def_id, trait_item_def_id): (DefI tcx, ObligationCause::dummy_with_span(*span), param_env, - ty::EarlyBinder(*pred).subst(tcx, impl_trait_ref.substs), + ty::EarlyBinder::new(*pred).subst(tcx, impl_trait_ref.substs), ) }) }); diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index c81bf6ebc2eaa..0be21156b6c96 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -642,7 +642,7 @@ fn receiver_for_self_ty<'tcx>( if param.index == 0 { self_ty.into() } else { tcx.mk_param_from_def(param) } }); - let result = EarlyBinder(receiver_ty).subst(tcx, substs); + let result = EarlyBinder::new(receiver_ty).subst(tcx, substs); debug!( "receiver_for_self_ty({:?}, {:?}, {:?}) = {:?}", receiver_ty, self_ty, method_def_id, result diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index 4e4172e7f41ec..0a1b1b10b0070 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -307,13 +307,13 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( // there, but that needs some way to handle cycles. constraints .dtorck_types - .extend(dtorck_types.iter().map(|t| EarlyBinder(*t).subst(tcx, substs))); + .extend(dtorck_types.iter().map(|t| EarlyBinder::new(*t).subst(tcx, substs))); constraints .outlives - .extend(outlives.iter().map(|t| EarlyBinder(*t).subst(tcx, substs))); + .extend(outlives.iter().map(|t| EarlyBinder::new(*t).subst(tcx, substs))); constraints .overflows - .extend(overflows.iter().map(|t| EarlyBinder(*t).subst(tcx, substs))); + .extend(overflows.iter().map(|t| EarlyBinder::new(*t).subst(tcx, substs))); } // Objects must be alive in order for their destructor diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index ed574f22e61d0..0925b3956de36 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -301,7 +301,7 @@ fn associated_type_for_impl_trait_in_trait( trait_assoc_ty.impl_defaultness(tcx.impl_defaultness(fn_def_id)); // Copy type_of of the opaque. - trait_assoc_ty.type_of(ty::EarlyBinder(tcx.mk_opaque( + trait_assoc_ty.type_of(ty::EarlyBinder::new(tcx.mk_opaque( opaque_ty_def_id.to_def_id(), InternalSubsts::identity_for_item(tcx, opaque_ty_def_id), ))); diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 1219bb4009886..bb723c9997ac1 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -419,7 +419,7 @@ pub fn thir_abstract_const( let root_span = body.exprs[body_id].span; - Ok(Some(ty::EarlyBinder(recurse_build(tcx, body, body_id, root_span)?))) + Ok(Some(ty::EarlyBinder::new(recurse_build(tcx, body, body_id, root_span)?))) } pub fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 16cd8bc8e698f..0e5b23ca423ef 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -610,7 +610,7 @@ fn generator_layout<'tcx>( ) -> Result, LayoutError<'tcx>> { use SavedLocalEligibility::*; let tcx = cx.tcx; - let subst_field = |ty: Ty<'tcx>| EarlyBinder(ty).subst(tcx, substs); + let subst_field = |ty: Ty<'tcx>| EarlyBinder::new(ty).subst(tcx, substs); let Some(info) = tcx.generator_layout(def_id) else { return Err(LayoutError::Unknown(ty)); diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index 1f9701b93226d..075fde6ddb654 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -210,7 +210,7 @@ fn drop_tys_helper<'tcx>( match subty.kind() { ty::Adt(adt_id, subst) => { for subty in tcx.adt_drop_tys(adt_id.did())? { - vec.push(EarlyBinder(subty).subst(tcx, subst)); + vec.push(EarlyBinder::new(subty).subst(tcx, subst)); } } _ => vec.push(subty), diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 65dc3c39c6ae6..4eb1256a1a720 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -508,7 +508,7 @@ fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option BlanketImplFinder<'a, 'tcx> { let infcx = cx.tcx.infer_ctxt().build(); let substs = infcx.fresh_substs_for_item(DUMMY_SP, item_def_id); let impl_ty = ty.subst(infcx.tcx, substs); - let param_env = EarlyBinder(param_env).subst(infcx.tcx, substs); + let param_env = EarlyBinder::new(param_env).subst(infcx.tcx, substs); let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id); let impl_trait_ref = trait_ref.subst(infcx.tcx, impl_substs); diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index b27ffe73ffda4..a418a910ba8ea 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -1219,7 +1219,7 @@ fn needless_borrow_impl_arg_position<'tcx>( return false; } - let predicate = EarlyBinder(predicate).subst(cx.tcx, &substs_with_referent_ty); + let predicate = EarlyBinder::new(predicate).subst(cx.tcx, &substs_with_referent_ty); let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate); let infcx = cx.tcx.infer_ctxt().build(); infcx.predicate_must_hold_modulo_regions(&obligation) diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs index b2071f4dcb1e2..af2aac6ac0d0a 100644 --- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs +++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs @@ -243,7 +243,7 @@ fn get_ufcs_type_name<'tcx>(cx: &LateContext<'tcx>, method_def_id: DefId, substs | ty::Ref(..) | ty::Slice(_) | ty::Tuple(_) => { - format!("<{}>", EarlyBinder(ty).subst(cx.tcx, substs)) + format!("<{}>", EarlyBinder::new(ty).subst(cx.tcx, substs)) }, _ => ty.to_string(), } diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs index 6841aaf626ca5..d4cc14bb85632 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs @@ -241,7 +241,7 @@ fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) - && let proj_ty = cx.tcx.mk_projection(iter_item.def_id, substs) && let Ok(item_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, proj_ty) { - item_ty == EarlyBinder(search_ty).subst(cx.tcx, cx.typeck_results().node_substs(call_id)) + item_ty == EarlyBinder::new(search_ty).subst(cx.tcx, cx.typeck_results().node_substs(call_id)) } else { false } diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index 67b7d3691dc02..fdacfa49e92d5 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -428,7 +428,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< })); if trait_predicates.any(|predicate| { - let predicate = EarlyBinder(predicate).subst(cx.tcx, new_subst); + let predicate = EarlyBinder::new(predicate).subst(cx.tcx, new_subst); let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate); !cx.tcx.infer_ctxt().build().predicate_must_hold_modulo_regions(&obligation) }) { @@ -438,7 +438,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< let output_ty = fn_sig.output(); if output_ty.contains(*param_ty) { if let Ok(new_ty) = cx.tcx.try_subst_and_normalize_erasing_regions( - new_subst, cx.param_env, EarlyBinder(output_ty)) { + new_subst, cx.param_env, EarlyBinder::new(output_ty)) { expr = parent_expr; ty = new_ty; continue; diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index fb772644c0d64..843538e1eb2db 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -462,7 +462,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { let substs = if self.substs.is_empty() { substs } else { - EarlyBinder(substs).subst(self.lcx.tcx, self.substs) + EarlyBinder::new(substs).subst(self.lcx.tcx, self.substs) }; let result = self From c40e9cc7ca3001cfd6098d1c2f6bf4e009920358 Mon Sep 17 00:00:00 2001 From: Kyle Matsuda Date: Fri, 26 May 2023 12:14:48 -0600 Subject: [PATCH 66/69] Make EarlyBinder's inner value private; and fix all of the resulting errors --- .../src/outlives/implicit_infer.rs | 11 ++++-- .../rustc_hir_analysis/src/outlives/mod.rs | 37 ++++++++++--------- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 2 +- .../rustc_infer/src/infer/outlives/verify.rs | 2 +- compiler/rustc_middle/src/ty/print/mod.rs | 2 +- compiler/rustc_middle/src/ty/sty.rs | 2 +- compiler/rustc_middle/src/ty/subst.rs | 2 +- compiler/rustc_mir_transform/src/shim.rs | 7 +++- .../src/solve/assembly/structural_traits.rs | 6 +-- .../src/traits/select/candidate_assembly.rs | 4 +- .../src/traits/select/confirmation.rs | 4 +- .../src/traits/select/mod.rs | 12 +++--- compiler/rustc_traits/src/chalk/db.rs | 2 +- compiler/rustc_ty_utils/src/ty.rs | 4 +- src/librustdoc/clean/blanket_impl.rs | 12 +++--- .../src/multiple_unsafe_ops_per_block.rs | 2 +- 16 files changed, 57 insertions(+), 54 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs index e386b1b7120f3..ced994aa6366e 100644 --- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs +++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs @@ -68,8 +68,9 @@ pub(super) fn infer_predicates( // Therefore mark `predicates_added` as true and which will ensure // we walk the crates again and re-calculate predicates for all // items. - let item_predicates_len: usize = - global_inferred_outlives.get(&item_did.to_def_id()).map_or(0, |p| p.0.len()); + let item_predicates_len: usize = global_inferred_outlives + .get(&item_did.to_def_id()) + .map_or(0, |p| p.as_ref().skip_binder().len()); if item_required_predicates.len() > item_predicates_len { predicates_added = true; global_inferred_outlives @@ -137,7 +138,9 @@ fn insert_required_predicates_to_be_wf<'tcx>( // 'a` holds for `Foo`. debug!("Adt"); if let Some(unsubstituted_predicates) = global_inferred_outlives.get(&def.did()) { - for (unsubstituted_predicate, &span) in &unsubstituted_predicates.0 { + for (unsubstituted_predicate, &span) in + unsubstituted_predicates.as_ref().skip_binder() + { // `unsubstituted_predicate` is `U: 'b` in the // example above. So apply the substitution to // get `T: 'a` (or `predicate`): @@ -251,7 +254,7 @@ fn check_explicit_predicates<'tcx>( ); let explicit_predicates = explicit_map.explicit_predicates_of(tcx, def_id); - for (outlives_predicate, &span) in &explicit_predicates.0 { + for (outlives_predicate, &span) in explicit_predicates.as_ref().skip_binder() { debug!("outlives_predicate = {:?}", &outlives_predicate); // Careful: If we are inferring the effects of a `dyn Trait<..>` diff --git a/compiler/rustc_hir_analysis/src/outlives/mod.rs b/compiler/rustc_hir_analysis/src/outlives/mod.rs index a8596c707f3a4..2106d6ff07dcc 100644 --- a/compiler/rustc_hir_analysis/src/outlives/mod.rs +++ b/compiler/rustc_hir_analysis/src/outlives/mod.rs @@ -98,24 +98,27 @@ fn inferred_outlives_crate(tcx: TyCtxt<'_>, (): ()) -> CratePredicatesMap<'_> { let predicates = global_inferred_outlives .iter() .map(|(&def_id, set)| { - let predicates = &*tcx.arena.alloc_from_iter(set.0.iter().filter_map( - |(ty::OutlivesPredicate(kind1, region2), &span)| { - match kind1.unpack() { - GenericArgKind::Type(ty1) => Some(( - ty::Clause::TypeOutlives(ty::OutlivesPredicate(ty1, *region2)), - span, - )), - GenericArgKind::Lifetime(region1) => Some(( - ty::Clause::RegionOutlives(ty::OutlivesPredicate(region1, *region2)), - span, - )), - GenericArgKind::Const(_) => { - // Generic consts don't impose any constraints. - None + let predicates = + &*tcx.arena.alloc_from_iter(set.as_ref().skip_binder().iter().filter_map( + |(ty::OutlivesPredicate(kind1, region2), &span)| { + match kind1.unpack() { + GenericArgKind::Type(ty1) => Some(( + ty::Clause::TypeOutlives(ty::OutlivesPredicate(ty1, *region2)), + span, + )), + GenericArgKind::Lifetime(region1) => Some(( + ty::Clause::RegionOutlives(ty::OutlivesPredicate( + region1, *region2, + )), + span, + )), + GenericArgKind::Const(_) => { + // Generic consts don't impose any constraints. + None + } } - } - }, - )); + }, + )); (def_id, predicates) }) .collect(); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 557950338a73b..38ddb7e760410 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1386,7 +1386,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // the referenced item. let ty = tcx.type_of(def_id); assert!(!substs.has_escaping_bound_vars()); - assert!(!ty.0.has_escaping_bound_vars()); + assert!(!ty.skip_binder().has_escaping_bound_vars()); let ty_substituted = self.normalize(span, ty.subst(tcx, substs)); if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty { diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index c2bf0f3db253c..59ae2ce6c603e 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -293,7 +293,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { ) -> impl Iterator> { let tcx = self.tcx; let bounds = tcx.item_bounds(alias_ty.def_id); - trace!("{:#?}", bounds.0); + trace!("{:#?}", bounds.skip_binder()); bounds .subst_iter(tcx, alias_ty.substs) .filter_map(|p| p.to_opt_type_outlives()) diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 64e7480e626d7..2de0a3f75dcf6 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -123,7 +123,7 @@ pub trait Printer<'tcx>: Sized { impl_trait_ref.map(|i| i.subst(self.tcx(), substs)), ) } else { - (self_ty.0, impl_trait_ref.map(|i| i.0)) + (self_ty.subst_identity(), impl_trait_ref.map(|i| i.subst_identity())) }; self.print_impl_path(def_id, substs, self_ty, impl_trait_ref) } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 945ef6aa25195..82f79a0c0887b 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2366,7 +2366,7 @@ impl<'tcx> Ty<'tcx> { ty::Tuple(tys) => tys.iter().all(|ty| ty.is_trivially_sized(tcx)), - ty::Adt(def, _substs) => def.sized_constraint(tcx).0.is_empty(), + ty::Adt(def, _substs) => def.sized_constraint(tcx).skip_binder().is_empty(), ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => false, diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 43450bda19b20..5422ee7db32fb 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -538,7 +538,7 @@ impl<'tcx, T: TypeVisitable>> TypeVisitable> for &'tcx /// [`subst_identity`](EarlyBinder::subst_identity) or [`skip_binder`](EarlyBinder::skip_binder). #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[derive(Encodable, Decodable, HashStable)] -pub struct EarlyBinder(pub T); +pub struct EarlyBinder(T); /// For early binders, you should first call `subst` before using any visitors. impl<'tcx, T> !TypeFoldable> for ty::EarlyBinder {} diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index fbe6a274ea19b..522220f3d77c1 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -644,8 +644,11 @@ fn build_call_shim<'tcx>( let sig = sig.map_bound(|sig| tcx.erase_late_bound_regions(sig)); assert_eq!(sig_substs.is_some(), !instance.has_polymorphic_mir_body()); - let mut sig = - if let Some(sig_substs) = sig_substs { sig.subst(tcx, &sig_substs) } else { sig.0 }; + let mut sig = if let Some(sig_substs) = sig_substs { + sig.subst(tcx, &sig_substs) + } else { + sig.skip_binder() + }; if let CallKind::Indirect(fnty) = call_kind { // `sig` determines our local decls, and thus the callee type in the `Call` terminator. This diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index 0ede32c753c69..1071b8fc7026f 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -148,11 +148,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( ty::Adt(def, substs) => { let sized_crit = def.sized_constraint(ecx.tcx()); - Ok(sized_crit - .0 - .iter() - .map(|ty| sized_crit.rebind(*ty).subst(ecx.tcx(), substs)) - .collect()) + Ok(sized_crit.subst_iter_copied(ecx.tcx(), substs).collect()) } } } diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 8bc82b9f54926..3c223db5a0b74 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -360,7 +360,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // consider a "quick reject". This avoids creating more types // and so forth that we need to. let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap(); - if !drcx.substs_refs_may_unify(obligation_substs, impl_trait_ref.0.substs) { + if !drcx + .substs_refs_may_unify(obligation_substs, impl_trait_ref.skip_binder().substs) + { return; } if self.reject_fn_ptr_impls( diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 0d9f55d4c2edf..0245dfd333bee 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -527,9 +527,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { substs.extend(trait_predicate.trait_ref.substs.iter()); let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> = smallvec::SmallVec::with_capacity( - bound.0.kind().bound_vars().len() + defs.count(), + bound.skip_binder().kind().bound_vars().len() + defs.count(), ); - bound_vars.extend(bound.0.kind().bound_vars().into_iter()); + bound_vars.extend(bound.skip_binder().kind().bound_vars().into_iter()); InternalSubsts::fill_single(&mut substs, defs, &mut |param, _| match param .kind { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 3baf1c97c9f46..ed380f32b72f4 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2149,13 +2149,11 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ty::Adt(def, substs) => { let sized_crit = def.sized_constraint(self.tcx()); // (*) binder moved here - Where(obligation.predicate.rebind({ - sized_crit - .0 - .iter() - .map(|ty| sized_crit.rebind(*ty).subst(self.tcx(), substs)) - .collect() - })) + Where( + obligation + .predicate + .rebind(sized_crit.subst_iter_copied(self.tcx(), substs).collect()), + ) } ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => None, diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index c319b2e31c7e6..1d3ea96666f2f 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -294,7 +294,7 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t }; Arc::new(chalk_solve::rust_ir::FnDefDatum { id: fn_def_id, - sig: sig.0.lower_into(self.interner), + sig: sig.skip_binder().lower_into(self.interner), binders: chalk_ir::Binders::new(binders, bound), }) } diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 4eb1256a1a720..52bc386cb009d 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -44,9 +44,7 @@ fn sized_constraint_for_ty<'tcx>( let adt_tys = adt.sized_constraint(tcx); debug!("sized_constraint_for_ty({:?}) intermediate = {:?}", ty, adt_tys); adt_tys - .0 - .iter() - .map(|ty| adt_tys.rebind(*ty).subst(tcx, substs)) + .subst_iter_copied(tcx, substs) .flat_map(|ty| sized_constraint_for_ty(tcx, adtdef, ty)) .collect() } diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 8e74e6e16bbe5..7d3ccb9def360 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -21,7 +21,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { let mut impls = Vec::new(); for trait_def_id in cx.tcx.all_traits() { if !cx.cache.effective_visibilities.is_reachable(cx.tcx, trait_def_id) - || cx.generated_synthetics.get(&(ty.0, trait_def_id)).is_some() + || cx.generated_synthetics.get(&(ty.skip_binder(), trait_def_id)).is_some() { continue; } @@ -34,7 +34,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { impl_def_id ); let trait_ref = cx.tcx.impl_trait_ref(impl_def_id).unwrap(); - if !matches!(trait_ref.0.self_ty().kind(), ty::Param(_)) { + if !matches!(trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) { continue; } let infcx = cx.tcx.infer_ctxt().build(); @@ -87,7 +87,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { trait_ref, ty ); - cx.generated_synthetics.insert((ty.0, trait_def_id)); + cx.generated_synthetics.insert((ty.skip_binder(), trait_def_id)); impls.push(Item { name: None, @@ -104,10 +104,10 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { // the post-inference `trait_ref`, as it's more accurate. trait_: Some(clean_trait_ref_with_bindings( cx, - ty::Binder::dummy(trait_ref.0), + ty::Binder::dummy(trait_ref.skip_binder()), ThinVec::new(), )), - for_: clean_middle_ty(ty::Binder::dummy(ty.0), cx, None), + for_: clean_middle_ty(ty::Binder::dummy(ty.skip_binder()), cx, None), items: cx .tcx .associated_items(impl_def_id) @@ -116,7 +116,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { .collect::>(), polarity: ty::ImplPolarity::Positive, kind: ImplKind::Blanket(Box::new(clean_middle_ty( - ty::Binder::dummy(trait_ref.0.self_ty()), + ty::Binder::dummy(trait_ref.skip_binder().self_ty()), cx, None, ))), diff --git a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs index 2abdfacd27634..e6fd65f001a6e 100644 --- a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -138,7 +138,7 @@ fn collect_unsafe_exprs<'tcx>( .type_dependent_def_id(expr.hir_id) .map(|def_id| cx.tcx.fn_sig(def_id)) { - if sig.0.unsafety() == Unsafety::Unsafe { + if sig.skip_binder().unsafety() == Unsafety::Unsafe { unsafe_ops.push(("unsafe method call occurs here", expr.span)); } } From c29c212f8dc80e40f099b6dbc9da3111177ba7bf Mon Sep 17 00:00:00 2001 From: Kyle Matsuda Date: Fri, 26 May 2023 14:10:58 -0600 Subject: [PATCH 67/69] Add documentation on skip_binder on how to get &T from &EarlyBinder --- compiler/rustc_middle/src/ty/subst.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 5422ee7db32fb..8691a3070bcf6 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -586,6 +586,9 @@ impl EarlyBinder { /// arguments of an `FnSig`). Otherwise, consider using /// [`subst_identity`](EarlyBinder::subst_identity). /// + /// To skip the binder on `x: &EarlyBinder` to obtain `&T`, leverage + /// [`EarlyBinder::as_ref`](EarlyBinder::as_ref): `x.as_ref().skip_binder()`. + /// /// See also [`Binder::skip_binder`](super::Binder::skip_binder), which is /// the analogous operation on [`super::Binder`]. pub fn skip_binder(self) -> T { From c5013ce996ff018d8c1de89c6505a76d2a83cfe8 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sun, 28 May 2023 22:03:00 -0400 Subject: [PATCH 68/69] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 2b3aa19805c68..e16c19b6bdfe1 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -be72f2587c91579406117f99fa332383d66b7dcd +089677eb32af83318467325edbef9b64053df532 From 2f65aac667302849407fe677cc34078300b57eee Mon Sep 17 00:00:00 2001 From: mu001999 Date: Mon, 29 May 2023 12:26:27 +0800 Subject: [PATCH 69/69] Determine `self_ty` with expected `ty` --- .../src/check/compare_impl_item.rs | 2 +- tests/ui/mismatched_types/E0053.stderr | 2 +- tests/ui/mismatched_types/issue-112036.rs | 7 +++++++ tests/ui/mismatched_types/issue-112036.stderr | 15 +++++++++++++++ 4 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 tests/ui/mismatched_types/issue-112036.rs create mode 100644 tests/ui/mismatched_types/issue-112036.stderr diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 283a9ed3388eb..7df811ccdb5c1 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -901,7 +901,7 @@ fn report_trait_method_mismatch<'tcx>( if trait_m.fn_has_self_parameter => { let ty = trait_sig.inputs()[0]; - let sugg = match ExplicitSelf::determine(ty, |_| ty == impl_trait_ref.self_ty()) { + let sugg = match ExplicitSelf::determine(ty, |ty| ty == impl_trait_ref.self_ty()) { ExplicitSelf::ByValue => "self".to_owned(), ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(), ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(), diff --git a/tests/ui/mismatched_types/E0053.stderr b/tests/ui/mismatched_types/E0053.stderr index 154f2fcbee0ff..d0bd5b46cf59f 100644 --- a/tests/ui/mismatched_types/E0053.stderr +++ b/tests/ui/mismatched_types/E0053.stderr @@ -22,7 +22,7 @@ LL | fn bar(&mut self) { } | ^^^^^^^^^ | | | types differ in mutability - | help: change the self-receiver type to match the trait: `self: &Bar` + | help: change the self-receiver type to match the trait: `&self` | note: type in trait --> $DIR/E0053.rs:3:12 diff --git a/tests/ui/mismatched_types/issue-112036.rs b/tests/ui/mismatched_types/issue-112036.rs new file mode 100644 index 0000000000000..e63471e974771 --- /dev/null +++ b/tests/ui/mismatched_types/issue-112036.rs @@ -0,0 +1,7 @@ +struct Foo; + +impl Drop for Foo { + fn drop(self) {} //~ ERROR method `drop` has an incompatible type for trait +} + +fn main() {} diff --git a/tests/ui/mismatched_types/issue-112036.stderr b/tests/ui/mismatched_types/issue-112036.stderr new file mode 100644 index 0000000000000..a883aba35bfba --- /dev/null +++ b/tests/ui/mismatched_types/issue-112036.stderr @@ -0,0 +1,15 @@ +error[E0053]: method `drop` has an incompatible type for trait + --> $DIR/issue-112036.rs:4:13 + | +LL | fn drop(self) {} + | ^^^^ + | | + | expected `&mut Foo`, found `Foo` + | help: change the self-receiver type to match the trait: `&mut self` + | + = note: expected signature `fn(&mut Foo)` + found signature `fn(Foo)` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0053`.