diff options
Diffstat (limited to 'src')
355 files changed, 6552 insertions, 6304 deletions
diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 4dd71ebade1..3694bdbf670 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -112,6 +112,9 @@ fn main() { if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") { cmd.arg(format!("-Clinker={}", host_linker)); } + if env::var_os("RUSTC_HOST_FUSE_LD_LLD").is_some() { + cmd.arg("-Clink-args=-fuse-ld=lld"); + } if let Ok(s) = env::var("RUSTC_HOST_CRT_STATIC") { if s == "true" { diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs index ab846adf942..cb58eb89ad8 100644 --- a/src/bootstrap/bin/rustdoc.rs +++ b/src/bootstrap/bin/rustdoc.rs @@ -42,11 +42,14 @@ fn main() { if env::var_os("RUSTC_FORCE_UNSTABLE").is_some() { cmd.arg("-Z").arg("force-unstable-if-unmarked"); } - if let Some(linker) = env::var_os("RUSTC_TARGET_LINKER") { + if let Some(linker) = env::var_os("RUSTDOC_LINKER") { let mut arg = OsString::from("-Clinker="); arg.push(&linker); cmd.arg(arg); } + if env::var_os("RUSTDOC_FUSE_LD_LLD").is_some() { + cmd.arg("-Clink-args=-fuse-ld=lld"); + } // Needed to be able to run all rustdoc tests. if let Some(ref x) = env::var_os("RUSTDOC_RESOURCE_SUFFIX") { diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index c3f1bac177d..955c72856dc 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -398,14 +398,6 @@ class RustBuild(object): with output(self.rustc_stamp()) as rust_stamp: rust_stamp.write(self.date) - # This is required so that we don't mix incompatible MinGW - # libraries/binaries that are included in rust-std with - # the system MinGW ones. - if "pc-windows-gnu" in self.build: - filename = "rust-mingw-{}-{}{}".format( - rustc_channel, self.build, tarball_suffix) - self._download_stage0_helper(filename, "rust-mingw", tarball_suffix) - if self.cargo().startswith(self.bin_root()) and \ (not os.path.exists(self.cargo()) or self.program_out_of_date(self.cargo_stamp())): @@ -714,7 +706,6 @@ class RustBuild(object): # See also: <https://github.com/rust-lang/rust/issues/70208>. if "CARGO_BUILD_TARGET" in env: del env["CARGO_BUILD_TARGET"] - env["RUSTC_BOOTSTRAP"] = '1' env["CARGO_TARGET_DIR"] = build_dir env["RUSTC"] = self.rustc() env["LD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \ diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index cecc9ef75ea..31d4f1f28a8 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -87,11 +87,16 @@ pub trait Step: 'static + Clone + Debug + PartialEq + Eq + Hash { pub struct RunConfig<'a> { pub builder: &'a Builder<'a>, - pub host: TargetSelection, pub target: TargetSelection, pub path: PathBuf, } +impl RunConfig<'_> { + pub fn build_triple(&self) -> TargetSelection { + self.builder.build.build + } +} + struct StepDescription { default: bool, only_hosts: bool, @@ -165,7 +170,6 @@ impl StepDescription { pathset, self.name, builder.config.exclude ); } - let hosts = &builder.hosts; // Determine the targets participating in this rule. let targets = if self.only_hosts { @@ -178,16 +182,9 @@ impl StepDescription { &builder.targets }; - for host in hosts { - for target in targets { - let run = RunConfig { - builder, - path: pathset.path(builder), - host: *host, - target: *target, - }; - (self.make_run)(run); - } + for target in targets { + let run = RunConfig { builder, path: pathset.path(builder), target: *target }; + (self.make_run)(run); } } @@ -382,7 +379,7 @@ impl<'a> Builder<'a> { native::Lld ), Kind::Check | Kind::Clippy | Kind::Fix | Kind::Format => { - describe!(check::Std, check::Rustc, check::Rustdoc, check::Clippy) + describe!(check::Std, check::Rustc, check::Rustdoc, check::Clippy, check::Bootstrap) } Kind::Test => describe!( crate::toolstate::ToolStateCheck, @@ -471,6 +468,7 @@ impl<'a> Builder<'a> { dist::Clippy, dist::Miri, dist::LlvmTools, + dist::RustDev, dist::Extended, dist::HashSign ), @@ -755,8 +753,11 @@ impl<'a> Builder<'a> { cmd.env_remove("MAKEFLAGS"); cmd.env_remove("MFLAGS"); - if let Some(linker) = self.linker(compiler.host, true) { - cmd.env("RUSTC_TARGET_LINKER", linker); + if let Some(linker) = self.linker(compiler.host) { + cmd.env("RUSTDOC_LINKER", linker); + } + if self.is_fuse_ld_lld(compiler.host) { + cmd.env("RUSTDOC_FUSE_LD_LLD", "1"); } cmd } @@ -796,7 +797,7 @@ impl<'a> Builder<'a> { if cmd == "doc" || cmd == "rustdoc" { let my_out = match mode { // This is the intended out directory for compiler documentation. - Mode::Rustc | Mode::ToolRustc | Mode::Codegen => self.compiler_doc_out(target), + Mode::Rustc | Mode::ToolRustc => self.compiler_doc_out(target), Mode::Std => out_dir.join(target.triple).join("doc"), _ => panic!("doc mode {:?} not expected", mode), }; @@ -811,7 +812,7 @@ impl<'a> Builder<'a> { format!("CARGO_PROFILE_{}_{}", profile, name) }; - // See comment in librustc_llvm/build.rs for why this is necessary, largely llvm-config + // See comment in rustc_llvm/build.rs for why this is necessary, largely llvm-config // needs to not accidentally link to libLLVM in stage0/lib. cargo.env("REAL_LIBRARY_PATH_VAR", &util::dylib_path_var()); if let Some(e) = env::var_os(util::dylib_path_var()) { @@ -828,9 +829,9 @@ impl<'a> Builder<'a> { // scripts can do less work (i.e. not building/requiring LLVM). if cmd == "check" || cmd == "clippy" || cmd == "fix" { // If we've not yet built LLVM, or it's stale, then bust - // the librustc_llvm cache. That will always work, even though it + // the rustc_llvm cache. That will always work, even though it // may mean that on the next non-check build we'll need to rebuild - // librustc_llvm. But if LLVM is stale, that'll be a tiny amount + // rustc_llvm. But if LLVM is stale, that'll be a tiny amount // of work comparitively, and we'd likely need to rebuild it anyway, // so that's okay. if crate::native::prebuilt_llvm_config(self, target).is_err() { @@ -874,7 +875,7 @@ impl<'a> Builder<'a> { match mode { Mode::Std | Mode::ToolBootstrap | Mode::ToolStd => {} - Mode::Rustc | Mode::Codegen | Mode::ToolRustc => { + Mode::Rustc | Mode::ToolRustc => { // Build proc macros both for the host and the target if target != compiler.host && cmd != "check" { cargo.arg("-Zdual-proc-macros"); @@ -1041,16 +1042,18 @@ impl<'a> Builder<'a> { } } - if let Some(host_linker) = self.linker(compiler.host, true) { + if let Some(host_linker) = self.linker(compiler.host) { cargo.env("RUSTC_HOST_LINKER", host_linker); } + if self.is_fuse_ld_lld(compiler.host) { + cargo.env("RUSTC_HOST_FUSE_LD_LLD", "1"); + } - if let Some(target_linker) = self.linker(target, true) { + if let Some(target_linker) = self.linker(target) { let target = crate::envify(&target.triple); cargo.env(&format!("CARGO_TARGET_{}_LINKER", target), target_linker); } - - if self.config.use_lld && !target.contains("msvc") { + if self.is_fuse_ld_lld(target) { rustflags.arg("-Clink-args=-fuse-ld=lld"); } @@ -1059,7 +1062,7 @@ impl<'a> Builder<'a> { } let debuginfo_level = match mode { - Mode::Rustc | Mode::Codegen => self.config.rust_debuginfo_level_rustc, + Mode::Rustc => self.config.rust_debuginfo_level_rustc, Mode::Std => self.config.rust_debuginfo_level_std, Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolRustc => { self.config.rust_debuginfo_level_tools @@ -1196,7 +1199,7 @@ impl<'a> Builder<'a> { rustdocflags.arg("-Winvalid_codeblock_attributes"); } - if let Mode::Rustc | Mode::Codegen = mode { + if mode == Mode::Rustc { rustflags.arg("-Zunstable-options"); rustflags.arg("-Wrustc::internal"); } @@ -1359,7 +1362,7 @@ impl<'a> Builder<'a> { // When we build Rust dylibs they're all intended for intermediate // usage, so make sure we pass the -Cprefer-dynamic flag instead of // linking all deps statically into the dylib. - if let Mode::Std | Mode::Rustc | Mode::Codegen = mode { + if matches!(mode, Mode::Std | Mode::Rustc) { rustflags.arg("-Cprefer-dynamic"); } diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index aeb0d713ef0..c6eac95c345 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -217,6 +217,16 @@ mod dist { dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, ] ); + assert_eq!( + first(builder.cache.all::<compile::Std>()), + &[ + compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a }, + compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, + compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a }, + compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, + compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b }, + ], + ); assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]); } @@ -384,12 +394,9 @@ mod dist { compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a }, compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a }, - compile::Std { compiler: Compiler { host: b, stage: 2 }, target: a }, compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b }, - compile::Std { compiler: Compiler { host: b, stage: 2 }, target: b }, compile::Std { compiler: Compiler { host: a, stage: 2 }, target: c }, - compile::Std { compiler: Compiler { host: b, stage: 2 }, target: c }, ] ); assert!(!builder.cache.all::<compile::Assemble>().is_empty()); @@ -399,10 +406,8 @@ mod dist { compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a }, compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: a }, compile::Rustc { compiler: Compiler { host: a, stage: 2 }, target: a }, - compile::Rustc { compiler: Compiler { host: b, stage: 2 }, target: a }, compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: b }, compile::Rustc { compiler: Compiler { host: a, stage: 2 }, target: b }, - compile::Rustc { compiler: Compiler { host: b, stage: 2 }, target: b }, ] ); } @@ -425,12 +430,9 @@ mod dist { compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a }, compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a }, - compile::Std { compiler: Compiler { host: b, stage: 2 }, target: a }, compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b }, - compile::Std { compiler: Compiler { host: b, stage: 2 }, target: b }, compile::Std { compiler: Compiler { host: a, stage: 2 }, target: c }, - compile::Std { compiler: Compiler { host: b, stage: 2 }, target: c }, ] ); assert_eq!( @@ -439,7 +441,6 @@ mod dist { compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } }, compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } }, compile::Assemble { target_compiler: Compiler { host: a, stage: 2 } }, - compile::Assemble { target_compiler: Compiler { host: b, stage: 2 } }, ] ); assert_eq!( @@ -447,7 +448,6 @@ mod dist { &[ compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a }, compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: a }, - compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: b }, ] ); } diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 9f34bb4e6cc..ead0bd0413b 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -66,6 +66,43 @@ impl Step for Std { let libdir = builder.sysroot_libdir(compiler, target); let hostdir = builder.sysroot_libdir(compiler, compiler.host); add_to_sysroot(&builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target)); + + // Then run cargo again, once we've put the rmeta files for the library + // crates into the sysroot. This is needed because e.g., core's tests + // depend on `libtest` -- Cargo presumes it will exist, but it doesn't + // since we initialize with an empty sysroot. + // + // Currently only the "libtest" tree of crates does this. + + let mut cargo = builder.cargo( + compiler, + Mode::Std, + SourceType::InTree, + target, + cargo_subcommand(builder.kind), + ); + std_cargo(builder, target, compiler.stage, &mut cargo); + cargo.arg("--all-targets"); + + // Explicitly pass -p for all dependencies krates -- this will force cargo + // to also check the tests/benches/examples for these crates, rather + // than just the leaf crate. + for krate in builder.in_tree_crates("test") { + cargo.arg("-p").arg(krate.name); + } + + builder.info(&format!( + "Checking std test/bench/example targets ({} -> {})", + &compiler.host, target + )); + run_cargo( + builder, + cargo, + args(builder.kind), + &libstd_test_stamp(builder, compiler, target), + vec![], + true, + ); } } @@ -106,6 +143,14 @@ impl Step for Rustc { cargo_subcommand(builder.kind), ); rustc_cargo(builder, &mut cargo, target); + cargo.arg("--all-targets"); + + // Explicitly pass -p for all compiler krates -- this will force cargo + // to also check the tests/benches/examples for these crates, rather + // than just the leaf crate. + for krate in builder.in_tree_crates("rustc-main") { + cargo.arg("-p").arg(krate.name); + } builder.info(&format!("Checking compiler artifacts ({} -> {})", &compiler.host, target)); run_cargo( @@ -149,7 +194,7 @@ macro_rules! tool_check_step { builder.ensure(Rustc { target }); - let cargo = prepare_tool_cargo( + let mut cargo = prepare_tool_cargo( builder, compiler, Mode::ToolRustc, @@ -160,12 +205,14 @@ macro_rules! tool_check_step { &[], ); - println!( + cargo.arg("--all-targets"); + + builder.info(&format!( "Checking {} artifacts ({} -> {})", stringify!($name).to_lowercase(), &compiler.host.triple, target.triple - ); + )); run_cargo( builder, cargo, @@ -202,12 +249,24 @@ tool_check_step!(Rustdoc, "src/tools/rustdoc", SourceType::InTree); // rejected. tool_check_step!(Clippy, "src/tools/clippy", SourceType::InTree); +tool_check_step!(Bootstrap, "src/bootstrap", SourceType::InTree); + /// Cargo's output path for the standard library in a given stage, compiled /// by a particular compiler for the specified target. fn libstd_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf { builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check.stamp") } +/// Cargo's output path for the standard library in a given stage, compiled +/// by a particular compiler for the specified target. +fn libstd_test_stamp( + builder: &Builder<'_>, + compiler: Compiler, + target: TargetSelection, +) -> PathBuf { + builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check-test.stamp") +} + /// Cargo's output path for librustc in a given stage, compiled by a particular /// compiler for the specified target. fn librustc_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf { diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 7814ca8e5bb..e0dddda83b9 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -45,7 +45,7 @@ impl Step for Std { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Std { - compiler: run.builder.compiler(run.builder.top_stage, run.host), + compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), target: run.target, }); } @@ -385,7 +385,7 @@ impl Step for StartupObjects { fn make_run(run: RunConfig<'_>) { run.builder.ensure(StartupObjects { - compiler: run.builder.compiler(run.builder.top_stage, run.host), + compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), target: run.target, }); } @@ -454,7 +454,7 @@ impl Step for Rustc { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Rustc { - compiler: run.builder.compiler(run.builder.top_stage, run.host), + compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), target: run.target, }); } @@ -560,7 +560,7 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS } // Pass down configuration from the LLVM build into the build of - // librustc_llvm and librustc_codegen_llvm. + // rustc_llvm and rustc_codegen_llvm. // // Note that this is disabled if LLVM itself is disabled or we're in a check // build. If we are in a check build we still go ahead here presuming we've @@ -579,7 +579,7 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { cargo.env("CFG_LLVM_ROOT", s); } - // Some LLVM linker flags (-L and -l) may be needed to link librustc_llvm. + // Some LLVM linker flags (-L and -l) may be needed to link rustc_llvm. if let Some(ref s) = builder.config.llvm_ldflags { cargo.env("LLVM_LINKER_FLAGS", s); } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index ad2f4877867..5a79d3db5c9 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -273,10 +273,8 @@ struct TomlConfig { #[serde(deny_unknown_fields, rename_all = "kebab-case")] struct Build { build: Option<String>, - #[serde(default)] - host: Vec<String>, - #[serde(default)] - target: Vec<String>, + host: Option<Vec<String>>, + target: Option<Vec<String>>, // This is ignored, the rust code always gets the build directory from the `BUILD_DIR` env variable build_dir: Option<String>, cargo: Option<String>, @@ -505,11 +503,6 @@ impl Config { config.out = dir; } - // If --target was specified but --host wasn't specified, don't run any host-only tests. - let has_hosts = !flags.host.is_empty(); - let has_targets = !flags.target.is_empty(); - config.skip_only_host_steps = !has_hosts && has_targets; - let toml = file .map(|file| { let contents = t!(fs::read_to_string(&file)); @@ -528,25 +521,28 @@ impl Config { .unwrap_or_else(TomlConfig::default); let build = toml.build.clone().unwrap_or_default(); - // set by bootstrap.py - config.hosts.push(config.build); - for host in build.host.iter().map(|h| TargetSelection::from_user(h)) { - if !config.hosts.contains(&host) { - config.hosts.push(host); - } - } - for target in config - .hosts - .iter() - .copied() - .chain(build.target.iter().map(|h| TargetSelection::from_user(h))) - { - if !config.targets.contains(&target) { - config.targets.push(target); - } - } - config.hosts = if !flags.host.is_empty() { flags.host } else { config.hosts }; - config.targets = if !flags.target.is_empty() { flags.target } else { config.targets }; + + // If --target was specified but --host wasn't specified, don't run any host-only tests. + let has_hosts = build.host.is_some() || flags.host.is_some(); + let has_targets = build.target.is_some() || flags.target.is_some(); + config.skip_only_host_steps = !has_hosts && has_targets; + + config.hosts = if let Some(arg_host) = flags.host.clone() { + arg_host + } else if let Some(file_host) = build.host { + file_host.iter().map(|h| TargetSelection::from_user(h)).collect() + } else { + vec![config.build] + }; + config.targets = if let Some(arg_target) = flags.target.clone() { + arg_target + } else if let Some(file_target) = build.target { + file_target.iter().map(|h| TargetSelection::from_user(h)).collect() + } else { + // If target is *not* configured, then default to the host + // toolchains. + config.hosts.clone() + }; config.nodejs = build.nodejs.map(PathBuf::from); config.gdb = build.gdb.map(PathBuf::from); diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index c1022099a02..e22cdb13928 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -323,8 +323,8 @@ fn make_win_dist( // Warn windows-gnu users that the bundled GCC cannot compile C files builder.create( &target_bin_dir.join("GCC-WARNING.txt"), - "gcc.exe contained in this folder cannot be used for compiling C files - it is only\ - used as a linker. In order to be able to compile projects containing C code use\ + "gcc.exe contained in this folder cannot be used for compiling C files - it is only \ + used as a linker. In order to be able to compile projects containing C code use \ the GCC provided by MinGW or Cygwin.", ); @@ -605,7 +605,9 @@ impl Step for DebuggerScripts { fn make_run(run: RunConfig<'_>) { run.builder.ensure(DebuggerScripts { - sysroot: run.builder.sysroot(run.builder.compiler(run.builder.top_stage, run.host)), + sysroot: run + .builder + .sysroot(run.builder.compiler(run.builder.top_stage, run.build_triple())), host: run.target, }); } @@ -2499,3 +2501,94 @@ impl Step for LlvmTools { Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple))) } } + +// Tarball intended for internal consumption to ease rustc/std development. +// +// Should not be considered stable by end users. +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct RustDev { + pub target: TargetSelection, +} + +impl Step for RustDev { + type Output = Option<PathBuf>; + const DEFAULT: bool = true; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("rust-dev") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(RustDev { target: run.target }); + } + + fn run(self, builder: &Builder<'_>) -> Option<PathBuf> { + let target = self.target; + + /* run only if llvm-config isn't used */ + if let Some(config) = builder.config.target_config.get(&target) { + if let Some(ref _s) = config.llvm_config { + builder.info(&format!("Skipping RustDev ({}): external LLVM", target)); + return None; + } + } + + builder.info(&format!("Dist RustDev ({})", target)); + let _time = timeit(builder); + let src = builder.src.join("src/llvm-project/llvm"); + let name = pkgname(builder, "rust-dev"); + + let tmp = tmpdir(builder); + let image = tmp.join("rust-dev-image"); + drop(fs::remove_dir_all(&image)); + + // Prepare the image directory + let dst_bindir = image.join("bin"); + t!(fs::create_dir_all(&dst_bindir)); + + let exe = builder.llvm_out(target).join("bin").join(exe("llvm-config", target)); + builder.install(&exe, &dst_bindir, 0o755); + builder.install(&builder.llvm_filecheck(target), &dst_bindir, 0o755); + + // Copy the include directory as well; needed mostly to build + // librustc_llvm properly (e.g., llvm-config.h is in here). But also + // just broadly useful to be able to link against the bundled LLVM. + builder.cp_r(&builder.llvm_out(target).join("include"), &image.join("include")); + + // Copy libLLVM.so to the target lib dir as well, so the RPATH like + // `$ORIGIN/../lib` can find it. It may also be used as a dependency + // of `rustc-dev` to support the inherited `-lLLVM` when using the + // compiler libraries. + maybe_install_llvm(builder, target, &image.join("lib")); + + // Prepare the overlay + let overlay = tmp.join("rust-dev-overlay"); + drop(fs::remove_dir_all(&overlay)); + builder.create_dir(&overlay); + builder.install(&src.join("README.txt"), &overlay, 0o644); + builder.install(&src.join("LICENSE.TXT"), &overlay, 0o644); + builder.create(&overlay.join("version"), &builder.rust_version()); + + // Generate the installer tarball + let mut cmd = rust_installer(builder); + cmd.arg("generate") + .arg("--product-name=Rust") + .arg("--rel-manifest-dir=rustlib") + .arg("--success-message=rust-dev-installed.") + .arg("--image-dir") + .arg(&image) + .arg("--work-dir") + .arg(&tmpdir(builder)) + .arg("--output-dir") + .arg(&distdir(builder)) + .arg("--non-installed-overlay") + .arg(&overlay) + .arg(format!("--package-name={}-{}", name, target.triple)) + .arg("--legacy-manifest-dirs=rustlib,cargo") + .arg("--component-name=rust-dev"); + + builder.run(&mut cmd); + Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple))) + } +} diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 2db4bb07a9f..ff846857446 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -20,8 +20,8 @@ pub struct Flags { pub stage: Option<u32>, pub keep_stage: Vec<u32>, - pub host: Vec<TargetSelection>, - pub target: Vec<TargetSelection>, + pub host: Option<Vec<TargetSelection>>, + pub target: Option<Vec<TargetSelection>>, pub config: Option<PathBuf>, pub jobs: Option<u32>, pub cmd: Subcommand, @@ -526,14 +526,26 @@ Arguments: .into_iter() .map(|j| j.parse().expect("`keep-stage` should be a number")) .collect(), - host: split(&matches.opt_strs("host")) - .into_iter() - .map(|x| TargetSelection::from_user(&x)) - .collect::<Vec<_>>(), - target: split(&matches.opt_strs("target")) - .into_iter() - .map(|x| TargetSelection::from_user(&x)) - .collect::<Vec<_>>(), + host: if matches.opt_present("host") { + Some( + split(&matches.opt_strs("host")) + .into_iter() + .map(|x| TargetSelection::from_user(&x)) + .collect::<Vec<_>>(), + ) + } else { + None + }, + target: if matches.opt_present("target") { + Some( + split(&matches.opt_strs("target")) + .into_iter() + .map(|x| TargetSelection::from_user(&x)) + .collect::<Vec<_>>(), + ) + } else { + None + }, config: cfg_file, jobs: matches.opt_str("jobs").map(|j| j.parse().expect("`jobs` should be a number")), cmd, diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 54651214363..f0224d88226 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -103,8 +103,6 @@ //! More documentation can be found in each respective module below, and you can //! also check out the `src/bootstrap/README.md` file for more information. -#![feature(drain_filter)] - use std::cell::{Cell, RefCell}; use std::collections::{HashMap, HashSet}; use std::env; @@ -300,9 +298,6 @@ pub enum Mode { /// Build librustc, and compiler libraries, placing output in the "stageN-rustc" directory. Rustc, - /// Build codegen libraries, placing output in the "stageN-codegen" directory - Codegen, - /// Build a tool, placing output in the "stage0-bootstrap-tools" /// directory. This is for miscellaneous sets of tools that are built /// using the bootstrap stage0 compiler in its entirety (target libraries @@ -572,7 +567,6 @@ impl Build { let suffix = match mode { Mode::Std => "-std", Mode::Rustc => "-rustc", - Mode::Codegen => "-codegen", Mode::ToolBootstrap => "-bootstrap-tools", Mode::ToolStd | Mode::ToolRustc => "-tools", }; @@ -850,7 +844,7 @@ impl Build { } /// Returns the path to the linker for the given target if it needs to be overridden. - fn linker(&self, target: TargetSelection, can_use_lld: bool) -> Option<&Path> { + fn linker(&self, target: TargetSelection) -> Option<&Path> { if let Some(linker) = self.config.target_config.get(&target).and_then(|c| c.linker.as_ref()) { Some(linker) @@ -863,13 +857,19 @@ impl Build { && !target.contains("msvc") { Some(self.cc(target)) - } else if can_use_lld && self.config.use_lld && self.build == target { + } else if self.config.use_lld && !self.is_fuse_ld_lld(target) && self.build == target { Some(&self.initial_lld) } else { None } } + // LLD is used through `-fuse-ld=lld` rather than directly. + // Only MSVC targets use LLD directly at the moment. + fn is_fuse_ld_lld(&self, target: TargetSelection) -> bool { + self.config.use_lld && !target.contains("msvc") + } + /// Returns if this target should statically link the C runtime, if specified fn crt_static(&self, target: TargetSelection) -> Option<bool> { if target.contains("pc-windows-msvc") { diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index a0c79e38f9d..6cd850bc0bf 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -169,7 +169,6 @@ impl Step for Llvm { .define("LLVM_INCLUDE_TESTS", "OFF") .define("LLVM_INCLUDE_DOCS", "OFF") .define("LLVM_INCLUDE_BENCHMARKS", "OFF") - .define("WITH_POLLY", "OFF") .define("LLVM_ENABLE_TERMINFO", "OFF") .define("LLVM_ENABLE_LIBEDIT", "OFF") .define("LLVM_ENABLE_BINDINGS", "OFF") @@ -305,10 +304,6 @@ impl Step for Llvm { cfg.define("LLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN", "YES"); } - if let Some(ref python) = builder.config.python { - cfg.define("PYTHON_EXECUTABLE", python); - } - configure_cmake(builder, target, &mut cfg, true); // FIXME: we don't actually need to build all LLVM tools and all LLVM diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index a7c9b99f45f..045dda2d4cb 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -584,7 +584,7 @@ impl Step for RustdocTheme { } fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler(run.builder.top_stage, run.host); + let compiler = run.builder.compiler(run.builder.top_stage, run.target); run.builder.ensure(RustdocTheme { compiler }); } @@ -600,8 +600,11 @@ impl Step for RustdocTheme { .env("CFG_RELEASE_CHANNEL", &builder.config.channel) .env("RUSTDOC_REAL", builder.rustdoc(self.compiler)) .env("RUSTC_BOOTSTRAP", "1"); - if let Some(linker) = builder.linker(self.compiler.host, true) { - cmd.env("RUSTC_TARGET_LINKER", linker); + if let Some(linker) = builder.linker(self.compiler.host) { + cmd.env("RUSTDOC_LINKER", linker); + } + if builder.is_fuse_ld_lld(self.compiler.host) { + cmd.env("RUSTDOC_FUSE_LD_LLD", "1"); } try_run(builder, &mut cmd); } @@ -648,7 +651,6 @@ impl Step for RustdocJSStd { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct RustdocJSNotStd { - pub host: TargetSelection, pub target: TargetSelection, pub compiler: Compiler, } @@ -663,8 +665,8 @@ impl Step for RustdocJSNotStd { } fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler(run.builder.top_stage, run.host); - run.builder.ensure(RustdocJSNotStd { host: run.host, target: run.target, compiler }); + let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple()); + run.builder.ensure(RustdocJSNotStd { target: run.target, compiler }); } fn run(self, builder: &Builder<'_>) { @@ -685,7 +687,6 @@ impl Step for RustdocJSNotStd { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct RustdocUi { - pub host: TargetSelection, pub target: TargetSelection, pub compiler: Compiler, } @@ -700,8 +701,8 @@ impl Step for RustdocUi { } fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler(run.builder.top_stage, run.host); - run.builder.ensure(RustdocUi { host: run.host, target: run.target, compiler }); + let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple()); + run.builder.ensure(RustdocUi { target: run.target, compiler }); } fn run(self, builder: &Builder<'_>) { @@ -870,7 +871,7 @@ macro_rules! test_definitions { } fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler(run.builder.top_stage, run.host); + let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple()); run.builder.ensure($name { compiler, target: run.target }); } @@ -1061,17 +1062,22 @@ impl Step for Compiletest { flags.push("-Zunstable-options".to_string()); flags.push(builder.config.cmd.rustc_args().join(" ")); - // Don't use LLD here since we want to test that rustc finds and uses a linker by itself. - if let Some(linker) = builder.linker(target, false) { + if let Some(linker) = builder.linker(target) { cmd.arg("--linker").arg(linker); } let mut hostflags = flags.clone(); hostflags.push(format!("-Lnative={}", builder.test_helpers_out(compiler.host).display())); + if builder.is_fuse_ld_lld(compiler.host) { + hostflags.push("-Clink-args=-fuse-ld=lld".to_string()); + } cmd.arg("--host-rustcflags").arg(hostflags.join(" ")); let mut targetflags = flags; targetflags.push(format!("-Lnative={}", builder.test_helpers_out(target).display())); + if builder.is_fuse_ld_lld(target) { + targetflags.push("-Clink-args=-fuse-ld=lld".to_string()); + } cmd.arg("--target-rustcflags").arg(targetflags.join(" ")); cmd.arg("--docck-python").arg(builder.python()); @@ -1414,7 +1420,7 @@ macro_rules! test_book { fn make_run(run: RunConfig<'_>) { run.builder.ensure($name { - compiler: run.builder.compiler(run.builder.top_stage, run.host), + compiler: run.builder.compiler(run.builder.top_stage, run.target), }); } @@ -1461,7 +1467,7 @@ impl Step for ErrorIndex { // error_index_generator depends on librustdoc. Use the compiler that // is normally used to build rustdoc for other tests (like compiletest // tests in src/test/rustdoc) so that it shares the same artifacts. - let compiler = run.builder.compiler_for(run.builder.top_stage, run.host, run.host); + let compiler = run.builder.compiler_for(run.builder.top_stage, run.target, run.target); run.builder.ensure(ErrorIndex { compiler }); } @@ -1565,7 +1571,7 @@ impl Step for CrateLibrustc { fn make_run(run: RunConfig<'_>) { let builder = run.builder; - let compiler = builder.compiler(builder.top_stage, run.host); + let compiler = builder.compiler(builder.top_stage, run.build_triple()); for krate in builder.in_tree_crates("rustc-main") { if krate.path.ends_with(&run.path) { @@ -1612,7 +1618,7 @@ impl Step for CrateNotDefault { fn make_run(run: RunConfig<'_>) { let builder = run.builder; - let compiler = builder.compiler(builder.top_stage, run.host); + let compiler = builder.compiler(builder.top_stage, run.build_triple()); let test_kind = builder.kind.into(); @@ -1660,7 +1666,7 @@ impl Step for Crate { fn make_run(run: RunConfig<'_>) { let builder = run.builder; - let compiler = builder.compiler(builder.top_stage, run.host); + let compiler = builder.compiler(builder.top_stage, run.build_triple()); let make = |mode: Mode, krate: &CargoCrate| { let test_kind = builder.kind.into(); @@ -1800,7 +1806,7 @@ impl Step for CrateRustdoc { let test_kind = builder.kind.into(); - builder.ensure(CrateRustdoc { host: run.host, test_kind }); + builder.ensure(CrateRustdoc { host: run.target, test_kind }); } fn run(self, builder: &Builder<'_>) { @@ -2046,7 +2052,6 @@ impl Step for Bootstrap { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct TierCheck { pub compiler: Compiler, - target: TargetSelection, } impl Step for TierCheck { @@ -2059,18 +2064,19 @@ impl Step for TierCheck { } fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler_for(run.builder.top_stage, run.host, run.host); - run.builder.ensure(TierCheck { compiler, target: run.host }); + let compiler = + run.builder.compiler_for(run.builder.top_stage, run.builder.build.build, run.target); + run.builder.ensure(TierCheck { compiler }); } /// Tests the Platform Support page in the rustc book. fn run(self, builder: &Builder<'_>) { - builder.ensure(compile::Std { compiler: self.compiler, target: self.target }); + builder.ensure(compile::Std { compiler: self.compiler, target: self.compiler.host }); let mut cargo = tool::prepare_tool_cargo( builder, self.compiler, - Mode::ToolRustc, - self.target, + Mode::ToolStd, + self.compiler.host, "run", "src/tools/tier-check", SourceType::InTree, diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index fe3f1e78029..a607f0fe258 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -162,13 +162,15 @@ impl Step for ToolBuild { "the following dependencies are duplicated although they \ have the same features enabled:" ); - for (id, cur, prev) in duplicates.drain_filter(|(_, cur, prev)| cur.2 == prev.2) { + let (same, different): (Vec<_>, Vec<_>) = + duplicates.into_iter().partition(|(_, cur, prev)| cur.2 == prev.2); + for (id, cur, prev) in same { println!(" {}", id); // same features println!(" `{}` ({:?})\n `{}` ({:?})", cur.0, cur.1, prev.0, prev.1); } println!("the following dependencies have different features:"); - for (id, cur, prev) in duplicates { + for (id, cur, prev) in different { println!(" {}", id); let cur_features: HashSet<_> = cur.2.into_iter().collect(); let prev_features: HashSet<_> = prev.2.into_iter().collect(); @@ -467,8 +469,9 @@ impl Step for Rustdoc { } fn make_run(run: RunConfig<'_>) { - run.builder - .ensure(Rustdoc { compiler: run.builder.compiler(run.builder.top_stage, run.host) }); + run.builder.ensure(Rustdoc { + compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), + }); } fn run(self, builder: &Builder<'_>) -> PathBuf { diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 522d5bd3d9c..aef4374c542 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -523,7 +523,7 @@ jobs: - name: x86_64-mingw-1 env: SCRIPT: make ci-mingw-subset-1 - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-profiler CUSTOM_MINGW: 1 # FIXME(#59637) NO_DEBUG_ASSERTIONS: 1 @@ -533,7 +533,7 @@ jobs: - name: x86_64-mingw-2 env: SCRIPT: make ci-mingw-subset-2 - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-profiler CUSTOM_MINGW: 1 <<: *job-windows-xl diff --git a/src/ci/scripts/symlink-build-dir.sh b/src/ci/scripts/symlink-build-dir.sh index 28d8aa3b6e7..23849f7047c 100755 --- a/src/ci/scripts/symlink-build-dir.sh +++ b/src/ci/scripts/symlink-build-dir.sh @@ -12,22 +12,4 @@ source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" if isWindows && isAzurePipelines; then cmd //c "mkdir c:\\MORE_SPACE" cmd //c "mklink /J build c:\\MORE_SPACE" -elif isLinux && isGitHubActions && ! isSelfHostedGitHubActions; then - sudo mkdir -p /mnt/more-space - sudo chown -R "$(whoami):" /mnt/more-space - - # Switch the whole workspace to the /mnt partition, which has more space. - # We don't just symlink the `obj` directory as doing that creates problems - # with the docker container. - current_dir="$(readlink -f "$(pwd)")" - cd /tmp - mv "${current_dir}" /mnt/more-space/workspace - ln -s /mnt/more-space/workspace "${current_dir}" - cd "${current_dir}" - - # Move the Docker data directory to /mnt - sudo systemctl stop docker.service - sudo mv /var/lib/docker /mnt/docker - sudo ln -s /mnt/docker /var/lib/docker - sudo systemctl start docker.service fi diff --git a/src/doc/rustc/src/linker-plugin-lto.md b/src/doc/rustc/src/linker-plugin-lto.md index c0b14352b7d..18f1be6a1fa 100644 --- a/src/doc/rustc/src/linker-plugin-lto.md +++ b/src/doc/rustc/src/linker-plugin-lto.md @@ -89,6 +89,28 @@ rustc -Clinker-plugin-lto="/path/to/LLVMgold.so" -L. -Copt-level=2 ./main.rs ## Toolchain Compatibility +<!-- NOTE: to update the below table, you can use this shell script: + +```sh +rustup toolchain install --profile minimal nightly +MINOR_VERSION=$(rustc +nightly --version | cut -d . -f 2) +LOWER_BOUND=44 + +llvm_version() { + toolchain="$1" + printf "Rust $toolchain | Clang " + rustc +"$toolchain" -Vv | grep LLVM | cut -d ':' -f 2 | tr -d ' ' +} + +for version in `seq $LOWER_BOUND $((MINOR_VERSION - 2))`; do + toolchain=1.$version.0 + rustup toolchain install --no-self-update --profile minimal $toolchain >/dev/null 2>&1 + llvm_version $toolchain +done +``` + +--> + In order for this kind of LTO to work, the LLVM linker plugin must be able to handle the LLVM bitcode produced by both `rustc` and `clang`. @@ -100,17 +122,20 @@ LLVM. However, the approximation is usually reliable. The following table shows known good combinations of toolchain versions. -| | Clang 7 | Clang 8 | Clang 9 | -|-----------|-----------|-----------|-----------| -| Rust 1.34 | ✗ | ✓ | ✗ | -| Rust 1.35 | ✗ | ✓ | ✗ | -| Rust 1.36 | ✗ | ✓ | ✗ | -| Rust 1.37 | ✗ | ✓ | ✗ | -| Rust 1.38 | ✗ | ✗ | ✓ | -| Rust 1.39 | ✗ | ✗ | ✓ | -| Rust 1.40 | ✗ | ✗ | ✓ | -| Rust 1.41 | ✗ | ✗ | ✓ | -| Rust 1.42 | ✗ | ✗ | ✓ | -| Rust 1.43 | ✗ | ✗ | ✓ | +| Rust Version | Clang Version | +|--------------|---------------| +| Rust 1.34 | Clang 8 | +| Rust 1.35 | Clang 8 | +| Rust 1.36 | Clang 8 | +| Rust 1.37 | Clang 8 | +| Rust 1.38 | Clang 9 | +| Rust 1.39 | Clang 9 | +| Rust 1.40 | Clang 9 | +| Rust 1.41 | Clang 9 | +| Rust 1.42 | Clang 9 | +| Rust 1.43 | Clang 9 | +| Rust 1.44 | Clang 9 | +| Rust 1.45 | Clang 10 | +| Rust 1.46 | Clang 10 | Note that the compatibility policy for this feature might change in the future. diff --git a/src/doc/rustc/src/lints/listing/allowed-by-default.md b/src/doc/rustc/src/lints/listing/allowed-by-default.md index d3dfc3197e2..d2d8c471efc 100644 --- a/src/doc/rustc/src/lints/listing/allowed-by-default.md +++ b/src/doc/rustc/src/lints/listing/allowed-by-default.md @@ -232,7 +232,8 @@ error: lifetime name `'x` only used once ## trivial-casts -This lint detects trivial casts which could be removed. Some example code +This lint detects trivial casts which could be replaced with coercion, which may require +type ascription or a temporary variable. Some example code that triggers this lint: ```rust diff --git a/src/doc/rustdoc/src/what-is-rustdoc.md b/src/doc/rustdoc/src/what-is-rustdoc.md index adcebc832bc..7a38c96d714 100644 --- a/src/doc/rustdoc/src/what-is-rustdoc.md +++ b/src/doc/rustdoc/src/what-is-rustdoc.md @@ -93,6 +93,29 @@ passes `-L`, a flag that helps rustdoc find the dependencies your code relies on. If our project used dependencies, we'd get documentation for them as well! +## Outer and inner documentation + +The `///` syntax is used to document the item present after it. +That's why it is called an outer documentation. +There is another syntax: `//!`, which is used to document the +item it is present inside. It is called an inner documentation. +It is often used when documenting the entire crate, +because nothing comes before it: it is the root of the crate. +So in order to document an entire crate, you need to use `//!` syntax. +For example: + +``` rust +//! This is my first rust crate +``` + +When used in the crate root, it documents the item it is inside, +which is the crate itself. + +For more information about the `//!` syntax, see [the Book]. + +[the Book]: https://doc.rust-lang.org/book/ch14-02-publishing-to-crates-io.html#commenting-contained-items + + ## Using standalone Markdown files `rustdoc` can also generate HTML from standalone Markdown files. Let's diff --git a/src/doc/unstable-book/src/language-features/ffi-const.md b/src/doc/unstable-book/src/language-features/ffi-const.md index 9a1ced4033b..24a30443754 100644 --- a/src/doc/unstable-book/src/language-features/ffi-const.md +++ b/src/doc/unstable-book/src/language-features/ffi-const.md @@ -1,5 +1,9 @@ # `ffi_const` +The tracking issue for this feature is: [#58328] + +------ + The `#[ffi_const]` attribute applies clang's `const` attribute to foreign functions declarations. @@ -42,6 +46,7 @@ implemented in this way on all of them. It is therefore also worth verifying that the semantics of the C toolchain used to compile the binary being linked against are compatible with those of the `#[ffi_const]`. +[#58328]: https://github.com/rust-lang/rust/issues/58328 [ARM C/C++ compiler]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491c/Cacgigch.html [GCC]: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-const-function-attribute [IBM ILE C/C++]: https://www.ibm.com/support/knowledgecenter/fr/ssw_ibm_i_71/rzarg/fn_attrib_const.htm diff --git a/src/doc/unstable-book/src/language-features/ffi-pure.md b/src/doc/unstable-book/src/language-features/ffi-pure.md index 7bfd7a378f0..4aef4eeab55 100644 --- a/src/doc/unstable-book/src/language-features/ffi-pure.md +++ b/src/doc/unstable-book/src/language-features/ffi-pure.md @@ -1,5 +1,9 @@ # `ffi_pure` +The tracking issue for this feature is: [#58329] + +------ + The `#[ffi_pure]` attribute applies clang's `pure` attribute to foreign functions declarations. @@ -46,6 +50,7 @@ that the semantics of the C toolchain used to compile the binary being linked against are compatible with those of the `#[ffi_pure]`. +[#58329]: https://github.com/rust-lang/rust/issues/58329 [ARM C/C++ compiler]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491c/Cacigdac.html [GCC]: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-pure-function-attribute [IBM ILE C/C++]: https://www.ibm.com/support/knowledgecenter/fr/ssw_ibm_i_71/rzarg/fn_attrib_pure.htm diff --git a/src/doc/unstable-book/src/language-features/rustc-attrs.md b/src/doc/unstable-book/src/language-features/rustc-attrs.md index 2967200faf8..1d9409ee9e4 100644 --- a/src/doc/unstable-book/src/language-features/rustc-attrs.md +++ b/src/doc/unstable-book/src/language-features/rustc-attrs.md @@ -13,8 +13,8 @@ The `rustc_attrs` feature allows debugging rustc type layouts by using with `cargo check`) as an alternative to `rustc -Z print-type-sizes` that is way more verbose. -Options provided by `#[rustc_layout(...)]` are `debug`, `size`, `abi`. -Note that it only work best with sized type without generics. +Options provided by `#[rustc_layout(...)]` are `debug`, `size`, `align`, +`abi`. Note that it only works on sized types without generics. ## Examples diff --git a/src/doc/unstable-book/src/library-features/slice-check-range.md b/src/doc/unstable-book/src/library-features/slice-check-range.md new file mode 100644 index 00000000000..83e5738cf54 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/slice-check-range.md @@ -0,0 +1,10 @@ +# `slice_check_range` + +The tracking issue for this feature is: [#76393] + +------------------------ + +This adds [`slice::check_range`]. + +[#76393]: https://github.com/rust-lang/rust/issues/76393 +[`slice::check_range`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.check_range diff --git a/src/etc/gdb_lookup.py b/src/etc/gdb_lookup.py index 2a46eaadad6..a5a1824c84e 100644 --- a/src/etc/gdb_lookup.py +++ b/src/etc/gdb_lookup.py @@ -69,9 +69,9 @@ def lookup(valobj): else: return StdOldHashMapProvider(valobj) if rust_type == RustType.STD_HASH_SET: - hash_map = valobj["map"] + hash_map = valobj[valobj.type.fields()[0]] if is_hashbrown_hashmap(hash_map): - return StdHashMapProvider(hash_map, show_values=False) + return StdHashMapProvider(valobj, show_values=False) else: return StdOldHashMapProvider(hash_map, show_values=False) diff --git a/src/etc/gdb_providers.py b/src/etc/gdb_providers.py index 67f99ec4e40..bae51e6f9ee 100644 --- a/src/etc/gdb_providers.py +++ b/src/etc/gdb_providers.py @@ -347,7 +347,7 @@ class StdHashMapProvider: self.valobj = valobj self.show_values = show_values - table = self.valobj["base"]["table"] + table = self.table() capacity = int(table["bucket_mask"]) + 1 ctrl = table["ctrl"]["pointer"] @@ -368,6 +368,18 @@ class StdHashMapProvider: if is_presented: self.valid_indices.append(idx) + def table(self): + if self.show_values: + hashbrown_hashmap = self.valobj["base"] + elif self.valobj.type.fields()[0].name == "map": + # BACKCOMPAT: rust 1.47 + # HashSet wraps std::collections::HashMap, which wraps hashbrown::HashMap + hashbrown_hashmap = self.valobj["map"]["base"] + else: + # HashSet wraps hashbrown::HashSet, which wraps hashbrown::HashMap + hashbrown_hashmap = self.valobj["base"]["map"] + return hashbrown_hashmap["table"] + def to_string(self): if self.show_values: return "HashMap(size={})".format(self.size) diff --git a/src/etc/lldb_lookup.py b/src/etc/lldb_lookup.py index 13420fbaf0a..3cee51982ba 100644 --- a/src/etc/lldb_lookup.py +++ b/src/etc/lldb_lookup.py @@ -94,7 +94,7 @@ def synthetic_lookup(valobj, dict): if rust_type == RustType.STD_HASH_SET: hash_map = valobj.GetChildAtIndex(0) if is_hashbrown_hashmap(hash_map): - return StdHashMapSyntheticProvider(hash_map, dict, show_values=False) + return StdHashMapSyntheticProvider(valobj, dict, show_values=False) else: return StdOldHashMapSyntheticProvider(hash_map, dict, show_values=False) diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py index 19da75c35b4..64cb9837943 100644 --- a/src/etc/lldb_providers.py +++ b/src/etc/lldb_providers.py @@ -526,7 +526,7 @@ class StdHashMapSyntheticProvider: def update(self): # type: () -> None - table = self.valobj.GetChildMemberWithName("base").GetChildMemberWithName("table") + table = self.table() capacity = table.GetChildMemberWithName("bucket_mask").GetValueAsUnsigned() + 1 ctrl = table.GetChildMemberWithName("ctrl").GetChildAtIndex(0) @@ -552,6 +552,17 @@ class StdHashMapSyntheticProvider: if is_present: self.valid_indices.append(idx) + def table(self): + # type: () -> SBValue + if self.show_values: + hashbrown_hashmap = self.valobj.GetChildMemberWithName("base") + else: + # BACKCOMPAT: rust 1.47 + # HashSet wraps either std HashMap or hashbrown::HashSet, which both + # wrap hashbrown::HashMap, so either way we "unwrap" twice. + hashbrown_hashmap = self.valobj.GetChildAtIndex(0).GetChildAtIndex(0) + return hashbrown_hashmap.GetChildMemberWithName("table") + def has_children(self): # type: () -> bool return True diff --git a/src/etc/natvis/libstd.natvis b/src/etc/natvis/libstd.natvis index 4e81173d3d0..9550c25f2fc 100644 --- a/src/etc/natvis/libstd.natvis +++ b/src/etc/natvis/libstd.natvis @@ -5,7 +5,7 @@ Current std impls: std::collections::hash::set::HashSet<K, S> is implemented in terms of... - std::collections::hash::map::HashMap<K, V, S> is implemented in terms of... + hashbrown::set::HashSet<K, S> is implemented in terms of... hashbrown::map::HashMap<K, V, S> is implemented in terms of... hashbrown::raw::RawTable<(K, V)> @@ -41,7 +41,7 @@ <If Condition="(base.table.ctrl.pointer[i] & 0x80) == 0"> <!-- Bucket is populated --> <Exec>n--</Exec> - <Item Name="{static_cast<tuple<$T1, $T2>*>(base.table.ctrl.pointer)[-(i + 1)].__0}">static_cast<tuple<$T1, $T2>*>(base.table.ctrl.pointer)[-(i + 1)].__1</Item> + <Item Name="{((tuple<$T1, $T2>*)base.table.ctrl.pointer)[-(i + 1)].__0}">((tuple<$T1, $T2>*)base.table.ctrl.pointer)[-(i + 1)].__1</Item> </If> <Exec>i++</Exec> </Loop> @@ -50,22 +50,22 @@ </Type> <Type Name="std::collections::hash::set::HashSet<*,*>"> - <DisplayString>{{ size={map.base.table.items} }}</DisplayString> + <DisplayString>{{ size={base.map.table.items} }}</DisplayString> <Expand> - <Item Name="[size]">map.base.table.items</Item> - <Item Name="[capacity]">map.base.table.items + map.base.table.growth_left</Item> - <Item Name="[state]">map.base.hash_builder</Item> + <Item Name="[size]">base.map.table.items</Item> + <Item Name="[capacity]">base.map.table.items + base.map.table.growth_left</Item> + <Item Name="[state]">base.map.hash_builder</Item> <CustomListItems> <Variable Name="i" InitialValue="0" /> - <Variable Name="n" InitialValue="map.base.table.items" /> - <Size>map.base.table.items</Size> + <Variable Name="n" InitialValue="base.map.table.items" /> + <Size>base.map.table.items</Size> <Loop> <Break Condition="n == 0" /> - <If Condition="(map.base.table.ctrl.pointer[i] & 0x80) == 0"> + <If Condition="(base.map.table.ctrl.pointer[i] & 0x80) == 0"> <!-- Bucket is populated --> <Exec>n--</Exec> - <Item>static_cast<$T1*>(map.base.table.ctrl.pointer)[-(i + 1)]</Item> + <Item>(($T1*)base.map.table.ctrl.pointer)[-(i + 1)]</Item> </If> <Exec>i++</Exec> </Loop> diff --git a/src/librustc_llvm/Cargo.toml b/src/librustc_llvm/Cargo.toml deleted file mode 100644 index 7120f2e991a..00000000000 --- a/src/librustc_llvm/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_llvm" -version = "0.0.0" -edition = "2018" - -[lib] -path = "lib.rs" - -[features] -static-libstdcpp = [] -emscripten = [] - -[dependencies] -libc = "0.2.73" - -[build-dependencies] -build_helper = { path = "../build_helper" } -cc = "1.0.58" diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs deleted file mode 100644 index 306ffbf5daa..00000000000 --- a/src/librustc_llvm/build.rs +++ /dev/null @@ -1,322 +0,0 @@ -use std::env; -use std::path::{Path, PathBuf}; -use std::process::Command; - -use build_helper::{output, tracked_env_var_os}; - -fn detect_llvm_link() -> (&'static str, &'static str) { - // Force the link mode we want, preferring static by default, but - // possibly overridden by `configure --enable-llvm-link-shared`. - if tracked_env_var_os("LLVM_LINK_SHARED").is_some() { - ("dylib", "--link-shared") - } else { - ("static", "--link-static") - } -} - -fn main() { - if tracked_env_var_os("RUST_CHECK").is_some() { - // If we're just running `check`, there's no need for LLVM to be built. - return; - } - - build_helper::restore_library_path(); - - let target = env::var("TARGET").expect("TARGET was not set"); - let llvm_config = - tracked_env_var_os("LLVM_CONFIG").map(|x| Some(PathBuf::from(x))).unwrap_or_else(|| { - if let Some(dir) = tracked_env_var_os("CARGO_TARGET_DIR").map(PathBuf::from) { - let to_test = dir - .parent() - .unwrap() - .parent() - .unwrap() - .join(&target) - .join("llvm/bin/llvm-config"); - if Command::new(&to_test).output().is_ok() { - return Some(to_test); - } - } - None - }); - - if let Some(llvm_config) = &llvm_config { - println!("cargo:rerun-if-changed={}", llvm_config.display()); - } - let llvm_config = llvm_config.unwrap_or_else(|| PathBuf::from("llvm-config")); - - // Test whether we're cross-compiling LLVM. This is a pretty rare case - // currently where we're producing an LLVM for a different platform than - // what this build script is currently running on. - // - // In that case, there's no guarantee that we can actually run the target, - // so the build system works around this by giving us the LLVM_CONFIG for - // the host platform. This only really works if the host LLVM and target - // LLVM are compiled the same way, but for us that's typically the case. - // - // We *want* detect this cross compiling situation by asking llvm-config - // what its host-target is. If that's not the TARGET, then we're cross - // compiling. Unfortunately `llvm-config` seems either be buggy, or we're - // misconfiguring it, because the `i686-pc-windows-gnu` build of LLVM will - // report itself with a `--host-target` of `x86_64-pc-windows-gnu`. This - // tricks us into thinking we're doing a cross build when we aren't, so - // havoc ensues. - // - // In any case, if we're cross compiling, this generally just means that we - // can't trust all the output of llvm-config because it might be targeted - // for the host rather than the target. As a result a bunch of blocks below - // are gated on `if !is_crossed` - let target = env::var("TARGET").expect("TARGET was not set"); - let host = env::var("HOST").expect("HOST was not set"); - let is_crossed = target != host; - - let mut optional_components = vec![ - "x86", - "arm", - "aarch64", - "amdgpu", - "avr", - "mips", - "powerpc", - "systemz", - "jsbackend", - "webassembly", - "msp430", - "sparc", - "nvptx", - "hexagon", - ]; - - let mut version_cmd = Command::new(&llvm_config); - version_cmd.arg("--version"); - let version_output = output(&mut version_cmd); - let mut parts = version_output.split('.').take(2).filter_map(|s| s.parse::<u32>().ok()); - let (major, _minor) = if let (Some(major), Some(minor)) = (parts.next(), parts.next()) { - (major, minor) - } else { - (6, 0) - }; - - if major > 6 { - optional_components.push("riscv"); - } - - let required_components = &[ - "ipo", - "bitreader", - "bitwriter", - "linker", - "asmparser", - "lto", - "coverage", - "instrumentation", - ]; - - let components = output(Command::new(&llvm_config).arg("--components")); - let mut components = components.split_whitespace().collect::<Vec<_>>(); - components.retain(|c| optional_components.contains(c) || required_components.contains(c)); - - for component in required_components { - if !components.contains(component) { - panic!("require llvm component {} but wasn't found", component); - } - } - - for component in components.iter() { - println!("cargo:rustc-cfg=llvm_component=\"{}\"", component); - } - - if major >= 9 { - println!("cargo:rustc-cfg=llvm_has_msp430_asm_parser"); - } - - // Link in our own LLVM shims, compiled with the same flags as LLVM - let mut cmd = Command::new(&llvm_config); - cmd.arg("--cxxflags"); - let cxxflags = output(&mut cmd); - let mut cfg = cc::Build::new(); - cfg.warnings(false); - for flag in cxxflags.split_whitespace() { - // Ignore flags like `-m64` when we're doing a cross build - if is_crossed && flag.starts_with("-m") { - continue; - } - - if flag.starts_with("-flto") { - continue; - } - - // -Wdate-time is not supported by the netbsd cross compiler - if is_crossed && target.contains("netbsd") && flag.contains("date-time") { - continue; - } - - // Include path contains host directory, replace it with target - if is_crossed && flag.starts_with("-I") { - cfg.flag(&flag.replace(&host, &target)); - continue; - } - - cfg.flag(flag); - } - - for component in &components { - let mut flag = String::from("LLVM_COMPONENT_"); - flag.push_str(&component.to_uppercase()); - cfg.define(&flag, None); - } - - if tracked_env_var_os("LLVM_RUSTLLVM").is_some() { - cfg.define("LLVM_RUSTLLVM", None); - } - - if tracked_env_var_os("LLVM_NDEBUG").is_some() { - cfg.define("NDEBUG", None); - cfg.debug(false); - } - - build_helper::rerun_if_changed_anything_in_dir(Path::new("../rustllvm")); - cfg.file("../rustllvm/PassWrapper.cpp") - .file("../rustllvm/RustWrapper.cpp") - .file("../rustllvm/ArchiveWrapper.cpp") - .file("../rustllvm/CoverageMappingWrapper.cpp") - .file("../rustllvm/Linker.cpp") - .cpp(true) - .cpp_link_stdlib(None) // we handle this below - .compile("rustllvm"); - - let (llvm_kind, llvm_link_arg) = detect_llvm_link(); - - // Link in all LLVM libraries, if we're using the "wrong" llvm-config then - // we don't pick up system libs because unfortunately they're for the host - // of llvm-config, not the target that we're attempting to link. - let mut cmd = Command::new(&llvm_config); - cmd.arg(llvm_link_arg).arg("--libs"); - - if !is_crossed { - cmd.arg("--system-libs"); - } else if target.contains("windows-gnu") { - println!("cargo:rustc-link-lib=shell32"); - println!("cargo:rustc-link-lib=uuid"); - } else if target.contains("netbsd") || target.contains("haiku") { - println!("cargo:rustc-link-lib=z"); - } - cmd.args(&components); - - for lib in output(&mut cmd).split_whitespace() { - let name = if lib.starts_with("-l") { - &lib[2..] - } else if lib.starts_with('-') { - &lib[1..] - } else if Path::new(lib).exists() { - // On MSVC llvm-config will print the full name to libraries, but - // we're only interested in the name part - let name = Path::new(lib).file_name().unwrap().to_str().unwrap(); - name.trim_end_matches(".lib") - } else if lib.ends_with(".lib") { - // Some MSVC libraries just come up with `.lib` tacked on, so chop - // that off - lib.trim_end_matches(".lib") - } else { - continue; - }; - - // Don't need or want this library, but LLVM's CMake build system - // doesn't provide a way to disable it, so filter it here even though we - // may or may not have built it. We don't reference anything from this - // library and it otherwise may just pull in extra dependencies on - // libedit which we don't want - if name == "LLVMLineEditor" { - continue; - } - - let kind = if name.starts_with("LLVM") { llvm_kind } else { "dylib" }; - println!("cargo:rustc-link-lib={}={}", kind, name); - } - - // LLVM ldflags - // - // If we're a cross-compile of LLVM then unfortunately we can't trust these - // ldflags (largely where all the LLVM libs are located). Currently just - // hack around this by replacing the host triple with the target and pray - // that those -L directories are the same! - let mut cmd = Command::new(&llvm_config); - cmd.arg(llvm_link_arg).arg("--ldflags"); - for lib in output(&mut cmd).split_whitespace() { - if is_crossed { - if lib.starts_with("-LIBPATH:") { - println!("cargo:rustc-link-search=native={}", lib[9..].replace(&host, &target)); - } else if lib.starts_with("-L") { - println!("cargo:rustc-link-search=native={}", lib[2..].replace(&host, &target)); - } - } else if lib.starts_with("-LIBPATH:") { - println!("cargo:rustc-link-search=native={}", &lib[9..]); - } else if lib.starts_with("-l") { - println!("cargo:rustc-link-lib={}", &lib[2..]); - } else if lib.starts_with("-L") { - println!("cargo:rustc-link-search=native={}", &lib[2..]); - } - } - - // Some LLVM linker flags (-L and -l) may be needed even when linking - // librustc_llvm, for example when using static libc++, we may need to - // manually specify the library search path and -ldl -lpthread as link - // dependencies. - let llvm_linker_flags = tracked_env_var_os("LLVM_LINKER_FLAGS"); - if let Some(s) = llvm_linker_flags { - for lib in s.into_string().unwrap().split_whitespace() { - if lib.starts_with("-l") { - println!("cargo:rustc-link-lib={}", &lib[2..]); - } else if lib.starts_with("-L") { - println!("cargo:rustc-link-search=native={}", &lib[2..]); - } - } - } - - let llvm_static_stdcpp = tracked_env_var_os("LLVM_STATIC_STDCPP"); - let llvm_use_libcxx = tracked_env_var_os("LLVM_USE_LIBCXX"); - - let stdcppname = if target.contains("openbsd") { - if target.contains("sparc64") { "estdc++" } else { "c++" } - } else if target.contains("freebsd") { - "c++" - } else if target.contains("darwin") { - "c++" - } else if target.contains("netbsd") && llvm_static_stdcpp.is_some() { - // NetBSD uses a separate library when relocation is required - "stdc++_pic" - } else if llvm_use_libcxx.is_some() { - "c++" - } else { - "stdc++" - }; - - // RISC-V requires libatomic for sub-word atomic operations - if target.starts_with("riscv") { - println!("cargo:rustc-link-lib=atomic"); - } - - // C++ runtime library - if !target.contains("msvc") { - if let Some(s) = llvm_static_stdcpp { - assert!(!cxxflags.contains("stdlib=libc++")); - let path = PathBuf::from(s); - println!("cargo:rustc-link-search=native={}", path.parent().unwrap().display()); - if target.contains("windows") { - println!("cargo:rustc-link-lib=static-nobundle={}", stdcppname); - } else { - println!("cargo:rustc-link-lib=static={}", stdcppname); - } - } else if cxxflags.contains("stdlib=libc++") { - println!("cargo:rustc-link-lib=c++"); - } else { - println!("cargo:rustc-link-lib={}", stdcppname); - } - } - - // Libstdc++ depends on pthread which Rust doesn't link on MinGW - // since nothing else requires it. - if target.contains("windows-gnu") { - println!("cargo:rustc-link-lib=static-nobundle=pthread"); - } -} diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs deleted file mode 100644 index 9d23397ade0..00000000000 --- a/src/librustc_llvm/lib.rs +++ /dev/null @@ -1,173 +0,0 @@ -#![feature(nll)] -#![feature(static_nobundle)] -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] - -// NOTE: This crate only exists to allow linking on mingw targets. - -use libc::{c_char, size_t}; -use std::cell::RefCell; -use std::slice; - -#[repr(C)] -pub struct RustString { - pub bytes: RefCell<Vec<u8>>, -} - -impl RustString { - pub fn len(&self) -> usize { - self.bytes.borrow().len() - } -} - -/// Appending to a Rust string -- used by RawRustStringOstream. -#[no_mangle] -#[allow(improper_ctypes_definitions)] -pub unsafe extern "C" fn LLVMRustStringWriteImpl( - sr: &RustString, - ptr: *const c_char, - size: size_t, -) { - let slice = slice::from_raw_parts(ptr as *const u8, size as usize); - - sr.bytes.borrow_mut().extend_from_slice(slice); -} - -/// Initialize targets enabled by the build script via `cfg(llvm_component = "...")`. -/// N.B., this function can't be moved to `rustc_codegen_llvm` because of the `cfg`s. -pub fn initialize_available_targets() { - macro_rules! init_target( - ($cfg:meta, $($method:ident),*) => { { - #[cfg($cfg)] - fn init() { - extern { - $(fn $method();)* - } - unsafe { - $($method();)* - } - } - #[cfg(not($cfg))] - fn init() { } - init(); - } } - ); - init_target!( - llvm_component = "x86", - LLVMInitializeX86TargetInfo, - LLVMInitializeX86Target, - LLVMInitializeX86TargetMC, - LLVMInitializeX86AsmPrinter, - LLVMInitializeX86AsmParser - ); - init_target!( - llvm_component = "arm", - LLVMInitializeARMTargetInfo, - LLVMInitializeARMTarget, - LLVMInitializeARMTargetMC, - LLVMInitializeARMAsmPrinter, - LLVMInitializeARMAsmParser - ); - init_target!( - llvm_component = "aarch64", - LLVMInitializeAArch64TargetInfo, - LLVMInitializeAArch64Target, - LLVMInitializeAArch64TargetMC, - LLVMInitializeAArch64AsmPrinter, - LLVMInitializeAArch64AsmParser - ); - init_target!( - llvm_component = "amdgpu", - LLVMInitializeAMDGPUTargetInfo, - LLVMInitializeAMDGPUTarget, - LLVMInitializeAMDGPUTargetMC, - LLVMInitializeAMDGPUAsmPrinter, - LLVMInitializeAMDGPUAsmParser - ); - init_target!( - llvm_component = "avr", - LLVMInitializeAVRTargetInfo, - LLVMInitializeAVRTarget, - LLVMInitializeAVRTargetMC, - LLVMInitializeAVRAsmPrinter, - LLVMInitializeAVRAsmParser - ); - init_target!( - llvm_component = "mips", - LLVMInitializeMipsTargetInfo, - LLVMInitializeMipsTarget, - LLVMInitializeMipsTargetMC, - LLVMInitializeMipsAsmPrinter, - LLVMInitializeMipsAsmParser - ); - init_target!( - llvm_component = "powerpc", - LLVMInitializePowerPCTargetInfo, - LLVMInitializePowerPCTarget, - LLVMInitializePowerPCTargetMC, - LLVMInitializePowerPCAsmPrinter, - LLVMInitializePowerPCAsmParser - ); - init_target!( - llvm_component = "systemz", - LLVMInitializeSystemZTargetInfo, - LLVMInitializeSystemZTarget, - LLVMInitializeSystemZTargetMC, - LLVMInitializeSystemZAsmPrinter, - LLVMInitializeSystemZAsmParser - ); - init_target!( - llvm_component = "jsbackend", - LLVMInitializeJSBackendTargetInfo, - LLVMInitializeJSBackendTarget, - LLVMInitializeJSBackendTargetMC - ); - init_target!( - llvm_component = "msp430", - LLVMInitializeMSP430TargetInfo, - LLVMInitializeMSP430Target, - LLVMInitializeMSP430TargetMC, - LLVMInitializeMSP430AsmPrinter - ); - init_target!( - all(llvm_component = "msp430", llvm_has_msp430_asm_parser), - LLVMInitializeMSP430AsmParser - ); - init_target!( - llvm_component = "riscv", - LLVMInitializeRISCVTargetInfo, - LLVMInitializeRISCVTarget, - LLVMInitializeRISCVTargetMC, - LLVMInitializeRISCVAsmPrinter, - LLVMInitializeRISCVAsmParser - ); - init_target!( - llvm_component = "sparc", - LLVMInitializeSparcTargetInfo, - LLVMInitializeSparcTarget, - LLVMInitializeSparcTargetMC, - LLVMInitializeSparcAsmPrinter, - LLVMInitializeSparcAsmParser - ); - init_target!( - llvm_component = "nvptx", - LLVMInitializeNVPTXTargetInfo, - LLVMInitializeNVPTXTarget, - LLVMInitializeNVPTXTargetMC, - LLVMInitializeNVPTXAsmPrinter - ); - init_target!( - llvm_component = "hexagon", - LLVMInitializeHexagonTargetInfo, - LLVMInitializeHexagonTarget, - LLVMInitializeHexagonTargetMC, - LLVMInitializeHexagonAsmPrinter, - LLVMInitializeHexagonAsmParser - ); - init_target!( - llvm_component = "webassembly", - LLVMInitializeWebAssemblyTargetInfo, - LLVMInitializeWebAssemblyTarget, - LLVMInitializeWebAssemblyTargetMC, - LLVMInitializeWebAssemblyAsmPrinter - ); -} diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1bdbad46755..9d784d24609 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1364,16 +1364,16 @@ impl Clean<Type> for hir::Ty<'_> { TyKind::Slice(ref ty) => Slice(box ty.clean(cx)), TyKind::Array(ref ty, ref length) => { let def_id = cx.tcx.hir().local_def_id(length.hir_id); - let length = match cx.tcx.const_eval_poly(def_id.to_def_id()) { - Ok(length) => { - print_const(cx, ty::Const::from_value(cx.tcx, length, cx.tcx.types.usize)) - } - Err(_) => cx - .sess() - .source_map() - .span_to_snippet(cx.tcx.def_span(def_id)) - .unwrap_or_else(|_| "_".to_string()), - }; + // NOTE(min_const_generics): We can't use `const_eval_poly` for constants + // as we currently do not supply the parent generics to anonymous constants + // but do allow `ConstKind::Param`. + // + // `const_eval_poly` tries to to first substitute generic parameters which + // results in an ICE while manually constructing the constant and using `eval` + // does nothing for `ConstKind::Param`. + let ct = ty::Const::from_anon_const(cx.tcx, def_id); + let param_env = cx.tcx.param_env(def_id); + let length = print_const(cx, ct.eval(cx.tcx, param_env)); Array(box ty.clean(cx), length) } TyKind::Tup(ref tys) => Tuple(tys.clean(cx)), diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index a458cdab303..223fda84871 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -118,7 +118,7 @@ impl Item { self.attrs.collapsed_doc_value() } - pub fn links(&self) -> Vec<(String, String)> { + pub fn links(&self) -> Vec<RenderedLink> { self.attrs.links(&self.def_id.krate) } @@ -425,10 +425,38 @@ pub struct Attributes { pub cfg: Option<Arc<Cfg>>, pub span: Option<rustc_span::Span>, /// map from Rust paths to resolved defs and potential URL fragments - pub links: Vec<(String, Option<DefId>, Option<String>)>, + pub links: Vec<ItemLink>, pub inner_docs: bool, } +#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] +/// A link that has not yet been rendered. +/// +/// This link will be turned into a rendered link by [`Attributes::links`] +pub struct ItemLink { + /// The original link written in the markdown + pub(crate) link: String, + /// The link text displayed in the HTML. + /// + /// This may not be the same as `link` if there was a disambiguator + /// in an intra-doc link (e.g. \[`fn@f`\]) + pub(crate) link_text: String, + pub(crate) did: Option<DefId>, + /// The url fragment to append to the link + pub(crate) fragment: Option<String>, +} + +pub struct RenderedLink { + /// The text the link was original written as. + /// + /// This could potentially include disambiguators and backticks. + pub(crate) original_text: String, + /// The text to display in the HTML + pub(crate) new_text: String, + /// The URL to put in the `href` + pub(crate) href: String, +} + impl Attributes { /// Extracts the content from an attribute `#[doc(cfg(content))]`. pub fn extract_cfg(mi: &ast::MetaItem) -> Option<&ast::MetaItem> { @@ -605,21 +633,25 @@ impl Attributes { /// Gets links as a vector /// /// Cache must be populated before call - pub fn links(&self, krate: &CrateNum) -> Vec<(String, String)> { + pub fn links(&self, krate: &CrateNum) -> Vec<RenderedLink> { use crate::html::format::href; use crate::html::render::CURRENT_DEPTH; self.links .iter() - .filter_map(|&(ref s, did, ref fragment)| { - match did { + .filter_map(|ItemLink { link: s, link_text, did, fragment }| { + match *did { Some(did) => { if let Some((mut href, ..)) = href(did) { if let Some(ref fragment) = *fragment { href.push_str("#"); href.push_str(fragment); } - Some((s.clone(), href)) + Some(RenderedLink { + original_text: s.clone(), + new_text: link_text.clone(), + href, + }) } else { None } @@ -639,16 +671,17 @@ impl Attributes { }; // This is a primitive so the url is done "by hand". let tail = fragment.find('#').unwrap_or_else(|| fragment.len()); - Some(( - s.clone(), - format!( + Some(RenderedLink { + original_text: s.clone(), + new_text: link_text.clone(), + href: format!( "{}{}std/primitive.{}.html{}", url, if !url.ends_with('/') { "/" } else { "" }, &fragment[..tail], &fragment[tail..] ), - )) + }) } else { panic!("This isn't a primitive?!"); } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 098ece9a1d5..a8c60e4a76d 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -34,6 +34,7 @@ use std::fmt::Write; use std::ops::Range; use std::str; +use crate::clean::RenderedLink; use crate::doctest; use crate::html::highlight; use crate::html::toc::TocBuilder; @@ -52,7 +53,7 @@ fn opts() -> Options { pub struct Markdown<'a>( pub &'a str, /// A list of link replacements. - pub &'a [(String, String)], + pub &'a [RenderedLink], /// The current list of used header IDs. pub &'a mut IdMap, /// Whether to allow the use of explicit error codes in doctest lang strings. @@ -78,7 +79,7 @@ pub struct MarkdownHtml<'a>( pub &'a Option<Playground>, ); /// A tuple struct like `Markdown` that renders only the first paragraph. -pub struct MarkdownSummaryLine<'a>(pub &'a str, pub &'a [(String, String)]); +pub struct MarkdownSummaryLine<'a>(pub &'a str, pub &'a [RenderedLink]); #[derive(Copy, Clone, PartialEq, Debug)] pub enum ErrorCodes { @@ -337,31 +338,107 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> { } /// Make headings links with anchor IDs and build up TOC. -struct LinkReplacer<'a, 'b, I: Iterator<Item = Event<'a>>> { +struct LinkReplacer<'a, I: Iterator<Item = Event<'a>>> { inner: I, - links: &'b [(String, String)], + links: &'a [RenderedLink], + shortcut_link: Option<&'a RenderedLink>, } -impl<'a, 'b, I: Iterator<Item = Event<'a>>> LinkReplacer<'a, 'b, I> { - fn new(iter: I, links: &'b [(String, String)]) -> Self { - LinkReplacer { inner: iter, links } +impl<'a, I: Iterator<Item = Event<'a>>> LinkReplacer<'a, I> { + fn new(iter: I, links: &'a [RenderedLink]) -> Self { + LinkReplacer { inner: iter, links, shortcut_link: None } } } -impl<'a, 'b, I: Iterator<Item = Event<'a>>> Iterator for LinkReplacer<'a, 'b, I> { +impl<'a, I: Iterator<Item = Event<'a>>> Iterator for LinkReplacer<'a, I> { type Item = Event<'a>; fn next(&mut self) -> Option<Self::Item> { - let event = self.inner.next(); - if let Some(Event::Start(Tag::Link(kind, dest, text))) = event { - if let Some(&(_, ref replace)) = self.links.iter().find(|link| link.0 == *dest) { - Some(Event::Start(Tag::Link(kind, replace.to_owned().into(), text))) - } else { - Some(Event::Start(Tag::Link(kind, dest, text))) + use pulldown_cmark::LinkType; + + let mut event = self.inner.next(); + + // Replace intra-doc links and remove disambiguators from shortcut links (`[fn@f]`). + match &mut event { + // This is a shortcut link that was resolved by the broken_link_callback: `[fn@f]` + // Remove any disambiguator. + Some(Event::Start(Tag::Link( + // [fn@f] or [fn@f][] + LinkType::ShortcutUnknown | LinkType::CollapsedUnknown, + dest, + title, + ))) => { + debug!("saw start of shortcut link to {} with title {}", dest, title); + // If this is a shortcut link, it was resolved by the broken_link_callback. + // So the URL will already be updated properly. + let link = self.links.iter().find(|&link| *link.href == **dest); + // Since this is an external iterator, we can't replace the inner text just yet. + // Store that we saw a link so we know to replace it later. + if let Some(link) = link { + trace!("it matched"); + assert!(self.shortcut_link.is_none(), "shortcut links cannot be nested"); + self.shortcut_link = Some(link); + } } - } else { - event + // Now that we're done with the shortcut link, don't replace any more text. + Some(Event::End(Tag::Link( + LinkType::ShortcutUnknown | LinkType::CollapsedUnknown, + dest, + _, + ))) => { + debug!("saw end of shortcut link to {}", dest); + if self.links.iter().find(|&link| *link.href == **dest).is_some() { + assert!(self.shortcut_link.is_some(), "saw closing link without opening tag"); + self.shortcut_link = None; + } + } + // Handle backticks in inline code blocks, but only if we're in the middle of a shortcut link. + // [`fn@f`] + Some(Event::Code(text)) => { + trace!("saw code {}", text); + if let Some(link) = self.shortcut_link { + trace!("original text was {}", link.original_text); + // NOTE: this only replaces if the code block is the *entire* text. + // If only part of the link has code highlighting, the disambiguator will not be removed. + // e.g. [fn@`f`] + // This is a limitation from `collect_intra_doc_links`: it passes a full link, + // and does not distinguish at all between code blocks. + // So we could never be sure we weren't replacing too much: + // [fn@my_`f`unc] is treated the same as [my_func()] in that pass. + // + // NOTE: &[1..len() - 1] is to strip the backticks + if **text == link.original_text[1..link.original_text.len() - 1] { + debug!("replacing {} with {}", text, link.new_text); + *text = CowStr::Borrowed(&link.new_text); + } + } + } + // Replace plain text in links, but only in the middle of a shortcut link. + // [fn@f] + Some(Event::Text(text)) => { + trace!("saw text {}", text); + if let Some(link) = self.shortcut_link { + trace!("original text was {}", link.original_text); + // NOTE: same limitations as `Event::Code` + if **text == *link.original_text { + debug!("replacing {} with {}", text, link.new_text); + *text = CowStr::Borrowed(&link.new_text); + } + } + } + // If this is a link, but not a shortcut link, + // replace the URL, since the broken_link_callback was not called. + Some(Event::Start(Tag::Link(_, dest, _))) => { + if let Some(link) = self.links.iter().find(|&link| *link.original_text == **dest) { + *dest = CowStr::Borrowed(link.href.as_ref()); + } + } + // Anything else couldn't have been a valid Rust path, so no need to replace the text. + _ => {} } + + // Yield the modified event + event } } @@ -855,8 +932,8 @@ impl Markdown<'_> { return String::new(); } let replacer = |_: &str, s: &str| { - if let Some(&(_, ref replace)) = links.iter().find(|link| &*link.0 == s) { - Some((replace.clone(), s.to_owned())) + if let Some(link) = links.iter().find(|link| &*link.original_text == s) { + Some((link.href.clone(), link.new_text.clone())) } else { None } @@ -933,8 +1010,8 @@ impl MarkdownSummaryLine<'_> { } let replacer = |_: &str, s: &str| { - if let Some(&(_, ref replace)) = links.iter().find(|link| &*link.0 == s) { - Some((replace.clone(), s.to_owned())) + if let Some(link) = links.iter().find(|link| &*link.original_text == s) { + Some((link.href.clone(), link.new_text.clone())) } else { None } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 57b3b9502a3..f095f67b54c 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -63,9 +63,8 @@ use rustc_span::symbol::{sym, Symbol}; use serde::ser::SerializeSeq; use serde::{Serialize, Serializer}; -use crate::clean::{self, AttributesExt, Deprecation, GetDefId, SelfTy, TypeKind}; -use crate::config::RenderInfo; -use crate::config::RenderOptions; +use crate::clean::{self, AttributesExt, Deprecation, GetDefId, RenderedLink, SelfTy, TypeKind}; +use crate::config::{RenderInfo, RenderOptions}; use crate::docfs::{DocFS, PathError}; use crate::doctree; use crate::error::Error; @@ -1774,7 +1773,7 @@ fn render_markdown( w: &mut Buffer, cx: &Context, md_text: &str, - links: Vec<(String, String)>, + links: Vec<RenderedLink>, prefix: &str, is_hidden: bool, ) { diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 55dcaec8ae1..935b96e51fc 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -126,6 +126,10 @@ h1, h2, h3, h4, font-family: "Fira Sans", sans-serif; } +.content ul.crate a.crate { + font: 16px/1.6 "Fira Sans"; +} + ol, ul { padding-left: 25px; } diff --git a/src/librustdoc/html/static/themes/ayu.css b/src/librustdoc/html/static/themes/ayu.css index b4571018270..3b15b21889d 100644 --- a/src/librustdoc/html/static/themes/ayu.css +++ b/src/librustdoc/html/static/themes/ayu.css @@ -129,9 +129,10 @@ pre { color: #ffb44c; } -.line-numbers span { color: #5c6773ab; } +.line-numbers span { color: #5c6773; } .line-numbers .line-highlighted { - background-color: rgba(255, 236, 164, 0.06) !important; + color: #708090; + background-color: rgba(255, 236, 164, 0.06); padding-right: 4px; border-right: 1px solid #ffb44c; } @@ -178,9 +179,6 @@ pre { .content span.externcrate, .content span.mod, .content a.mod { color: #acccf9; } -.content ul.crate a.crate { - font: 16px/1.6 "Fira Sans"; -} .content span.struct, .content a.struct { color: #ffa0a5; } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index a4f5530815c..5780610c862 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -17,8 +17,9 @@ use rustc_span::hygiene::MacroKind; use rustc_span::symbol::Ident; use rustc_span::symbol::Symbol; use rustc_span::DUMMY_SP; -use smallvec::SmallVec; +use smallvec::{smallvec, SmallVec}; +use std::borrow::Cow; use std::cell::Cell; use std::ops::Range; @@ -46,19 +47,73 @@ pub fn collect_intra_doc_links(krate: Crate, cx: &DocContext<'_>) -> Crate { } } -enum ErrorKind { - ResolutionFailure, +enum ErrorKind<'a> { + Resolve(Box<ResolutionFailure<'a>>), AnchorFailure(AnchorFailure), } +impl<'a> From<ResolutionFailure<'a>> for ErrorKind<'a> { + fn from(err: ResolutionFailure<'a>) -> Self { + ErrorKind::Resolve(box err) + } +} + +#[derive(Debug)] +enum ResolutionFailure<'a> { + /// This resolved, but with the wrong namespace. + /// `Namespace` is the expected namespace (as opposed to the actual). + WrongNamespace(Res, Namespace), + /// This has a partial resolution, but is not in the TypeNS and so cannot + /// have associated items or fields. + CannotHaveAssociatedItems(Res, Namespace), + /// `name` is the base name of the path (not necessarily the whole link) + NotInScope { module_id: DefId, name: Cow<'a, str> }, + /// this is a primitive type without an impls (no associated methods) + /// when will this actually happen? + /// the `Res` is the primitive it resolved to + NoPrimitiveImpl(Res, String), + /// `[u8::not_found]` + /// the `Res` is the primitive it resolved to + NoPrimitiveAssocItem { res: Res, prim_name: &'a str, assoc_item: Symbol }, + /// `[S::not_found]` + /// the `String` is the associated item that wasn't found + NoAssocItem(Res, Symbol), + /// should not ever happen + NoParentItem, + /// this could be an enum variant, but the last path fragment wasn't resolved. + /// the `String` is the variant that didn't exist + NotAVariant(Res, Symbol), + /// used to communicate that this should be ignored, but shouldn't be reported to the user + Dummy, +} + +impl ResolutionFailure<'a> { + // A partial or full resolution + fn res(&self) -> Option<Res> { + use ResolutionFailure::*; + match self { + NoPrimitiveAssocItem { res, .. } + | NoAssocItem(res, _) + | NoPrimitiveImpl(res, _) + | NotAVariant(res, _) + | WrongNamespace(res, _) + | CannotHaveAssociatedItems(res, _) => Some(*res), + NotInScope { .. } | NoParentItem | Dummy => None, + } + } + + // This resolved fully (not just partially) but is erroneous for some other reason + fn full_res(&self) -> Option<Res> { + match self { + Self::WrongNamespace(res, _) => Some(*res), + _ => None, + } + } +} + enum AnchorFailure { MultipleAnchors, - Primitive, - Variant, - AssocConstant, - AssocType, - Field, - Method, + RustdocAnchorConflict(Res), } struct LinkCollector<'a, 'tcx> { @@ -68,7 +123,7 @@ struct LinkCollector<'a, 'tcx> { /// This is used to store the kind of associated items, /// because `clean` and the disambiguator code expect them to be different. /// See the code for associated items on inherent impls for details. - kind_side_channel: Cell<Option<DefKind>>, + kind_side_channel: Cell<Option<(DefKind, DefId)>>, } impl<'a, 'tcx> LinkCollector<'a, 'tcx> { @@ -78,17 +133,25 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { fn variant_field( &self, - path_str: &str, + path_str: &'path str, current_item: &Option<String>, module_id: DefId, - ) -> Result<(Res, Option<String>), ErrorKind> { + extra_fragment: &Option<String>, + ) -> Result<(Res, Option<String>), ErrorKind<'path>> { let cx = self.cx; + debug!("looking for enum variant {}", path_str); let mut split = path_str.rsplitn(3, "::"); - let variant_field_name = - split.next().map(|f| Symbol::intern(f)).ok_or(ErrorKind::ResolutionFailure)?; + let variant_field_name = split + .next() + .map(|f| Symbol::intern(f)) + .expect("fold_item should ensure link is non-empty"); let variant_name = - split.next().map(|f| Symbol::intern(f)).ok_or(ErrorKind::ResolutionFailure)?; + // we're not sure this is a variant at all, so use the full string + split.next().map(|f| Symbol::intern(f)).ok_or_else(|| ResolutionFailure::NotInScope { + module_id, + name: path_str.into(), + })?; let path = split .next() .map(|f| { @@ -99,14 +162,18 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } f.to_owned() }) - .ok_or(ErrorKind::ResolutionFailure)?; - let (_, ty_res) = cx + .ok_or_else(|| ResolutionFailure::NotInScope { + module_id, + name: variant_name.to_string().into(), + })?; + let ty_res = cx .enter_resolver(|resolver| { resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id) }) - .map_err(|_| ErrorKind::ResolutionFailure)?; + .map(|(_, res)| res) + .unwrap_or(Res::Err); if let Res::Err = ty_res { - return Err(ErrorKind::ResolutionFailure); + return Err(ResolutionFailure::NotInScope { module_id, name: path.into() }.into()); } let ty_res = ty_res.map_id(|_| panic!("unexpected node_id")); match ty_res { @@ -118,7 +185,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { .flat_map(|imp| cx.tcx.associated_items(*imp).in_definition_order()) .any(|item| item.ident.name == variant_name) { - return Err(ErrorKind::ResolutionFailure); + // This is just to let `fold_item` know that this shouldn't be considered; + // it's a bug for the error to make it to the user + return Err(ResolutionFailure::Dummy.into()); } match cx.tcx.type_of(did).kind() { ty::Adt(def, _) if def.is_enum() => { @@ -131,18 +200,43 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { )), )) } else { - Err(ErrorKind::ResolutionFailure) + Err(ResolutionFailure::NotAVariant(ty_res, variant_field_name).into()) } } - _ => Err(ErrorKind::ResolutionFailure), + _ => unreachable!(), } } - _ => Err(ErrorKind::ResolutionFailure), + // `variant_field` looks at 3 different path segments in a row. + // But `NoAssocItem` assumes there are only 2. Check to see if there's + // an intermediate segment that resolves. + _ => { + let intermediate_path = format!("{}::{}", path, variant_name); + // NOTE: we have to be careful here, because we're already in `resolve`. + // We know this doesn't recurse forever because we use a shorter path each time. + // NOTE: this uses `TypeNS` because nothing else has a valid path segment after + let kind = if let Some(intermediate) = self.check_full_res( + TypeNS, + &intermediate_path, + Some(module_id), + current_item, + extra_fragment, + ) { + ResolutionFailure::NoAssocItem(intermediate, variant_field_name) + } else { + // Even with the shorter path, it didn't resolve, so say that. + ResolutionFailure::NoAssocItem(ty_res, variant_name) + }; + Err(kind.into()) + } } } /// Resolves a string as a macro. - fn macro_resolve(&self, path_str: &str, parent_id: Option<DefId>) -> Option<Res> { + fn macro_resolve( + &self, + path_str: &'a str, + parent_id: Option<DefId>, + ) -> Result<Res, ResolutionFailure<'a>> { let cx = self.cx; let path = ast::Path::from_ident(Ident::from_str(path_str)); cx.enter_resolver(|resolver| { @@ -154,11 +248,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { false, ) { if let SyntaxExtensionKind::LegacyBang { .. } = ext.kind { - return Some(res.map_id(|_| panic!("unexpected id"))); + return Some(Ok(res.map_id(|_| panic!("unexpected id")))); } } if let Some(res) = resolver.all_macros().get(&Symbol::intern(path_str)) { - return Some(res.map_id(|_| panic!("unexpected id"))); + return Some(Ok(res.map_id(|_| panic!("unexpected id")))); } if let Some(module_id) = parent_id { debug!("resolving {} as a macro in the module {:?}", path_str, module_id); @@ -168,25 +262,47 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // don't resolve builtins like `#[derive]` if let Res::Def(..) = res { let res = res.map_id(|_| panic!("unexpected node_id")); - return Some(res); + return Some(Ok(res)); } } } else { debug!("attempting to resolve item without parent module: {}", path_str); + return Some(Err(ResolutionFailure::NoParentItem)); } None }) + // This weird control flow is so we don't borrow the resolver more than once at a time + .unwrap_or_else(|| { + let mut split = path_str.rsplitn(2, "::"); + if let Some((parent, base)) = split.next().and_then(|x| Some((split.next()?, x))) { + if let Some(res) = self.check_full_res(TypeNS, parent, parent_id, &None, &None) { + return Err(if matches!(res, Res::PrimTy(_)) { + ResolutionFailure::NoPrimitiveAssocItem { + res, + prim_name: parent, + assoc_item: Symbol::intern(base), + } + } else { + ResolutionFailure::NoAssocItem(res, Symbol::intern(base)) + }); + } + } + Err(ResolutionFailure::NotInScope { + module_id: parent_id.expect("already saw `Some` when resolving as a macro"), + name: path_str.into(), + }) + }) } /// Resolves a string as a path within a particular namespace. Also returns an optional /// URL fragment in the case of variants and methods. - fn resolve( + fn resolve<'path>( &self, - path_str: &str, + path_str: &'path str, ns: Namespace, current_item: &Option<String>, parent_id: Option<DefId>, extra_fragment: &Option<String>, - ) -> Result<(Res, Option<String>), ErrorKind> { + ) -> Result<(Res, Option<String>), ErrorKind<'path>> { let cx = self.cx; // In case we're in a module, try to resolve the relative path. @@ -196,8 +312,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }); debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns); let result = match result { - Ok((_, Res::Err)) => Err(ErrorKind::ResolutionFailure), - _ => result.map_err(|_| ErrorKind::ResolutionFailure), + Ok((_, Res::Err)) => Err(()), + x => x, }; if let Ok((_, res)) = result { @@ -213,7 +329,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // Not a trait item; just return what we found. Res::PrimTy(..) => { if extra_fragment.is_some() { - return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive)); + return Err(ErrorKind::AnchorFailure( + AnchorFailure::RustdocAnchorConflict(res), + )); } return Ok((res, Some(path_str.to_owned()))); } @@ -226,20 +344,22 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }; if value != (ns == ValueNS) { - return Err(ErrorKind::ResolutionFailure); + return Err(ResolutionFailure::WrongNamespace(res, ns).into()); } } else if let Some((path, prim)) = is_primitive(path_str, ns) { if extra_fragment.is_some() { - return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive)); + return Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict( + prim, + ))); } return Ok((prim, Some(path.to_owned()))); } // Try looking for methods and associated items. let mut split = path_str.rsplitn(2, "::"); - let item_name = - split.next().map(|f| Symbol::intern(f)).ok_or(ErrorKind::ResolutionFailure)?; - let path = split + // this can be an `unwrap()` because we ensure the link is never empty + let item_name = Symbol::intern(split.next().unwrap()); + let path_root = split .next() .map(|f| { if f == "self" || f == "Self" { @@ -249,10 +369,17 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } f.to_owned() }) - .ok_or(ErrorKind::ResolutionFailure)?; - - if let Some((path, prim)) = is_primitive(&path, TypeNS) { - for &impl_ in primitive_impl(cx, &path).ok_or(ErrorKind::ResolutionFailure)? { + // If there's no `::`, it's not an associated item. + // So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved. + .ok_or_else(|| { + debug!("found no `::`, assumming {} was correctly not in scope", item_name); + ResolutionFailure::NotInScope { module_id, name: item_name.to_string().into() } + })?; + + if let Some((path, prim)) = is_primitive(&path_root, TypeNS) { + let impls = primitive_impl(cx, &path) + .ok_or_else(|| ResolutionFailure::NoPrimitiveImpl(prim, path_root.into()))?; + for &impl_ in impls { let link = cx .tcx .associated_items(impl_) @@ -272,21 +399,54 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { return Ok(link); } } - return Err(ErrorKind::ResolutionFailure); + debug!( + "returning primitive error for {}::{} in {} namespace", + path, + item_name, + ns.descr() + ); + return Err(ResolutionFailure::NoPrimitiveAssocItem { + res: prim, + prim_name: path, + assoc_item: item_name, + } + .into()); } - let (_, ty_res) = cx + let ty_res = cx .enter_resolver(|resolver| { - resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id) + // only types can have associated items + resolver.resolve_str_path_error(DUMMY_SP, &path_root, TypeNS, module_id) }) - .map_err(|_| ErrorKind::ResolutionFailure)?; - if let Res::Err = ty_res { - return if ns == Namespace::ValueNS { - self.variant_field(path_str, current_item, module_id) - } else { - Err(ErrorKind::ResolutionFailure) - }; - } + .map(|(_, res)| res); + let ty_res = match ty_res { + Err(()) | Ok(Res::Err) => { + return if ns == Namespace::ValueNS { + self.variant_field(path_str, current_item, module_id, extra_fragment) + } else { + // See if it only broke because of the namespace. + let kind = cx.enter_resolver(|resolver| { + // NOTE: this doesn't use `check_full_res` because we explicitly want to ignore `TypeNS` (we already checked it) + for &ns in &[MacroNS, ValueNS] { + match resolver + .resolve_str_path_error(DUMMY_SP, &path_root, ns, module_id) + { + Ok((_, Res::Err)) | Err(()) => {} + Ok((_, res)) => { + let res = res.map_id(|_| panic!("unexpected node_id")); + return ResolutionFailure::CannotHaveAssociatedItems( + res, ns, + ); + } + } + } + ResolutionFailure::NotInScope { module_id, name: path_root.into() } + }); + Err(kind.into()) + }; + } + Ok(res) => res, + }; let ty_res = ty_res.map_id(|_| panic!("unexpected node_id")); let res = match ty_res { Res::Def( @@ -295,7 +455,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { ) => { debug!("looking for associated item named {} for item {:?}", item_name, did); // Checks if item_name belongs to `impl SomeItem` - let kind = cx + let assoc_item = cx .tcx .inherent_impls(did) .iter() @@ -307,7 +467,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { imp, ) }) - .map(|item| item.kind) + .map(|item| (item.kind, item.def_id)) // There should only ever be one associated item that matches from any inherent impl .next() // Check if item_name belongs to `impl SomeTrait for SomeItem` @@ -323,26 +483,25 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { kind }); - if let Some(kind) = kind { + if let Some((kind, id)) = assoc_item { let out = match kind { ty::AssocKind::Fn => "method", ty::AssocKind::Const => "associatedconstant", ty::AssocKind::Type => "associatedtype", }; Some(if extra_fragment.is_some() { - Err(ErrorKind::AnchorFailure(if kind == ty::AssocKind::Fn { - AnchorFailure::Method - } else { - AnchorFailure::AssocConstant - })) + Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict( + ty_res, + ))) } else { // HACK(jynelson): `clean` expects the type, not the associated item. // but the disambiguator logic expects the associated item. // Store the kind in a side channel so that only the disambiguator logic looks at it. - self.kind_side_channel.set(Some(kind.as_def_kind())); + self.kind_side_channel.set(Some((kind.as_def_kind(), id))); Ok((ty_res, Some(format!("{}.{}", out, item_name)))) }) } else if ns == Namespace::ValueNS { + debug!("looking for variants or fields named {} for {:?}", item_name, did); match cx.tcx.type_of(did).kind() { ty::Adt(def, _) => { let field = if def.is_enum() { @@ -355,11 +514,17 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }; field.map(|item| { if extra_fragment.is_some() { - Err(ErrorKind::AnchorFailure(if def.is_enum() { - AnchorFailure::Variant - } else { - AnchorFailure::Field - })) + let res = Res::Def( + if def.is_enum() { + DefKind::Variant + } else { + DefKind::Field + }, + item.did, + ); + Err(ErrorKind::AnchorFailure( + AnchorFailure::RustdocAnchorConflict(res), + )) } else { Ok(( ty_res, @@ -380,7 +545,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } } else { // We already know this isn't in ValueNS, so no need to check variant_field - return Err(ErrorKind::ResolutionFailure); + return Err(ResolutionFailure::NoAssocItem(ty_res, item_name).into()); } } Res::Def(DefKind::Trait, did) => cx @@ -401,13 +566,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }; if extra_fragment.is_some() { - Err(ErrorKind::AnchorFailure(if item.kind == ty::AssocKind::Const { - AnchorFailure::AssocConstant - } else if item.kind == ty::AssocKind::Type { - AnchorFailure::AssocType - } else { - AnchorFailure::Method - })) + Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict( + ty_res, + ))) } else { let res = Res::Def(item.kind.as_def_kind(), item.def_id); Ok((res, Some(format!("{}.{}", kind, item_name)))) @@ -417,14 +578,54 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }; res.unwrap_or_else(|| { if ns == Namespace::ValueNS { - self.variant_field(path_str, current_item, module_id) + self.variant_field(path_str, current_item, module_id, extra_fragment) } else { - Err(ErrorKind::ResolutionFailure) + Err(ResolutionFailure::NoAssocItem(ty_res, item_name).into()) } }) } else { debug!("attempting to resolve item without parent module: {}", path_str); - Err(ErrorKind::ResolutionFailure) + Err(ResolutionFailure::NoParentItem.into()) + } + } + + /// Used for reporting better errors. + /// + /// Returns whether the link resolved 'fully' in another namespace. + /// 'fully' here means that all parts of the link resolved, not just some path segments. + /// This returns the `Res` even if it was erroneous for some reason + /// (such as having invalid URL fragments or being in the wrong namespace). + fn check_full_res( + &self, + ns: Namespace, + path_str: &str, + base_node: Option<DefId>, + current_item: &Option<String>, + extra_fragment: &Option<String>, + ) -> Option<Res> { + let check_full_res_inner = |this: &Self, result: Result<Res, ErrorKind<'_>>| { + let res = match result { + Ok(res) => Some(res), + Err(ErrorKind::Resolve(box kind)) => kind.full_res(), + Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(res))) => { + Some(res) + } + Err(ErrorKind::AnchorFailure(AnchorFailure::MultipleAnchors)) => None, + }; + this.kind_side_channel.take().map(|(kind, id)| Res::Def(kind, id)).or(res) + }; + // cannot be used for macro namespace + let check_full_res = |this: &Self, ns| { + let result = this.resolve(path_str, ns, current_item, base_node, extra_fragment); + check_full_res_inner(this, result.map(|(res, _)| res)) + }; + let check_full_res_macro = |this: &Self| { + let result = this.macro_resolve(path_str, base_node); + check_full_res_inner(this, result.map_err(ErrorKind::from)) + }; + match ns { + Namespace::MacroNS => check_full_res_macro(self), + Namespace::TypeNS | Namespace::ValueNS => check_full_res(self, ns), } } } @@ -435,7 +636,7 @@ fn resolve_associated_trait_item( item_name: Symbol, ns: Namespace, cx: &DocContext<'_>, -) -> Option<ty::AssocKind> { +) -> Option<(ty::AssocKind, DefId)> { let ty = cx.tcx.type_of(did); // First consider automatic impls: `impl From<T> for T` let implicit_impls = crate::clean::get_auto_trait_and_blanket_impls(cx, ty, did); @@ -463,7 +664,7 @@ fn resolve_associated_trait_item( // but provided methods come directly from `tcx`. // Fortunately, we don't need the whole method, we just need to know // what kind of associated item it is. - Some((assoc.def_id, kind)) + Some((kind, assoc.def_id)) }); let assoc = items.next(); debug_assert_eq!(items.count(), 0); @@ -485,7 +686,7 @@ fn resolve_associated_trait_item( ns, trait_, ) - .map(|assoc| (assoc.def_id, assoc.kind)) + .map(|assoc| (assoc.kind, assoc.def_id)) } } _ => panic!("get_impls returned something that wasn't an impl"), @@ -502,12 +703,12 @@ fn resolve_associated_trait_item( cx.tcx .associated_items(trait_) .find_by_name_and_namespace(cx.tcx, Ident::with_dummy_span(item_name), ns, trait_) - .map(|assoc| (assoc.def_id, assoc.kind)) + .map(|assoc| (assoc.kind, assoc.def_id)) })); } // FIXME: warn about ambiguity debug!("the candidates were {:?}", candidates); - candidates.pop().map(|(_, kind)| kind) + candidates.pop() } /// Given a type, return all traits in scope in `module` implemented by that type. @@ -536,7 +737,7 @@ fn traits_implemented_by(cx: &DocContext<'_>, type_: DefId, module: DefId) -> Fx let trait_ref = cx.tcx.impl_trait_ref(impl_).expect("this is not an inherent impl"); // Check if these are the same type. let impl_type = trait_ref.self_ty(); - debug!( + trace!( "comparing type {} with kind {:?} against type {:?}", impl_type, impl_type.kind(), @@ -562,10 +763,10 @@ fn traits_implemented_by(cx: &DocContext<'_>, type_: DefId, module: DefId) -> Fx /// Check for resolve collisions between a trait and its derive /// /// These are common and we should just resolve to the trait in that case -fn is_derive_trait_collision<T>(ns: &PerNS<Option<(Res, T)>>) -> bool { +fn is_derive_trait_collision<T>(ns: &PerNS<Result<(Res, T), ResolutionFailure<'_>>>) -> bool { if let PerNS { - type_ns: Some((Res::Def(DefKind::Trait, _), _)), - macro_ns: Some((Res::Def(DefKind::Macro(MacroKind::Derive), _), _)), + type_ns: Ok((Res::Def(DefKind::Trait, _), _)), + macro_ns: Ok((Res::Def(DefKind::Macro(MacroKind::Derive), _), _)), .. } = *ns { @@ -582,6 +783,9 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { let parent_node = if item.is_fake() { // FIXME: is this correct? None + // If we're documenting the crate root itself, it has no parent. Use the root instead. + } else if item.def_id.is_top_level_module() { + Some(item.def_id) } else { let mut current = item.def_id; // The immediate parent might not always be a module. @@ -593,6 +797,12 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } current = parent; } else { + debug!( + "{:?} has no parent (kind={:?}, original was {:?})", + current, + self.cx.tcx.def_kind(current), + item.def_id + ); break None; } } @@ -697,11 +907,12 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { // This is an anchor to an element of the current page, nothing to do in here! continue; } - (parts[0].to_owned(), Some(parts[1].to_owned())) + (parts[0], Some(parts[1].to_owned())) } else { - (parts[0].to_owned(), None) + (parts[0], None) }; let resolved_self; + let link_text; let mut path_str; let disambiguator; let (mut res, mut fragment) = { @@ -718,6 +929,12 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { continue; } + // We stripped `()` and `!` when parsing the disambiguator. + // Add them back to be displayed, but not prefix disambiguators. + link_text = disambiguator + .map(|d| d.display_for(path_str)) + .unwrap_or_else(|| path_str.to_owned()); + // In order to correctly resolve intra-doc-links we need to // pick a base AST node to work from. If the documentation for // this module came from an inner comment (//!) then we anchor @@ -748,8 +965,32 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { match self.resolve(path_str, ns, ¤t_item, base_node, &extra_fragment) { Ok(res) => res, - Err(ErrorKind::ResolutionFailure) => { - resolution_failure(cx, &item, path_str, &dox, link_range); + Err(ErrorKind::Resolve(box mut kind)) => { + // We only looked in one namespace. Try to give a better error if possible. + if kind.full_res().is_none() { + let other_ns = if ns == ValueNS { TypeNS } else { ValueNS }; + for &new_ns in &[other_ns, MacroNS] { + if let Some(res) = self.check_full_res( + new_ns, + path_str, + base_node, + ¤t_item, + &extra_fragment, + ) { + kind = ResolutionFailure::WrongNamespace(res, ns); + break; + } + } + } + resolution_failure( + self, + &item, + path_str, + disambiguator, + &dox, + link_range, + smallvec![kind], + ); // This could just be a normal link or a broken link // we could potentially check if something is // "intra-doc-link-like" and warn in that case. @@ -776,13 +1017,13 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { ) { Ok(res) => { debug!("got res in TypeNS: {:?}", res); - Some(res) + Ok(res) } Err(ErrorKind::AnchorFailure(msg)) => { anchor_failure(cx, &item, &ori_link, &dox, link_range, msg); continue; } - Err(ErrorKind::ResolutionFailure) => None, + Err(ErrorKind::Resolve(box kind)) => Err(kind), }, value_ns: match self.resolve( path_str, @@ -791,48 +1032,57 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { base_node, &extra_fragment, ) { - Ok(res) => Some(res), + Ok(res) => Ok(res), Err(ErrorKind::AnchorFailure(msg)) => { anchor_failure(cx, &item, &ori_link, &dox, link_range, msg); continue; } - Err(ErrorKind::ResolutionFailure) => None, + Err(ErrorKind::Resolve(box kind)) => Err(kind), } .and_then(|(res, fragment)| { // Constructors are picked up in the type namespace. match res { - Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) => None, + Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) => { + Err(ResolutionFailure::WrongNamespace(res, TypeNS)) + } _ => match (fragment, extra_fragment) { (Some(fragment), Some(_)) => { // Shouldn't happen but who knows? - Some((res, Some(fragment))) - } - (fragment, None) | (None, fragment) => { - Some((res, fragment)) + Ok((res, Some(fragment))) } + (fragment, None) | (None, fragment) => Ok((res, fragment)), }, } }), }; - if candidates.is_empty() { - resolution_failure(cx, &item, path_str, &dox, link_range); + let len = candidates.iter().filter(|res| res.is_ok()).count(); + + if len == 0 { + resolution_failure( + self, + &item, + path_str, + disambiguator, + &dox, + link_range, + candidates.into_iter().filter_map(|res| res.err()).collect(), + ); // this could just be a normal link continue; } - let len = candidates.clone().present_items().count(); - if len == 1 { - candidates.present_items().next().unwrap() + candidates.into_iter().filter_map(|res| res.ok()).next().unwrap() } else if len == 2 && is_derive_trait_collision(&candidates) { candidates.type_ns.unwrap() } else { if is_derive_trait_collision(&candidates) { - candidates.macro_ns = None; + candidates.macro_ns = Err(ResolutionFailure::Dummy); } + // If we're reporting an ambiguity, don't mention the namespaces that failed let candidates = - candidates.map(|candidate| candidate.map(|(res, _)| res)); + candidates.map(|candidate| candidate.ok().map(|(res, _)| res)); ambiguity_error( cx, &item, @@ -845,11 +1095,33 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } } Some(MacroNS) => { - if let Some(res) = self.macro_resolve(path_str, base_node) { - (res, extra_fragment) - } else { - resolution_failure(cx, &item, path_str, &dox, link_range); - continue; + match self.macro_resolve(path_str, base_node) { + Ok(res) => (res, extra_fragment), + Err(mut kind) => { + // `macro_resolve` only looks in the macro namespace. Try to give a better error if possible. + for &ns in &[TypeNS, ValueNS] { + if let Some(res) = self.check_full_res( + ns, + path_str, + base_node, + ¤t_item, + &extra_fragment, + ) { + kind = ResolutionFailure::WrongNamespace(res, MacroNS); + break; + } + } + resolution_failure( + self, + &item, + path_str, + disambiguator, + &dox, + link_range, + smallvec![kind], + ); + continue; + } } } } @@ -873,7 +1145,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { path_str, &dox, link_range, - AnchorFailure::Primitive, + AnchorFailure::RustdocAnchorConflict(prim), ); continue; } @@ -891,7 +1163,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { let report_mismatch = |specified: Disambiguator, resolved: Disambiguator| { // The resolved item did not match the disambiguator; give a better error than 'not found' let msg = format!("incompatible link kind for `{}`", path_str); - report_diagnostic(cx, &msg, &item, &dox, link_range.clone(), |diag, sp| { + report_diagnostic(cx, &msg, &item, &dox, &link_range, |diag, sp| { let note = format!( "this link resolved to {} {}, which is not {} {}", resolved.article(), @@ -906,7 +1178,12 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { if let Res::PrimTy(_) = res { match disambiguator { Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => { - item.attrs.links.push((ori_link, None, fragment)) + item.attrs.links.push(ItemLink { + link: ori_link, + link_text: path_str.to_owned(), + did: None, + fragment, + }); } Some(other) => { report_mismatch(other, Disambiguator::Primitive); @@ -919,7 +1196,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { // Disallow e.g. linking to enums with `struct@` if let Res::Def(kind, _) = res { debug!("saw kind {:?} with disambiguator {:?}", kind, disambiguator); - match (self.kind_side_channel.take().unwrap_or(kind), disambiguator) { + match (self.kind_side_channel.take().map(|(kind, _)| kind).unwrap_or(kind), disambiguator) { | (DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst, Some(Disambiguator::Kind(DefKind::Const))) // NOTE: this allows 'method' to mean both normal functions and associated functions // This can't cause ambiguity because both are in the same namespace. @@ -957,7 +1234,12 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } } let id = register_res(cx, res); - item.attrs.links.push((ori_link, Some(id), fragment)); + item.attrs.links.push(ItemLink { + link: ori_link, + link_text, + did: Some(id), + fragment, + }); } } @@ -985,6 +1267,18 @@ enum Disambiguator { } impl Disambiguator { + /// The text that should be displayed when the path is rendered as HTML. + /// + /// NOTE: `path` is not the original link given by the user, but a name suitable for passing to `resolve`. + fn display_for(&self, path: &str) -> String { + match self { + // FIXME: this will have different output if the user had `m!()` originally. + Self::Kind(DefKind::Macro(MacroKind::Bang)) => format!("{}!", path), + Self::Kind(DefKind::Fn) => format!("{}()", path), + _ => path.to_owned(), + } + } + /// (disambiguator, path_str) fn from_str(link: &str) -> Result<(Self, &str), ()> { use Disambiguator::{Kind, Namespace as NS, Primitive}; @@ -1036,21 +1330,16 @@ impl Disambiguator { } } - /// Return (description of the change, suggestion) - fn display_for(self, path_str: &str) -> (&'static str, String) { - const PREFIX: &str = "prefix with the item kind"; - const FUNCTION: &str = "add parentheses"; - const MACRO: &str = "add an exclamation mark"; - + fn suggestion(self) -> Suggestion { let kind = match self { - Disambiguator::Primitive => return (PREFIX, format!("prim@{}", path_str)), + Disambiguator::Primitive => return Suggestion::Prefix("prim"), Disambiguator::Kind(kind) => kind, Disambiguator::Namespace(_) => panic!("display_for cannot be used on namespaces"), }; if kind == DefKind::Macro(MacroKind::Bang) { - return (MACRO, format!("{}!", path_str)); + return Suggestion::Macro; } else if kind == DefKind::Fn || kind == DefKind::AssocFn { - return (FUNCTION, format!("{}()", path_str)); + return Suggestion::Function; } let prefix = match kind { @@ -1075,8 +1364,7 @@ impl Disambiguator { }, }; - // FIXME: if this is an implied shortcut link, it's bad style to suggest `@` - (PREFIX, format!("{}@{}", prefix, path_str)) + Suggestion::Prefix(prefix) } fn ns(self) -> Namespace { @@ -1108,6 +1396,31 @@ impl Disambiguator { } } +enum Suggestion { + Prefix(&'static str), + Function, + Macro, +} + +impl Suggestion { + fn descr(&self) -> Cow<'static, str> { + match self { + Self::Prefix(x) => format!("prefix with `{}@`", x).into(), + Self::Function => "add parentheses".into(), + Self::Macro => "add an exclamation mark".into(), + } + } + + fn as_help(&self, path_str: &str) -> String { + // FIXME: if this is an implied shortcut link, it's bad style to suggest `@` + match self { + Self::Prefix(prefix) => format!("{}@{}", prefix, path_str), + Self::Function => format!("{}()", path_str), + Self::Macro => format!("{}!", path_str), + } + } +} + /// Reports a diagnostic for an intra-doc link. /// /// If no link range is provided, or the source span of the link cannot be determined, the span of @@ -1123,7 +1436,7 @@ fn report_diagnostic( msg: &str, item: &Item, dox: &str, - link_range: Option<Range<usize>>, + link_range: &Option<Range<usize>>, decorate: impl FnOnce(&mut DiagnosticBuilder<'_>, Option<rustc_span::Span>), ) { let hir_id = match cx.as_local_hir_id(item.def_id) { @@ -1175,24 +1488,197 @@ fn report_diagnostic( } fn resolution_failure( - cx: &DocContext<'_>, + collector: &LinkCollector<'_, '_>, item: &Item, path_str: &str, + disambiguator: Option<Disambiguator>, dox: &str, link_range: Option<Range<usize>>, + kinds: SmallVec<[ResolutionFailure<'_>; 3]>, ) { report_diagnostic( - cx, + collector.cx, &format!("unresolved link to `{}`", path_str), item, dox, - link_range, + &link_range, |diag, sp| { - if let Some(sp) = sp { - diag.span_label(sp, "unresolved link"); - } + let in_scope = kinds.iter().any(|kind| kind.res().is_some()); + let item = |res: Res| { + format!( + "the {} `{}`", + res.descr(), + collector.cx.tcx.item_name(res.def_id()).to_string() + ) + }; + let assoc_item_not_allowed = |res: Res| { + let def_id = res.def_id(); + let name = collector.cx.tcx.item_name(def_id); + format!( + "`{}` is {} {}, not a module or type, and cannot have associated items", + name, + res.article(), + res.descr() + ) + }; + // ignore duplicates + let mut variants_seen = SmallVec::<[_; 3]>::new(); + for mut failure in kinds { + // Check if _any_ parent of the path gets resolved. + // If so, report it and say the first which failed; if not, say the first path segment didn't resolve. + if let ResolutionFailure::NotInScope { module_id, name } = &mut failure { + let mut current = name.as_ref(); + loop { + current = match current.rsplitn(2, "::").nth(1) { + Some(p) => p, + None => { + *name = current.to_owned().into(); + break; + } + }; + if let Some(res) = collector.check_full_res( + TypeNS, + ¤t, + Some(*module_id), + &None, + &None, + ) { + failure = ResolutionFailure::NoAssocItem(res, Symbol::intern(current)); + break; + } + } + } + let variant = std::mem::discriminant(&failure); + if variants_seen.contains(&variant) { + continue; + } + variants_seen.push(variant); + let note = match failure { + ResolutionFailure::NotInScope { module_id, name, .. } => { + if in_scope { + continue; + } + // NOTE: uses an explicit `continue` so the `note:` will come before the `help:` + let module_name = collector.cx.tcx.item_name(module_id); + let note = format!("no item named `{}` in `{}`", name, module_name); + if let Some(span) = sp { + diag.span_label(span, ¬e); + } else { + diag.note(¬e); + } + // If the link has `::` in the path, assume it's meant to be an intra-doc link + if !path_str.contains("::") { + // Otherwise, the `[]` might be unrelated. + // FIXME(https://github.com/raphlinus/pulldown-cmark/issues/373): + // don't show this for autolinks (`<>`), `()` style links, or reference links + diag.help(r#"to escape `[` and `]` characters, add '\' before them like `\[` or `\]`"#); + } + continue; + } + ResolutionFailure::Dummy => continue, + ResolutionFailure::WrongNamespace(res, expected_ns) => { + if let Res::Def(kind, _) = res { + let disambiguator = Disambiguator::Kind(kind); + suggest_disambiguator( + disambiguator, + diag, + path_str, + dox, + sp, + &link_range, + ) + } - diag.help(r#"to escape `[` and `]` characters, add '\' before them like `\[` or `\]`"#); + format!( + "this link resolves to {}, which is not in the {} namespace", + item(res), + expected_ns.descr() + ) + } + ResolutionFailure::NoParentItem => { + diag.level = rustc_errors::Level::Bug; + "all intra doc links should have a parent item".to_owned() + } + ResolutionFailure::NoPrimitiveImpl(res, _) => format!( + "this link partially resolves to {}, which does not have any associated items", + item(res), + ), + ResolutionFailure::NoPrimitiveAssocItem { prim_name, assoc_item, .. } => { + format!( + "the builtin type `{}` does not have an associated item named `{}`", + prim_name, assoc_item + ) + } + ResolutionFailure::NoAssocItem(res, assoc_item) => { + use DefKind::*; + + let (kind, def_id) = match res { + Res::Def(kind, def_id) => (kind, def_id), + x => unreachable!( + "primitives are covered above and other `Res` variants aren't possible at module scope: {:?}", + x, + ), + }; + let name = collector.cx.tcx.item_name(def_id); + let path_description = if let Some(disambiguator) = disambiguator { + disambiguator.descr() + } else { + match kind { + Mod | ForeignMod => "inner item", + Struct => "field or associated item", + Enum | Union => "variant or associated item", + Variant + | Field + | Closure + | Generator + | AssocTy + | AssocConst + | AssocFn + | Fn + | Macro(_) + | Const + | ConstParam + | ExternCrate + | Use + | LifetimeParam + | Ctor(_, _) + | AnonConst => { + let note = assoc_item_not_allowed(res); + if let Some(span) = sp { + diag.span_label(span, ¬e); + } else { + diag.note(¬e); + } + return; + } + Trait | TyAlias | ForeignTy | OpaqueTy | TraitAlias | TyParam + | Static => "associated item", + Impl | GlobalAsm => unreachable!("not a path"), + } + }; + format!( + "the {} `{}` has no {} named `{}`", + res.descr(), + name, + path_description, + assoc_item + ) + } + ResolutionFailure::CannotHaveAssociatedItems(res, _) => { + assoc_item_not_allowed(res) + } + ResolutionFailure::NotAVariant(res, variant) => format!( + "this link partially resolves to {}, but there is no variant named {}", + item(res), + variant + ), + }; + if let Some(span) = sp { + diag.span_label(span, ¬e); + } else { + diag.note(¬e); + } + } }, ); } @@ -1207,31 +1693,14 @@ fn anchor_failure( ) { let msg = match failure { AnchorFailure::MultipleAnchors => format!("`{}` contains multiple anchors", path_str), - AnchorFailure::Primitive - | AnchorFailure::Variant - | AnchorFailure::AssocConstant - | AnchorFailure::AssocType - | AnchorFailure::Field - | AnchorFailure::Method => { - let kind = match failure { - AnchorFailure::Primitive => "primitive type", - AnchorFailure::Variant => "enum variant", - AnchorFailure::AssocConstant => "associated constant", - AnchorFailure::AssocType => "associated type", - AnchorFailure::Field => "struct field", - AnchorFailure::Method => "method", - AnchorFailure::MultipleAnchors => unreachable!("should be handled already"), - }; - - format!( - "`{}` contains an anchor, but links to {kind}s are already anchored", - path_str, - kind = kind - ) - } + AnchorFailure::RustdocAnchorConflict(res) => format!( + "`{}` contains an anchor, but links to {kind}s are already anchored", + path_str, + kind = res.descr(), + ), }; - report_diagnostic(cx, &msg, item, dox, link_range, |diag, sp| { + report_diagnostic(cx, &msg, item, dox, &link_range, |diag, sp| { if let Some(sp) = sp { diag.span_label(sp, "contains invalid anchor"); } @@ -1270,7 +1739,7 @@ fn ambiguity_error( } } - report_diagnostic(cx, &msg, item, dox, link_range.clone(), |diag, sp| { + report_diagnostic(cx, &msg, item, dox, &link_range, |diag, sp| { if let Some(sp) = sp { diag.span_label(sp, "ambiguous link"); } else { @@ -1292,18 +1761,20 @@ fn suggest_disambiguator( sp: Option<rustc_span::Span>, link_range: &Option<Range<usize>>, ) { - let (action, mut suggestion) = disambiguator.display_for(path_str); - let help = format!("to link to the {}, {}", disambiguator.descr(), action); + let suggestion = disambiguator.suggestion(); + let help = format!("to link to the {}, {}", disambiguator.descr(), suggestion.descr()); if let Some(sp) = sp { let link_range = link_range.as_ref().expect("must have a link range if we have a span"); - if dox.bytes().nth(link_range.start) == Some(b'`') { - suggestion = format!("`{}`", suggestion); - } + let msg = if dox.bytes().nth(link_range.start) == Some(b'`') { + format!("`{}`", suggestion.as_help(path_str)) + } else { + suggestion.as_help(path_str) + }; - diag.span_suggestion(sp, &help, suggestion, Applicability::MaybeIncorrect); + diag.span_suggestion(sp, &help, msg, Applicability::MaybeIncorrect); } else { - diag.help(&format!("{}: {}", help, suggestion)); + diag.help(&format!("{}: {}", help, suggestion.as_help(path_str))); } } @@ -1318,7 +1789,7 @@ fn privacy_error( let msg = format!("public documentation for `{}` links to private item `{}`", item_name, path_str); - report_diagnostic(cx, &msg, item, dox, link_range, |diag, sp| { + report_diagnostic(cx, &msg, item, dox, &link_range, |diag, sp| { if let Some(sp) = sp { diag.span_label(sp, "this item is private"); } @@ -1337,16 +1808,16 @@ fn handle_variant( cx: &DocContext<'_>, res: Res, extra_fragment: &Option<String>, -) -> Result<(Res, Option<String>), ErrorKind> { +) -> Result<(Res, Option<String>), ErrorKind<'static>> { use rustc_middle::ty::DefIdTree; if extra_fragment.is_some() { - return Err(ErrorKind::AnchorFailure(AnchorFailure::Variant)); + return Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(res))); } let parent = if let Some(parent) = cx.tcx.parent(res.def_id()) { parent } else { - return Err(ErrorKind::ResolutionFailure); + return Err(ResolutionFailure::NoParentItem.into()); }; let parent_def = Res::Def(DefKind::Enum, parent); let variant = cx.tcx.expect_variant_res(res); diff --git a/src/llvm-project b/src/llvm-project -Subproject 45790d79496be37fbce6ec57abad5af8fa7a34d +Subproject 833dd1e3d4fd350c7c9f6fb2ce0c5f16af7a1e2 diff --git a/src/rustllvm/.editorconfig b/src/rustllvm/.editorconfig deleted file mode 100644 index 865cd45f708..00000000000 --- a/src/rustllvm/.editorconfig +++ /dev/null @@ -1,6 +0,0 @@ -[*.{h,cpp}] -end_of_line = lf -insert_final_newline = true -charset = utf-8 -indent_style = space -indent_size = 2 diff --git a/src/rustllvm/ArchiveWrapper.cpp b/src/rustllvm/ArchiveWrapper.cpp deleted file mode 100644 index 9ce614fda57..00000000000 --- a/src/rustllvm/ArchiveWrapper.cpp +++ /dev/null @@ -1,226 +0,0 @@ -#include "rustllvm.h" - -#include "llvm/Object/Archive.h" -#include "llvm/Object/ArchiveWriter.h" -#include "llvm/Support/Path.h" - -using namespace llvm; -using namespace llvm::object; - -struct RustArchiveMember { - const char *Filename; - const char *Name; - Archive::Child Child; - - RustArchiveMember() - : Filename(nullptr), Name(nullptr), - Child(nullptr, nullptr, nullptr) - { - } - ~RustArchiveMember() {} -}; - -struct RustArchiveIterator { - bool First; - Archive::child_iterator Cur; - Archive::child_iterator End; - std::unique_ptr<Error> Err; - - RustArchiveIterator(Archive::child_iterator Cur, Archive::child_iterator End, - std::unique_ptr<Error> Err) - : First(true), - Cur(Cur), - End(End), - Err(std::move(Err)) {} -}; - -enum class LLVMRustArchiveKind { - GNU, - BSD, - DARWIN, - COFF, -}; - -static Archive::Kind fromRust(LLVMRustArchiveKind Kind) { - switch (Kind) { - case LLVMRustArchiveKind::GNU: - return Archive::K_GNU; - case LLVMRustArchiveKind::BSD: - return Archive::K_BSD; - case LLVMRustArchiveKind::DARWIN: - return Archive::K_DARWIN; - case LLVMRustArchiveKind::COFF: - return Archive::K_COFF; - default: - report_fatal_error("Bad ArchiveKind."); - } -} - -typedef OwningBinary<Archive> *LLVMRustArchiveRef; -typedef RustArchiveMember *LLVMRustArchiveMemberRef; -typedef Archive::Child *LLVMRustArchiveChildRef; -typedef Archive::Child const *LLVMRustArchiveChildConstRef; -typedef RustArchiveIterator *LLVMRustArchiveIteratorRef; - -extern "C" LLVMRustArchiveRef LLVMRustOpenArchive(char *Path) { - ErrorOr<std::unique_ptr<MemoryBuffer>> BufOr = - MemoryBuffer::getFile(Path, -1, false); - if (!BufOr) { - LLVMRustSetLastError(BufOr.getError().message().c_str()); - return nullptr; - } - - Expected<std::unique_ptr<Archive>> ArchiveOr = - Archive::create(BufOr.get()->getMemBufferRef()); - - if (!ArchiveOr) { - LLVMRustSetLastError(toString(ArchiveOr.takeError()).c_str()); - return nullptr; - } - - OwningBinary<Archive> *Ret = new OwningBinary<Archive>( - std::move(ArchiveOr.get()), std::move(BufOr.get())); - - return Ret; -} - -extern "C" void LLVMRustDestroyArchive(LLVMRustArchiveRef RustArchive) { - delete RustArchive; -} - -extern "C" LLVMRustArchiveIteratorRef -LLVMRustArchiveIteratorNew(LLVMRustArchiveRef RustArchive) { - Archive *Archive = RustArchive->getBinary(); -#if LLVM_VERSION_GE(10, 0) - std::unique_ptr<Error> Err = std::make_unique<Error>(Error::success()); -#else - std::unique_ptr<Error> Err = llvm::make_unique<Error>(Error::success()); -#endif - auto Cur = Archive->child_begin(*Err); - if (*Err) { - LLVMRustSetLastError(toString(std::move(*Err)).c_str()); - return nullptr; - } - auto End = Archive->child_end(); - return new RustArchiveIterator(Cur, End, std::move(Err)); -} - -extern "C" LLVMRustArchiveChildConstRef -LLVMRustArchiveIteratorNext(LLVMRustArchiveIteratorRef RAI) { - if (RAI->Cur == RAI->End) - return nullptr; - - // Advancing the iterator validates the next child, and this can - // uncover an error. LLVM requires that we check all Errors, - // so we only advance the iterator if we actually need to fetch - // the next child. - // This means we must not advance the iterator in the *first* call, - // but instead advance it *before* fetching the child in all later calls. - if (!RAI->First) { - ++RAI->Cur; - if (*RAI->Err) { - LLVMRustSetLastError(toString(std::move(*RAI->Err)).c_str()); - return nullptr; - } - } else { - RAI->First = false; - } - - if (RAI->Cur == RAI->End) - return nullptr; - - const Archive::Child &Child = *RAI->Cur.operator->(); - Archive::Child *Ret = new Archive::Child(Child); - - return Ret; -} - -extern "C" void LLVMRustArchiveChildFree(LLVMRustArchiveChildRef Child) { - delete Child; -} - -extern "C" void LLVMRustArchiveIteratorFree(LLVMRustArchiveIteratorRef RAI) { - delete RAI; -} - -extern "C" const char * -LLVMRustArchiveChildName(LLVMRustArchiveChildConstRef Child, size_t *Size) { - Expected<StringRef> NameOrErr = Child->getName(); - if (!NameOrErr) { - // rustc_codegen_llvm currently doesn't use this error string, but it might be - // useful in the future, and in the mean time this tells LLVM that the - // error was not ignored and that it shouldn't abort the process. - LLVMRustSetLastError(toString(NameOrErr.takeError()).c_str()); - return nullptr; - } - StringRef Name = NameOrErr.get(); - *Size = Name.size(); - return Name.data(); -} - -extern "C" const char *LLVMRustArchiveChildData(LLVMRustArchiveChildRef Child, - size_t *Size) { - StringRef Buf; - Expected<StringRef> BufOrErr = Child->getBuffer(); - if (!BufOrErr) { - LLVMRustSetLastError(toString(BufOrErr.takeError()).c_str()); - return nullptr; - } - Buf = BufOrErr.get(); - *Size = Buf.size(); - return Buf.data(); -} - -extern "C" LLVMRustArchiveMemberRef -LLVMRustArchiveMemberNew(char *Filename, char *Name, - LLVMRustArchiveChildRef Child) { - RustArchiveMember *Member = new RustArchiveMember; - Member->Filename = Filename; - Member->Name = Name; - if (Child) - Member->Child = *Child; - return Member; -} - -extern "C" void LLVMRustArchiveMemberFree(LLVMRustArchiveMemberRef Member) { - delete Member; -} - -extern "C" LLVMRustResult -LLVMRustWriteArchive(char *Dst, size_t NumMembers, - const LLVMRustArchiveMemberRef *NewMembers, - bool WriteSymbtab, LLVMRustArchiveKind RustKind) { - - std::vector<NewArchiveMember> Members; - auto Kind = fromRust(RustKind); - - for (size_t I = 0; I < NumMembers; I++) { - auto Member = NewMembers[I]; - assert(Member->Name); - if (Member->Filename) { - Expected<NewArchiveMember> MOrErr = - NewArchiveMember::getFile(Member->Filename, true); - if (!MOrErr) { - LLVMRustSetLastError(toString(MOrErr.takeError()).c_str()); - return LLVMRustResult::Failure; - } - MOrErr->MemberName = sys::path::filename(MOrErr->MemberName); - Members.push_back(std::move(*MOrErr)); - } else { - Expected<NewArchiveMember> MOrErr = - NewArchiveMember::getOldMember(Member->Child, true); - if (!MOrErr) { - LLVMRustSetLastError(toString(MOrErr.takeError()).c_str()); - return LLVMRustResult::Failure; - } - Members.push_back(std::move(*MOrErr)); - } - } - - auto Result = writeArchive(Dst, Members, WriteSymbtab, Kind, true, false); - if (!Result) - return LLVMRustResult::Success; - LLVMRustSetLastError(toString(std::move(Result)).c_str()); - - return LLVMRustResult::Failure; -} diff --git a/src/rustllvm/CoverageMappingWrapper.cpp b/src/rustllvm/CoverageMappingWrapper.cpp deleted file mode 100644 index 81aba0cbf7d..00000000000 --- a/src/rustllvm/CoverageMappingWrapper.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include "rustllvm.h" -#include "llvm/ProfileData/Coverage/CoverageMapping.h" -#include "llvm/ProfileData/Coverage/CoverageMappingWriter.h" -#include "llvm/ProfileData/InstrProf.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/Support/LEB128.h" - -#include <iostream> - -using namespace llvm; - -extern "C" void LLVMRustCoverageWriteFilenamesSectionToBuffer( - const char* const Filenames[], - size_t FilenamesLen, - RustStringRef BufferOut) { - // LLVM 11's CoverageFilenamesSectionWriter uses its new `Version4` format, - // so we're manually writing the `Version3` format ourselves. - RawRustStringOstream OS(BufferOut); - encodeULEB128(FilenamesLen, OS); - for (size_t i = 0; i < FilenamesLen; i++) { - StringRef Filename(Filenames[i]); - encodeULEB128(Filename.size(), OS); - OS << Filename; - } -} - -extern "C" void LLVMRustCoverageWriteMappingToBuffer( - const unsigned *VirtualFileMappingIDs, - unsigned NumVirtualFileMappingIDs, - const coverage::CounterExpression *Expressions, - unsigned NumExpressions, - coverage::CounterMappingRegion *MappingRegions, - unsigned NumMappingRegions, - RustStringRef BufferOut) { - auto CoverageMappingWriter = coverage::CoverageMappingWriter( - makeArrayRef(VirtualFileMappingIDs, NumVirtualFileMappingIDs), - makeArrayRef(Expressions, NumExpressions), - makeMutableArrayRef(MappingRegions, NumMappingRegions)); - RawRustStringOstream OS(BufferOut); - CoverageMappingWriter.write(OS); -} - -extern "C" LLVMValueRef LLVMRustCoverageCreatePGOFuncNameVar(LLVMValueRef F, const char *FuncName) { - StringRef FuncNameRef(FuncName); - return wrap(createPGOFuncNameVar(*cast<Function>(unwrap(F)), FuncNameRef)); -} - -extern "C" uint64_t LLVMRustCoverageComputeHash(const char *Name) { - StringRef NameRef(Name); - return IndexedInstrProf::ComputeHash(NameRef); -} - -extern "C" void LLVMRustCoverageWriteSectionNameToString(LLVMModuleRef M, - RustStringRef Str) { - Triple TargetTriple(unwrap(M)->getTargetTriple()); - auto name = getInstrProfSectionName(IPSK_covmap, - TargetTriple.getObjectFormat()); - RawRustStringOstream OS(Str); - OS << name; -} - -extern "C" void LLVMRustCoverageWriteMappingVarNameToString(RustStringRef Str) { - auto name = getCoverageMappingVarName(); - RawRustStringOstream OS(Str); - OS << name; -} - -extern "C" uint32_t LLVMRustCoverageMappingVersion() { - return coverage::CovMapVersion::Version3; -} diff --git a/src/rustllvm/Linker.cpp b/src/rustllvm/Linker.cpp deleted file mode 100644 index 69176f9cb1f..00000000000 --- a/src/rustllvm/Linker.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "llvm/Linker/Linker.h" - -#include "rustllvm.h" - -using namespace llvm; - -struct RustLinker { - Linker L; - LLVMContext &Ctx; - - RustLinker(Module &M) : - L(M), - Ctx(M.getContext()) - {} -}; - -extern "C" RustLinker* -LLVMRustLinkerNew(LLVMModuleRef DstRef) { - Module *Dst = unwrap(DstRef); - - return new RustLinker(*Dst); -} - -extern "C" void -LLVMRustLinkerFree(RustLinker *L) { - delete L; -} - -extern "C" bool -LLVMRustLinkerAdd(RustLinker *L, char *BC, size_t Len) { - std::unique_ptr<MemoryBuffer> Buf = - MemoryBuffer::getMemBufferCopy(StringRef(BC, Len)); - - Expected<std::unique_ptr<Module>> SrcOrError = - llvm::getLazyBitcodeModule(Buf->getMemBufferRef(), L->Ctx); - if (!SrcOrError) { - LLVMRustSetLastError(toString(SrcOrError.takeError()).c_str()); - return false; - } - - auto Src = std::move(*SrcOrError); - - if (L->L.linkInModule(std::move(Src))) { - LLVMRustSetLastError(""); - return false; - } - return true; -} diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp deleted file mode 100644 index 76fe5e7f769..00000000000 --- a/src/rustllvm/PassWrapper.cpp +++ /dev/null @@ -1,1655 +0,0 @@ -#include <stdio.h> - -#include <vector> -#include <set> - -#include "rustllvm.h" - -#include "llvm/Analysis/TargetLibraryInfo.h" -#include "llvm/Analysis/TargetTransformInfo.h" -#include "llvm/CodeGen/TargetSubtargetInfo.h" -#include "llvm/InitializePasses.h" -#include "llvm/IR/AutoUpgrade.h" -#include "llvm/IR/AssemblyAnnotationWriter.h" -#include "llvm/IR/IntrinsicInst.h" -#include "llvm/IR/Verifier.h" -#include "llvm/Object/ObjectFile.h" -#include "llvm/Object/IRObjectFile.h" -#include "llvm/Passes/PassBuilder.h" -#if LLVM_VERSION_GE(9, 0) -#include "llvm/Passes/StandardInstrumentations.h" -#endif -#include "llvm/Support/CBindingWrapping.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Host.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Transforms/IPO/PassManagerBuilder.h" -#include "llvm/Transforms/IPO/AlwaysInliner.h" -#include "llvm/Transforms/IPO/FunctionImport.h" -#include "llvm/Transforms/Utils/FunctionImportUtils.h" -#include "llvm/LTO/LTO.h" -#include "llvm-c/Transforms/PassManagerBuilder.h" - -#include "llvm/Transforms/Instrumentation.h" -#if LLVM_VERSION_GE(9, 0) -#include "llvm/Transforms/Instrumentation/AddressSanitizer.h" -#include "llvm/Support/TimeProfiler.h" -#endif -#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h" -#include "llvm/Transforms/Instrumentation/MemorySanitizer.h" -#if LLVM_VERSION_GE(9, 0) -#include "llvm/Transforms/Utils/CanonicalizeAliases.h" -#endif -#include "llvm/Transforms/Utils/NameAnonGlobals.h" - -using namespace llvm; - -typedef struct LLVMOpaquePass *LLVMPassRef; -typedef struct LLVMOpaqueTargetMachine *LLVMTargetMachineRef; - -DEFINE_STDCXX_CONVERSION_FUNCTIONS(Pass, LLVMPassRef) -DEFINE_STDCXX_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef) -#if LLVM_VERSION_LT(11, 0) -DEFINE_STDCXX_CONVERSION_FUNCTIONS(PassManagerBuilder, - LLVMPassManagerBuilderRef) -#endif - -extern "C" void LLVMInitializePasses() { - PassRegistry &Registry = *PassRegistry::getPassRegistry(); - initializeCore(Registry); - initializeCodeGen(Registry); - initializeScalarOpts(Registry); - initializeVectorization(Registry); - initializeIPO(Registry); - initializeAnalysis(Registry); - initializeTransformUtils(Registry); - initializeInstCombine(Registry); - initializeInstrumentation(Registry); - initializeTarget(Registry); -} - -extern "C" void LLVMTimeTraceProfilerInitialize() { -#if LLVM_VERSION_GE(10, 0) - timeTraceProfilerInitialize( - /* TimeTraceGranularity */ 0, - /* ProcName */ "rustc"); -#elif LLVM_VERSION_GE(9, 0) - timeTraceProfilerInitialize(); -#endif -} - -extern "C" void LLVMTimeTraceProfilerFinish(const char* FileName) { -#if LLVM_VERSION_GE(9, 0) - StringRef FN(FileName); - std::error_code EC; - raw_fd_ostream OS(FN, EC, sys::fs::CD_CreateAlways); - - timeTraceProfilerWrite(OS); - timeTraceProfilerCleanup(); -#endif -} - -enum class LLVMRustPassKind { - Other, - Function, - Module, -}; - -static LLVMRustPassKind toRust(PassKind Kind) { - switch (Kind) { - case PT_Function: - return LLVMRustPassKind::Function; - case PT_Module: - return LLVMRustPassKind::Module; - default: - return LLVMRustPassKind::Other; - } -} - -extern "C" LLVMPassRef LLVMRustFindAndCreatePass(const char *PassName) { - StringRef SR(PassName); - PassRegistry *PR = PassRegistry::getPassRegistry(); - - const PassInfo *PI = PR->getPassInfo(SR); - if (PI) { - return wrap(PI->createPass()); - } - return nullptr; -} - -extern "C" LLVMPassRef LLVMRustCreateAddressSanitizerFunctionPass(bool Recover) { - const bool CompileKernel = false; - const bool UseAfterScope = true; - - return wrap(createAddressSanitizerFunctionPass(CompileKernel, Recover, UseAfterScope)); -} - -extern "C" LLVMPassRef LLVMRustCreateModuleAddressSanitizerPass(bool Recover) { - const bool CompileKernel = false; - -#if LLVM_VERSION_GE(9, 0) - return wrap(createModuleAddressSanitizerLegacyPassPass(CompileKernel, Recover)); -#else - return wrap(createAddressSanitizerModulePass(CompileKernel, Recover)); -#endif -} - -extern "C" LLVMPassRef LLVMRustCreateMemorySanitizerPass(int TrackOrigins, bool Recover) { -#if LLVM_VERSION_GE(9, 0) - const bool CompileKernel = false; - - return wrap(createMemorySanitizerLegacyPassPass( - MemorySanitizerOptions{TrackOrigins, Recover, CompileKernel})); -#else - return wrap(createMemorySanitizerLegacyPassPass(TrackOrigins, Recover)); -#endif -} - -extern "C" LLVMPassRef LLVMRustCreateThreadSanitizerPass() { - return wrap(createThreadSanitizerLegacyPassPass()); -} - -extern "C" LLVMRustPassKind LLVMRustPassKind(LLVMPassRef RustPass) { - assert(RustPass); - Pass *Pass = unwrap(RustPass); - return toRust(Pass->getPassKind()); -} - -extern "C" void LLVMRustAddPass(LLVMPassManagerRef PMR, LLVMPassRef RustPass) { - assert(RustPass); - Pass *Pass = unwrap(RustPass); - PassManagerBase *PMB = unwrap(PMR); - PMB->add(Pass); -} - -extern "C" -void LLVMRustPassManagerBuilderPopulateThinLTOPassManager( - LLVMPassManagerBuilderRef PMBR, - LLVMPassManagerRef PMR -) { - unwrap(PMBR)->populateThinLTOPassManager(*unwrap(PMR)); -} - -extern "C" -void LLVMRustAddLastExtensionPasses( - LLVMPassManagerBuilderRef PMBR, LLVMPassRef *Passes, size_t NumPasses) { - auto AddExtensionPasses = [Passes, NumPasses]( - const PassManagerBuilder &Builder, PassManagerBase &PM) { - for (size_t I = 0; I < NumPasses; I++) { - PM.add(unwrap(Passes[I])); - } - }; - // Add the passes to both of the pre-finalization extension points, - // so they are run for optimized and non-optimized builds. - unwrap(PMBR)->addExtension(PassManagerBuilder::EP_OptimizerLast, - AddExtensionPasses); - unwrap(PMBR)->addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0, - AddExtensionPasses); -} - -#ifdef LLVM_COMPONENT_X86 -#define SUBTARGET_X86 SUBTARGET(X86) -#else -#define SUBTARGET_X86 -#endif - -#ifdef LLVM_COMPONENT_ARM -#define SUBTARGET_ARM SUBTARGET(ARM) -#else -#define SUBTARGET_ARM -#endif - -#ifdef LLVM_COMPONENT_AARCH64 -#define SUBTARGET_AARCH64 SUBTARGET(AArch64) -#else -#define SUBTARGET_AARCH64 -#endif - -#ifdef LLVM_COMPONENT_AVR -#define SUBTARGET_AVR SUBTARGET(AVR) -#else -#define SUBTARGET_AVR -#endif - -#ifdef LLVM_COMPONENT_MIPS -#define SUBTARGET_MIPS SUBTARGET(Mips) -#else -#define SUBTARGET_MIPS -#endif - -#ifdef LLVM_COMPONENT_POWERPC -#define SUBTARGET_PPC SUBTARGET(PPC) -#else -#define SUBTARGET_PPC -#endif - -#ifdef LLVM_COMPONENT_SYSTEMZ -#define SUBTARGET_SYSTEMZ SUBTARGET(SystemZ) -#else -#define SUBTARGET_SYSTEMZ -#endif - -#ifdef LLVM_COMPONENT_MSP430 -#define SUBTARGET_MSP430 SUBTARGET(MSP430) -#else -#define SUBTARGET_MSP430 -#endif - -#ifdef LLVM_COMPONENT_RISCV -#define SUBTARGET_RISCV SUBTARGET(RISCV) -#else -#define SUBTARGET_RISCV -#endif - -#ifdef LLVM_COMPONENT_SPARC -#define SUBTARGET_SPARC SUBTARGET(Sparc) -#else -#define SUBTARGET_SPARC -#endif - -#ifdef LLVM_COMPONENT_HEXAGON -#define SUBTARGET_HEXAGON SUBTARGET(Hexagon) -#else -#define SUBTARGET_HEXAGON -#endif - -#define GEN_SUBTARGETS \ - SUBTARGET_X86 \ - SUBTARGET_ARM \ - SUBTARGET_AARCH64 \ - SUBTARGET_AVR \ - SUBTARGET_MIPS \ - SUBTARGET_PPC \ - SUBTARGET_SYSTEMZ \ - SUBTARGET_MSP430 \ - SUBTARGET_SPARC \ - SUBTARGET_HEXAGON \ - SUBTARGET_RISCV \ - -#define SUBTARGET(x) \ - namespace llvm { \ - extern const SubtargetFeatureKV x##FeatureKV[]; \ - extern const SubtargetFeatureKV x##SubTypeKV[]; \ - } - -GEN_SUBTARGETS -#undef SUBTARGET - -extern "C" bool LLVMRustHasFeature(LLVMTargetMachineRef TM, - const char *Feature) { - TargetMachine *Target = unwrap(TM); - const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo(); - return MCInfo->checkFeatures(std::string("+") + Feature); -} - -enum class LLVMRustCodeModel { - Tiny, - Small, - Kernel, - Medium, - Large, - None, -}; - -static Optional<CodeModel::Model> fromRust(LLVMRustCodeModel Model) { - switch (Model) { - case LLVMRustCodeModel::Tiny: - return CodeModel::Tiny; - case LLVMRustCodeModel::Small: - return CodeModel::Small; - case LLVMRustCodeModel::Kernel: - return CodeModel::Kernel; - case LLVMRustCodeModel::Medium: - return CodeModel::Medium; - case LLVMRustCodeModel::Large: - return CodeModel::Large; - case LLVMRustCodeModel::None: - return None; - default: - report_fatal_error("Bad CodeModel."); - } -} - -enum class LLVMRustCodeGenOptLevel { - None, - Less, - Default, - Aggressive, -}; - -static CodeGenOpt::Level fromRust(LLVMRustCodeGenOptLevel Level) { - switch (Level) { - case LLVMRustCodeGenOptLevel::None: - return CodeGenOpt::None; - case LLVMRustCodeGenOptLevel::Less: - return CodeGenOpt::Less; - case LLVMRustCodeGenOptLevel::Default: - return CodeGenOpt::Default; - case LLVMRustCodeGenOptLevel::Aggressive: - return CodeGenOpt::Aggressive; - default: - report_fatal_error("Bad CodeGenOptLevel."); - } -} - -enum class LLVMRustPassBuilderOptLevel { - O0, - O1, - O2, - O3, - Os, - Oz, -}; - -static PassBuilder::OptimizationLevel fromRust(LLVMRustPassBuilderOptLevel Level) { - switch (Level) { - case LLVMRustPassBuilderOptLevel::O0: - return PassBuilder::OptimizationLevel::O0; - case LLVMRustPassBuilderOptLevel::O1: - return PassBuilder::OptimizationLevel::O1; - case LLVMRustPassBuilderOptLevel::O2: - return PassBuilder::OptimizationLevel::O2; - case LLVMRustPassBuilderOptLevel::O3: - return PassBuilder::OptimizationLevel::O3; - case LLVMRustPassBuilderOptLevel::Os: - return PassBuilder::OptimizationLevel::Os; - case LLVMRustPassBuilderOptLevel::Oz: - return PassBuilder::OptimizationLevel::Oz; - default: - report_fatal_error("Bad PassBuilderOptLevel."); - } -} - -enum class LLVMRustRelocModel { - Static, - PIC, - DynamicNoPic, - ROPI, - RWPI, - ROPIRWPI, -}; - -static Reloc::Model fromRust(LLVMRustRelocModel RustReloc) { - switch (RustReloc) { - case LLVMRustRelocModel::Static: - return Reloc::Static; - case LLVMRustRelocModel::PIC: - return Reloc::PIC_; - case LLVMRustRelocModel::DynamicNoPic: - return Reloc::DynamicNoPIC; - case LLVMRustRelocModel::ROPI: - return Reloc::ROPI; - case LLVMRustRelocModel::RWPI: - return Reloc::RWPI; - case LLVMRustRelocModel::ROPIRWPI: - return Reloc::ROPI_RWPI; - } - report_fatal_error("Bad RelocModel."); -} - -#ifdef LLVM_RUSTLLVM -/// getLongestEntryLength - Return the length of the longest entry in the table. -template<typename KV> -static size_t getLongestEntryLength(ArrayRef<KV> Table) { - size_t MaxLen = 0; - for (auto &I : Table) - MaxLen = std::max(MaxLen, std::strlen(I.Key)); - return MaxLen; -} - -extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef TM) { - const TargetMachine *Target = unwrap(TM); - const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo(); - const Triple::ArchType HostArch = Triple(sys::getProcessTriple()).getArch(); - const Triple::ArchType TargetArch = Target->getTargetTriple().getArch(); - const ArrayRef<SubtargetSubTypeKV> CPUTable = MCInfo->getCPUTable(); - unsigned MaxCPULen = getLongestEntryLength(CPUTable); - - printf("Available CPUs for this target:\n"); - if (HostArch == TargetArch) { - const StringRef HostCPU = sys::getHostCPUName(); - printf(" %-*s - Select the CPU of the current host (currently %.*s).\n", - MaxCPULen, "native", (int)HostCPU.size(), HostCPU.data()); - } - for (auto &CPU : CPUTable) - printf(" %-*s\n", MaxCPULen, CPU.Key); - printf("\n"); -} - -extern "C" void LLVMRustPrintTargetFeatures(LLVMTargetMachineRef TM) { - const TargetMachine *Target = unwrap(TM); - const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo(); - const ArrayRef<SubtargetFeatureKV> FeatTable = MCInfo->getFeatureTable(); - unsigned MaxFeatLen = getLongestEntryLength(FeatTable); - - printf("Available features for this target:\n"); - for (auto &Feature : FeatTable) - printf(" %-*s - %s.\n", MaxFeatLen, Feature.Key, Feature.Desc); - printf("\nRust-specific features:\n"); - printf(" %-*s - %s.\n", - MaxFeatLen, - "crt-static", - "Enables libraries with C Run-time Libraries(CRT) to be statically linked" - ); - printf("\n"); - - printf("Use +feature to enable a feature, or -feature to disable it.\n" - "For example, rustc -C -target-cpu=mycpu -C " - "target-feature=+feature1,-feature2\n\n"); -} - -#else - -extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef) { - printf("Target CPU help is not supported by this LLVM version.\n\n"); -} - -extern "C" void LLVMRustPrintTargetFeatures(LLVMTargetMachineRef) { - printf("Target features help is not supported by this LLVM version.\n\n"); -} -#endif - -extern "C" const char* LLVMRustGetHostCPUName(size_t *len) { - StringRef Name = sys::getHostCPUName(); - *len = Name.size(); - return Name.data(); -} - -extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( - const char *TripleStr, const char *CPU, const char *Feature, - const char *ABIStr, LLVMRustCodeModel RustCM, LLVMRustRelocModel RustReloc, - LLVMRustCodeGenOptLevel RustOptLevel, bool UseSoftFloat, - bool FunctionSections, - bool DataSections, - bool TrapUnreachable, - bool Singlethread, - bool AsmComments, - bool EmitStackSizeSection, - bool RelaxELFRelocations, - bool UseInitArray) { - - auto OptLevel = fromRust(RustOptLevel); - auto RM = fromRust(RustReloc); - auto CM = fromRust(RustCM); - - std::string Error; - Triple Trip(Triple::normalize(TripleStr)); - const llvm::Target *TheTarget = - TargetRegistry::lookupTarget(Trip.getTriple(), Error); - if (TheTarget == nullptr) { - LLVMRustSetLastError(Error.c_str()); - return nullptr; - } - - TargetOptions Options; - - Options.FloatABIType = FloatABI::Default; - if (UseSoftFloat) { - Options.FloatABIType = FloatABI::Soft; - } - Options.DataSections = DataSections; - Options.FunctionSections = FunctionSections; - Options.MCOptions.AsmVerbose = AsmComments; - Options.MCOptions.PreserveAsmComments = AsmComments; - Options.MCOptions.ABIName = ABIStr; - Options.RelaxELFRelocations = RelaxELFRelocations; - Options.UseInitArray = UseInitArray; - - if (TrapUnreachable) { - // Tell LLVM to codegen `unreachable` into an explicit trap instruction. - // This limits the extent of possible undefined behavior in some cases, as - // it prevents control flow from "falling through" into whatever code - // happens to be laid out next in memory. - Options.TrapUnreachable = true; - } - - if (Singlethread) { - Options.ThreadModel = ThreadModel::Single; - } - - Options.EmitStackSizeSection = EmitStackSizeSection; - - TargetMachine *TM = TheTarget->createTargetMachine( - Trip.getTriple(), CPU, Feature, Options, RM, CM, OptLevel); - return wrap(TM); -} - -extern "C" void LLVMRustDisposeTargetMachine(LLVMTargetMachineRef TM) { - delete unwrap(TM); -} - -extern "C" void LLVMRustConfigurePassManagerBuilder( - LLVMPassManagerBuilderRef PMBR, LLVMRustCodeGenOptLevel OptLevel, - bool MergeFunctions, bool SLPVectorize, bool LoopVectorize, bool PrepareForThinLTO, - const char* PGOGenPath, const char* PGOUsePath) { - unwrap(PMBR)->MergeFunctions = MergeFunctions; - unwrap(PMBR)->SLPVectorize = SLPVectorize; - unwrap(PMBR)->OptLevel = fromRust(OptLevel); - unwrap(PMBR)->LoopVectorize = LoopVectorize; - unwrap(PMBR)->PrepareForThinLTO = PrepareForThinLTO; - - if (PGOGenPath) { - assert(!PGOUsePath); - unwrap(PMBR)->EnablePGOInstrGen = true; - unwrap(PMBR)->PGOInstrGen = PGOGenPath; - } - if (PGOUsePath) { - assert(!PGOGenPath); - unwrap(PMBR)->PGOInstrUse = PGOUsePath; - } -} - -// Unfortunately, the LLVM C API doesn't provide a way to set the `LibraryInfo` -// field of a PassManagerBuilder, we expose our own method of doing so. -extern "C" void LLVMRustAddBuilderLibraryInfo(LLVMPassManagerBuilderRef PMBR, - LLVMModuleRef M, - bool DisableSimplifyLibCalls) { - Triple TargetTriple(unwrap(M)->getTargetTriple()); - TargetLibraryInfoImpl *TLI = new TargetLibraryInfoImpl(TargetTriple); - if (DisableSimplifyLibCalls) - TLI->disableAllFunctions(); - unwrap(PMBR)->LibraryInfo = TLI; -} - -// Unfortunately, the LLVM C API doesn't provide a way to create the -// TargetLibraryInfo pass, so we use this method to do so. -extern "C" void LLVMRustAddLibraryInfo(LLVMPassManagerRef PMR, LLVMModuleRef M, - bool DisableSimplifyLibCalls) { - Triple TargetTriple(unwrap(M)->getTargetTriple()); - TargetLibraryInfoImpl TLII(TargetTriple); - if (DisableSimplifyLibCalls) - TLII.disableAllFunctions(); - unwrap(PMR)->add(new TargetLibraryInfoWrapperPass(TLII)); -} - -// Unfortunately, the LLVM C API doesn't provide an easy way of iterating over -// all the functions in a module, so we do that manually here. You'll find -// similar code in clang's BackendUtil.cpp file. -extern "C" void LLVMRustRunFunctionPassManager(LLVMPassManagerRef PMR, - LLVMModuleRef M) { - llvm::legacy::FunctionPassManager *P = - unwrap<llvm::legacy::FunctionPassManager>(PMR); - P->doInitialization(); - - // Upgrade all calls to old intrinsics first. - for (Module::iterator I = unwrap(M)->begin(), E = unwrap(M)->end(); I != E;) - UpgradeCallsToIntrinsic(&*I++); // must be post-increment, as we remove - - for (Module::iterator I = unwrap(M)->begin(), E = unwrap(M)->end(); I != E; - ++I) - if (!I->isDeclaration()) - P->run(*I); - - P->doFinalization(); -} - -extern "C" void LLVMRustSetLLVMOptions(int Argc, char **Argv) { - // Initializing the command-line options more than once is not allowed. So, - // check if they've already been initialized. (This could happen if we're - // being called from rustpkg, for example). If the arguments change, then - // that's just kinda unfortunate. - static bool Initialized = false; - if (Initialized) - return; - Initialized = true; - cl::ParseCommandLineOptions(Argc, Argv); -} - -enum class LLVMRustFileType { - AssemblyFile, - ObjectFile, -}; - -#if LLVM_VERSION_GE(10, 0) -static CodeGenFileType fromRust(LLVMRustFileType Type) { - switch (Type) { - case LLVMRustFileType::AssemblyFile: - return CGFT_AssemblyFile; - case LLVMRustFileType::ObjectFile: - return CGFT_ObjectFile; - default: - report_fatal_error("Bad FileType."); - } -} -#else -static TargetMachine::CodeGenFileType fromRust(LLVMRustFileType Type) { - switch (Type) { - case LLVMRustFileType::AssemblyFile: - return TargetMachine::CGFT_AssemblyFile; - case LLVMRustFileType::ObjectFile: - return TargetMachine::CGFT_ObjectFile; - default: - report_fatal_error("Bad FileType."); - } -} -#endif - -extern "C" LLVMRustResult -LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMPassManagerRef PMR, - LLVMModuleRef M, const char *Path, - LLVMRustFileType RustFileType) { - llvm::legacy::PassManager *PM = unwrap<llvm::legacy::PassManager>(PMR); - auto FileType = fromRust(RustFileType); - - std::string ErrorInfo; - std::error_code EC; - raw_fd_ostream OS(Path, EC, sys::fs::F_None); - if (EC) - ErrorInfo = EC.message(); - if (ErrorInfo != "") { - LLVMRustSetLastError(ErrorInfo.c_str()); - return LLVMRustResult::Failure; - } - - buffer_ostream BOS(OS); - unwrap(Target)->addPassesToEmitFile(*PM, BOS, nullptr, FileType, false); - PM->run(*unwrap(M)); - - // Apparently `addPassesToEmitFile` adds a pointer to our on-the-stack output - // stream (OS), so the only real safe place to delete this is here? Don't we - // wish this was written in Rust? - LLVMDisposePassManager(PMR); - return LLVMRustResult::Success; -} - -extern "C" typedef void (*LLVMRustSelfProfileBeforePassCallback)(void*, // LlvmSelfProfiler - const char*, // pass name - const char*); // IR name -extern "C" typedef void (*LLVMRustSelfProfileAfterPassCallback)(void*); // LlvmSelfProfiler - -#if LLVM_VERSION_GE(9, 0) - -std::string LLVMRustwrappedIrGetName(const llvm::Any &WrappedIr) { - if (any_isa<const Module *>(WrappedIr)) - return any_cast<const Module *>(WrappedIr)->getName().str(); - if (any_isa<const Function *>(WrappedIr)) - return any_cast<const Function *>(WrappedIr)->getName().str(); - if (any_isa<const Loop *>(WrappedIr)) - return any_cast<const Loop *>(WrappedIr)->getName().str(); - if (any_isa<const LazyCallGraph::SCC *>(WrappedIr)) - return any_cast<const LazyCallGraph::SCC *>(WrappedIr)->getName(); - return "<UNKNOWN>"; -} - - -void LLVMSelfProfileInitializeCallbacks( - PassInstrumentationCallbacks& PIC, void* LlvmSelfProfiler, - LLVMRustSelfProfileBeforePassCallback BeforePassCallback, - LLVMRustSelfProfileAfterPassCallback AfterPassCallback) { - PIC.registerBeforePassCallback([LlvmSelfProfiler, BeforePassCallback]( - StringRef Pass, llvm::Any Ir) { - std::string PassName = Pass.str(); - std::string IrName = LLVMRustwrappedIrGetName(Ir); - BeforePassCallback(LlvmSelfProfiler, PassName.c_str(), IrName.c_str()); - return true; - }); - - PIC.registerAfterPassCallback( - [LlvmSelfProfiler, AfterPassCallback](StringRef Pass, llvm::Any Ir) { - AfterPassCallback(LlvmSelfProfiler); - }); - - PIC.registerAfterPassInvalidatedCallback( - [LlvmSelfProfiler, AfterPassCallback](StringRef Pass) { - AfterPassCallback(LlvmSelfProfiler); - }); - - PIC.registerBeforeAnalysisCallback([LlvmSelfProfiler, BeforePassCallback]( - StringRef Pass, llvm::Any Ir) { - std::string PassName = Pass.str(); - std::string IrName = LLVMRustwrappedIrGetName(Ir); - BeforePassCallback(LlvmSelfProfiler, PassName.c_str(), IrName.c_str()); - }); - - PIC.registerAfterAnalysisCallback( - [LlvmSelfProfiler, AfterPassCallback](StringRef Pass, llvm::Any Ir) { - AfterPassCallback(LlvmSelfProfiler); - }); -} -#endif - -enum class LLVMRustOptStage { - PreLinkNoLTO, - PreLinkThinLTO, - PreLinkFatLTO, - ThinLTO, - FatLTO, -}; - -struct LLVMRustSanitizerOptions { - bool SanitizeAddress; - bool SanitizeAddressRecover; - bool SanitizeMemory; - bool SanitizeMemoryRecover; - int SanitizeMemoryTrackOrigins; - bool SanitizeThread; -}; - -extern "C" void -LLVMRustOptimizeWithNewPassManager( - LLVMModuleRef ModuleRef, - LLVMTargetMachineRef TMRef, - LLVMRustPassBuilderOptLevel OptLevelRust, - LLVMRustOptStage OptStage, - bool NoPrepopulatePasses, bool VerifyIR, bool UseThinLTOBuffers, - bool MergeFunctions, bool UnrollLoops, bool SLPVectorize, bool LoopVectorize, - bool DisableSimplifyLibCalls, bool EmitLifetimeMarkers, - LLVMRustSanitizerOptions *SanitizerOptions, - const char *PGOGenPath, const char *PGOUsePath, - void* LlvmSelfProfiler, - LLVMRustSelfProfileBeforePassCallback BeforePassCallback, - LLVMRustSelfProfileAfterPassCallback AfterPassCallback) { -#if LLVM_VERSION_GE(9, 0) - Module *TheModule = unwrap(ModuleRef); - TargetMachine *TM = unwrap(TMRef); - PassBuilder::OptimizationLevel OptLevel = fromRust(OptLevelRust); - - // FIXME: MergeFunctions is not supported by NewPM yet. - (void) MergeFunctions; - - PipelineTuningOptions PTO; - PTO.LoopUnrolling = UnrollLoops; - PTO.LoopInterleaving = UnrollLoops; - PTO.LoopVectorization = LoopVectorize; - PTO.SLPVectorization = SLPVectorize; - - PassInstrumentationCallbacks PIC; - StandardInstrumentations SI; - SI.registerCallbacks(PIC); - - if (LlvmSelfProfiler){ - LLVMSelfProfileInitializeCallbacks(PIC,LlvmSelfProfiler,BeforePassCallback,AfterPassCallback); - } - - Optional<PGOOptions> PGOOpt; - if (PGOGenPath) { - assert(!PGOUsePath); - PGOOpt = PGOOptions(PGOGenPath, "", "", PGOOptions::IRInstr); - } else if (PGOUsePath) { - assert(!PGOGenPath); - PGOOpt = PGOOptions(PGOUsePath, "", "", PGOOptions::IRUse); - } - - PassBuilder PB(TM, PTO, PGOOpt, &PIC); - - // FIXME: We may want to expose this as an option. - bool DebugPassManager = false; - LoopAnalysisManager LAM(DebugPassManager); - FunctionAnalysisManager FAM(DebugPassManager); - CGSCCAnalysisManager CGAM(DebugPassManager); - ModuleAnalysisManager MAM(DebugPassManager); - - FAM.registerPass([&] { return PB.buildDefaultAAPipeline(); }); - - Triple TargetTriple(TheModule->getTargetTriple()); - std::unique_ptr<TargetLibraryInfoImpl> TLII(new TargetLibraryInfoImpl(TargetTriple)); - if (DisableSimplifyLibCalls) - TLII->disableAllFunctions(); - FAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); }); - - PB.registerModuleAnalyses(MAM); - PB.registerCGSCCAnalyses(CGAM); - PB.registerFunctionAnalyses(FAM); - PB.registerLoopAnalyses(LAM); - PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); - - // We manually collect pipeline callbacks so we can apply them at O0, where the - // PassBuilder does not create a pipeline. - std::vector<std::function<void(ModulePassManager &)>> PipelineStartEPCallbacks; -#if LLVM_VERSION_GE(11, 0) - std::vector<std::function<void(ModulePassManager &, PassBuilder::OptimizationLevel)>> - OptimizerLastEPCallbacks; -#else - std::vector<std::function<void(FunctionPassManager &, PassBuilder::OptimizationLevel)>> - OptimizerLastEPCallbacks; -#endif - - if (VerifyIR) { - PipelineStartEPCallbacks.push_back([VerifyIR](ModulePassManager &MPM) { - MPM.addPass(VerifierPass()); - }); - } - - if (SanitizerOptions) { - if (SanitizerOptions->SanitizeMemory) { - MemorySanitizerOptions Options( - SanitizerOptions->SanitizeMemoryTrackOrigins, - SanitizerOptions->SanitizeMemoryRecover, - /*CompileKernel=*/false); -#if LLVM_VERSION_GE(11, 0) - OptimizerLastEPCallbacks.push_back( - [Options](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) { - MPM.addPass(MemorySanitizerPass(Options)); - MPM.addPass(createModuleToFunctionPassAdaptor(MemorySanitizerPass(Options))); - } - ); -#else -#if LLVM_VERSION_GE(10, 0) - PipelineStartEPCallbacks.push_back([Options](ModulePassManager &MPM) { - MPM.addPass(MemorySanitizerPass(Options)); - }); -#endif - OptimizerLastEPCallbacks.push_back( - [Options](FunctionPassManager &FPM, PassBuilder::OptimizationLevel Level) { - FPM.addPass(MemorySanitizerPass(Options)); - } - ); -#endif - } - - if (SanitizerOptions->SanitizeThread) { -#if LLVM_VERSION_GE(11, 0) - OptimizerLastEPCallbacks.push_back( - [](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) { - MPM.addPass(ThreadSanitizerPass()); - MPM.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass())); - } - ); -#else -#if LLVM_VERSION_GE(10, 0) - PipelineStartEPCallbacks.push_back([](ModulePassManager &MPM) { - MPM.addPass(ThreadSanitizerPass()); - }); -#endif - OptimizerLastEPCallbacks.push_back( - [](FunctionPassManager &FPM, PassBuilder::OptimizationLevel Level) { - FPM.addPass(ThreadSanitizerPass()); - } - ); -#endif - } - - if (SanitizerOptions->SanitizeAddress) { -#if LLVM_VERSION_GE(11, 0) - OptimizerLastEPCallbacks.push_back( - [SanitizerOptions](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) { - MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>()); - MPM.addPass(ModuleAddressSanitizerPass( - /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover)); - MPM.addPass(createModuleToFunctionPassAdaptor(AddressSanitizerPass( - /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover, - /*UseAfterScope=*/true))); - } - ); -#else - PipelineStartEPCallbacks.push_back([&](ModulePassManager &MPM) { - MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>()); - }); - OptimizerLastEPCallbacks.push_back( - [SanitizerOptions](FunctionPassManager &FPM, PassBuilder::OptimizationLevel Level) { - FPM.addPass(AddressSanitizerPass( - /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover, - /*UseAfterScope=*/true)); - } - ); - PipelineStartEPCallbacks.push_back( - [SanitizerOptions](ModulePassManager &MPM) { - MPM.addPass(ModuleAddressSanitizerPass( - /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover)); - } - ); -#endif - } - } - - ModulePassManager MPM(DebugPassManager); - if (!NoPrepopulatePasses) { - if (OptLevel == PassBuilder::OptimizationLevel::O0) { - for (const auto &C : PipelineStartEPCallbacks) - C(MPM); - -#if LLVM_VERSION_GE(11, 0) - for (const auto &C : OptimizerLastEPCallbacks) - C(MPM, OptLevel); -#else - if (!OptimizerLastEPCallbacks.empty()) { - FunctionPassManager FPM(DebugPassManager); - for (const auto &C : OptimizerLastEPCallbacks) - C(FPM, OptLevel); - MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); - } -#endif - - MPM.addPass(AlwaysInlinerPass(EmitLifetimeMarkers)); - -#if LLVM_VERSION_GE(10, 0) - if (PGOOpt) { - PB.addPGOInstrPassesForO0( - MPM, DebugPassManager, PGOOpt->Action == PGOOptions::IRInstr, - /*IsCS=*/false, PGOOpt->ProfileFile, PGOOpt->ProfileRemappingFile); - } -#endif - } else { - for (const auto &C : PipelineStartEPCallbacks) - PB.registerPipelineStartEPCallback(C); - if (OptStage != LLVMRustOptStage::PreLinkThinLTO) { - for (const auto &C : OptimizerLastEPCallbacks) - PB.registerOptimizerLastEPCallback(C); - } - - switch (OptStage) { - case LLVMRustOptStage::PreLinkNoLTO: - MPM = PB.buildPerModuleDefaultPipeline(OptLevel, DebugPassManager); - break; - case LLVMRustOptStage::PreLinkThinLTO: - MPM = PB.buildThinLTOPreLinkDefaultPipeline(OptLevel, DebugPassManager); -#if LLVM_VERSION_GE(11, 0) - for (const auto &C : OptimizerLastEPCallbacks) - C(MPM, OptLevel); -#else - if (!OptimizerLastEPCallbacks.empty()) { - FunctionPassManager FPM(DebugPassManager); - for (const auto &C : OptimizerLastEPCallbacks) - C(FPM, OptLevel); - MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); - } -#endif - break; - case LLVMRustOptStage::PreLinkFatLTO: - MPM = PB.buildLTOPreLinkDefaultPipeline(OptLevel, DebugPassManager); - break; - case LLVMRustOptStage::ThinLTO: - // FIXME: Does it make sense to pass the ModuleSummaryIndex? - // It only seems to be needed for C++ specific optimizations. - MPM = PB.buildThinLTODefaultPipeline(OptLevel, DebugPassManager, nullptr); - break; - case LLVMRustOptStage::FatLTO: - MPM = PB.buildLTODefaultPipeline(OptLevel, DebugPassManager, nullptr); - break; - } - } - } - - if (UseThinLTOBuffers) { - MPM.addPass(CanonicalizeAliasesPass()); - MPM.addPass(NameAnonGlobalPass()); - } - - // Upgrade all calls to old intrinsics first. - for (Module::iterator I = TheModule->begin(), E = TheModule->end(); I != E;) - UpgradeCallsToIntrinsic(&*I++); // must be post-increment, as we remove - - MPM.run(*TheModule, MAM); -#else - // The new pass manager has been available for a long time, - // but we don't bother supporting it on old LLVM versions. - report_fatal_error("New pass manager only supported since LLVM 9"); -#endif -} - -// Callback to demangle function name -// Parameters: -// * name to be demangled -// * name len -// * output buffer -// * output buffer len -// Returns len of demangled string, or 0 if demangle failed. -typedef size_t (*DemangleFn)(const char*, size_t, char*, size_t); - - -namespace { - -class RustAssemblyAnnotationWriter : public AssemblyAnnotationWriter { - DemangleFn Demangle; - std::vector<char> Buf; - -public: - RustAssemblyAnnotationWriter(DemangleFn Demangle) : Demangle(Demangle) {} - - // Return empty string if demangle failed - // or if name does not need to be demangled - StringRef CallDemangle(StringRef name) { - if (!Demangle) { - return StringRef(); - } - - if (Buf.size() < name.size() * 2) { - // Semangled name usually shorter than mangled, - // but allocate twice as much memory just in case - Buf.resize(name.size() * 2); - } - - auto R = Demangle(name.data(), name.size(), Buf.data(), Buf.size()); - if (!R) { - // Demangle failed. - return StringRef(); - } - - auto Demangled = StringRef(Buf.data(), R); - if (Demangled == name) { - // Do not print anything if demangled name is equal to mangled. - return StringRef(); - } - - return Demangled; - } - - void emitFunctionAnnot(const Function *F, - formatted_raw_ostream &OS) override { - StringRef Demangled = CallDemangle(F->getName()); - if (Demangled.empty()) { - return; - } - - OS << "; " << Demangled << "\n"; - } - - void emitInstructionAnnot(const Instruction *I, - formatted_raw_ostream &OS) override { - const char *Name; - const Value *Value; - if (const CallInst *CI = dyn_cast<CallInst>(I)) { - Name = "call"; - Value = CI->getCalledOperand(); - } else if (const InvokeInst* II = dyn_cast<InvokeInst>(I)) { - Name = "invoke"; - Value = II->getCalledOperand(); - } else { - // Could demangle more operations, e. g. - // `store %place, @function`. - return; - } - - if (!Value->hasName()) { - return; - } - - StringRef Demangled = CallDemangle(Value->getName()); - if (Demangled.empty()) { - return; - } - - OS << "; " << Name << " " << Demangled << "\n"; - } -}; - -} // namespace - -extern "C" LLVMRustResult -LLVMRustPrintModule(LLVMModuleRef M, const char *Path, DemangleFn Demangle) { - std::string ErrorInfo; - std::error_code EC; - raw_fd_ostream OS(Path, EC, sys::fs::F_None); - if (EC) - ErrorInfo = EC.message(); - if (ErrorInfo != "") { - LLVMRustSetLastError(ErrorInfo.c_str()); - return LLVMRustResult::Failure; - } - - RustAssemblyAnnotationWriter AAW(Demangle); - formatted_raw_ostream FOS(OS); - unwrap(M)->print(FOS, &AAW); - - return LLVMRustResult::Success; -} - -extern "C" void LLVMRustPrintPasses() { - LLVMInitializePasses(); - struct MyListener : PassRegistrationListener { - void passEnumerate(const PassInfo *Info) { - StringRef PassArg = Info->getPassArgument(); - StringRef PassName = Info->getPassName(); - if (!PassArg.empty()) { - // These unsigned->signed casts could theoretically overflow, but - // realistically never will (and even if, the result is implementation - // defined rather plain UB). - printf("%15.*s - %.*s\n", (int)PassArg.size(), PassArg.data(), - (int)PassName.size(), PassName.data()); - } - } - } Listener; - - PassRegistry *PR = PassRegistry::getPassRegistry(); - PR->enumerateWith(&Listener); -} - -extern "C" void LLVMRustAddAlwaysInlinePass(LLVMPassManagerBuilderRef PMBR, - bool AddLifetimes) { - unwrap(PMBR)->Inliner = llvm::createAlwaysInlinerLegacyPass(AddLifetimes); -} - -extern "C" void LLVMRustRunRestrictionPass(LLVMModuleRef M, char **Symbols, - size_t Len) { - llvm::legacy::PassManager passes; - - auto PreserveFunctions = [=](const GlobalValue &GV) { - for (size_t I = 0; I < Len; I++) { - if (GV.getName() == Symbols[I]) { - return true; - } - } - return false; - }; - - passes.add(llvm::createInternalizePass(PreserveFunctions)); - - passes.run(*unwrap(M)); -} - -extern "C" void LLVMRustMarkAllFunctionsNounwind(LLVMModuleRef M) { - for (Module::iterator GV = unwrap(M)->begin(), E = unwrap(M)->end(); GV != E; - ++GV) { - GV->setDoesNotThrow(); - Function *F = dyn_cast<Function>(GV); - if (F == nullptr) - continue; - - for (Function::iterator B = F->begin(), BE = F->end(); B != BE; ++B) { - for (BasicBlock::iterator I = B->begin(), IE = B->end(); I != IE; ++I) { - if (isa<InvokeInst>(I)) { - InvokeInst *CI = cast<InvokeInst>(I); - CI->setDoesNotThrow(); - } - } - } - } -} - -extern "C" void -LLVMRustSetDataLayoutFromTargetMachine(LLVMModuleRef Module, - LLVMTargetMachineRef TMR) { - TargetMachine *Target = unwrap(TMR); - unwrap(Module)->setDataLayout(Target->createDataLayout()); -} - -extern "C" void LLVMRustSetModulePICLevel(LLVMModuleRef M) { - unwrap(M)->setPICLevel(PICLevel::Level::BigPIC); -} - -extern "C" void LLVMRustSetModulePIELevel(LLVMModuleRef M) { - unwrap(M)->setPIELevel(PIELevel::Level::Large); -} - -// Here you'll find an implementation of ThinLTO as used by the Rust compiler -// right now. This ThinLTO support is only enabled on "recent ish" versions of -// LLVM, and otherwise it's just blanket rejected from other compilers. -// -// Most of this implementation is straight copied from LLVM. At the time of -// this writing it wasn't *quite* suitable to reuse more code from upstream -// for our purposes, but we should strive to upstream this support once it's -// ready to go! I figure we may want a bit of testing locally first before -// sending this upstream to LLVM. I hear though they're quite eager to receive -// feedback like this! -// -// If you're reading this code and wondering "what in the world" or you're -// working "good lord by LLVM upgrade is *still* failing due to these bindings" -// then fear not! (ok maybe fear a little). All code here is mostly based -// on `lib/LTO/ThinLTOCodeGenerator.cpp` in LLVM. -// -// You'll find that the general layout here roughly corresponds to the `run` -// method in that file as well as `ProcessThinLTOModule`. Functions are -// specifically commented below as well, but if you're updating this code -// or otherwise trying to understand it, the LLVM source will be useful in -// interpreting the mysteries within. -// -// Otherwise I'll apologize in advance, it probably requires a relatively -// significant investment on your part to "truly understand" what's going on -// here. Not saying I do myself, but it took me awhile staring at LLVM's source -// and various online resources about ThinLTO to make heads or tails of all -// this. - -// This is a shared data structure which *must* be threadsafe to share -// read-only amongst threads. This also corresponds basically to the arguments -// of the `ProcessThinLTOModule` function in the LLVM source. -struct LLVMRustThinLTOData { - // The combined index that is the global analysis over all modules we're - // performing ThinLTO for. This is mostly managed by LLVM. - ModuleSummaryIndex Index; - - // All modules we may look at, stored as in-memory serialized versions. This - // is later used when inlining to ensure we can extract any module to inline - // from. - StringMap<MemoryBufferRef> ModuleMap; - - // A set that we manage of everything we *don't* want internalized. Note that - // this includes all transitive references right now as well, but it may not - // always! - DenseSet<GlobalValue::GUID> GUIDPreservedSymbols; - - // Not 100% sure what these are, but they impact what's internalized and - // what's inlined across modules, I believe. - StringMap<FunctionImporter::ImportMapTy> ImportLists; - StringMap<FunctionImporter::ExportSetTy> ExportLists; - StringMap<GVSummaryMapTy> ModuleToDefinedGVSummaries; - - LLVMRustThinLTOData() : Index(/* HaveGVs = */ false) {} -}; - -// Just an argument to the `LLVMRustCreateThinLTOData` function below. -struct LLVMRustThinLTOModule { - const char *identifier; - const char *data; - size_t len; -}; - -// This is copied from `lib/LTO/ThinLTOCodeGenerator.cpp`, not sure what it -// does. -static const GlobalValueSummary * -getFirstDefinitionForLinker(const GlobalValueSummaryList &GVSummaryList) { - auto StrongDefForLinker = llvm::find_if( - GVSummaryList, [](const std::unique_ptr<GlobalValueSummary> &Summary) { - auto Linkage = Summary->linkage(); - return !GlobalValue::isAvailableExternallyLinkage(Linkage) && - !GlobalValue::isWeakForLinker(Linkage); - }); - if (StrongDefForLinker != GVSummaryList.end()) - return StrongDefForLinker->get(); - - auto FirstDefForLinker = llvm::find_if( - GVSummaryList, [](const std::unique_ptr<GlobalValueSummary> &Summary) { - auto Linkage = Summary->linkage(); - return !GlobalValue::isAvailableExternallyLinkage(Linkage); - }); - if (FirstDefForLinker == GVSummaryList.end()) - return nullptr; - return FirstDefForLinker->get(); -} - -// The main entry point for creating the global ThinLTO analysis. The structure -// here is basically the same as before threads are spawned in the `run` -// function of `lib/LTO/ThinLTOCodeGenerator.cpp`. -extern "C" LLVMRustThinLTOData* -LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, - int num_modules, - const char **preserved_symbols, - int num_symbols) { -#if LLVM_VERSION_GE(10, 0) - auto Ret = std::make_unique<LLVMRustThinLTOData>(); -#else - auto Ret = llvm::make_unique<LLVMRustThinLTOData>(); -#endif - - // Load each module's summary and merge it into one combined index - for (int i = 0; i < num_modules; i++) { - auto module = &modules[i]; - StringRef buffer(module->data, module->len); - MemoryBufferRef mem_buffer(buffer, module->identifier); - - Ret->ModuleMap[module->identifier] = mem_buffer; - - if (Error Err = readModuleSummaryIndex(mem_buffer, Ret->Index, i)) { - LLVMRustSetLastError(toString(std::move(Err)).c_str()); - return nullptr; - } - } - - // Collect for each module the list of function it defines (GUID -> Summary) - Ret->Index.collectDefinedGVSummariesPerModule(Ret->ModuleToDefinedGVSummaries); - - // Convert the preserved symbols set from string to GUID, this is then needed - // for internalization. - for (int i = 0; i < num_symbols; i++) { - auto GUID = GlobalValue::getGUID(preserved_symbols[i]); - Ret->GUIDPreservedSymbols.insert(GUID); - } - - // Collect the import/export lists for all modules from the call-graph in the - // combined index - // - // This is copied from `lib/LTO/ThinLTOCodeGenerator.cpp` - auto deadIsPrevailing = [&](GlobalValue::GUID G) { - return PrevailingType::Unknown; - }; - // We don't have a complete picture in our use of ThinLTO, just our immediate - // crate, so we need `ImportEnabled = false` to limit internalization. - // Otherwise, we sometimes lose `static` values -- see #60184. - computeDeadSymbolsWithConstProp(Ret->Index, Ret->GUIDPreservedSymbols, - deadIsPrevailing, /* ImportEnabled = */ false); - ComputeCrossModuleImport( - Ret->Index, - Ret->ModuleToDefinedGVSummaries, - Ret->ImportLists, - Ret->ExportLists - ); - - // Resolve LinkOnce/Weak symbols, this has to be computed early be cause it - // impacts the caching. - // - // This is copied from `lib/LTO/ThinLTOCodeGenerator.cpp` with some of this - // being lifted from `lib/LTO/LTO.cpp` as well - StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR; - DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy; - for (auto &I : Ret->Index) { - if (I.second.SummaryList.size() > 1) - PrevailingCopy[I.first] = getFirstDefinitionForLinker(I.second.SummaryList); - } - auto isPrevailing = [&](GlobalValue::GUID GUID, const GlobalValueSummary *S) { - const auto &Prevailing = PrevailingCopy.find(GUID); - if (Prevailing == PrevailingCopy.end()) - return true; - return Prevailing->second == S; - }; - auto recordNewLinkage = [&](StringRef ModuleIdentifier, - GlobalValue::GUID GUID, - GlobalValue::LinkageTypes NewLinkage) { - ResolvedODR[ModuleIdentifier][GUID] = NewLinkage; - }; -#if LLVM_VERSION_GE(9, 0) - thinLTOResolvePrevailingInIndex(Ret->Index, isPrevailing, recordNewLinkage, - Ret->GUIDPreservedSymbols); -#else - thinLTOResolvePrevailingInIndex(Ret->Index, isPrevailing, recordNewLinkage); -#endif - - // Here we calculate an `ExportedGUIDs` set for use in the `isExported` - // callback below. This callback below will dictate the linkage for all - // summaries in the index, and we basically just only want to ensure that dead - // symbols are internalized. Otherwise everything that's already external - // linkage will stay as external, and internal will stay as internal. - std::set<GlobalValue::GUID> ExportedGUIDs; - for (auto &List : Ret->Index) { - for (auto &GVS: List.second.SummaryList) { - if (GlobalValue::isLocalLinkage(GVS->linkage())) - continue; - auto GUID = GVS->getOriginalName(); - if (GVS->flags().Live) - ExportedGUIDs.insert(GUID); - } - } -#if LLVM_VERSION_GE(10, 0) - auto isExported = [&](StringRef ModuleIdentifier, ValueInfo VI) { - const auto &ExportList = Ret->ExportLists.find(ModuleIdentifier); - return (ExportList != Ret->ExportLists.end() && - ExportList->second.count(VI)) || - ExportedGUIDs.count(VI.getGUID()); - }; - thinLTOInternalizeAndPromoteInIndex(Ret->Index, isExported, isPrevailing); -#else - auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) { - const auto &ExportList = Ret->ExportLists.find(ModuleIdentifier); - return (ExportList != Ret->ExportLists.end() && - ExportList->second.count(GUID)) || - ExportedGUIDs.count(GUID); - }; - thinLTOInternalizeAndPromoteInIndex(Ret->Index, isExported); -#endif - - return Ret.release(); -} - -extern "C" void -LLVMRustFreeThinLTOData(LLVMRustThinLTOData *Data) { - delete Data; -} - -// Below are the various passes that happen *per module* when doing ThinLTO. -// -// In other words, these are the functions that are all run concurrently -// with one another, one per module. The passes here correspond to the analysis -// passes in `lib/LTO/ThinLTOCodeGenerator.cpp`, currently found in the -// `ProcessThinLTOModule` function. Here they're split up into separate steps -// so rustc can save off the intermediate bytecode between each step. - -#if LLVM_VERSION_GE(11, 0) -static bool -clearDSOLocalOnDeclarations(Module &Mod, TargetMachine &TM) { - // When linking an ELF shared object, dso_local should be dropped. We - // conservatively do this for -fpic. - bool ClearDSOLocalOnDeclarations = - TM.getTargetTriple().isOSBinFormatELF() && - TM.getRelocationModel() != Reloc::Static && - Mod.getPIELevel() == PIELevel::Default; - return ClearDSOLocalOnDeclarations; -} -#endif - -extern "C" bool -LLVMRustPrepareThinLTORename(const LLVMRustThinLTOData *Data, LLVMModuleRef M, - LLVMTargetMachineRef TM) { - Module &Mod = *unwrap(M); - TargetMachine &Target = *unwrap(TM); - -#if LLVM_VERSION_GE(11, 0) - bool ClearDSOLocal = clearDSOLocalOnDeclarations(Mod, Target); - bool error = renameModuleForThinLTO(Mod, Data->Index, ClearDSOLocal); -#else - bool error = renameModuleForThinLTO(Mod, Data->Index); -#endif - - if (error) { - LLVMRustSetLastError("renameModuleForThinLTO failed"); - return false; - } - return true; -} - -extern "C" bool -LLVMRustPrepareThinLTOResolveWeak(const LLVMRustThinLTOData *Data, LLVMModuleRef M) { - Module &Mod = *unwrap(M); - const auto &DefinedGlobals = Data->ModuleToDefinedGVSummaries.lookup(Mod.getModuleIdentifier()); - thinLTOResolvePrevailingInModule(Mod, DefinedGlobals); - return true; -} - -extern "C" bool -LLVMRustPrepareThinLTOInternalize(const LLVMRustThinLTOData *Data, LLVMModuleRef M) { - Module &Mod = *unwrap(M); - const auto &DefinedGlobals = Data->ModuleToDefinedGVSummaries.lookup(Mod.getModuleIdentifier()); - thinLTOInternalizeModule(Mod, DefinedGlobals); - return true; -} - -extern "C" bool -LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data, LLVMModuleRef M, - LLVMTargetMachineRef TM) { - Module &Mod = *unwrap(M); - TargetMachine &Target = *unwrap(TM); - - const auto &ImportList = Data->ImportLists.lookup(Mod.getModuleIdentifier()); - auto Loader = [&](StringRef Identifier) { - const auto &Memory = Data->ModuleMap.lookup(Identifier); - auto &Context = Mod.getContext(); - auto MOrErr = getLazyBitcodeModule(Memory, Context, true, true); - - if (!MOrErr) - return MOrErr; - - // The rest of this closure is a workaround for - // https://bugs.llvm.org/show_bug.cgi?id=38184 where during ThinLTO imports - // we accidentally import wasm custom sections into different modules, - // duplicating them by in the final output artifact. - // - // The issue is worked around here by manually removing the - // `wasm.custom_sections` named metadata node from any imported module. This - // we know isn't used by any optimization pass so there's no need for it to - // be imported. - // - // Note that the metadata is currently lazily loaded, so we materialize it - // here before looking up if there's metadata inside. The `FunctionImporter` - // will immediately materialize metadata anyway after an import, so this - // shouldn't be a perf hit. - if (Error Err = (*MOrErr)->materializeMetadata()) { - Expected<std::unique_ptr<Module>> Ret(std::move(Err)); - return Ret; - } - - auto *WasmCustomSections = (*MOrErr)->getNamedMetadata("wasm.custom_sections"); - if (WasmCustomSections) - WasmCustomSections->eraseFromParent(); - - return MOrErr; - }; -#if LLVM_VERSION_GE(11, 0) - bool ClearDSOLocal = clearDSOLocalOnDeclarations(Mod, Target); - FunctionImporter Importer(Data->Index, Loader, ClearDSOLocal); -#else - FunctionImporter Importer(Data->Index, Loader); -#endif - Expected<bool> Result = Importer.importFunctions(Mod, ImportList); - if (!Result) { - LLVMRustSetLastError(toString(Result.takeError()).c_str()); - return false; - } - return true; -} - -extern "C" typedef void (*LLVMRustModuleNameCallback)(void*, // payload - const char*, // importing module name - const char*); // imported module name - -// Calls `module_name_callback` for each module import done by ThinLTO. -// The callback is provided with regular null-terminated C strings. -extern "C" void -LLVMRustGetThinLTOModuleImports(const LLVMRustThinLTOData *data, - LLVMRustModuleNameCallback module_name_callback, - void* callback_payload) { - for (const auto& importing_module : data->ImportLists) { - const std::string importing_module_id = importing_module.getKey().str(); - const auto& imports = importing_module.getValue(); - for (const auto& imported_module : imports) { - const std::string imported_module_id = imported_module.getKey().str(); - module_name_callback(callback_payload, - importing_module_id.c_str(), - imported_module_id.c_str()); - } - } -} - -// This struct and various functions are sort of a hack right now, but the -// problem is that we've got in-memory LLVM modules after we generate and -// optimize all codegen-units for one compilation in rustc. To be compatible -// with the LTO support above we need to serialize the modules plus their -// ThinLTO summary into memory. -// -// This structure is basically an owned version of a serialize module, with -// a ThinLTO summary attached. -struct LLVMRustThinLTOBuffer { - std::string data; -}; - -extern "C" LLVMRustThinLTOBuffer* -LLVMRustThinLTOBufferCreate(LLVMModuleRef M) { -#if LLVM_VERSION_GE(10, 0) - auto Ret = std::make_unique<LLVMRustThinLTOBuffer>(); -#else - auto Ret = llvm::make_unique<LLVMRustThinLTOBuffer>(); -#endif - { - raw_string_ostream OS(Ret->data); - { - legacy::PassManager PM; - PM.add(createWriteThinLTOBitcodePass(OS)); - PM.run(*unwrap(M)); - } - } - return Ret.release(); -} - -extern "C" void -LLVMRustThinLTOBufferFree(LLVMRustThinLTOBuffer *Buffer) { - delete Buffer; -} - -extern "C" const void* -LLVMRustThinLTOBufferPtr(const LLVMRustThinLTOBuffer *Buffer) { - return Buffer->data.data(); -} - -extern "C" size_t -LLVMRustThinLTOBufferLen(const LLVMRustThinLTOBuffer *Buffer) { - return Buffer->data.length(); -} - -// This is what we used to parse upstream bitcode for actual ThinLTO -// processing. We'll call this once per module optimized through ThinLTO, and -// it'll be called concurrently on many threads. -extern "C" LLVMModuleRef -LLVMRustParseBitcodeForLTO(LLVMContextRef Context, - const char *data, - size_t len, - const char *identifier) { - StringRef Data(data, len); - MemoryBufferRef Buffer(Data, identifier); - unwrap(Context)->enableDebugTypeODRUniquing(); - Expected<std::unique_ptr<Module>> SrcOrError = - parseBitcodeFile(Buffer, *unwrap(Context)); - if (!SrcOrError) { - LLVMRustSetLastError(toString(SrcOrError.takeError()).c_str()); - return nullptr; - } - return wrap(std::move(*SrcOrError).release()); -} - -// Find the bitcode section in the object file data and return it as a slice. -// Fail if the bitcode section is present but empty. -// -// On success, the return value is the pointer to the start of the slice and -// `out_len` is filled with the (non-zero) length. On failure, the return value -// is `nullptr` and `out_len` is set to zero. -extern "C" const char* -LLVMRustGetBitcodeSliceFromObjectData(const char *data, - size_t len, - size_t *out_len) { - *out_len = 0; - - StringRef Data(data, len); - MemoryBufferRef Buffer(Data, ""); // The id is unused. - - Expected<MemoryBufferRef> BitcodeOrError = - object::IRObjectFile::findBitcodeInMemBuffer(Buffer); - if (!BitcodeOrError) { - LLVMRustSetLastError(toString(BitcodeOrError.takeError()).c_str()); - return nullptr; - } - - *out_len = BitcodeOrError->getBufferSize(); - return BitcodeOrError->getBufferStart(); -} - -// Rewrite all `DICompileUnit` pointers to the `DICompileUnit` specified. See -// the comment in `back/lto.rs` for why this exists. -extern "C" void -LLVMRustThinLTOGetDICompileUnit(LLVMModuleRef Mod, - DICompileUnit **A, - DICompileUnit **B) { - Module *M = unwrap(Mod); - DICompileUnit **Cur = A; - DICompileUnit **Next = B; - for (DICompileUnit *CU : M->debug_compile_units()) { - *Cur = CU; - Cur = Next; - Next = nullptr; - if (Cur == nullptr) - break; - } -} - -// Rewrite all `DICompileUnit` pointers to the `DICompileUnit` specified. See -// the comment in `back/lto.rs` for why this exists. -extern "C" void -LLVMRustThinLTOPatchDICompileUnit(LLVMModuleRef Mod, DICompileUnit *Unit) { - Module *M = unwrap(Mod); - - // If the original source module didn't have a `DICompileUnit` then try to - // merge all the existing compile units. If there aren't actually any though - // then there's not much for us to do so return. - if (Unit == nullptr) { - for (DICompileUnit *CU : M->debug_compile_units()) { - Unit = CU; - break; - } - if (Unit == nullptr) - return; - } - - // Use LLVM's built-in `DebugInfoFinder` to find a bunch of debuginfo and - // process it recursively. Note that we used to specifically iterate over - // instructions to ensure we feed everything into it, but `processModule` - // started doing this the same way in LLVM 7 (commit d769eb36ab2b8). - DebugInfoFinder Finder; - Finder.processModule(*M); - - // After we've found all our debuginfo, rewrite all subprograms to point to - // the same `DICompileUnit`. - for (auto &F : Finder.subprograms()) { - F->replaceUnit(Unit); - } - - // Erase any other references to other `DICompileUnit` instances, the verifier - // will later ensure that we don't actually have any other stale references to - // worry about. - auto *MD = M->getNamedMetadata("llvm.dbg.cu"); - MD->clearOperands(); - MD->addOperand(Unit); -} diff --git a/src/rustllvm/README b/src/rustllvm/README deleted file mode 100644 index e1c6dd07d2b..00000000000 --- a/src/rustllvm/README +++ /dev/null @@ -1,16 +0,0 @@ -This directory currently contains some LLVM support code. This will generally -be sent upstream to LLVM in time; for now it lives here. - -NOTE: the LLVM C++ ABI is subject to between-version breakage and must *never* -be exposed to Rust. To allow for easy auditing of that, all Rust-exposed types -must be typedef-ed as "LLVMXyz", or "LLVMRustXyz" if they were defined here. - -Functions that return a failure status and leave the error in -the LLVM last error should return an LLVMRustResult rather than an -int or anything to avoid confusion. - -When translating enums, add a single `Other` variant as the first -one to allow for new variants to be added. It should abort when used -as an input. - -All other types must not be typedef-ed as such. diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp deleted file mode 100644 index 9d90b0dfe07..00000000000 --- a/src/rustllvm/RustWrapper.cpp +++ /dev/null @@ -1,1721 +0,0 @@ -#include "rustllvm.h" -#include "llvm/IR/DebugInfoMetadata.h" -#include "llvm/IR/DiagnosticInfo.h" -#include "llvm/IR/DiagnosticPrinter.h" -#include "llvm/IR/GlobalVariable.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/Intrinsics.h" -#include "llvm/Object/Archive.h" -#include "llvm/Object/ObjectFile.h" -#include "llvm/Bitcode/BitcodeWriterPass.h" -#include "llvm/Support/Signals.h" -#include "llvm/ADT/Optional.h" - -#include <iostream> - -//===----------------------------------------------------------------------=== -// -// This file defines alternate interfaces to core functions that are more -// readily callable by Rust's FFI. -// -//===----------------------------------------------------------------------=== - -using namespace llvm; -using namespace llvm::sys; -using namespace llvm::object; - -// LLVMAtomicOrdering is already an enum - don't create another -// one. -static AtomicOrdering fromRust(LLVMAtomicOrdering Ordering) { - switch (Ordering) { - case LLVMAtomicOrderingNotAtomic: - return AtomicOrdering::NotAtomic; - case LLVMAtomicOrderingUnordered: - return AtomicOrdering::Unordered; - case LLVMAtomicOrderingMonotonic: - return AtomicOrdering::Monotonic; - case LLVMAtomicOrderingAcquire: - return AtomicOrdering::Acquire; - case LLVMAtomicOrderingRelease: - return AtomicOrdering::Release; - case LLVMAtomicOrderingAcquireRelease: - return AtomicOrdering::AcquireRelease; - case LLVMAtomicOrderingSequentiallyConsistent: - return AtomicOrdering::SequentiallyConsistent; - } - - report_fatal_error("Invalid LLVMAtomicOrdering value!"); -} - -static LLVM_THREAD_LOCAL char *LastError; - -// Custom error handler for fatal LLVM errors. -// -// Notably it exits the process with code 101, unlike LLVM's default of 1. -static void FatalErrorHandler(void *UserData, - const std::string& Reason, - bool GenCrashDiag) { - // Do the same thing that the default error handler does. - std::cerr << "LLVM ERROR: " << Reason << std::endl; - - // Since this error handler exits the process, we have to run any cleanup that - // LLVM would run after handling the error. This might change with an LLVM - // upgrade. - sys::RunInterruptHandlers(); - - exit(101); -} - -extern "C" void LLVMRustInstallFatalErrorHandler() { - install_fatal_error_handler(FatalErrorHandler); -} - -extern "C" LLVMMemoryBufferRef -LLVMRustCreateMemoryBufferWithContentsOfFile(const char *Path) { - ErrorOr<std::unique_ptr<MemoryBuffer>> BufOr = - MemoryBuffer::getFile(Path, -1, false); - if (!BufOr) { - LLVMRustSetLastError(BufOr.getError().message().c_str()); - return nullptr; - } - return wrap(BufOr.get().release()); -} - -extern "C" char *LLVMRustGetLastError(void) { - char *Ret = LastError; - LastError = nullptr; - return Ret; -} - -extern "C" unsigned int LLVMRustGetInstructionCount(LLVMModuleRef M) { - return unwrap(M)->getInstructionCount(); -} - -extern "C" void LLVMRustSetLastError(const char *Err) { - free((void *)LastError); - LastError = strdup(Err); -} - -extern "C" LLVMContextRef LLVMRustContextCreate(bool shouldDiscardNames) { - auto ctx = new LLVMContext(); - ctx->setDiscardValueNames(shouldDiscardNames); - return wrap(ctx); -} - -extern "C" void LLVMRustSetNormalizedTarget(LLVMModuleRef M, - const char *Triple) { - unwrap(M)->setTargetTriple(Triple::normalize(Triple)); -} - -extern "C" void LLVMRustPrintPassTimings() { - raw_fd_ostream OS(2, false); // stderr. - TimerGroup::printAll(OS); -} - -extern "C" LLVMValueRef LLVMRustGetNamedValue(LLVMModuleRef M, const char *Name, - size_t NameLen) { - return wrap(unwrap(M)->getNamedValue(StringRef(Name, NameLen))); -} - -extern "C" LLVMValueRef LLVMRustGetOrInsertFunction(LLVMModuleRef M, - const char *Name, - size_t NameLen, - LLVMTypeRef FunctionTy) { - return wrap(unwrap(M) - ->getOrInsertFunction(StringRef(Name, NameLen), - unwrap<FunctionType>(FunctionTy)) -#if LLVM_VERSION_GE(9, 0) - .getCallee() -#endif - ); -} - -extern "C" LLVMValueRef -LLVMRustGetOrInsertGlobal(LLVMModuleRef M, const char *Name, size_t NameLen, LLVMTypeRef Ty) { - StringRef NameRef(Name, NameLen); - return wrap(unwrap(M)->getOrInsertGlobal(NameRef, unwrap(Ty))); -} - -extern "C" LLVMValueRef -LLVMRustInsertPrivateGlobal(LLVMModuleRef M, LLVMTypeRef Ty) { - return wrap(new GlobalVariable(*unwrap(M), - unwrap(Ty), - false, - GlobalValue::PrivateLinkage, - nullptr)); -} - -extern "C" LLVMTypeRef LLVMRustMetadataTypeInContext(LLVMContextRef C) { - return wrap(Type::getMetadataTy(*unwrap(C))); -} - -static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) { - switch (Kind) { - case AlwaysInline: - return Attribute::AlwaysInline; - case ByVal: - return Attribute::ByVal; - case Cold: - return Attribute::Cold; - case InlineHint: - return Attribute::InlineHint; - case MinSize: - return Attribute::MinSize; - case Naked: - return Attribute::Naked; - case NoAlias: - return Attribute::NoAlias; - case NoCapture: - return Attribute::NoCapture; - case NoInline: - return Attribute::NoInline; - case NonNull: - return Attribute::NonNull; - case NoRedZone: - return Attribute::NoRedZone; - case NoReturn: - return Attribute::NoReturn; - case NoUnwind: - return Attribute::NoUnwind; - case OptimizeForSize: - return Attribute::OptimizeForSize; - case ReadOnly: - return Attribute::ReadOnly; - case SExt: - return Attribute::SExt; - case StructRet: - return Attribute::StructRet; - case UWTable: - return Attribute::UWTable; - case ZExt: - return Attribute::ZExt; - case InReg: - return Attribute::InReg; - case SanitizeThread: - return Attribute::SanitizeThread; - case SanitizeAddress: - return Attribute::SanitizeAddress; - case SanitizeMemory: - return Attribute::SanitizeMemory; - case NonLazyBind: - return Attribute::NonLazyBind; - case OptimizeNone: - return Attribute::OptimizeNone; - case ReturnsTwice: - return Attribute::ReturnsTwice; - case ReadNone: - return Attribute::ReadNone; - case InaccessibleMemOnly: - return Attribute::InaccessibleMemOnly; - } - report_fatal_error("bad AttributeKind"); -} - -extern "C" void LLVMRustAddCallSiteAttribute(LLVMValueRef Instr, unsigned Index, - LLVMRustAttribute RustAttr) { - CallBase *Call = unwrap<CallBase>(Instr); - Attribute Attr = Attribute::get(Call->getContext(), fromRust(RustAttr)); - Call->addAttribute(Index, Attr); -} - -extern "C" void LLVMRustAddAlignmentCallSiteAttr(LLVMValueRef Instr, - unsigned Index, - uint32_t Bytes) { - CallBase *Call = unwrap<CallBase>(Instr); - AttrBuilder B; - B.addAlignmentAttr(Bytes); - Call->setAttributes(Call->getAttributes().addAttributes( - Call->getContext(), Index, B)); -} - -extern "C" void LLVMRustAddDereferenceableCallSiteAttr(LLVMValueRef Instr, - unsigned Index, - uint64_t Bytes) { - CallBase *Call = unwrap<CallBase>(Instr); - AttrBuilder B; - B.addDereferenceableAttr(Bytes); - Call->setAttributes(Call->getAttributes().addAttributes( - Call->getContext(), Index, B)); -} - -extern "C" void LLVMRustAddDereferenceableOrNullCallSiteAttr(LLVMValueRef Instr, - unsigned Index, - uint64_t Bytes) { - CallBase *Call = unwrap<CallBase>(Instr); - AttrBuilder B; - B.addDereferenceableOrNullAttr(Bytes); - Call->setAttributes(Call->getAttributes().addAttributes( - Call->getContext(), Index, B)); -} - -extern "C" void LLVMRustAddByValCallSiteAttr(LLVMValueRef Instr, unsigned Index, - LLVMTypeRef Ty) { - CallBase *Call = unwrap<CallBase>(Instr); -#if LLVM_VERSION_GE(9, 0) - Attribute Attr = Attribute::getWithByValType(Call->getContext(), unwrap(Ty)); -#else - Attribute Attr = Attribute::get(Call->getContext(), Attribute::ByVal); -#endif - Call->addAttribute(Index, Attr); -} - -extern "C" void LLVMRustAddFunctionAttribute(LLVMValueRef Fn, unsigned Index, - LLVMRustAttribute RustAttr) { - Function *A = unwrap<Function>(Fn); - Attribute Attr = Attribute::get(A->getContext(), fromRust(RustAttr)); - AttrBuilder B(Attr); - A->addAttributes(Index, B); -} - -extern "C" void LLVMRustAddAlignmentAttr(LLVMValueRef Fn, - unsigned Index, - uint32_t Bytes) { - Function *A = unwrap<Function>(Fn); - AttrBuilder B; - B.addAlignmentAttr(Bytes); - A->addAttributes(Index, B); -} - -extern "C" void LLVMRustAddDereferenceableAttr(LLVMValueRef Fn, unsigned Index, - uint64_t Bytes) { - Function *A = unwrap<Function>(Fn); - AttrBuilder B; - B.addDereferenceableAttr(Bytes); - A->addAttributes(Index, B); -} - -extern "C" void LLVMRustAddDereferenceableOrNullAttr(LLVMValueRef Fn, - unsigned Index, - uint64_t Bytes) { - Function *A = unwrap<Function>(Fn); - AttrBuilder B; - B.addDereferenceableOrNullAttr(Bytes); - A->addAttributes(Index, B); -} - -extern "C" void LLVMRustAddByValAttr(LLVMValueRef Fn, unsigned Index, - LLVMTypeRef Ty) { - Function *F = unwrap<Function>(Fn); -#if LLVM_VERSION_GE(9, 0) - Attribute Attr = Attribute::getWithByValType(F->getContext(), unwrap(Ty)); -#else - Attribute Attr = Attribute::get(F->getContext(), Attribute::ByVal); -#endif - F->addAttribute(Index, Attr); -} - -extern "C" void LLVMRustAddFunctionAttrStringValue(LLVMValueRef Fn, - unsigned Index, - const char *Name, - const char *Value) { - Function *F = unwrap<Function>(Fn); - AttrBuilder B; - B.addAttribute(Name, Value); - F->addAttributes(Index, B); -} - -extern "C" void LLVMRustRemoveFunctionAttributes(LLVMValueRef Fn, - unsigned Index, - LLVMRustAttribute RustAttr) { - Function *F = unwrap<Function>(Fn); - Attribute Attr = Attribute::get(F->getContext(), fromRust(RustAttr)); - AttrBuilder B(Attr); - auto PAL = F->getAttributes(); - auto PALNew = PAL.removeAttributes(F->getContext(), Index, B); - F->setAttributes(PALNew); -} - -// enable fpmath flag UnsafeAlgebra -extern "C" void LLVMRustSetHasUnsafeAlgebra(LLVMValueRef V) { - if (auto I = dyn_cast<Instruction>(unwrap<Value>(V))) { - I->setFast(true); - } -} - -extern "C" LLVMValueRef -LLVMRustBuildAtomicLoad(LLVMBuilderRef B, LLVMValueRef Source, const char *Name, - LLVMAtomicOrdering Order) { - Value *Ptr = unwrap(Source); - Type *Ty = Ptr->getType()->getPointerElementType(); - LoadInst *LI = unwrap(B)->CreateLoad(Ty, Ptr, Name); - LI->setAtomic(fromRust(Order)); - return wrap(LI); -} - -extern "C" LLVMValueRef LLVMRustBuildAtomicStore(LLVMBuilderRef B, - LLVMValueRef V, - LLVMValueRef Target, - LLVMAtomicOrdering Order) { - StoreInst *SI = unwrap(B)->CreateStore(unwrap(V), unwrap(Target)); - SI->setAtomic(fromRust(Order)); - return wrap(SI); -} - -// FIXME: Use the C-API LLVMBuildAtomicCmpXchg and LLVMSetWeak -// once we raise our minimum support to LLVM 10. -extern "C" LLVMValueRef -LLVMRustBuildAtomicCmpXchg(LLVMBuilderRef B, LLVMValueRef Target, - LLVMValueRef Old, LLVMValueRef Source, - LLVMAtomicOrdering Order, - LLVMAtomicOrdering FailureOrder, LLVMBool Weak) { - AtomicCmpXchgInst *ACXI = unwrap(B)->CreateAtomicCmpXchg( - unwrap(Target), unwrap(Old), unwrap(Source), fromRust(Order), - fromRust(FailureOrder)); - ACXI->setWeak(Weak); - return wrap(ACXI); -} - -enum class LLVMRustSynchronizationScope { - SingleThread, - CrossThread, -}; - -static SyncScope::ID fromRust(LLVMRustSynchronizationScope Scope) { - switch (Scope) { - case LLVMRustSynchronizationScope::SingleThread: - return SyncScope::SingleThread; - case LLVMRustSynchronizationScope::CrossThread: - return SyncScope::System; - default: - report_fatal_error("bad SynchronizationScope."); - } -} - -extern "C" LLVMValueRef -LLVMRustBuildAtomicFence(LLVMBuilderRef B, LLVMAtomicOrdering Order, - LLVMRustSynchronizationScope Scope) { - return wrap(unwrap(B)->CreateFence(fromRust(Order), fromRust(Scope))); -} - -enum class LLVMRustAsmDialect { - Att, - Intel, -}; - -static InlineAsm::AsmDialect fromRust(LLVMRustAsmDialect Dialect) { - switch (Dialect) { - case LLVMRustAsmDialect::Att: - return InlineAsm::AD_ATT; - case LLVMRustAsmDialect::Intel: - return InlineAsm::AD_Intel; - default: - report_fatal_error("bad AsmDialect."); - } -} - -extern "C" LLVMValueRef -LLVMRustInlineAsm(LLVMTypeRef Ty, char *AsmString, size_t AsmStringLen, - char *Constraints, size_t ConstraintsLen, - LLVMBool HasSideEffects, LLVMBool IsAlignStack, - LLVMRustAsmDialect Dialect) { - return wrap(InlineAsm::get(unwrap<FunctionType>(Ty), - StringRef(AsmString, AsmStringLen), - StringRef(Constraints, ConstraintsLen), - HasSideEffects, IsAlignStack, fromRust(Dialect))); -} - -extern "C" bool LLVMRustInlineAsmVerify(LLVMTypeRef Ty, char *Constraints, - size_t ConstraintsLen) { - return InlineAsm::Verify(unwrap<FunctionType>(Ty), - StringRef(Constraints, ConstraintsLen)); -} - -extern "C" void LLVMRustAppendModuleInlineAsm(LLVMModuleRef M, const char *Asm, - size_t AsmLen) { - unwrap(M)->appendModuleInlineAsm(StringRef(Asm, AsmLen)); -} - -typedef DIBuilder *LLVMRustDIBuilderRef; - -template <typename DIT> DIT *unwrapDIPtr(LLVMMetadataRef Ref) { - return (DIT *)(Ref ? unwrap<MDNode>(Ref) : nullptr); -} - -#define DIDescriptor DIScope -#define DIArray DINodeArray -#define unwrapDI unwrapDIPtr - -// These values **must** match debuginfo::DIFlags! They also *happen* -// to match LLVM, but that isn't required as we do giant sets of -// matching below. The value shouldn't be directly passed to LLVM. -enum class LLVMRustDIFlags : uint32_t { - FlagZero = 0, - FlagPrivate = 1, - FlagProtected = 2, - FlagPublic = 3, - FlagFwdDecl = (1 << 2), - FlagAppleBlock = (1 << 3), - FlagBlockByrefStruct = (1 << 4), - FlagVirtual = (1 << 5), - FlagArtificial = (1 << 6), - FlagExplicit = (1 << 7), - FlagPrototyped = (1 << 8), - FlagObjcClassComplete = (1 << 9), - FlagObjectPointer = (1 << 10), - FlagVector = (1 << 11), - FlagStaticMember = (1 << 12), - FlagLValueReference = (1 << 13), - FlagRValueReference = (1 << 14), - FlagExternalTypeRef = (1 << 15), - FlagIntroducedVirtual = (1 << 18), - FlagBitField = (1 << 19), - FlagNoReturn = (1 << 20), - // Do not add values that are not supported by the minimum LLVM - // version we support! see llvm/include/llvm/IR/DebugInfoFlags.def -}; - -inline LLVMRustDIFlags operator&(LLVMRustDIFlags A, LLVMRustDIFlags B) { - return static_cast<LLVMRustDIFlags>(static_cast<uint32_t>(A) & - static_cast<uint32_t>(B)); -} - -inline LLVMRustDIFlags operator|(LLVMRustDIFlags A, LLVMRustDIFlags B) { - return static_cast<LLVMRustDIFlags>(static_cast<uint32_t>(A) | - static_cast<uint32_t>(B)); -} - -inline LLVMRustDIFlags &operator|=(LLVMRustDIFlags &A, LLVMRustDIFlags B) { - return A = A | B; -} - -inline bool isSet(LLVMRustDIFlags F) { return F != LLVMRustDIFlags::FlagZero; } - -inline LLVMRustDIFlags visibility(LLVMRustDIFlags F) { - return static_cast<LLVMRustDIFlags>(static_cast<uint32_t>(F) & 0x3); -} - -static DINode::DIFlags fromRust(LLVMRustDIFlags Flags) { - DINode::DIFlags Result = DINode::DIFlags::FlagZero; - - switch (visibility(Flags)) { - case LLVMRustDIFlags::FlagPrivate: - Result |= DINode::DIFlags::FlagPrivate; - break; - case LLVMRustDIFlags::FlagProtected: - Result |= DINode::DIFlags::FlagProtected; - break; - case LLVMRustDIFlags::FlagPublic: - Result |= DINode::DIFlags::FlagPublic; - break; - default: - // The rest are handled below - break; - } - - if (isSet(Flags & LLVMRustDIFlags::FlagFwdDecl)) { - Result |= DINode::DIFlags::FlagFwdDecl; - } - if (isSet(Flags & LLVMRustDIFlags::FlagAppleBlock)) { - Result |= DINode::DIFlags::FlagAppleBlock; - } -#if LLVM_VERSION_LT(10, 0) - if (isSet(Flags & LLVMRustDIFlags::FlagBlockByrefStruct)) { - Result |= DINode::DIFlags::FlagBlockByrefStruct; - } -#endif - if (isSet(Flags & LLVMRustDIFlags::FlagVirtual)) { - Result |= DINode::DIFlags::FlagVirtual; - } - if (isSet(Flags & LLVMRustDIFlags::FlagArtificial)) { - Result |= DINode::DIFlags::FlagArtificial; - } - if (isSet(Flags & LLVMRustDIFlags::FlagExplicit)) { - Result |= DINode::DIFlags::FlagExplicit; - } - if (isSet(Flags & LLVMRustDIFlags::FlagPrototyped)) { - Result |= DINode::DIFlags::FlagPrototyped; - } - if (isSet(Flags & LLVMRustDIFlags::FlagObjcClassComplete)) { - Result |= DINode::DIFlags::FlagObjcClassComplete; - } - if (isSet(Flags & LLVMRustDIFlags::FlagObjectPointer)) { - Result |= DINode::DIFlags::FlagObjectPointer; - } - if (isSet(Flags & LLVMRustDIFlags::FlagVector)) { - Result |= DINode::DIFlags::FlagVector; - } - if (isSet(Flags & LLVMRustDIFlags::FlagStaticMember)) { - Result |= DINode::DIFlags::FlagStaticMember; - } - if (isSet(Flags & LLVMRustDIFlags::FlagLValueReference)) { - Result |= DINode::DIFlags::FlagLValueReference; - } - if (isSet(Flags & LLVMRustDIFlags::FlagRValueReference)) { - Result |= DINode::DIFlags::FlagRValueReference; - } - if (isSet(Flags & LLVMRustDIFlags::FlagIntroducedVirtual)) { - Result |= DINode::DIFlags::FlagIntroducedVirtual; - } - if (isSet(Flags & LLVMRustDIFlags::FlagBitField)) { - Result |= DINode::DIFlags::FlagBitField; - } - if (isSet(Flags & LLVMRustDIFlags::FlagNoReturn)) { - Result |= DINode::DIFlags::FlagNoReturn; - } - - return Result; -} - -// These values **must** match debuginfo::DISPFlags! They also *happen* -// to match LLVM, but that isn't required as we do giant sets of -// matching below. The value shouldn't be directly passed to LLVM. -enum class LLVMRustDISPFlags : uint32_t { - SPFlagZero = 0, - SPFlagVirtual = 1, - SPFlagPureVirtual = 2, - SPFlagLocalToUnit = (1 << 2), - SPFlagDefinition = (1 << 3), - SPFlagOptimized = (1 << 4), - SPFlagMainSubprogram = (1 << 5), - // Do not add values that are not supported by the minimum LLVM - // version we support! see llvm/include/llvm/IR/DebugInfoFlags.def - // (In LLVM < 8, createFunction supported these as separate bool arguments.) -}; - -inline LLVMRustDISPFlags operator&(LLVMRustDISPFlags A, LLVMRustDISPFlags B) { - return static_cast<LLVMRustDISPFlags>(static_cast<uint32_t>(A) & - static_cast<uint32_t>(B)); -} - -inline LLVMRustDISPFlags operator|(LLVMRustDISPFlags A, LLVMRustDISPFlags B) { - return static_cast<LLVMRustDISPFlags>(static_cast<uint32_t>(A) | - static_cast<uint32_t>(B)); -} - -inline LLVMRustDISPFlags &operator|=(LLVMRustDISPFlags &A, LLVMRustDISPFlags B) { - return A = A | B; -} - -inline bool isSet(LLVMRustDISPFlags F) { return F != LLVMRustDISPFlags::SPFlagZero; } - -inline LLVMRustDISPFlags virtuality(LLVMRustDISPFlags F) { - return static_cast<LLVMRustDISPFlags>(static_cast<uint32_t>(F) & 0x3); -} - -static DISubprogram::DISPFlags fromRust(LLVMRustDISPFlags SPFlags) { - DISubprogram::DISPFlags Result = DISubprogram::DISPFlags::SPFlagZero; - - switch (virtuality(SPFlags)) { - case LLVMRustDISPFlags::SPFlagVirtual: - Result |= DISubprogram::DISPFlags::SPFlagVirtual; - break; - case LLVMRustDISPFlags::SPFlagPureVirtual: - Result |= DISubprogram::DISPFlags::SPFlagPureVirtual; - break; - default: - // The rest are handled below - break; - } - - if (isSet(SPFlags & LLVMRustDISPFlags::SPFlagLocalToUnit)) { - Result |= DISubprogram::DISPFlags::SPFlagLocalToUnit; - } - if (isSet(SPFlags & LLVMRustDISPFlags::SPFlagDefinition)) { - Result |= DISubprogram::DISPFlags::SPFlagDefinition; - } - if (isSet(SPFlags & LLVMRustDISPFlags::SPFlagOptimized)) { - Result |= DISubprogram::DISPFlags::SPFlagOptimized; - } -#if LLVM_VERSION_GE(9, 0) - if (isSet(SPFlags & LLVMRustDISPFlags::SPFlagMainSubprogram)) { - Result |= DISubprogram::DISPFlags::SPFlagMainSubprogram; - } -#endif - - return Result; -} - -enum class LLVMRustDebugEmissionKind { - NoDebug, - FullDebug, - LineTablesOnly, -}; - -static DICompileUnit::DebugEmissionKind fromRust(LLVMRustDebugEmissionKind Kind) { - switch (Kind) { - case LLVMRustDebugEmissionKind::NoDebug: - return DICompileUnit::DebugEmissionKind::NoDebug; - case LLVMRustDebugEmissionKind::FullDebug: - return DICompileUnit::DebugEmissionKind::FullDebug; - case LLVMRustDebugEmissionKind::LineTablesOnly: - return DICompileUnit::DebugEmissionKind::LineTablesOnly; - default: - report_fatal_error("bad DebugEmissionKind."); - } -} - -enum class LLVMRustChecksumKind { - None, - MD5, - SHA1, -}; - -static Optional<DIFile::ChecksumKind> fromRust(LLVMRustChecksumKind Kind) { - switch (Kind) { - case LLVMRustChecksumKind::None: - return None; - case LLVMRustChecksumKind::MD5: - return DIFile::ChecksumKind::CSK_MD5; - case LLVMRustChecksumKind::SHA1: - return DIFile::ChecksumKind::CSK_SHA1; - default: - report_fatal_error("bad ChecksumKind."); - } -} - -extern "C" uint32_t LLVMRustDebugMetadataVersion() { - return DEBUG_METADATA_VERSION; -} - -extern "C" uint32_t LLVMRustVersionMinor() { return LLVM_VERSION_MINOR; } - -extern "C" uint32_t LLVMRustVersionMajor() { return LLVM_VERSION_MAJOR; } - -extern "C" void LLVMRustAddModuleFlag(LLVMModuleRef M, const char *Name, - uint32_t Value) { - unwrap(M)->addModuleFlag(Module::Warning, Name, Value); -} - -extern "C" LLVMValueRef LLVMRustMetadataAsValue(LLVMContextRef C, LLVMMetadataRef MD) { - return wrap(MetadataAsValue::get(*unwrap(C), unwrap(MD))); -} - -extern "C" LLVMRustDIBuilderRef LLVMRustDIBuilderCreate(LLVMModuleRef M) { - return new DIBuilder(*unwrap(M)); -} - -extern "C" void LLVMRustDIBuilderDispose(LLVMRustDIBuilderRef Builder) { - delete Builder; -} - -extern "C" void LLVMRustDIBuilderFinalize(LLVMRustDIBuilderRef Builder) { - Builder->finalize(); -} - -extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateCompileUnit( - LLVMRustDIBuilderRef Builder, unsigned Lang, LLVMMetadataRef FileRef, - const char *Producer, size_t ProducerLen, bool isOptimized, - const char *Flags, unsigned RuntimeVer, - const char *SplitName, size_t SplitNameLen, - LLVMRustDebugEmissionKind Kind) { - auto *File = unwrapDI<DIFile>(FileRef); - - return wrap(Builder->createCompileUnit(Lang, File, StringRef(Producer, ProducerLen), - isOptimized, Flags, RuntimeVer, - StringRef(SplitName, SplitNameLen), - fromRust(Kind))); -} - -extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFile( - LLVMRustDIBuilderRef Builder, - const char *Filename, size_t FilenameLen, - const char *Directory, size_t DirectoryLen, LLVMRustChecksumKind CSKind, - const char *Checksum, size_t ChecksumLen) { - Optional<DIFile::ChecksumKind> llvmCSKind = fromRust(CSKind); - Optional<DIFile::ChecksumInfo<StringRef>> CSInfo{}; - if (llvmCSKind) - CSInfo.emplace(*llvmCSKind, StringRef{Checksum, ChecksumLen}); - return wrap(Builder->createFile(StringRef(Filename, FilenameLen), - StringRef(Directory, DirectoryLen), - CSInfo)); -} - -extern "C" LLVMMetadataRef -LLVMRustDIBuilderCreateSubroutineType(LLVMRustDIBuilderRef Builder, - LLVMMetadataRef ParameterTypes) { - return wrap(Builder->createSubroutineType( - DITypeRefArray(unwrap<MDTuple>(ParameterTypes)))); -} - -extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFunction( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, - const char *Name, size_t NameLen, - const char *LinkageName, size_t LinkageNameLen, - LLVMMetadataRef File, unsigned LineNo, - LLVMMetadataRef Ty, unsigned ScopeLine, LLVMRustDIFlags Flags, - LLVMRustDISPFlags SPFlags, LLVMValueRef Fn, LLVMMetadataRef TParam, - LLVMMetadataRef Decl) { - DITemplateParameterArray TParams = - DITemplateParameterArray(unwrap<MDTuple>(TParam)); - DISubprogram::DISPFlags llvmSPFlags = fromRust(SPFlags); - DINode::DIFlags llvmFlags = fromRust(Flags); -#if LLVM_VERSION_LT(9, 0) - if (isSet(SPFlags & LLVMRustDISPFlags::SPFlagMainSubprogram)) - llvmFlags |= DINode::DIFlags::FlagMainSubprogram; -#endif - DISubprogram *Sub = Builder->createFunction( - unwrapDI<DIScope>(Scope), - StringRef(Name, NameLen), - StringRef(LinkageName, LinkageNameLen), - unwrapDI<DIFile>(File), LineNo, - unwrapDI<DISubroutineType>(Ty), ScopeLine, llvmFlags, - llvmSPFlags, TParams, unwrapDIPtr<DISubprogram>(Decl)); - unwrap<Function>(Fn)->setSubprogram(Sub); - return wrap(Sub); -} - -extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateBasicType( - LLVMRustDIBuilderRef Builder, const char *Name, size_t NameLen, - uint64_t SizeInBits, unsigned Encoding) { - return wrap(Builder->createBasicType(StringRef(Name, NameLen), SizeInBits, Encoding)); -} - -extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateTypedef( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Type, const char *Name, size_t NameLen, - LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Scope) { - return wrap(Builder->createTypedef( - unwrap<DIType>(Type), StringRef(Name, NameLen), unwrap<DIFile>(File), - LineNo, unwrap<DIScope>(Scope))); -} - -extern "C" LLVMMetadataRef LLVMRustDIBuilderCreatePointerType( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef PointeeTy, - uint64_t SizeInBits, uint32_t AlignInBits, unsigned AddressSpace, - const char *Name, size_t NameLen) { - return wrap(Builder->createPointerType(unwrapDI<DIType>(PointeeTy), - SizeInBits, AlignInBits, - AddressSpace, - StringRef(Name, NameLen))); -} - -extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStructType( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, - const char *Name, size_t NameLen, - LLVMMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, - uint32_t AlignInBits, LLVMRustDIFlags Flags, - LLVMMetadataRef DerivedFrom, LLVMMetadataRef Elements, - unsigned RunTimeLang, LLVMMetadataRef VTableHolder, - const char *UniqueId, size_t UniqueIdLen) { - return wrap(Builder->createStructType( - unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), - unwrapDI<DIFile>(File), LineNumber, - SizeInBits, AlignInBits, fromRust(Flags), unwrapDI<DIType>(DerivedFrom), - DINodeArray(unwrapDI<MDTuple>(Elements)), RunTimeLang, - unwrapDI<DIType>(VTableHolder), StringRef(UniqueId, UniqueIdLen))); -} - -extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantPart( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, - const char *Name, size_t NameLen, - LLVMMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, - uint32_t AlignInBits, LLVMRustDIFlags Flags, LLVMMetadataRef Discriminator, - LLVMMetadataRef Elements, const char *UniqueId, size_t UniqueIdLen) { - return wrap(Builder->createVariantPart( - unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), - unwrapDI<DIFile>(File), LineNumber, - SizeInBits, AlignInBits, fromRust(Flags), unwrapDI<DIDerivedType>(Discriminator), - DINodeArray(unwrapDI<MDTuple>(Elements)), StringRef(UniqueId, UniqueIdLen))); -} - -extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMemberType( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, - const char *Name, size_t NameLen, - LLVMMetadataRef File, unsigned LineNo, uint64_t SizeInBits, - uint32_t AlignInBits, uint64_t OffsetInBits, LLVMRustDIFlags Flags, - LLVMMetadataRef Ty) { - return wrap(Builder->createMemberType(unwrapDI<DIDescriptor>(Scope), - StringRef(Name, NameLen), - unwrapDI<DIFile>(File), LineNo, - SizeInBits, AlignInBits, OffsetInBits, - fromRust(Flags), unwrapDI<DIType>(Ty))); -} - -extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantMemberType( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, - const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNo, - uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, LLVMValueRef Discriminant, - LLVMRustDIFlags Flags, LLVMMetadataRef Ty) { - llvm::ConstantInt* D = nullptr; - if (Discriminant) { - D = unwrap<llvm::ConstantInt>(Discriminant); - } - return wrap(Builder->createVariantMemberType(unwrapDI<DIDescriptor>(Scope), - StringRef(Name, NameLen), - unwrapDI<DIFile>(File), LineNo, - SizeInBits, AlignInBits, OffsetInBits, D, - fromRust(Flags), unwrapDI<DIType>(Ty))); -} - -extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateLexicalBlock( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, - LLVMMetadataRef File, unsigned Line, unsigned Col) { - return wrap(Builder->createLexicalBlock(unwrapDI<DIDescriptor>(Scope), - unwrapDI<DIFile>(File), Line, Col)); -} - -extern "C" LLVMMetadataRef -LLVMRustDIBuilderCreateLexicalBlockFile(LLVMRustDIBuilderRef Builder, - LLVMMetadataRef Scope, - LLVMMetadataRef File) { - return wrap(Builder->createLexicalBlockFile(unwrapDI<DIDescriptor>(Scope), - unwrapDI<DIFile>(File))); -} - -extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticVariable( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Context, - const char *Name, size_t NameLen, - const char *LinkageName, size_t LinkageNameLen, - LLVMMetadataRef File, unsigned LineNo, - LLVMMetadataRef Ty, bool IsLocalToUnit, LLVMValueRef V, - LLVMMetadataRef Decl = nullptr, uint32_t AlignInBits = 0) { - llvm::GlobalVariable *InitVal = cast<llvm::GlobalVariable>(unwrap(V)); - - llvm::DIExpression *InitExpr = nullptr; - if (llvm::ConstantInt *IntVal = llvm::dyn_cast<llvm::ConstantInt>(InitVal)) { - InitExpr = Builder->createConstantValueExpression( - IntVal->getValue().getSExtValue()); - } else if (llvm::ConstantFP *FPVal = - llvm::dyn_cast<llvm::ConstantFP>(InitVal)) { - InitExpr = Builder->createConstantValueExpression( - FPVal->getValueAPF().bitcastToAPInt().getZExtValue()); - } - - llvm::DIGlobalVariableExpression *VarExpr = Builder->createGlobalVariableExpression( - unwrapDI<DIDescriptor>(Context), StringRef(Name, NameLen), - StringRef(LinkageName, LinkageNameLen), - unwrapDI<DIFile>(File), LineNo, unwrapDI<DIType>(Ty), IsLocalToUnit, -#if LLVM_VERSION_GE(10, 0) - /* isDefined */ true, -#endif - InitExpr, unwrapDIPtr<MDNode>(Decl), - /* templateParams */ nullptr, - AlignInBits); - - InitVal->setMetadata("dbg", VarExpr); - - return wrap(VarExpr); -} - -extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariable( - LLVMRustDIBuilderRef Builder, unsigned Tag, LLVMMetadataRef Scope, - const char *Name, size_t NameLen, - LLVMMetadataRef File, unsigned LineNo, - LLVMMetadataRef Ty, bool AlwaysPreserve, LLVMRustDIFlags Flags, - unsigned ArgNo, uint32_t AlignInBits) { - if (Tag == 0x100) { // DW_TAG_auto_variable - return wrap(Builder->createAutoVariable( - unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), - unwrapDI<DIFile>(File), LineNo, - unwrapDI<DIType>(Ty), AlwaysPreserve, fromRust(Flags), AlignInBits)); - } else { - return wrap(Builder->createParameterVariable( - unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), ArgNo, - unwrapDI<DIFile>(File), LineNo, - unwrapDI<DIType>(Ty), AlwaysPreserve, fromRust(Flags))); - } -} - -extern "C" LLVMMetadataRef -LLVMRustDIBuilderCreateArrayType(LLVMRustDIBuilderRef Builder, uint64_t Size, - uint32_t AlignInBits, LLVMMetadataRef Ty, - LLVMMetadataRef Subscripts) { - return wrap( - Builder->createArrayType(Size, AlignInBits, unwrapDI<DIType>(Ty), - DINodeArray(unwrapDI<MDTuple>(Subscripts)))); -} - -extern "C" LLVMMetadataRef -LLVMRustDIBuilderGetOrCreateSubrange(LLVMRustDIBuilderRef Builder, int64_t Lo, - int64_t Count) { - return wrap(Builder->getOrCreateSubrange(Lo, Count)); -} - -extern "C" LLVMMetadataRef -LLVMRustDIBuilderGetOrCreateArray(LLVMRustDIBuilderRef Builder, - LLVMMetadataRef *Ptr, unsigned Count) { - Metadata **DataValue = unwrap(Ptr); - return wrap( - Builder->getOrCreateArray(ArrayRef<Metadata *>(DataValue, Count)).get()); -} - -extern "C" LLVMValueRef LLVMRustDIBuilderInsertDeclareAtEnd( - LLVMRustDIBuilderRef Builder, LLVMValueRef V, LLVMMetadataRef VarInfo, - int64_t *AddrOps, unsigned AddrOpsCount, LLVMValueRef DL, - LLVMBasicBlockRef InsertAtEnd) { - return wrap(Builder->insertDeclare( - unwrap(V), unwrap<DILocalVariable>(VarInfo), - Builder->createExpression(llvm::ArrayRef<int64_t>(AddrOps, AddrOpsCount)), - DebugLoc(cast<MDNode>(unwrap<MetadataAsValue>(DL)->getMetadata())), - unwrap(InsertAtEnd))); -} - -extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerator( - LLVMRustDIBuilderRef Builder, const char *Name, size_t NameLen, - int64_t Value, bool IsUnsigned) { - return wrap(Builder->createEnumerator(StringRef(Name, NameLen), Value, IsUnsigned)); -} - -extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerationType( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, - const char *Name, size_t NameLen, - LLVMMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, - uint32_t AlignInBits, LLVMMetadataRef Elements, - LLVMMetadataRef ClassTy, bool IsScoped) { - return wrap(Builder->createEnumerationType( - unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), - unwrapDI<DIFile>(File), LineNumber, - SizeInBits, AlignInBits, DINodeArray(unwrapDI<MDTuple>(Elements)), - unwrapDI<DIType>(ClassTy), "", IsScoped)); -} - -extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateUnionType( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, - const char *Name, size_t NameLen, - LLVMMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, - uint32_t AlignInBits, LLVMRustDIFlags Flags, LLVMMetadataRef Elements, - unsigned RunTimeLang, const char *UniqueId, size_t UniqueIdLen) { - return wrap(Builder->createUnionType( - unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), unwrapDI<DIFile>(File), - LineNumber, SizeInBits, AlignInBits, fromRust(Flags), - DINodeArray(unwrapDI<MDTuple>(Elements)), RunTimeLang, - StringRef(UniqueId, UniqueIdLen))); -} - -extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateTemplateTypeParameter( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, - const char *Name, size_t NameLen, LLVMMetadataRef Ty) { -#if LLVM_VERSION_GE(11, 0) - bool IsDefault = false; // FIXME: should we ever set this true? - return wrap(Builder->createTemplateTypeParameter( - unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), unwrapDI<DIType>(Ty), IsDefault)); -#else - return wrap(Builder->createTemplateTypeParameter( - unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), unwrapDI<DIType>(Ty))); -#endif -} - -extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateNameSpace( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, - const char *Name, size_t NameLen, bool ExportSymbols) { - return wrap(Builder->createNameSpace( - unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), ExportSymbols - )); -} - -extern "C" void -LLVMRustDICompositeTypeReplaceArrays(LLVMRustDIBuilderRef Builder, - LLVMMetadataRef CompositeTy, - LLVMMetadataRef Elements, - LLVMMetadataRef Params) { - DICompositeType *Tmp = unwrapDI<DICompositeType>(CompositeTy); - Builder->replaceArrays(Tmp, DINodeArray(unwrap<MDTuple>(Elements)), - DINodeArray(unwrap<MDTuple>(Params))); -} - -extern "C" LLVMValueRef -LLVMRustDIBuilderCreateDebugLocation(LLVMContextRef ContextRef, unsigned Line, - unsigned Column, LLVMMetadataRef Scope, - LLVMMetadataRef InlinedAt) { - LLVMContext &Context = *unwrap(ContextRef); - - DebugLoc debug_loc = DebugLoc::get(Line, Column, unwrapDIPtr<MDNode>(Scope), - unwrapDIPtr<MDNode>(InlinedAt)); - - return wrap(MetadataAsValue::get(Context, debug_loc.getAsMDNode())); -} - -extern "C" int64_t LLVMRustDIBuilderCreateOpDeref() { - return dwarf::DW_OP_deref; -} - -extern "C" int64_t LLVMRustDIBuilderCreateOpPlusUconst() { - return dwarf::DW_OP_plus_uconst; -} - -extern "C" void LLVMRustWriteTypeToString(LLVMTypeRef Ty, RustStringRef Str) { - RawRustStringOstream OS(Str); - unwrap<llvm::Type>(Ty)->print(OS); -} - -extern "C" void LLVMRustWriteValueToString(LLVMValueRef V, - RustStringRef Str) { - RawRustStringOstream OS(Str); - if (!V) { - OS << "(null)"; - } else { - OS << "("; - unwrap<llvm::Value>(V)->getType()->print(OS); - OS << ":"; - unwrap<llvm::Value>(V)->print(OS); - OS << ")"; - } -} - -// Note that the two following functions look quite similar to the -// LLVMGetSectionName function. Sadly, it appears that this function only -// returns a char* pointer, which isn't guaranteed to be null-terminated. The -// function provided by LLVM doesn't return the length, so we've created our own -// function which returns the length as well as the data pointer. -// -// For an example of this not returning a null terminated string, see -// lib/Object/COFFObjectFile.cpp in the getSectionName function. One of the -// branches explicitly creates a StringRef without a null terminator, and then -// that's returned. - -inline section_iterator *unwrap(LLVMSectionIteratorRef SI) { - return reinterpret_cast<section_iterator *>(SI); -} - -extern "C" size_t LLVMRustGetSectionName(LLVMSectionIteratorRef SI, - const char **Ptr) { -#if LLVM_VERSION_GE(10, 0) - auto NameOrErr = (*unwrap(SI))->getName(); - if (!NameOrErr) - report_fatal_error(NameOrErr.takeError()); - *Ptr = NameOrErr->data(); - return NameOrErr->size(); -#else - StringRef Ret; - if (std::error_code EC = (*unwrap(SI))->getName(Ret)) - report_fatal_error(EC.message()); - *Ptr = Ret.data(); - return Ret.size(); -#endif -} - -// LLVMArrayType function does not support 64-bit ElementCount -extern "C" LLVMTypeRef LLVMRustArrayType(LLVMTypeRef ElementTy, - uint64_t ElementCount) { - return wrap(ArrayType::get(unwrap(ElementTy), ElementCount)); -} - -DEFINE_SIMPLE_CONVERSION_FUNCTIONS(Twine, LLVMTwineRef) - -extern "C" void LLVMRustWriteTwineToString(LLVMTwineRef T, RustStringRef Str) { - RawRustStringOstream OS(Str); - unwrap(T)->print(OS); -} - -extern "C" void LLVMRustUnpackOptimizationDiagnostic( - LLVMDiagnosticInfoRef DI, RustStringRef PassNameOut, - LLVMValueRef *FunctionOut, unsigned* Line, unsigned* Column, - RustStringRef FilenameOut, RustStringRef MessageOut) { - // Undefined to call this not on an optimization diagnostic! - llvm::DiagnosticInfoOptimizationBase *Opt = - static_cast<llvm::DiagnosticInfoOptimizationBase *>(unwrap(DI)); - - RawRustStringOstream PassNameOS(PassNameOut); - PassNameOS << Opt->getPassName(); - *FunctionOut = wrap(&Opt->getFunction()); - - RawRustStringOstream FilenameOS(FilenameOut); - DiagnosticLocation loc = Opt->getLocation(); - if (loc.isValid()) { - *Line = loc.getLine(); - *Column = loc.getColumn(); - FilenameOS << loc.getAbsolutePath(); - } - - RawRustStringOstream MessageOS(MessageOut); - MessageOS << Opt->getMsg(); -} - -enum class LLVMRustDiagnosticLevel { - Error, - Warning, - Note, - Remark, -}; - -extern "C" void -LLVMRustUnpackInlineAsmDiagnostic(LLVMDiagnosticInfoRef DI, - LLVMRustDiagnosticLevel *LevelOut, - unsigned *CookieOut, - LLVMTwineRef *MessageOut, - LLVMValueRef *InstructionOut) { - // Undefined to call this not on an inline assembly diagnostic! - llvm::DiagnosticInfoInlineAsm *IA = - static_cast<llvm::DiagnosticInfoInlineAsm *>(unwrap(DI)); - - *CookieOut = IA->getLocCookie(); - *MessageOut = wrap(&IA->getMsgStr()); - *InstructionOut = wrap(IA->getInstruction()); - - switch (IA->getSeverity()) { - case DS_Error: - *LevelOut = LLVMRustDiagnosticLevel::Error; - break; - case DS_Warning: - *LevelOut = LLVMRustDiagnosticLevel::Warning; - break; - case DS_Note: - *LevelOut = LLVMRustDiagnosticLevel::Note; - break; - case DS_Remark: - *LevelOut = LLVMRustDiagnosticLevel::Remark; - break; - default: - report_fatal_error("Invalid LLVMRustDiagnosticLevel value!"); - } -} - -extern "C" void LLVMRustWriteDiagnosticInfoToString(LLVMDiagnosticInfoRef DI, - RustStringRef Str) { - RawRustStringOstream OS(Str); - DiagnosticPrinterRawOStream DP(OS); - unwrap(DI)->print(DP); -} - -enum class LLVMRustDiagnosticKind { - Other, - InlineAsm, - StackSize, - DebugMetadataVersion, - SampleProfile, - OptimizationRemark, - OptimizationRemarkMissed, - OptimizationRemarkAnalysis, - OptimizationRemarkAnalysisFPCommute, - OptimizationRemarkAnalysisAliasing, - OptimizationRemarkOther, - OptimizationFailure, - PGOProfile, - Linker, -}; - -static LLVMRustDiagnosticKind toRust(DiagnosticKind Kind) { - switch (Kind) { - case DK_InlineAsm: - return LLVMRustDiagnosticKind::InlineAsm; - case DK_StackSize: - return LLVMRustDiagnosticKind::StackSize; - case DK_DebugMetadataVersion: - return LLVMRustDiagnosticKind::DebugMetadataVersion; - case DK_SampleProfile: - return LLVMRustDiagnosticKind::SampleProfile; - case DK_OptimizationRemark: - return LLVMRustDiagnosticKind::OptimizationRemark; - case DK_OptimizationRemarkMissed: - return LLVMRustDiagnosticKind::OptimizationRemarkMissed; - case DK_OptimizationRemarkAnalysis: - return LLVMRustDiagnosticKind::OptimizationRemarkAnalysis; - case DK_OptimizationRemarkAnalysisFPCommute: - return LLVMRustDiagnosticKind::OptimizationRemarkAnalysisFPCommute; - case DK_OptimizationRemarkAnalysisAliasing: - return LLVMRustDiagnosticKind::OptimizationRemarkAnalysisAliasing; - case DK_PGOProfile: - return LLVMRustDiagnosticKind::PGOProfile; - case DK_Linker: - return LLVMRustDiagnosticKind::Linker; - default: - return (Kind >= DK_FirstRemark && Kind <= DK_LastRemark) - ? LLVMRustDiagnosticKind::OptimizationRemarkOther - : LLVMRustDiagnosticKind::Other; - } -} - -extern "C" LLVMRustDiagnosticKind -LLVMRustGetDiagInfoKind(LLVMDiagnosticInfoRef DI) { - return toRust((DiagnosticKind)unwrap(DI)->getKind()); -} - -// This is kept distinct from LLVMGetTypeKind, because when -// a new type kind is added, the Rust-side enum must be -// updated or UB will result. -extern "C" LLVMTypeKind LLVMRustGetTypeKind(LLVMTypeRef Ty) { - switch (unwrap(Ty)->getTypeID()) { - case Type::VoidTyID: - return LLVMVoidTypeKind; - case Type::HalfTyID: - return LLVMHalfTypeKind; - case Type::FloatTyID: - return LLVMFloatTypeKind; - case Type::DoubleTyID: - return LLVMDoubleTypeKind; - case Type::X86_FP80TyID: - return LLVMX86_FP80TypeKind; - case Type::FP128TyID: - return LLVMFP128TypeKind; - case Type::PPC_FP128TyID: - return LLVMPPC_FP128TypeKind; - case Type::LabelTyID: - return LLVMLabelTypeKind; - case Type::MetadataTyID: - return LLVMMetadataTypeKind; - case Type::IntegerTyID: - return LLVMIntegerTypeKind; - case Type::FunctionTyID: - return LLVMFunctionTypeKind; - case Type::StructTyID: - return LLVMStructTypeKind; - case Type::ArrayTyID: - return LLVMArrayTypeKind; - case Type::PointerTyID: - return LLVMPointerTypeKind; -#if LLVM_VERSION_GE(11, 0) - case Type::FixedVectorTyID: - return LLVMVectorTypeKind; -#else - case Type::VectorTyID: - return LLVMVectorTypeKind; -#endif - case Type::X86_MMXTyID: - return LLVMX86_MMXTypeKind; - case Type::TokenTyID: - return LLVMTokenTypeKind; -#if LLVM_VERSION_GE(11, 0) - case Type::ScalableVectorTyID: - return LLVMScalableVectorTypeKind; - case Type::BFloatTyID: - return LLVMBFloatTypeKind; -#endif - } - report_fatal_error("Unhandled TypeID."); -} - -DEFINE_SIMPLE_CONVERSION_FUNCTIONS(SMDiagnostic, LLVMSMDiagnosticRef) - -extern "C" void LLVMRustSetInlineAsmDiagnosticHandler( - LLVMContextRef C, LLVMContext::InlineAsmDiagHandlerTy H, void *CX) { - unwrap(C)->setInlineAsmDiagnosticHandler(H, CX); -} - -extern "C" bool LLVMRustUnpackSMDiagnostic(LLVMSMDiagnosticRef DRef, - RustStringRef MessageOut, - RustStringRef BufferOut, - LLVMRustDiagnosticLevel* LevelOut, - unsigned* LocOut, - unsigned* RangesOut, - size_t* NumRanges) { - SMDiagnostic& D = *unwrap(DRef); - RawRustStringOstream MessageOS(MessageOut); - MessageOS << D.getMessage(); - - switch (D.getKind()) { - case SourceMgr::DK_Error: - *LevelOut = LLVMRustDiagnosticLevel::Error; - break; - case SourceMgr::DK_Warning: - *LevelOut = LLVMRustDiagnosticLevel::Warning; - break; - case SourceMgr::DK_Note: - *LevelOut = LLVMRustDiagnosticLevel::Note; - break; - case SourceMgr::DK_Remark: - *LevelOut = LLVMRustDiagnosticLevel::Remark; - break; - default: - report_fatal_error("Invalid LLVMRustDiagnosticLevel value!"); - } - - if (D.getLoc() == SMLoc()) - return false; - - const SourceMgr &LSM = *D.getSourceMgr(); - const MemoryBuffer *LBuf = LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc())); - LLVMRustStringWriteImpl(BufferOut, LBuf->getBufferStart(), LBuf->getBufferSize()); - - *LocOut = D.getLoc().getPointer() - LBuf->getBufferStart(); - - *NumRanges = std::min(*NumRanges, D.getRanges().size()); - size_t LineStart = *LocOut - (size_t)D.getColumnNo(); - for (size_t i = 0; i < *NumRanges; i++) { - RangesOut[i * 2] = LineStart + D.getRanges()[i].first; - RangesOut[i * 2 + 1] = LineStart + D.getRanges()[i].second; - } - - return true; -} - -extern "C" LLVMValueRef LLVMRustBuildCleanupPad(LLVMBuilderRef B, - LLVMValueRef ParentPad, - unsigned ArgCount, - LLVMValueRef *LLArgs, - const char *Name) { - Value **Args = unwrap(LLArgs); - if (ParentPad == nullptr) { - Type *Ty = Type::getTokenTy(unwrap(B)->getContext()); - ParentPad = wrap(Constant::getNullValue(Ty)); - } - return wrap(unwrap(B)->CreateCleanupPad( - unwrap(ParentPad), ArrayRef<Value *>(Args, ArgCount), Name)); -} - -extern "C" LLVMValueRef LLVMRustBuildCleanupRet(LLVMBuilderRef B, - LLVMValueRef CleanupPad, - LLVMBasicBlockRef UnwindBB) { - CleanupPadInst *Inst = cast<CleanupPadInst>(unwrap(CleanupPad)); - return wrap(unwrap(B)->CreateCleanupRet(Inst, unwrap(UnwindBB))); -} - -extern "C" LLVMValueRef -LLVMRustBuildCatchPad(LLVMBuilderRef B, LLVMValueRef ParentPad, - unsigned ArgCount, LLVMValueRef *LLArgs, const char *Name) { - Value **Args = unwrap(LLArgs); - return wrap(unwrap(B)->CreateCatchPad( - unwrap(ParentPad), ArrayRef<Value *>(Args, ArgCount), Name)); -} - -extern "C" LLVMValueRef LLVMRustBuildCatchRet(LLVMBuilderRef B, - LLVMValueRef Pad, - LLVMBasicBlockRef BB) { - return wrap(unwrap(B)->CreateCatchRet(cast<CatchPadInst>(unwrap(Pad)), - unwrap(BB))); -} - -extern "C" LLVMValueRef LLVMRustBuildCatchSwitch(LLVMBuilderRef B, - LLVMValueRef ParentPad, - LLVMBasicBlockRef BB, - unsigned NumHandlers, - const char *Name) { - if (ParentPad == nullptr) { - Type *Ty = Type::getTokenTy(unwrap(B)->getContext()); - ParentPad = wrap(Constant::getNullValue(Ty)); - } - return wrap(unwrap(B)->CreateCatchSwitch(unwrap(ParentPad), unwrap(BB), - NumHandlers, Name)); -} - -extern "C" void LLVMRustAddHandler(LLVMValueRef CatchSwitchRef, - LLVMBasicBlockRef Handler) { - Value *CatchSwitch = unwrap(CatchSwitchRef); - cast<CatchSwitchInst>(CatchSwitch)->addHandler(unwrap(Handler)); -} - -extern "C" OperandBundleDef *LLVMRustBuildOperandBundleDef(const char *Name, - LLVMValueRef *Inputs, - unsigned NumInputs) { - return new OperandBundleDef(Name, makeArrayRef(unwrap(Inputs), NumInputs)); -} - -extern "C" void LLVMRustFreeOperandBundleDef(OperandBundleDef *Bundle) { - delete Bundle; -} - -extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, - LLVMValueRef *Args, unsigned NumArgs, - OperandBundleDef *Bundle) { - Value *Callee = unwrap(Fn); - FunctionType *FTy = cast<FunctionType>(Callee->getType()->getPointerElementType()); - unsigned Len = Bundle ? 1 : 0; - ArrayRef<OperandBundleDef> Bundles = makeArrayRef(Bundle, Len); - return wrap(unwrap(B)->CreateCall( - FTy, Callee, makeArrayRef(unwrap(Args), NumArgs), Bundles)); -} - -extern "C" LLVMValueRef LLVMRustGetInstrProfIncrementIntrinsic(LLVMModuleRef M) { - return wrap(llvm::Intrinsic::getDeclaration(unwrap(M), - (llvm::Intrinsic::ID)llvm::Intrinsic::instrprof_increment)); -} - -extern "C" LLVMValueRef LLVMRustBuildMemCpy(LLVMBuilderRef B, - LLVMValueRef Dst, unsigned DstAlign, - LLVMValueRef Src, unsigned SrcAlign, - LLVMValueRef Size, bool IsVolatile) { -#if LLVM_VERSION_GE(10, 0) - return wrap(unwrap(B)->CreateMemCpy( - unwrap(Dst), MaybeAlign(DstAlign), - unwrap(Src), MaybeAlign(SrcAlign), - unwrap(Size), IsVolatile)); -#else - return wrap(unwrap(B)->CreateMemCpy( - unwrap(Dst), DstAlign, - unwrap(Src), SrcAlign, - unwrap(Size), IsVolatile)); -#endif -} - -extern "C" LLVMValueRef LLVMRustBuildMemMove(LLVMBuilderRef B, - LLVMValueRef Dst, unsigned DstAlign, - LLVMValueRef Src, unsigned SrcAlign, - LLVMValueRef Size, bool IsVolatile) { -#if LLVM_VERSION_GE(10, 0) - return wrap(unwrap(B)->CreateMemMove( - unwrap(Dst), MaybeAlign(DstAlign), - unwrap(Src), MaybeAlign(SrcAlign), - unwrap(Size), IsVolatile)); -#else - return wrap(unwrap(B)->CreateMemMove( - unwrap(Dst), DstAlign, - unwrap(Src), SrcAlign, - unwrap(Size), IsVolatile)); -#endif -} - -extern "C" LLVMValueRef LLVMRustBuildMemSet(LLVMBuilderRef B, - LLVMValueRef Dst, unsigned DstAlign, - LLVMValueRef Val, - LLVMValueRef Size, bool IsVolatile) { -#if LLVM_VERSION_GE(10, 0) - return wrap(unwrap(B)->CreateMemSet( - unwrap(Dst), unwrap(Val), unwrap(Size), MaybeAlign(DstAlign), IsVolatile)); -#else - return wrap(unwrap(B)->CreateMemSet( - unwrap(Dst), unwrap(Val), unwrap(Size), DstAlign, IsVolatile)); -#endif -} - -extern "C" LLVMValueRef -LLVMRustBuildInvoke(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args, - unsigned NumArgs, LLVMBasicBlockRef Then, - LLVMBasicBlockRef Catch, OperandBundleDef *Bundle, - const char *Name) { - Value *Callee = unwrap(Fn); - FunctionType *FTy = cast<FunctionType>(Callee->getType()->getPointerElementType()); - unsigned Len = Bundle ? 1 : 0; - ArrayRef<OperandBundleDef> Bundles = makeArrayRef(Bundle, Len); - return wrap(unwrap(B)->CreateInvoke(FTy, Callee, unwrap(Then), unwrap(Catch), - makeArrayRef(unwrap(Args), NumArgs), - Bundles, Name)); -} - -extern "C" void LLVMRustPositionBuilderAtStart(LLVMBuilderRef B, - LLVMBasicBlockRef BB) { - auto Point = unwrap(BB)->getFirstInsertionPt(); - unwrap(B)->SetInsertPoint(unwrap(BB), Point); -} - -extern "C" void LLVMRustSetComdat(LLVMModuleRef M, LLVMValueRef V, - const char *Name, size_t NameLen) { - Triple TargetTriple(unwrap(M)->getTargetTriple()); - GlobalObject *GV = unwrap<GlobalObject>(V); - if (!TargetTriple.isOSBinFormatMachO()) { - StringRef NameRef(Name, NameLen); - GV->setComdat(unwrap(M)->getOrInsertComdat(NameRef)); - } -} - -extern "C" void LLVMRustUnsetComdat(LLVMValueRef V) { - GlobalObject *GV = unwrap<GlobalObject>(V); - GV->setComdat(nullptr); -} - -enum class LLVMRustLinkage { - ExternalLinkage = 0, - AvailableExternallyLinkage = 1, - LinkOnceAnyLinkage = 2, - LinkOnceODRLinkage = 3, - WeakAnyLinkage = 4, - WeakODRLinkage = 5, - AppendingLinkage = 6, - InternalLinkage = 7, - PrivateLinkage = 8, - ExternalWeakLinkage = 9, - CommonLinkage = 10, -}; - -static LLVMRustLinkage toRust(LLVMLinkage Linkage) { - switch (Linkage) { - case LLVMExternalLinkage: - return LLVMRustLinkage::ExternalLinkage; - case LLVMAvailableExternallyLinkage: - return LLVMRustLinkage::AvailableExternallyLinkage; - case LLVMLinkOnceAnyLinkage: - return LLVMRustLinkage::LinkOnceAnyLinkage; - case LLVMLinkOnceODRLinkage: - return LLVMRustLinkage::LinkOnceODRLinkage; - case LLVMWeakAnyLinkage: - return LLVMRustLinkage::WeakAnyLinkage; - case LLVMWeakODRLinkage: - return LLVMRustLinkage::WeakODRLinkage; - case LLVMAppendingLinkage: - return LLVMRustLinkage::AppendingLinkage; - case LLVMInternalLinkage: - return LLVMRustLinkage::InternalLinkage; - case LLVMPrivateLinkage: - return LLVMRustLinkage::PrivateLinkage; - case LLVMExternalWeakLinkage: - return LLVMRustLinkage::ExternalWeakLinkage; - case LLVMCommonLinkage: - return LLVMRustLinkage::CommonLinkage; - default: - report_fatal_error("Invalid LLVMRustLinkage value!"); - } -} - -static LLVMLinkage fromRust(LLVMRustLinkage Linkage) { - switch (Linkage) { - case LLVMRustLinkage::ExternalLinkage: - return LLVMExternalLinkage; - case LLVMRustLinkage::AvailableExternallyLinkage: - return LLVMAvailableExternallyLinkage; - case LLVMRustLinkage::LinkOnceAnyLinkage: - return LLVMLinkOnceAnyLinkage; - case LLVMRustLinkage::LinkOnceODRLinkage: - return LLVMLinkOnceODRLinkage; - case LLVMRustLinkage::WeakAnyLinkage: - return LLVMWeakAnyLinkage; - case LLVMRustLinkage::WeakODRLinkage: - return LLVMWeakODRLinkage; - case LLVMRustLinkage::AppendingLinkage: - return LLVMAppendingLinkage; - case LLVMRustLinkage::InternalLinkage: - return LLVMInternalLinkage; - case LLVMRustLinkage::PrivateLinkage: - return LLVMPrivateLinkage; - case LLVMRustLinkage::ExternalWeakLinkage: - return LLVMExternalWeakLinkage; - case LLVMRustLinkage::CommonLinkage: - return LLVMCommonLinkage; - } - report_fatal_error("Invalid LLVMRustLinkage value!"); -} - -extern "C" LLVMRustLinkage LLVMRustGetLinkage(LLVMValueRef V) { - return toRust(LLVMGetLinkage(V)); -} - -extern "C" void LLVMRustSetLinkage(LLVMValueRef V, - LLVMRustLinkage RustLinkage) { - LLVMSetLinkage(V, fromRust(RustLinkage)); -} - -// Returns true if both high and low were successfully set. Fails in case constant wasn’t any of -// the common sizes (1, 8, 16, 32, 64, 128 bits) -extern "C" bool LLVMRustConstInt128Get(LLVMValueRef CV, bool sext, uint64_t *high, uint64_t *low) -{ - auto C = unwrap<llvm::ConstantInt>(CV); - if (C->getBitWidth() > 128) { return false; } - APInt AP; - if (sext) { - AP = C->getValue().sextOrSelf(128); - } else { - AP = C->getValue().zextOrSelf(128); - } - *low = AP.getLoBits(64).getZExtValue(); - *high = AP.getHiBits(64).getZExtValue(); - return true; -} - -enum class LLVMRustVisibility { - Default = 0, - Hidden = 1, - Protected = 2, -}; - -static LLVMRustVisibility toRust(LLVMVisibility Vis) { - switch (Vis) { - case LLVMDefaultVisibility: - return LLVMRustVisibility::Default; - case LLVMHiddenVisibility: - return LLVMRustVisibility::Hidden; - case LLVMProtectedVisibility: - return LLVMRustVisibility::Protected; - } - report_fatal_error("Invalid LLVMRustVisibility value!"); -} - -static LLVMVisibility fromRust(LLVMRustVisibility Vis) { - switch (Vis) { - case LLVMRustVisibility::Default: - return LLVMDefaultVisibility; - case LLVMRustVisibility::Hidden: - return LLVMHiddenVisibility; - case LLVMRustVisibility::Protected: - return LLVMProtectedVisibility; - } - report_fatal_error("Invalid LLVMRustVisibility value!"); -} - -extern "C" LLVMRustVisibility LLVMRustGetVisibility(LLVMValueRef V) { - return toRust(LLVMGetVisibility(V)); -} - -// Oh hey, a binding that makes sense for once? (because LLVM’s own do not) -extern "C" LLVMValueRef LLVMRustBuildIntCast(LLVMBuilderRef B, LLVMValueRef Val, - LLVMTypeRef DestTy, bool isSigned) { - return wrap(unwrap(B)->CreateIntCast(unwrap(Val), unwrap(DestTy), isSigned, "")); -} - -extern "C" void LLVMRustSetVisibility(LLVMValueRef V, - LLVMRustVisibility RustVisibility) { - LLVMSetVisibility(V, fromRust(RustVisibility)); -} - -struct LLVMRustModuleBuffer { - std::string data; -}; - -extern "C" LLVMRustModuleBuffer* -LLVMRustModuleBufferCreate(LLVMModuleRef M) { -#if LLVM_VERSION_GE(10, 0) - auto Ret = std::make_unique<LLVMRustModuleBuffer>(); -#else - auto Ret = llvm::make_unique<LLVMRustModuleBuffer>(); -#endif - { - raw_string_ostream OS(Ret->data); - { - legacy::PassManager PM; - PM.add(createBitcodeWriterPass(OS)); - PM.run(*unwrap(M)); - } - } - return Ret.release(); -} - -extern "C" void -LLVMRustModuleBufferFree(LLVMRustModuleBuffer *Buffer) { - delete Buffer; -} - -extern "C" const void* -LLVMRustModuleBufferPtr(const LLVMRustModuleBuffer *Buffer) { - return Buffer->data.data(); -} - -extern "C" size_t -LLVMRustModuleBufferLen(const LLVMRustModuleBuffer *Buffer) { - return Buffer->data.length(); -} - -extern "C" uint64_t -LLVMRustModuleCost(LLVMModuleRef M) { - auto f = unwrap(M)->functions(); - return std::distance(std::begin(f), std::end(f)); -} - -// Vector reductions: -extern "C" LLVMValueRef -LLVMRustBuildVectorReduceFAdd(LLVMBuilderRef B, LLVMValueRef Acc, LLVMValueRef Src) { - return wrap(unwrap(B)->CreateFAddReduce(unwrap(Acc),unwrap(Src))); -} -extern "C" LLVMValueRef -LLVMRustBuildVectorReduceFMul(LLVMBuilderRef B, LLVMValueRef Acc, LLVMValueRef Src) { - return wrap(unwrap(B)->CreateFMulReduce(unwrap(Acc),unwrap(Src))); -} -extern "C" LLVMValueRef -LLVMRustBuildVectorReduceAdd(LLVMBuilderRef B, LLVMValueRef Src) { - return wrap(unwrap(B)->CreateAddReduce(unwrap(Src))); -} -extern "C" LLVMValueRef -LLVMRustBuildVectorReduceMul(LLVMBuilderRef B, LLVMValueRef Src) { - return wrap(unwrap(B)->CreateMulReduce(unwrap(Src))); -} -extern "C" LLVMValueRef -LLVMRustBuildVectorReduceAnd(LLVMBuilderRef B, LLVMValueRef Src) { - return wrap(unwrap(B)->CreateAndReduce(unwrap(Src))); -} -extern "C" LLVMValueRef -LLVMRustBuildVectorReduceOr(LLVMBuilderRef B, LLVMValueRef Src) { - return wrap(unwrap(B)->CreateOrReduce(unwrap(Src))); -} -extern "C" LLVMValueRef -LLVMRustBuildVectorReduceXor(LLVMBuilderRef B, LLVMValueRef Src) { - return wrap(unwrap(B)->CreateXorReduce(unwrap(Src))); -} -extern "C" LLVMValueRef -LLVMRustBuildVectorReduceMin(LLVMBuilderRef B, LLVMValueRef Src, bool IsSigned) { - return wrap(unwrap(B)->CreateIntMinReduce(unwrap(Src), IsSigned)); -} -extern "C" LLVMValueRef -LLVMRustBuildVectorReduceMax(LLVMBuilderRef B, LLVMValueRef Src, bool IsSigned) { - return wrap(unwrap(B)->CreateIntMaxReduce(unwrap(Src), IsSigned)); -} -extern "C" LLVMValueRef -LLVMRustBuildVectorReduceFMin(LLVMBuilderRef B, LLVMValueRef Src, bool NoNaN) { - return wrap(unwrap(B)->CreateFPMinReduce(unwrap(Src), NoNaN)); -} -extern "C" LLVMValueRef -LLVMRustBuildVectorReduceFMax(LLVMBuilderRef B, LLVMValueRef Src, bool NoNaN) { - return wrap(unwrap(B)->CreateFPMaxReduce(unwrap(Src), NoNaN)); -} - -extern "C" LLVMValueRef -LLVMRustBuildMinNum(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS) { - return wrap(unwrap(B)->CreateMinNum(unwrap(LHS),unwrap(RHS))); -} -extern "C" LLVMValueRef -LLVMRustBuildMaxNum(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS) { - return wrap(unwrap(B)->CreateMaxNum(unwrap(LHS),unwrap(RHS))); -} diff --git a/src/rustllvm/rustllvm.h b/src/rustllvm/rustllvm.h deleted file mode 100644 index 57b8664d3b6..00000000000 --- a/src/rustllvm/rustllvm.h +++ /dev/null @@ -1,115 +0,0 @@ -#include "llvm-c/BitReader.h" -#include "llvm-c/Core.h" -#include "llvm-c/Object.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/Triple.h" -#include "llvm/Analysis/Lint.h" -#include "llvm/Analysis/Passes.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/InlineAsm.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/Module.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/DynamicLibrary.h" -#include "llvm/Support/FormattedStream.h" -#include "llvm/Support/Host.h" -#include "llvm/Support/Memory.h" -#include "llvm/Support/SourceMgr.h" -#include "llvm/Support/TargetRegistry.h" -#include "llvm/Support/TargetSelect.h" -#include "llvm/Support/Timer.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetOptions.h" -#include "llvm/Transforms/IPO.h" -#include "llvm/Transforms/Instrumentation.h" -#include "llvm/Transforms/Scalar.h" -#include "llvm/Transforms/Vectorize.h" - -#define LLVM_VERSION_GE(major, minor) \ - (LLVM_VERSION_MAJOR > (major) || \ - LLVM_VERSION_MAJOR == (major) && LLVM_VERSION_MINOR >= (minor)) - -#define LLVM_VERSION_EQ(major, minor) \ - (LLVM_VERSION_MAJOR == (major) && LLVM_VERSION_MINOR == (minor)) - -#define LLVM_VERSION_LE(major, minor) \ - (LLVM_VERSION_MAJOR < (major) || \ - LLVM_VERSION_MAJOR == (major) && LLVM_VERSION_MINOR <= (minor)) - -#define LLVM_VERSION_LT(major, minor) (!LLVM_VERSION_GE((major), (minor))) - -#include "llvm/IR/LegacyPassManager.h" - -#include "llvm/Bitcode/BitcodeReader.h" -#include "llvm/Bitcode/BitcodeWriter.h" - -#include "llvm/IR/DIBuilder.h" -#include "llvm/IR/DebugInfo.h" -#include "llvm/IR/IRPrintingPasses.h" -#include "llvm/Linker/Linker.h" - -extern "C" void LLVMRustSetLastError(const char *); - -enum class LLVMRustResult { Success, Failure }; - -enum LLVMRustAttribute { - AlwaysInline = 0, - ByVal = 1, - Cold = 2, - InlineHint = 3, - MinSize = 4, - Naked = 5, - NoAlias = 6, - NoCapture = 7, - NoInline = 8, - NonNull = 9, - NoRedZone = 10, - NoReturn = 11, - NoUnwind = 12, - OptimizeForSize = 13, - ReadOnly = 14, - SExt = 15, - StructRet = 16, - UWTable = 17, - ZExt = 18, - InReg = 19, - SanitizeThread = 20, - SanitizeAddress = 21, - SanitizeMemory = 22, - NonLazyBind = 23, - OptimizeNone = 24, - ReturnsTwice = 25, - ReadNone = 26, - InaccessibleMemOnly = 27, -}; - -typedef struct OpaqueRustString *RustStringRef; -typedef struct LLVMOpaqueTwine *LLVMTwineRef; -typedef struct LLVMOpaqueSMDiagnostic *LLVMSMDiagnosticRef; - -extern "C" void LLVMRustStringWriteImpl(RustStringRef Str, const char *Ptr, - size_t Size); - -class RawRustStringOstream : public llvm::raw_ostream { - RustStringRef Str; - uint64_t Pos; - - void write_impl(const char *Ptr, size_t Size) override { - LLVMRustStringWriteImpl(Str, Ptr, Size); - Pos += Size; - } - - uint64_t current_pos() const override { return Pos; } - -public: - explicit RawRustStringOstream(RustStringRef Str) : Str(Str), Pos(0) {} - - ~RawRustStringOstream() { - // LLVM requires this. - flush(); - } -}; diff --git a/src/test/debuginfo/pretty-std-collections-hash.rs b/src/test/debuginfo/pretty-std-collections-hash.rs index e8f52deabd8..9f59936a92d 100644 --- a/src/test/debuginfo/pretty-std-collections-hash.rs +++ b/src/test/debuginfo/pretty-std-collections-hash.rs @@ -1,3 +1,7 @@ +// CDB doesn't like how libstd.natvis casts to tuples before this version. +// https://github.com/rust-lang/rust/issues/76352#issuecomment-687640746 +// min-cdb-version: 10.0.18362.1 + // cdb-only // compile-flags:-g diff --git a/src/test/mir-opt/equal_true.opt.InstCombine.diff b/src/test/mir-opt/equal_true.opt.InstCombine.diff new file mode 100644 index 00000000000..a26776e70d6 --- /dev/null +++ b/src/test/mir-opt/equal_true.opt.InstCombine.diff @@ -0,0 +1,35 @@ +- // MIR for `opt` before InstCombine ++ // MIR for `opt` after InstCombine + + fn opt(_1: bool) -> i32 { + debug x => _1; // in scope 0 at $DIR/equal_true.rs:3:8: 3:9 + let mut _0: i32; // return place in scope 0 at $DIR/equal_true.rs:3:20: 3:23 + let mut _2: bool; // in scope 0 at $DIR/equal_true.rs:4:8: 4:17 + let mut _3: bool; // in scope 0 at $DIR/equal_true.rs:4:8: 4:9 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/equal_true.rs:4:8: 4:17 + StorageLive(_3); // scope 0 at $DIR/equal_true.rs:4:8: 4:9 + _3 = _1; // scope 0 at $DIR/equal_true.rs:4:8: 4:9 +- _2 = Eq(move _3, const true); // scope 0 at $DIR/equal_true.rs:4:8: 4:17 ++ _2 = move _3; // scope 0 at $DIR/equal_true.rs:4:8: 4:17 + StorageDead(_3); // scope 0 at $DIR/equal_true.rs:4:16: 4:17 + switchInt(_2) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/equal_true.rs:4:5: 4:34 + } + + bb1: { + _0 = const 1_i32; // scope 0 at $DIR/equal_true.rs:4:31: 4:32 + goto -> bb3; // scope 0 at $DIR/equal_true.rs:4:5: 4:34 + } + + bb2: { + _0 = const 0_i32; // scope 0 at $DIR/equal_true.rs:4:20: 4:21 + goto -> bb3; // scope 0 at $DIR/equal_true.rs:4:5: 4:34 + } + + bb3: { + StorageDead(_2); // scope 0 at $DIR/equal_true.rs:5:1: 5:2 + return; // scope 0 at $DIR/equal_true.rs:5:2: 5:2 + } + } + diff --git a/src/test/mir-opt/equal_true.rs b/src/test/mir-opt/equal_true.rs new file mode 100644 index 00000000000..994cd194a45 --- /dev/null +++ b/src/test/mir-opt/equal_true.rs @@ -0,0 +1,9 @@ +// EMIT_MIR equal_true.opt.InstCombine.diff + +fn opt(x: bool) -> i32 { + if x == true { 0 } else { 1 } +} + +fn main() { + opt(true); +} diff --git a/src/test/mir-opt/graphviz.main.mir_map.0.dot b/src/test/mir-opt/graphviz.main.mir_map.0.dot index f5d8b84812a..df4f11f0f21 100644 --- a/src/test/mir-opt/graphviz.main.mir_map.0.dot +++ b/src/test/mir-opt/graphviz.main.mir_map.0.dot @@ -1,7 +1,7 @@ digraph Mir_0_3 { - graph [fontname="monospace"]; - node [fontname="monospace"]; - edge [fontname="monospace"]; + graph [fontname="Courier, monospace"]; + node [fontname="Courier, monospace"]; + edge [fontname="Courier, monospace"]; label=<fn main() -> ()<br align="left"/>>; bb0__0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">0</td></tr><tr><td align="left" balign="left">_0 = const ()<br/></td></tr><tr><td align="left">goto</td></tr></table>>]; bb1__0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">1</td></tr><tr><td align="left">resume</td></tr></table>>]; diff --git a/src/test/mir-opt/inline/inline-compatibility.rs b/src/test/mir-opt/inline/inline-compatibility.rs new file mode 100644 index 00000000000..ff9049edb4f --- /dev/null +++ b/src/test/mir-opt/inline/inline-compatibility.rs @@ -0,0 +1,39 @@ +// Checks that only functions with compatible attributes are inlined. +// +// only-x86_64 +// needs-sanitizer-address +// compile-flags: -Zsanitizer=address + +#![crate_type = "lib"] +#![feature(no_sanitize)] +#![feature(target_feature_11)] + +// EMIT_MIR inline_compatibility.inlined_target_feature.Inline.diff +#[target_feature(enable = "sse2")] +pub unsafe fn inlined_target_feature() { + target_feature(); +} + +// EMIT_MIR inline_compatibility.not_inlined_target_feature.Inline.diff +pub unsafe fn not_inlined_target_feature() { + target_feature(); +} + +// EMIT_MIR inline_compatibility.inlined_no_sanitize.Inline.diff +#[no_sanitize(address)] +pub unsafe fn inlined_no_sanitize() { + no_sanitize(); +} + +// EMIT_MIR inline_compatibility.not_inlined_no_sanitize.Inline.diff +pub unsafe fn not_inlined_no_sanitize() { + no_sanitize(); +} + +#[inline] +#[target_feature(enable = "sse2")] +pub unsafe fn target_feature() {} + +#[inline] +#[no_sanitize(address, memory)] +pub unsafe fn no_sanitize() {} diff --git a/src/test/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff b/src/test/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff new file mode 100644 index 00000000000..7b0ecaffdd7 --- /dev/null +++ b/src/test/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff @@ -0,0 +1,25 @@ +- // MIR for `inlined_no_sanitize` before Inline ++ // MIR for `inlined_no_sanitize` after Inline + + fn inlined_no_sanitize() -> () { + let mut _0: (); // return place in scope 0 at $DIR/inline-compatibility.rs:24:37: 24:37 + let _1: (); // in scope 0 at $DIR/inline-compatibility.rs:25:5: 25:18 ++ scope 1 { ++ } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/inline-compatibility.rs:25:5: 25:18 +- _1 = no_sanitize() -> bb1; // scope 0 at $DIR/inline-compatibility.rs:25:5: 25:18 +- // mir::Constant +- // + span: $DIR/inline-compatibility.rs:25:5: 25:16 +- // + literal: Const { ty: unsafe fn() {no_sanitize}, val: Value(Scalar(<ZST>)) } +- } +- +- bb1: { ++ _1 = const (); // scope 1 at $DIR/inline-compatibility.rs:39:29: 39:31 + StorageDead(_1); // scope 0 at $DIR/inline-compatibility.rs:25:18: 25:19 + _0 = const (); // scope 0 at $DIR/inline-compatibility.rs:24:37: 26:2 + return; // scope 0 at $DIR/inline-compatibility.rs:26:2: 26:2 + } + } + diff --git a/src/test/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff b/src/test/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff new file mode 100644 index 00000000000..f55eae6c50a --- /dev/null +++ b/src/test/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff @@ -0,0 +1,25 @@ +- // MIR for `inlined_target_feature` before Inline ++ // MIR for `inlined_target_feature` after Inline + + fn inlined_target_feature() -> () { + let mut _0: (); // return place in scope 0 at $DIR/inline-compatibility.rs:13:40: 13:40 + let _1: (); // in scope 0 at $DIR/inline-compatibility.rs:14:5: 14:21 ++ scope 1 { ++ } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/inline-compatibility.rs:14:5: 14:21 +- _1 = target_feature() -> bb1; // scope 0 at $DIR/inline-compatibility.rs:14:5: 14:21 +- // mir::Constant +- // + span: $DIR/inline-compatibility.rs:14:5: 14:19 +- // + literal: Const { ty: unsafe fn() {target_feature}, val: Value(Scalar(<ZST>)) } +- } +- +- bb1: { ++ _1 = const (); // scope 1 at $DIR/inline-compatibility.rs:35:32: 35:34 + StorageDead(_1); // scope 0 at $DIR/inline-compatibility.rs:14:21: 14:22 + _0 = const (); // scope 0 at $DIR/inline-compatibility.rs:13:40: 15:2 + return; // scope 0 at $DIR/inline-compatibility.rs:15:2: 15:2 + } + } + diff --git a/src/test/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.diff b/src/test/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.diff new file mode 100644 index 00000000000..651eadc1e84 --- /dev/null +++ b/src/test/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.diff @@ -0,0 +1,22 @@ +- // MIR for `not_inlined_no_sanitize` before Inline ++ // MIR for `not_inlined_no_sanitize` after Inline + + fn not_inlined_no_sanitize() -> () { + let mut _0: (); // return place in scope 0 at $DIR/inline-compatibility.rs:29:41: 29:41 + let _1: (); // in scope 0 at $DIR/inline-compatibility.rs:30:5: 30:18 + + bb0: { + StorageLive(_1); // scope 0 at $DIR/inline-compatibility.rs:30:5: 30:18 + _1 = no_sanitize() -> bb1; // scope 0 at $DIR/inline-compatibility.rs:30:5: 30:18 + // mir::Constant + // + span: $DIR/inline-compatibility.rs:30:5: 30:16 + // + literal: Const { ty: unsafe fn() {no_sanitize}, val: Value(Scalar(<ZST>)) } + } + + bb1: { + StorageDead(_1); // scope 0 at $DIR/inline-compatibility.rs:30:18: 30:19 + _0 = const (); // scope 0 at $DIR/inline-compatibility.rs:29:41: 31:2 + return; // scope 0 at $DIR/inline-compatibility.rs:31:2: 31:2 + } + } + diff --git a/src/test/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.diff b/src/test/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.diff new file mode 100644 index 00000000000..55b9edf3adc --- /dev/null +++ b/src/test/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.diff @@ -0,0 +1,22 @@ +- // MIR for `not_inlined_target_feature` before Inline ++ // MIR for `not_inlined_target_feature` after Inline + + fn not_inlined_target_feature() -> () { + let mut _0: (); // return place in scope 0 at $DIR/inline-compatibility.rs:18:44: 18:44 + let _1: (); // in scope 0 at $DIR/inline-compatibility.rs:19:5: 19:21 + + bb0: { + StorageLive(_1); // scope 0 at $DIR/inline-compatibility.rs:19:5: 19:21 + _1 = target_feature() -> bb1; // scope 0 at $DIR/inline-compatibility.rs:19:5: 19:21 + // mir::Constant + // + span: $DIR/inline-compatibility.rs:19:5: 19:19 + // + literal: Const { ty: unsafe fn() {target_feature}, val: Value(Scalar(<ZST>)) } + } + + bb1: { + StorageDead(_1); // scope 0 at $DIR/inline-compatibility.rs:19:21: 19:22 + _0 = const (); // scope 0 at $DIR/inline-compatibility.rs:18:44: 20:2 + return; // scope 0 at $DIR/inline-compatibility.rs:20:2: 20:2 + } + } + diff --git a/src/test/mir-opt/not_equal_false.opt.InstCombine.diff b/src/test/mir-opt/not_equal_false.opt.InstCombine.diff new file mode 100644 index 00000000000..d8621b90ad8 --- /dev/null +++ b/src/test/mir-opt/not_equal_false.opt.InstCombine.diff @@ -0,0 +1,72 @@ +- // MIR for `opt` before InstCombine ++ // MIR for `opt` after InstCombine + + fn opt(_1: Option<()>) -> bool { + debug x => _1; // in scope 0 at $DIR/not_equal_false.rs:3:8: 3:9 + let mut _0: bool; // return place in scope 0 at $DIR/not_equal_false.rs:3:26: 3:30 + let mut _2: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _3: isize; // in scope 0 at $DIR/not_equal_false.rs:4:17: 4:21 + let mut _4: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _5: isize; // in scope 0 at $DIR/not_equal_false.rs:4:38: 4:45 + + bb0: { + StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _3 = discriminant(_1); // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21 + _2 = Eq(_3, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + goto -> bb7; // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21 + } + + bb1: { + _0 = const true; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 + goto -> bb4; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 + } + + bb2: { + _0 = const false; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 + goto -> bb4; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 + } + + bb3: { + StorageLive(_4); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _5 = discriminant(_1); // scope 0 at $DIR/not_equal_false.rs:4:38: 4:45 + _4 = Eq(_5, const 1_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + goto -> bb10; // scope 0 at $DIR/not_equal_false.rs:4:38: 4:45 + } + + bb4: { + StorageDead(_4); // scope 0 at $DIR/not_equal_false.rs:4:45: 4:46 + StorageDead(_2); // scope 0 at $DIR/not_equal_false.rs:4:45: 4:46 + return; // scope 0 at $DIR/not_equal_false.rs:5:2: 5:2 + } + + bb5: { + _2 = const false; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + goto -> bb7; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + } + + bb6: { + _2 = const true; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + goto -> bb7; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + } + + bb7: { + switchInt(move _2) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 + } + + bb8: { + _4 = const false; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + goto -> bb10; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + } + + bb9: { + _4 = const true; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + goto -> bb10; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + } + + bb10: { +- _0 = Ne(_4, const false); // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 ++ _0 = _4; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 + goto -> bb4; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 + } + } + diff --git a/src/test/mir-opt/not_equal_false.rs b/src/test/mir-opt/not_equal_false.rs new file mode 100644 index 00000000000..a98a2834e8e --- /dev/null +++ b/src/test/mir-opt/not_equal_false.rs @@ -0,0 +1,9 @@ +// EMIT_MIR not_equal_false.opt.InstCombine.diff + +fn opt(x: Option<()>) -> bool { + matches!(x, None) || matches!(x, Some(_)) +} + +fn main() { + opt(None); +} diff --git a/src/test/mir-opt/simplify_try_if_let.{{impl}}-append.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_try_if_let.{{impl}}-append.SimplifyArmIdentity.diff index 869e3647f45..11f6b533741 100644 --- a/src/test/mir-opt/simplify_try_if_let.{{impl}}-append.SimplifyArmIdentity.diff +++ b/src/test/mir-opt/simplify_try_if_let.{{impl}}-append.SimplifyArmIdentity.diff @@ -18,7 +18,8 @@ debug tail => _4; // in scope 1 at $DIR/simplify_try_if_let.rs:23:18: 23:26 let _8: std::ptr::NonNull<Node>; // in scope 1 at $DIR/simplify_try_if_let.rs:26:29: 26:39 scope 2 { - debug other_head => _8; // in scope 2 at $DIR/simplify_try_if_let.rs:26:29: 26:39 +- debug other_head => _8; // in scope 2 at $DIR/simplify_try_if_let.rs:26:29: 26:39 ++ debug other_head => ((_9 as Some).0: std::ptr::NonNull<Node>); // in scope 2 at $DIR/simplify_try_if_let.rs:26:29: 26:39 scope 3 { } } @@ -65,11 +66,12 @@ StorageLive(_8); // scope 1 at $DIR/simplify_try_if_let.rs:26:29: 26:39 _8 = ((_5 as Some).0: std::ptr::NonNull<Node>); // scope 1 at $DIR/simplify_try_if_let.rs:26:29: 26:39 StorageLive(_9); // scope 3 at $DIR/simplify_try_if_let.rs:28:46: 28:62 - StorageLive(_10); // scope 3 at $DIR/simplify_try_if_let.rs:28:51: 28:61 - _10 = _8; // scope 3 at $DIR/simplify_try_if_let.rs:28:51: 28:61 - ((_9 as Some).0: std::ptr::NonNull<Node>) = move _10; // scope 3 at $DIR/simplify_try_if_let.rs:28:46: 28:62 - discriminant(_9) = 1; // scope 3 at $DIR/simplify_try_if_let.rs:28:46: 28:62 - StorageDead(_10); // scope 3 at $DIR/simplify_try_if_let.rs:28:61: 28:62 +- StorageLive(_10); // scope 3 at $DIR/simplify_try_if_let.rs:28:51: 28:61 +- _10 = _8; // scope 3 at $DIR/simplify_try_if_let.rs:28:51: 28:61 +- ((_9 as Some).0: std::ptr::NonNull<Node>) = move _10; // scope 3 at $DIR/simplify_try_if_let.rs:28:46: 28:62 +- discriminant(_9) = 1; // scope 3 at $DIR/simplify_try_if_let.rs:28:46: 28:62 +- StorageDead(_10); // scope 3 at $DIR/simplify_try_if_let.rs:28:61: 28:62 ++ _9 = move _5; // scope 3 at $DIR/simplify_try_if_let.rs:28:46: 28:62 StorageLive(_11); // scope 3 at $DIR/simplify_try_if_let.rs:28:25: 28:38 StorageLive(_12); // scope 3 at $DIR/simplify_try_if_let.rs:28:25: 28:29 _12 = &mut _4; // scope 3 at $DIR/simplify_try_if_let.rs:28:25: 28:29 diff --git a/src/test/mir-opt/spanview_block.main.mir_map.0.html b/src/test/mir-opt/spanview_block.main.mir_map.0.html index 7c1b7bc3b84..8f6b1307971 100644 --- a/src/test/mir-opt/spanview_block.main.mir_map.0.html +++ b/src/test/mir-opt/spanview_block.main.mir_map.0.html @@ -59,9 +59,9 @@ </style> </head> <body> -<div class="code" style="counter-reset: line 4"><span class="line"><span class="code" style="--layer: 0">fn main() </span><span><span class="code even" style="--layer: 1" title="bb0: $DIR/spanview-block.rs:5:11: 5:13: +<div class="code" style="counter-reset: line 4"><span class="line"><span class="code" style="--layer: 0">fn main() </span><span><span class="code even" style="--layer: 1" title="0: $DIR/spanview-block.rs:5:11: 5:13: 5:11-5:13: Assign: _0 = const () - 5:13-5:13: Goto: goto -> bb2"><span class="annotation">@bb0:</span> {}</span></span><span><span class="code even" style="--layer: 1" title="bb2: $DIR/spanview-block.rs:5:13: 5:13: - 5:13-5:13: Return: return"><span class="annotation">@bb2</span></span></span></span></div> + 5:13-5:13: Goto: goto -> bb2"><span class="annotation">0⦊</span>{}<span class="annotation">⦉0</span></span></span><span><span class="code odd" style="--layer: 1" title="2: $DIR/spanview-block.rs:5:13: 5:13: + 5:13-5:13: Return: return"><span class="annotation">2⦊</span>‸<span class="annotation">⦉2</span></span></span></span></div> </body> </html> diff --git a/src/test/mir-opt/spanview_statement.main.mir_map.0.html b/src/test/mir-opt/spanview_statement.main.mir_map.0.html index f8662a3277a..072d22473a9 100644 --- a/src/test/mir-opt/spanview_statement.main.mir_map.0.html +++ b/src/test/mir-opt/spanview_statement.main.mir_map.0.html @@ -59,9 +59,9 @@ </style> </head> <body> -<div class="code" style="counter-reset: line 4"><span class="line"><span class="code" style="--layer: 0">fn main() </span><span><span class="code even" style="--layer: 1" title="bb0[0]: $DIR/spanview-statement.rs:5:11: 5:13: - 5:11-5:13: Assign: _0 = const ()"><span class="annotation">@bb0[0]:</span> {}</span></span><span><span class="code even" style="--layer: 1" title="bb0`Goto`: $DIR/spanview-statement.rs:5:13: 5:13: - 5:13-5:13: Goto: goto -> bb2"><span class="annotation">@bb0`Goto`</span></span></span><span><span class="code even" style="--layer: 1" title="bb2`Return`: $DIR/spanview-statement.rs:5:13: 5:13: - 5:13-5:13: Return: return"><span class="annotation">@bb2`Return`</span></span></span></span></div> +<div class="code" style="counter-reset: line 4"><span class="line"><span class="code" style="--layer: 0">fn main() </span><span><span class="code even" style="--layer: 1" title="0[0]: $DIR/spanview-statement.rs:5:11: 5:13: + 5:11-5:13: Assign: _0 = const ()"><span class="annotation">0[0]⦊</span>{}<span class="annotation">⦉0[0]</span></span></span><span><span class="code odd" style="--layer: 1" title="0:Goto: $DIR/spanview-statement.rs:5:13: 5:13: + 5:13-5:13: Goto: goto -> bb2"><span class="annotation">0:Goto⦊</span>‸<span class="annotation">⦉0:Goto</span></span></span><span><span class="code even" style="--layer: 1" title="2:Return: $DIR/spanview-statement.rs:5:13: 5:13: + 5:13-5:13: Return: return"><span class="annotation">2:Return⦊</span>‸<span class="annotation">⦉2:Return</span></span></span></span></div> </body> </html> diff --git a/src/test/mir-opt/spanview_terminator.main.mir_map.0.html b/src/test/mir-opt/spanview_terminator.main.mir_map.0.html index d0a11a8d262..e023f0f8aea 100644 --- a/src/test/mir-opt/spanview_terminator.main.mir_map.0.html +++ b/src/test/mir-opt/spanview_terminator.main.mir_map.0.html @@ -59,8 +59,8 @@ </style> </head> <body> -<div class="code" style="counter-reset: line 4"><span class="line"><span class="code" style="--layer: 0">fn main() {}</span><span><span class="code even" style="--layer: 1" title="bb0`Goto`: $DIR/spanview-terminator.rs:5:13: 5:13: - 5:13-5:13: Goto: goto -> bb2"><span class="annotation">@bb0`Goto`</span></span></span><span><span class="code even" style="--layer: 1" title="bb2`Return`: $DIR/spanview-terminator.rs:5:13: 5:13: - 5:13-5:13: Return: return"><span class="annotation">@bb2`Return`</span></span></span></span></div> +<div class="code" style="counter-reset: line 4"><span class="line"><span class="code" style="--layer: 0">fn main() {}</span><span><span class="code even" style="--layer: 1" title="0:Goto: $DIR/spanview-terminator.rs:5:13: 5:13: + 5:13-5:13: Goto: goto -> bb2"><span class="annotation">0:Goto⦊</span>‸<span class="annotation">⦉0:Goto</span></span></span><span><span class="code odd" style="--layer: 1" title="2:Return: $DIR/spanview-terminator.rs:5:13: 5:13: + 5:13-5:13: Return: return"><span class="annotation">2:Return⦊</span>‸<span class="annotation">⦉2:Return</span></span></span></span></div> </body> </html> diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/Makefile b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/Makefile index a16b4f61dcb..cb081fb641b 100644 --- a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/Makefile +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/Makefile @@ -1,4 +1,8 @@ # needs-profiler-support +# ignore-windows-gnu + +# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works +# properly. Since we only have GCC on the CI ignore the test for now. # ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and # `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`. diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/Makefile b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/Makefile index 08f311f1702..ab826d07e05 100644 --- a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/Makefile +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/Makefile @@ -1,5 +1,9 @@ # needs-profiler-support # ignore-msvc +# ignore-windows-gnu + +# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works +# properly. Since we only have GCC on the CI ignore the test for now. # LINK_DEAD_CODE requires ignore-msvc due to Issue #76038 LINK_DEAD_CODE=yes @@ -8,4 +12,4 @@ LINK_DEAD_CODE=yes # ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and # `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`. -# See ../instrument-coverage/coverage_tools.mk for more information. \ No newline at end of file +# See ../instrument-coverage/coverage_tools.mk for more information. diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html index faa5d65e7e7..1ea9aba488e 100644 --- a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html @@ -62,12 +62,12 @@ <div class="code" style="counter-reset: line 2"><span class="line"><span class="code" style="--layer: 0">fn main() {</span></span> <span class="line"><span class="code" style="--layer: 0"> let mut countdown = 0;</span></span> <span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="bb2: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6: - 5:5-7:6: FalseEdge: falseEdge -> [real: bb4, imaginary: bb3]"><span class="annotation">@2</span></span></span><span class="code even" style="--layer: 2" title="bb4: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6: + 5:5-7:6: FalseEdge: falseEdge -> [real: bb4, imaginary: bb3]"><span class="annotation">2⦊</span></span></span><span class="code even" style="--layer: 2" title="bb4: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6: 6:9-6:23: Assign: _1 = const 10_i32 5:13-7:6: Assign: _2 = const () - 5:5-7:6: Goto: goto -> bb5"><span class="annotation">@4</span></span><span class="code even" style="--layer: 3" title="bb3: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6: + 5:5-7:6: Goto: goto -> bb5"><span class="annotation">4⦊</span></span><span class="code even" style="--layer: 3" title="bb3: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6: 5:5-7:6: Assign: _2 = const () - 5:5-7:6: Goto: goto -> bb5"><span class="annotation">@3:</span> if </span><span class="code even" style="--layer: 4" title="bb0: ../instrument-coverage/coverage_of_if_else.rs:5:8: 5:12: + 5:5-7:6: Goto: goto -> bb5"><span class="annotation">3⦊</span>if </span><span class="code even" style="--layer: 4" title="bb0: ../instrument-coverage/coverage_of_if_else.rs:5:8: 5:12: 4:9-4:22: StorageLive: StorageLive(_1) 4:25-4:26: Assign: _1 = const 0_i32 4:9-4:22: FakeRead: FakeRead(ForLet, _1) @@ -75,25 +75,29 @@ 5:8-5:12: StorageLive: StorageLive(_3) 5:8-5:12: Assign: _3 = const true 5:8-5:12: FakeRead: FakeRead(ForMatchedPlace, _3) - 5:5-7:6: SwitchInt: switchInt(_3) -> [false: bb3, otherwise: bb2]"><span class="annotation">@0:</span> true</span><span class="code even" style="--layer: 3" title="bb3: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6: + 5:5-7:6: SwitchInt: switchInt(_3) -> [false: bb3, otherwise: bb2]"><span class="annotation">0⦊</span>true<span class="annotation">⦉0</span></span><span class="code even" style="--layer: 3" title="bb3: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6: 5:5-7:6: Assign: _2 = const () - 5:5-7:6: Goto: goto -> bb5"><span class="annotation">@3:</span> {</span></span> + 5:5-7:6: Goto: goto -> bb5"> {</span></span> <span class="line"><span class="code even" style="--layer: 3" title="bb3: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6: 5:5-7:6: Assign: _2 = const () 5:5-7:6: Goto: goto -> bb5"> countdown = 10;</span></span> <span class="line"><span class="code even" style="--layer: 3" title="bb3: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6: 5:5-7:6: Assign: _2 = const () - 5:5-7:6: Goto: goto -> bb5"> }</span><span class="code" style="--layer: 0"></span></span> + 5:5-7:6: Goto: goto -> bb5"> }<span class="annotation">⦉3</span></span><span class="code even" style="--layer: 2" title="bb4: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6: + 6:9-6:23: Assign: _1 = const 10_i32 + 5:13-7:6: Assign: _2 = const () + 5:5-7:6: Goto: goto -> bb5"><span class="annotation">⦉4</span></span><span><span class="code even" style="--layer: 1" title="bb2: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6: + 5:5-7:6: FalseEdge: falseEdge -> [real: bb4, imaginary: bb3]"><span class="annotation">⦉2</span></span></span><span class="code" style="--layer: 0"></span></span> <span class="line"><span class="code" style="--layer: 0"></span></span> -<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="bb6: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: - 9:5-18:6: FalseEdge: falseEdge -> [real: bb8, imaginary: bb7]"><span class="annotation">@6</span></span></span><span class="code even" style="--layer: 2" title="bb9: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: +<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="bb6: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: + 9:5-18:6: FalseEdge: falseEdge -> [real: bb8, imaginary: bb7]"><span class="annotation">6⦊</span></span></span><span class="code even" style="--layer: 2" title="bb9: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: 10:9-10:23: Assign: _1 = move (_7.0: i32) 9:22-11:6: Assign: _4 = const () - 9:5-18:6: Goto: goto -> bb28"><span class="annotation">@9</span></span><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: + 9:5-18:6: Goto: goto -> bb28"><span class="annotation">9⦊</span></span><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: 15:9-15:23: Assign: _1 = move (_19.0: i32) 11:29-16:6: Assign: _4 = const () 18:5-18:6: StorageDead: StorageDead(_8) - 9:5-18:6: Goto: goto -> bb28"><span class="annotation">@25:</span> if </span><span class="code even" style="--layer: 4" title="bb5: ../instrument-coverage/coverage_of_if_else.rs:9:8: 9:21: + 9:5-18:6: Goto: goto -> bb28"><span class="annotation">25⦊</span>if </span><span class="code even" style="--layer: 4" title="bb5: ../instrument-coverage/coverage_of_if_else.rs:9:8: 9:21: 7:5-7:6: StorageDead: StorageDead(_3) 7:5-7:6: StorageDead: StorageDead(_2) 9:5-18:6: StorageLive: StorageLive(_4) @@ -103,61 +107,61 @@ 9:8-9:21: Assign: _5 = Gt(move _6, const 7_i32) 9:20-9:21: StorageDead: StorageDead(_6) 9:8-9:21: FakeRead: FakeRead(ForMatchedPlace, _5) - 9:5-18:6: SwitchInt: switchInt(_5) -> [false: bb7, otherwise: bb6]"><span class="annotation">@5:</span> countdown > 7</span><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: + 9:5-18:6: SwitchInt: switchInt(_5) -> [false: bb7, otherwise: bb6]"><span class="annotation">5⦊</span>countdown > 7<span class="annotation">⦉5</span></span><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: 15:9-15:23: Assign: _1 = move (_19.0: i32) 11:29-16:6: Assign: _4 = const () 18:5-18:6: StorageDead: StorageDead(_8) - 9:5-18:6: Goto: goto -> bb28"><span class="annotation">@25:</span> {</span></span> + 9:5-18:6: Goto: goto -> bb28"> {</span></span> <span class="line"><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: 15:9-15:23: Assign: _1 = move (_19.0: i32) 11:29-16:6: Assign: _4 = const () 18:5-18:6: StorageDead: StorageDead(_8) 9:5-18:6: Goto: goto -> bb28"> </span><span class="code odd" style="--layer: 4" title="bb8: ../instrument-coverage/coverage_of_if_else.rs:10:9: 10:23: 10:9-10:23: Assign: _7 = CheckedSub(_1, const 4_i32) - 10:9-10:23: Assert: assert(!move (_7.1: bool), "attempt to compute `{} - {}` which would overflow", _1, const 4_i32) -> [success: bb9, unwind: bb1]"><span class="annotation">@8:</span> countdown -= 4</span><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: + 10:9-10:23: Assert: assert(!move (_7.1: bool), "attempt to compute `{} - {}` which would overflow", _1, const 4_i32) -> [success: bb9, unwind: bb1]"><span class="annotation">8⦊</span>countdown -= 4<span class="annotation">⦉8</span></span><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: 15:9-15:23: Assign: _1 = move (_19.0: i32) 11:29-16:6: Assign: _4 = const () 18:5-18:6: StorageDead: StorageDead(_8) - 9:5-18:6: Goto: goto -> bb28"><span class="annotation">@25:</span> ;</span></span> + 9:5-18:6: Goto: goto -> bb28">;</span></span> <span class="line"><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: 15:9-15:23: Assign: _1 = move (_19.0: i32) 11:29-16:6: Assign: _4 = const () 18:5-18:6: StorageDead: StorageDead(_8) 9:5-18:6: Goto: goto -> bb28"> } else </span><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6: - 11:12-18:6: FalseEdge: falseEdge -> [real: bb12, imaginary: bb11]"><span class="annotation">@10:</span> if </span><span class="code even" style="--layer: 5" title="bb7: ../instrument-coverage/coverage_of_if_else.rs:11:15: 11:28: + 11:12-18:6: FalseEdge: falseEdge -> [real: bb12, imaginary: bb11]"><span class="annotation">10⦊</span>if </span><span class="code even" style="--layer: 5" title="bb7: ../instrument-coverage/coverage_of_if_else.rs:11:15: 11:28: 11:15-11:28: StorageLive: StorageLive(_8) 11:15-11:24: StorageLive: StorageLive(_9) 11:15-11:24: Assign: _9 = _1 11:15-11:28: Assign: _8 = Gt(move _9, const 2_i32) 11:27-11:28: StorageDead: StorageDead(_9) 11:15-11:28: FakeRead: FakeRead(ForMatchedPlace, _8) - 11:12-18:6: SwitchInt: switchInt(_8) -> [false: bb11, otherwise: bb10]"><span class="annotation">@7:</span> countdown > 2</span><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6: - 11:12-18:6: FalseEdge: falseEdge -> [real: bb12, imaginary: bb11]"><span class="annotation">@10:</span> {</span></span> + 11:12-18:6: SwitchInt: switchInt(_8) -> [false: bb11, otherwise: bb10]"><span class="annotation">7⦊</span>countdown > 2<span class="annotation">⦉7</span></span><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6: + 11:12-18:6: FalseEdge: falseEdge -> [real: bb12, imaginary: bb11]"> {</span></span> <span class="line"><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6: 11:12-18:6: FalseEdge: falseEdge -> [real: bb12, imaginary: bb11]"> </span><span class="code odd" style="--layer: 5" title="bb22: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10: 12:9-14:10: Assign: _10 = const () - 12:9-14:10: Goto: goto -> bb24"><span class="annotation">@22</span></span><span class="code even" style="--layer: 6" title="bb23: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10: + 12:9-14:10: Goto: goto -> bb24"><span class="annotation">22⦊</span></span><span class="code even" style="--layer: 6" title="bb23: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10: 13:13-13:26: Assign: _1 = const 0_i32 12:61-14:10: Assign: _10 = const () - 12:9-14:10: Goto: goto -> bb24"><span class="annotation">@23</span></span><span class="code even" style="--layer: 7" title="bb21: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10: - 12:9-14:10: FalseEdge: falseEdge -> [real: bb23, imaginary: bb22]"><span class="annotation">@21:</span> if </span><span class="code even" style="--layer: 8" title="bb14: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: + 12:9-14:10: Goto: goto -> bb24"><span class="annotation">23⦊</span></span><span class="code even" style="--layer: 7" title="bb21: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10: + 12:9-14:10: FalseEdge: falseEdge -> [real: bb23, imaginary: bb22]"><span class="annotation">21⦊</span>if </span><span class="code even" style="--layer: 8" title="bb14: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: 12:12-12:60: Assign: _11 = const false - 12:12-12:60: Goto: goto -> bb16"><span class="annotation">@14</span></span><span class="code even" style="--layer: 9" title="bb15: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: + 12:12-12:60: Goto: goto -> bb16"><span class="annotation">14⦊</span></span><span class="code even" style="--layer: 9" title="bb15: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: 12:46-12:60: StorageLive: StorageLive(_17) 12:46-12:55: StorageLive: StorageLive(_18) 12:46-12:55: Assign: _18 = _1 12:46-12:60: Assign: _17 = Ne(move _18, const 9_i32) 12:59-12:60: StorageDead: StorageDead(_18) - 12:12-12:60: SwitchInt: switchInt(move _17) -> [false: bb14, otherwise: bb13]"><span class="annotation">@15</span></span><span class="code even" style="--layer: 10" title="bb16: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: + 12:12-12:60: SwitchInt: switchInt(move _17) -> [false: bb14, otherwise: bb13]"><span class="annotation">15⦊</span></span><span class="code even" style="--layer: 10" title="bb16: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: 12:59-12:60: StorageDead: StorageDead(_17) 12:59-12:60: StorageDead: StorageDead(_12) 12:12-12:60: FakeRead: FakeRead(ForMatchedPlace, _11) - 12:9-14:10: SwitchInt: switchInt(_11) -> [false: bb22, otherwise: bb21]"><span class="annotation">@16</span></span><span class="code even" style="--layer: 11" title="bb13: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: + 12:9-14:10: SwitchInt: switchInt(_11) -> [false: bb22, otherwise: bb21]"><span class="annotation">16⦊</span></span><span class="code even" style="--layer: 11" title="bb13: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: 12:12-12:60: Assign: _11 = const true - 12:12-12:60: Goto: goto -> bb16"><span class="annotation">@13</span></span><span class="code even" style="--layer: 12" title="bb20: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: + 12:12-12:60: Goto: goto -> bb16"><span class="annotation">13⦊</span></span><span class="code even" style="--layer: 12" title="bb20: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: 12:41-12:42: StorageDead: StorageDead(_15) 12:41-12:42: StorageDead: StorageDead(_13) - 12:12-12:60: SwitchInt: switchInt(move _12) -> [false: bb15, otherwise: bb13]"><span class="annotation">@20</span></span><span class="code even" style="--layer: 13" title="bb12: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: + 12:12-12:60: SwitchInt: switchInt(move _12) -> [false: bb15, otherwise: bb13]"><span class="annotation">20⦊</span></span><span class="code even" style="--layer: 13" title="bb12: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: 12:9-14:10: StorageLive: StorageLive(_10) 12:12-12:60: StorageLive: StorageLive(_11) 12:12-12:42: StorageLive: StorageLive(_12) @@ -166,17 +170,25 @@ 12:12-12:21: Assign: _14 = _1 12:12-12:25: Assign: _13 = Lt(move _14, const 1_i32) 12:24-12:25: StorageDead: StorageDead(_14) - 12:12-12:42: SwitchInt: switchInt(move _13) -> [false: bb19, otherwise: bb17]"><span class="annotation">@12</span></span><span class="code even" style="--layer: 14" title="bb18: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:42: + 12:12-12:42: SwitchInt: switchInt(move _13) -> [false: bb19, otherwise: bb17]"><span class="annotation">12⦊</span></span><span class="code even" style="--layer: 14" title="bb18: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:42: 12:12-12:42: Assign: _12 = const false - 12:12-12:42: Goto: goto -> bb20"><span class="annotation">@18</span></span><span class="code even" style="--layer: 15" title="bb19: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:42: + 12:12-12:42: Goto: goto -> bb20"><span class="annotation">18⦊</span></span><span class="code even" style="--layer: 15" title="bb19: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:42: 12:29-12:42: StorageLive: StorageLive(_15) 12:29-12:38: StorageLive: StorageLive(_16) 12:29-12:38: Assign: _16 = _1 12:29-12:42: Assign: _15 = Gt(move _16, const 5_i32) 12:41-12:42: StorageDead: StorageDead(_16) - 12:12-12:42: SwitchInt: switchInt(move _15) -> [false: bb18, otherwise: bb17]"><span class="annotation">@19</span></span><span class="code even" style="--layer: 16" title="bb17: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:42: + 12:12-12:42: SwitchInt: switchInt(move _15) -> [false: bb18, otherwise: bb17]"><span class="annotation">19⦊</span></span><span class="code even" style="--layer: 16" title="bb17: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:42: 12:12-12:42: Assign: _12 = const true - 12:12-12:42: Goto: goto -> bb20"><span class="annotation">@17:</span> countdown < 1 || countdown > 5</span><span class="code even" style="--layer: 13" title="bb12: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: + 12:12-12:42: Goto: goto -> bb20"><span class="annotation">17⦊</span>countdown < 1 || countdown > 5<span class="annotation">⦉17</span></span><span class="code even" style="--layer: 15" title="bb19: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:42: + 12:29-12:42: StorageLive: StorageLive(_15) + 12:29-12:38: StorageLive: StorageLive(_16) + 12:29-12:38: Assign: _16 = _1 + 12:29-12:42: Assign: _15 = Gt(move _16, const 5_i32) + 12:41-12:42: StorageDead: StorageDead(_16) + 12:12-12:42: SwitchInt: switchInt(move _15) -> [false: bb18, otherwise: bb17]"><span class="annotation">⦉19</span></span><span class="code even" style="--layer: 14" title="bb18: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:42: + 12:12-12:42: Assign: _12 = const false + 12:12-12:42: Goto: goto -> bb20"><span class="annotation">⦉18</span></span><span class="code even" style="--layer: 13" title="bb12: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: 12:9-14:10: StorageLive: StorageLive(_10) 12:12-12:60: StorageLive: StorageLive(_11) 12:12-12:42: StorageLive: StorageLive(_12) @@ -185,8 +197,25 @@ 12:12-12:21: Assign: _14 = _1 12:12-12:25: Assign: _13 = Lt(move _14, const 1_i32) 12:24-12:25: StorageDead: StorageDead(_14) - 12:12-12:42: SwitchInt: switchInt(move _13) -> [false: bb19, otherwise: bb17]"><span class="annotation">@12:</span> || countdown != 9</span><span class="code even" style="--layer: 7" title="bb21: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10: - 12:9-14:10: FalseEdge: falseEdge -> [real: bb23, imaginary: bb22]"><span class="annotation">@21:</span> {</span></span> + 12:12-12:42: SwitchInt: switchInt(move _13) -> [false: bb19, otherwise: bb17]"> || countdown != 9<span class="annotation">⦉12</span></span><span class="code even" style="--layer: 12" title="bb20: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: + 12:41-12:42: StorageDead: StorageDead(_15) + 12:41-12:42: StorageDead: StorageDead(_13) + 12:12-12:60: SwitchInt: switchInt(move _12) -> [false: bb15, otherwise: bb13]"><span class="annotation">⦉20</span></span><span class="code even" style="--layer: 11" title="bb13: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: + 12:12-12:60: Assign: _11 = const true + 12:12-12:60: Goto: goto -> bb16"><span class="annotation">⦉13</span></span><span class="code even" style="--layer: 10" title="bb16: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: + 12:59-12:60: StorageDead: StorageDead(_17) + 12:59-12:60: StorageDead: StorageDead(_12) + 12:12-12:60: FakeRead: FakeRead(ForMatchedPlace, _11) + 12:9-14:10: SwitchInt: switchInt(_11) -> [false: bb22, otherwise: bb21]"><span class="annotation">⦉16</span></span><span class="code even" style="--layer: 9" title="bb15: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: + 12:46-12:60: StorageLive: StorageLive(_17) + 12:46-12:55: StorageLive: StorageLive(_18) + 12:46-12:55: Assign: _18 = _1 + 12:46-12:60: Assign: _17 = Ne(move _18, const 9_i32) + 12:59-12:60: StorageDead: StorageDead(_18) + 12:12-12:60: SwitchInt: switchInt(move _17) -> [false: bb14, otherwise: bb13]"><span class="annotation">⦉15</span></span><span class="code even" style="--layer: 8" title="bb14: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: + 12:12-12:60: Assign: _11 = const false + 12:12-12:60: Goto: goto -> bb16"><span class="annotation">⦉14</span></span><span class="code even" style="--layer: 7" title="bb21: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10: + 12:9-14:10: FalseEdge: falseEdge -> [real: bb23, imaginary: bb22]"> {</span></span> <span class="line"><span class="code even" style="--layer: 7" title="bb21: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10: 12:9-14:10: FalseEdge: falseEdge -> [real: bb23, imaginary: bb22]"> countdown = 0;</span></span> <span class="line"><span class="code even" style="--layer: 7" title="bb21: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10: @@ -194,32 +223,67 @@ 14:9-14:10: StorageDead: StorageDead(_11) 14:9-14:10: StorageDead: StorageDead(_10) 15:9-15:23: Assign: _19 = CheckedSub(_1, const 5_i32) - 15:9-15:23: Assert: assert(!move (_19.1: bool), "attempt to compute `{} - {}` which would overflow", _1, const 5_i32) -> [success: bb25, unwind: bb1]"><span class="annotation">@24:</span> }</span></span> + 15:9-15:23: Assert: assert(!move (_19.1: bool), "attempt to compute `{} - {}` which would overflow", _1, const 5_i32) -> [success: bb25, unwind: bb1]"><span class="annotation">24⦊</span>}</span><span class="code odd" style="--layer: 5" title="bb22: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10: + 12:9-14:10: Assign: _10 = const () + 12:9-14:10: Goto: goto -> bb24"><span class="annotation">⦉22</span></span><span class="code even" style="--layer: 6" title="bb23: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10: + 13:13-13:26: Assign: _1 = const 0_i32 + 12:61-14:10: Assign: _10 = const () + 12:9-14:10: Goto: goto -> bb24"><span class="annotation">⦉23</span></span><span class="code even" style="--layer: 7" title="bb21: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10: + 12:9-14:10: FalseEdge: falseEdge -> [real: bb23, imaginary: bb22]"><span class="annotation">⦉21</span></span><span class="code even" style="--layer: 7" title="bb21: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10: + 12:9-14:10: FalseEdge: falseEdge -> [real: bb23, imaginary: bb22]"><span class="annotation">⦉21</span></span><span class="code odd" style="--layer: 8" title="bb24: ../instrument-coverage/coverage_of_if_else.rs:14:9: 15:23: + 14:9-14:10: StorageDead: StorageDead(_11) + 14:9-14:10: StorageDead: StorageDead(_10) + 15:9-15:23: Assign: _19 = CheckedSub(_1, const 5_i32) + 15:9-15:23: Assert: assert(!move (_19.1: bool), "attempt to compute `{} - {}` which would overflow", _1, const 5_i32) -> [success: bb25, unwind: bb1]"></span></span> <span class="line"><span class="code odd" style="--layer: 8" title="bb24: ../instrument-coverage/coverage_of_if_else.rs:14:9: 15:23: 14:9-14:10: StorageDead: StorageDead(_11) 14:9-14:10: StorageDead: StorageDead(_10) 15:9-15:23: Assign: _19 = CheckedSub(_1, const 5_i32) - 15:9-15:23: Assert: assert(!move (_19.1: bool), "attempt to compute `{} - {}` which would overflow", _1, const 5_i32) -> [success: bb25, unwind: bb1]"> countdown -= 5</span><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6: - 11:12-18:6: FalseEdge: falseEdge -> [real: bb12, imaginary: bb11]"><span class="annotation">@10:</span> ;</span></span> + 15:9-15:23: Assert: assert(!move (_19.1: bool), "attempt to compute `{} - {}` which would overflow", _1, const 5_i32) -> [success: bb25, unwind: bb1]"> countdown -= 5<span class="annotation">⦉24</span></span><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6: + 11:12-18:6: FalseEdge: falseEdge -> [real: bb12, imaginary: bb11]">;</span></span> <span class="line"><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6: 11:12-18:6: FalseEdge: falseEdge -> [real: bb12, imaginary: bb11]"> } else {</span></span> <span class="line"><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6: 11:12-18:6: FalseEdge: falseEdge -> [real: bb12, imaginary: bb11]"> </span><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2: 51:1-51:2: StorageDead: StorageDead(_1) - 17:9-17:15: Goto: goto -> bb26"><span class="annotation">@27</span></span><span class="code even" style="--layer: 6" title="bb11: ../instrument-coverage/coverage_of_if_else.rs:17:9: 18:6: + 17:9-17:15: Goto: goto -> bb26"><span class="annotation">27⦊</span></span><span class="code even" style="--layer: 6" title="bb11: ../instrument-coverage/coverage_of_if_else.rs:17:9: 18:6: 17:9-17:15: Assign: _0 = const () 18:5-18:6: StorageDead: StorageDead(_8) 18:5-18:6: StorageDead: StorageDead(_5) 18:5-18:6: StorageDead: StorageDead(_4) - 17:9-17:15: Goto: goto -> bb27"><span class="annotation">@11:</span> return;</span></span> + 17:9-17:15: Goto: goto -> bb27"><span class="annotation">11⦊</span>return;</span></span> <span class="line"><span class="code even" style="--layer: 6" title="bb11: ../instrument-coverage/coverage_of_if_else.rs:17:9: 18:6: 17:9-17:15: Assign: _0 = const () 18:5-18:6: StorageDead: StorageDead(_8) 18:5-18:6: StorageDead: StorageDead(_5) 18:5-18:6: StorageDead: StorageDead(_4) - 17:9-17:15: Goto: goto -> bb27"> }</span><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2: + 17:9-17:15: Goto: goto -> bb27"> }<span class="annotation">⦉11</span></span><span><span class="code odd" style="--layer: 1" title="bb6: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: + 9:5-18:6: FalseEdge: falseEdge -> [real: bb8, imaginary: bb7]"><span class="annotation">⦉6</span></span></span><span class="code even" style="--layer: 2" title="bb9: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: + 10:9-10:23: Assign: _1 = move (_7.0: i32) + 9:22-11:6: Assign: _4 = const () + 9:5-18:6: Goto: goto -> bb28"><span class="annotation">⦉9</span></span><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: + 15:9-15:23: Assign: _1 = move (_19.0: i32) + 11:29-16:6: Assign: _4 = const () + 18:5-18:6: StorageDead: StorageDead(_8) + 9:5-18:6: Goto: goto -> bb28"><span class="annotation">⦉25</span></span><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: + 15:9-15:23: Assign: _1 = move (_19.0: i32) + 11:29-16:6: Assign: _4 = const () + 18:5-18:6: StorageDead: StorageDead(_8) + 9:5-18:6: Goto: goto -> bb28"><span class="annotation">⦉25</span></span><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: + 15:9-15:23: Assign: _1 = move (_19.0: i32) + 11:29-16:6: Assign: _4 = const () + 18:5-18:6: StorageDead: StorageDead(_8) + 9:5-18:6: Goto: goto -> bb28"><span class="annotation">⦉25</span></span><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6: + 11:12-18:6: FalseEdge: falseEdge -> [real: bb12, imaginary: bb11]"><span class="annotation">⦉10</span></span><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6: + 11:12-18:6: FalseEdge: falseEdge -> [real: bb12, imaginary: bb11]"><span class="annotation">⦉10</span></span><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6: + 11:12-18:6: FalseEdge: falseEdge -> [real: bb12, imaginary: bb11]"><span class="annotation">⦉10</span></span><span class="code even" style="--layer: 6" title="bb11: ../instrument-coverage/coverage_of_if_else.rs:17:9: 18:6: + 17:9-17:15: Assign: _0 = const () + 18:5-18:6: StorageDead: StorageDead(_8) + 18:5-18:6: StorageDead: StorageDead(_5) + 18:5-18:6: StorageDead: StorageDead(_4) + 17:9-17:15: Goto: goto -> bb27"><span class="annotation">⦉11</span></span><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2: 51:1-51:2: StorageDead: StorageDead(_1) - 17:9-17:15: Goto: goto -> bb26"><span class="annotation">@27:</span> </span></span> + 17:9-17:15: Goto: goto -> bb26"></span></span> <span class="line"><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2: 51:1-51:2: StorageDead: StorageDead(_1) 17:9-17:15: Goto: goto -> bb26"></span></span> @@ -230,11 +294,11 @@ 51:1-51:2: StorageDead: StorageDead(_1) 17:9-17:15: Goto: goto -> bb26"> </span><span class="code odd" style="--layer: 6" title="bb30: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6: 21:5-23:6: Assign: _22 = const () - 21:5-23:6: Goto: goto -> bb32"><span class="annotation">@30</span></span><span class="code even" style="--layer: 7" title="bb31: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6: + 21:5-23:6: Goto: goto -> bb32"><span class="annotation">30⦊</span></span><span class="code even" style="--layer: 7" title="bb31: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6: 22:9-22:23: Assign: _21 = const 10_i32 21:13-23:6: Assign: _22 = const () - 21:5-23:6: Goto: goto -> bb32"><span class="annotation">@31</span></span><span class="code even" style="--layer: 8" title="bb29: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6: - 21:5-23:6: FalseEdge: falseEdge -> [real: bb31, imaginary: bb30]"><span class="annotation">@29:</span> if </span><span class="code even" style="--layer: 9" title="bb28: ../instrument-coverage/coverage_of_if_else.rs:21:8: 21:12: + 21:5-23:6: Goto: goto -> bb32"><span class="annotation">31⦊</span></span><span class="code even" style="--layer: 8" title="bb29: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6: + 21:5-23:6: FalseEdge: falseEdge -> [real: bb31, imaginary: bb30]"><span class="annotation">29⦊</span>if </span><span class="code even" style="--layer: 9" title="bb28: ../instrument-coverage/coverage_of_if_else.rs:21:8: 21:12: 18:5-18:6: StorageDead: StorageDead(_5) 18:5-18:6: StorageDead: StorageDead(_4) 20:9-20:22: StorageLive: StorageLive(_21) @@ -244,28 +308,33 @@ 21:8-21:12: StorageLive: StorageLive(_23) 21:8-21:12: Assign: _23 = const true 21:8-21:12: FakeRead: FakeRead(ForMatchedPlace, _23) - 21:5-23:6: SwitchInt: switchInt(_23) -> [false: bb30, otherwise: bb29]"><span class="annotation">@28:</span> true</span><span class="code even" style="--layer: 8" title="bb29: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6: - 21:5-23:6: FalseEdge: falseEdge -> [real: bb31, imaginary: bb30]"><span class="annotation">@29:</span> {</span></span> + 21:5-23:6: SwitchInt: switchInt(_23) -> [false: bb30, otherwise: bb29]"><span class="annotation">28⦊</span>true<span class="annotation">⦉28</span></span><span class="code even" style="--layer: 8" title="bb29: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6: + 21:5-23:6: FalseEdge: falseEdge -> [real: bb31, imaginary: bb30]"> {</span></span> <span class="line"><span class="code even" style="--layer: 8" title="bb29: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6: 21:5-23:6: FalseEdge: falseEdge -> [real: bb31, imaginary: bb30]"> countdown = 10;</span></span> <span class="line"><span class="code even" style="--layer: 8" title="bb29: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6: - 21:5-23:6: FalseEdge: falseEdge -> [real: bb31, imaginary: bb30]"> }</span><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2: + 21:5-23:6: FalseEdge: falseEdge -> [real: bb31, imaginary: bb30]"> }<span class="annotation">⦉29</span></span><span class="code even" style="--layer: 7" title="bb31: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6: + 22:9-22:23: Assign: _21 = const 10_i32 + 21:13-23:6: Assign: _22 = const () + 21:5-23:6: Goto: goto -> bb32"><span class="annotation">⦉31</span></span><span class="code odd" style="--layer: 6" title="bb30: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6: + 21:5-23:6: Assign: _22 = const () + 21:5-23:6: Goto: goto -> bb32"><span class="annotation">⦉30</span></span><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2: 51:1-51:2: StorageDead: StorageDead(_1) - 17:9-17:15: Goto: goto -> bb26"><span class="annotation">@27:</span> </span></span> + 17:9-17:15: Goto: goto -> bb26"></span></span> <span class="line"><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2: 51:1-51:2: StorageDead: StorageDead(_1) 17:9-17:15: Goto: goto -> bb26"></span></span> <span class="line"><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2: 51:1-51:2: StorageDead: StorageDead(_1) 17:9-17:15: Goto: goto -> bb26"> </span><span class="code even" style="--layer: 6" title="bb33: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6: - 25:5-34:6: FalseEdge: falseEdge -> [real: bb35, imaginary: bb34]"><span class="annotation">@33</span></span><span class="code even" style="--layer: 7" title="bb52: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6: + 25:5-34:6: FalseEdge: falseEdge -> [real: bb35, imaginary: bb34]"><span class="annotation">33⦊</span></span><span class="code even" style="--layer: 7" title="bb52: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6: 31:9-31:23: Assign: _21 = move (_39.0: i32) 27:29-32:6: Assign: _24 = const () 34:5-34:6: StorageDead: StorageDead(_28) - 25:5-34:6: Goto: goto -> bb53"><span class="annotation">@52</span></span><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6: + 25:5-34:6: Goto: goto -> bb53"><span class="annotation">52⦊</span></span><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6: 26:9-26:23: Assign: _21 = move (_27.0: i32) 25:22-27:6: Assign: _24 = const () - 25:5-34:6: Goto: goto -> bb53"><span class="annotation">@36:</span> if </span><span class="code even" style="--layer: 9" title="bb32: ../instrument-coverage/coverage_of_if_else.rs:25:8: 25:21: + 25:5-34:6: Goto: goto -> bb53"><span class="annotation">36⦊</span>if </span><span class="code even" style="--layer: 9" title="bb32: ../instrument-coverage/coverage_of_if_else.rs:25:8: 25:21: 23:5-23:6: StorageDead: StorageDead(_23) 23:5-23:6: StorageDead: StorageDead(_22) 25:5-34:6: StorageLive: StorageLive(_24) @@ -275,40 +344,40 @@ 25:8-25:21: Assign: _25 = Gt(move _26, const 7_i32) 25:20-25:21: StorageDead: StorageDead(_26) 25:8-25:21: FakeRead: FakeRead(ForMatchedPlace, _25) - 25:5-34:6: SwitchInt: switchInt(_25) -> [false: bb34, otherwise: bb33]"><span class="annotation">@32:</span> countdown > 7</span><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6: + 25:5-34:6: SwitchInt: switchInt(_25) -> [false: bb34, otherwise: bb33]"><span class="annotation">32⦊</span>countdown > 7<span class="annotation">⦉32</span></span><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6: 26:9-26:23: Assign: _21 = move (_27.0: i32) 25:22-27:6: Assign: _24 = const () - 25:5-34:6: Goto: goto -> bb53"><span class="annotation">@36:</span> {</span></span> + 25:5-34:6: Goto: goto -> bb53"> {</span></span> <span class="line"><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6: 26:9-26:23: Assign: _21 = move (_27.0: i32) 25:22-27:6: Assign: _24 = const () 25:5-34:6: Goto: goto -> bb53"> </span><span class="code odd" style="--layer: 9" title="bb35: ../instrument-coverage/coverage_of_if_else.rs:26:9: 26:23: 26:9-26:23: Assign: _27 = CheckedSub(_21, const 4_i32) - 26:9-26:23: Assert: assert(!move (_27.1: bool), "attempt to compute `{} - {}` which would overflow", _21, const 4_i32) -> [success: bb36, unwind: bb1]"><span class="annotation">@35:</span> countdown -= 4</span><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6: + 26:9-26:23: Assert: assert(!move (_27.1: bool), "attempt to compute `{} - {}` which would overflow", _21, const 4_i32) -> [success: bb36, unwind: bb1]"><span class="annotation">35⦊</span>countdown -= 4<span class="annotation">⦉35</span></span><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6: 26:9-26:23: Assign: _21 = move (_27.0: i32) 25:22-27:6: Assign: _24 = const () - 25:5-34:6: Goto: goto -> bb53"><span class="annotation">@36:</span> ;</span></span> + 25:5-34:6: Goto: goto -> bb53">;</span></span> <span class="line"><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6: 26:9-26:23: Assign: _21 = move (_27.0: i32) 25:22-27:6: Assign: _24 = const () 25:5-34:6: Goto: goto -> bb53"> } else </span><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6: - 27:12-34:6: FalseEdge: falseEdge -> [real: bb39, imaginary: bb38]"><span class="annotation">@37:</span> if </span><span class="code even" style="--layer: 10" title="bb34: ../instrument-coverage/coverage_of_if_else.rs:27:15: 27:28: + 27:12-34:6: FalseEdge: falseEdge -> [real: bb39, imaginary: bb38]"><span class="annotation">37⦊</span>if </span><span class="code even" style="--layer: 10" title="bb34: ../instrument-coverage/coverage_of_if_else.rs:27:15: 27:28: 27:15-27:28: StorageLive: StorageLive(_28) 27:15-27:24: StorageLive: StorageLive(_29) 27:15-27:24: Assign: _29 = _21 27:15-27:28: Assign: _28 = Gt(move _29, const 2_i32) 27:27-27:28: StorageDead: StorageDead(_29) 27:15-27:28: FakeRead: FakeRead(ForMatchedPlace, _28) - 27:12-34:6: SwitchInt: switchInt(_28) -> [false: bb38, otherwise: bb37]"><span class="annotation">@34:</span> countdown > 2</span><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6: - 27:12-34:6: FalseEdge: falseEdge -> [real: bb39, imaginary: bb38]"><span class="annotation">@37:</span> {</span></span> + 27:12-34:6: SwitchInt: switchInt(_28) -> [false: bb38, otherwise: bb37]"><span class="annotation">34⦊</span>countdown > 2<span class="annotation">⦉34</span></span><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6: + 27:12-34:6: FalseEdge: falseEdge -> [real: bb39, imaginary: bb38]"> {</span></span> <span class="line"><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6: 27:12-34:6: FalseEdge: falseEdge -> [real: bb39, imaginary: bb38]"> </span><span class="code odd" style="--layer: 10" title="bb48: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10: - 28:9-30:10: FalseEdge: falseEdge -> [real: bb50, imaginary: bb49]"><span class="annotation">@48</span></span><span class="code even" style="--layer: 11" title="bb50: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10: + 28:9-30:10: FalseEdge: falseEdge -> [real: bb50, imaginary: bb49]"><span class="annotation">48⦊</span></span><span class="code even" style="--layer: 11" title="bb50: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10: 29:13-29:26: Assign: _21 = const 0_i32 28:61-30:10: Assign: _30 = const () - 28:9-30:10: Goto: goto -> bb51"><span class="annotation">@50</span></span><span class="code even" style="--layer: 12" title="bb49: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10: + 28:9-30:10: Goto: goto -> bb51"><span class="annotation">50⦊</span></span><span class="code even" style="--layer: 12" title="bb49: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10: 28:9-30:10: Assign: _30 = const () - 28:9-30:10: Goto: goto -> bb51"><span class="annotation">@49:</span> if </span><span class="code even" style="--layer: 13" title="bb39: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: + 28:9-30:10: Goto: goto -> bb51"><span class="annotation">49⦊</span>if </span><span class="code even" style="--layer: 13" title="bb39: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: 28:9-30:10: StorageLive: StorageLive(_30) 28:12-28:60: StorageLive: StorageLive(_31) 28:12-28:42: StorageLive: StorageLive(_32) @@ -317,38 +386,70 @@ 28:12-28:21: Assign: _34 = _21 28:12-28:25: Assign: _33 = Lt(move _34, const 1_i32) 28:24-28:25: StorageDead: StorageDead(_34) - 28:12-28:42: SwitchInt: switchInt(move _33) -> [false: bb46, otherwise: bb44]"><span class="annotation">@39</span></span><span class="code even" style="--layer: 14" title="bb47: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: + 28:12-28:42: SwitchInt: switchInt(move _33) -> [false: bb46, otherwise: bb44]"><span class="annotation">39⦊</span></span><span class="code even" style="--layer: 14" title="bb47: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: 28:41-28:42: StorageDead: StorageDead(_35) 28:41-28:42: StorageDead: StorageDead(_33) - 28:12-28:60: SwitchInt: switchInt(move _32) -> [false: bb42, otherwise: bb40]"><span class="annotation">@47</span></span><span class="code even" style="--layer: 15" title="bb40: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: + 28:12-28:60: SwitchInt: switchInt(move _32) -> [false: bb42, otherwise: bb40]"><span class="annotation">47⦊</span></span><span class="code even" style="--layer: 15" title="bb40: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: 28:12-28:60: Assign: _31 = const true - 28:12-28:60: Goto: goto -> bb43"><span class="annotation">@40</span></span><span class="code even" style="--layer: 16" title="bb43: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: + 28:12-28:60: Goto: goto -> bb43"><span class="annotation">40⦊</span></span><span class="code even" style="--layer: 16" title="bb43: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: 28:59-28:60: StorageDead: StorageDead(_37) 28:59-28:60: StorageDead: StorageDead(_32) 28:12-28:60: FakeRead: FakeRead(ForMatchedPlace, _31) - 28:9-30:10: SwitchInt: switchInt(_31) -> [false: bb49, otherwise: bb48]"><span class="annotation">@43</span></span><span class="code even" style="--layer: 17" title="bb42: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: + 28:9-30:10: SwitchInt: switchInt(_31) -> [false: bb49, otherwise: bb48]"><span class="annotation">43⦊</span></span><span class="code even" style="--layer: 17" title="bb42: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: 28:46-28:60: StorageLive: StorageLive(_37) 28:46-28:55: StorageLive: StorageLive(_38) 28:46-28:55: Assign: _38 = _21 28:46-28:60: Assign: _37 = Ne(move _38, const 9_i32) 28:59-28:60: StorageDead: StorageDead(_38) - 28:12-28:60: SwitchInt: switchInt(move _37) -> [false: bb41, otherwise: bb40]"><span class="annotation">@42</span></span><span class="code even" style="--layer: 18" title="bb41: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: + 28:12-28:60: SwitchInt: switchInt(move _37) -> [false: bb41, otherwise: bb40]"><span class="annotation">42⦊</span></span><span class="code even" style="--layer: 18" title="bb41: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: 28:12-28:60: Assign: _31 = const false - 28:12-28:60: Goto: goto -> bb43"><span class="annotation">@41</span></span><span class="code even" style="--layer: 19" title="bb46: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:42: + 28:12-28:60: Goto: goto -> bb43"><span class="annotation">41⦊</span></span><span class="code even" style="--layer: 19" title="bb46: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:42: 28:29-28:42: StorageLive: StorageLive(_35) 28:29-28:38: StorageLive: StorageLive(_36) 28:29-28:38: Assign: _36 = _21 28:29-28:42: Assign: _35 = Gt(move _36, const 5_i32) 28:41-28:42: StorageDead: StorageDead(_36) - 28:12-28:42: SwitchInt: switchInt(move _35) -> [false: bb45, otherwise: bb44]"><span class="annotation">@46</span></span><span class="code even" style="--layer: 20" title="bb45: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:42: + 28:12-28:42: SwitchInt: switchInt(move _35) -> [false: bb45, otherwise: bb44]"><span class="annotation">46⦊</span></span><span class="code even" style="--layer: 20" title="bb45: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:42: 28:12-28:42: Assign: _32 = const false - 28:12-28:42: Goto: goto -> bb47"><span class="annotation">@45</span></span><span class="code even" style="--layer: 21" title="bb44: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:42: + 28:12-28:42: Goto: goto -> bb47"><span class="annotation">45⦊</span></span><span class="code even" style="--layer: 21" title="bb44: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:42: 28:12-28:42: Assign: _32 = const true - 28:12-28:42: Goto: goto -> bb47"><span class="annotation">@44:</span> countdown < 1 || countdown > 5</span><span class="code even" style="--layer: 18" title="bb41: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: + 28:12-28:42: Goto: goto -> bb47"><span class="annotation">44⦊</span>countdown < 1 || countdown > 5<span class="annotation">⦉44</span></span><span class="code even" style="--layer: 20" title="bb45: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:42: + 28:12-28:42: Assign: _32 = const false + 28:12-28:42: Goto: goto -> bb47"><span class="annotation">⦉45</span></span><span class="code even" style="--layer: 19" title="bb46: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:42: + 28:29-28:42: StorageLive: StorageLive(_35) + 28:29-28:38: StorageLive: StorageLive(_36) + 28:29-28:38: Assign: _36 = _21 + 28:29-28:42: Assign: _35 = Gt(move _36, const 5_i32) + 28:41-28:42: StorageDead: StorageDead(_36) + 28:12-28:42: SwitchInt: switchInt(move _35) -> [false: bb45, otherwise: bb44]"><span class="annotation">⦉46</span></span><span class="code even" style="--layer: 18" title="bb41: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: 28:12-28:60: Assign: _31 = const false - 28:12-28:60: Goto: goto -> bb43"><span class="annotation">@41:</span> || countdown != 9</span><span class="code even" style="--layer: 12" title="bb49: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10: + 28:12-28:60: Goto: goto -> bb43"> || countdown != 9<span class="annotation">⦉41</span></span><span class="code even" style="--layer: 17" title="bb42: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: + 28:46-28:60: StorageLive: StorageLive(_37) + 28:46-28:55: StorageLive: StorageLive(_38) + 28:46-28:55: Assign: _38 = _21 + 28:46-28:60: Assign: _37 = Ne(move _38, const 9_i32) + 28:59-28:60: StorageDead: StorageDead(_38) + 28:12-28:60: SwitchInt: switchInt(move _37) -> [false: bb41, otherwise: bb40]"><span class="annotation">⦉42</span></span><span class="code even" style="--layer: 16" title="bb43: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: + 28:59-28:60: StorageDead: StorageDead(_37) + 28:59-28:60: StorageDead: StorageDead(_32) + 28:12-28:60: FakeRead: FakeRead(ForMatchedPlace, _31) + 28:9-30:10: SwitchInt: switchInt(_31) -> [false: bb49, otherwise: bb48]"><span class="annotation">⦉43</span></span><span class="code even" style="--layer: 15" title="bb40: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: + 28:12-28:60: Assign: _31 = const true + 28:12-28:60: Goto: goto -> bb43"><span class="annotation">⦉40</span></span><span class="code even" style="--layer: 14" title="bb47: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: + 28:41-28:42: StorageDead: StorageDead(_35) + 28:41-28:42: StorageDead: StorageDead(_33) + 28:12-28:60: SwitchInt: switchInt(move _32) -> [false: bb42, otherwise: bb40]"><span class="annotation">⦉47</span></span><span class="code even" style="--layer: 13" title="bb39: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: + 28:9-30:10: StorageLive: StorageLive(_30) + 28:12-28:60: StorageLive: StorageLive(_31) + 28:12-28:42: StorageLive: StorageLive(_32) + 28:12-28:25: StorageLive: StorageLive(_33) + 28:12-28:21: StorageLive: StorageLive(_34) + 28:12-28:21: Assign: _34 = _21 + 28:12-28:25: Assign: _33 = Lt(move _34, const 1_i32) + 28:24-28:25: StorageDead: StorageDead(_34) + 28:12-28:42: SwitchInt: switchInt(move _33) -> [false: bb46, otherwise: bb44]"><span class="annotation">⦉39</span></span><span class="code even" style="--layer: 12" title="bb49: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10: 28:9-30:10: Assign: _30 = const () - 28:9-30:10: Goto: goto -> bb51"><span class="annotation">@49:</span> {</span></span> + 28:9-30:10: Goto: goto -> bb51"> {</span></span> <span class="line"><span class="code even" style="--layer: 12" title="bb49: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10: 28:9-30:10: Assign: _30 = const () 28:9-30:10: Goto: goto -> bb51"> countdown = 0;</span></span> @@ -358,13 +459,25 @@ 30:9-30:10: StorageDead: StorageDead(_31) 30:9-30:10: StorageDead: StorageDead(_30) 31:9-31:23: Assign: _39 = CheckedSub(_21, const 5_i32) - 31:9-31:23: Assert: assert(!move (_39.1: bool), "attempt to compute `{} - {}` which would overflow", _21, const 5_i32) -> [success: bb52, unwind: bb1]"><span class="annotation">@51:</span> }</span></span> + 31:9-31:23: Assert: assert(!move (_39.1: bool), "attempt to compute `{} - {}` which would overflow", _21, const 5_i32) -> [success: bb52, unwind: bb1]"><span class="annotation">51⦊</span>}</span><span class="code odd" style="--layer: 10" title="bb48: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10: + 28:9-30:10: FalseEdge: falseEdge -> [real: bb50, imaginary: bb49]"><span class="annotation">⦉48</span></span><span class="code even" style="--layer: 11" title="bb50: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10: + 29:13-29:26: Assign: _21 = const 0_i32 + 28:61-30:10: Assign: _30 = const () + 28:9-30:10: Goto: goto -> bb51"><span class="annotation">⦉50</span></span><span class="code even" style="--layer: 12" title="bb49: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10: + 28:9-30:10: Assign: _30 = const () + 28:9-30:10: Goto: goto -> bb51"><span class="annotation">⦉49</span></span><span class="code even" style="--layer: 12" title="bb49: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10: + 28:9-30:10: Assign: _30 = const () + 28:9-30:10: Goto: goto -> bb51"><span class="annotation">⦉49</span></span><span class="code odd" style="--layer: 13" title="bb51: ../instrument-coverage/coverage_of_if_else.rs:30:9: 31:23: + 30:9-30:10: StorageDead: StorageDead(_31) + 30:9-30:10: StorageDead: StorageDead(_30) + 31:9-31:23: Assign: _39 = CheckedSub(_21, const 5_i32) + 31:9-31:23: Assert: assert(!move (_39.1: bool), "attempt to compute `{} - {}` which would overflow", _21, const 5_i32) -> [success: bb52, unwind: bb1]"></span></span> <span class="line"><span class="code odd" style="--layer: 13" title="bb51: ../instrument-coverage/coverage_of_if_else.rs:30:9: 31:23: 30:9-30:10: StorageDead: StorageDead(_31) 30:9-30:10: StorageDead: StorageDead(_30) 31:9-31:23: Assign: _39 = CheckedSub(_21, const 5_i32) - 31:9-31:23: Assert: assert(!move (_39.1: bool), "attempt to compute `{} - {}` which would overflow", _21, const 5_i32) -> [success: bb52, unwind: bb1]"> countdown -= 5</span><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6: - 27:12-34:6: FalseEdge: falseEdge -> [real: bb39, imaginary: bb38]"><span class="annotation">@37:</span> ;</span></span> + 31:9-31:23: Assert: assert(!move (_39.1: bool), "attempt to compute `{} - {}` which would overflow", _21, const 5_i32) -> [success: bb52, unwind: bb1]"> countdown -= 5<span class="annotation">⦉51</span></span><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6: + 27:12-34:6: FalseEdge: falseEdge -> [real: bb39, imaginary: bb38]">;</span></span> <span class="line"><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6: 27:12-34:6: FalseEdge: falseEdge -> [real: bb39, imaginary: bb38]"> } else {</span></span> <span class="line"><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6: @@ -374,14 +487,37 @@ 34:5-34:6: StorageDead: StorageDead(_25) 34:5-34:6: StorageDead: StorageDead(_24) 51:1-51:2: StorageDead: StorageDead(_21) - 33:9-33:15: Goto: goto -> bb27"><span class="annotation">@38:</span> return;</span></span> + 33:9-33:15: Goto: goto -> bb27"><span class="annotation">38⦊</span>return;</span></span> <span class="line"><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2: 33:9-33:15: Assign: _0 = const () 34:5-34:6: StorageDead: StorageDead(_28) 34:5-34:6: StorageDead: StorageDead(_25) 34:5-34:6: StorageDead: StorageDead(_24) 51:1-51:2: StorageDead: StorageDead(_21) - 33:9-33:15: Goto: goto -> bb27"> }</span></span> + 33:9-33:15: Goto: goto -> bb27"> }</span><span class="code even" style="--layer: 6" title="bb33: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6: + 25:5-34:6: FalseEdge: falseEdge -> [real: bb35, imaginary: bb34]"><span class="annotation">⦉33</span></span><span class="code even" style="--layer: 7" title="bb52: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6: + 31:9-31:23: Assign: _21 = move (_39.0: i32) + 27:29-32:6: Assign: _24 = const () + 34:5-34:6: StorageDead: StorageDead(_28) + 25:5-34:6: Goto: goto -> bb53"><span class="annotation">⦉52</span></span><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6: + 26:9-26:23: Assign: _21 = move (_27.0: i32) + 25:22-27:6: Assign: _24 = const () + 25:5-34:6: Goto: goto -> bb53"><span class="annotation">⦉36</span></span><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6: + 26:9-26:23: Assign: _21 = move (_27.0: i32) + 25:22-27:6: Assign: _24 = const () + 25:5-34:6: Goto: goto -> bb53"><span class="annotation">⦉36</span></span><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6: + 26:9-26:23: Assign: _21 = move (_27.0: i32) + 25:22-27:6: Assign: _24 = const () + 25:5-34:6: Goto: goto -> bb53"><span class="annotation">⦉36</span></span><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6: + 27:12-34:6: FalseEdge: falseEdge -> [real: bb39, imaginary: bb38]"><span class="annotation">⦉37</span></span><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6: + 27:12-34:6: FalseEdge: falseEdge -> [real: bb39, imaginary: bb38]"><span class="annotation">⦉37</span></span><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6: + 27:12-34:6: FalseEdge: falseEdge -> [real: bb39, imaginary: bb38]"><span class="annotation">⦉37</span></span><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2: + 33:9-33:15: Assign: _0 = const () + 34:5-34:6: StorageDead: StorageDead(_28) + 34:5-34:6: StorageDead: StorageDead(_25) + 34:5-34:6: StorageDead: StorageDead(_24) + 51:1-51:2: StorageDead: StorageDead(_21) + 33:9-33:15: Goto: goto -> bb27"></span></span> <span class="line"><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2: 33:9-33:15: Assign: _0 = const () 34:5-34:6: StorageDead: StorageDead(_28) @@ -405,10 +541,10 @@ 33:9-33:15: Goto: goto -> bb27"> </span><span class="code even" style="--layer: 11" title="bb56: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6: 38:9-38:23: Assign: _41 = const 10_i32 37:13-39:6: Assign: _42 = const () - 37:5-39:6: Goto: goto -> bb57"><span class="annotation">@56</span></span><span class="code even" style="--layer: 12" title="bb54: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6: - 37:5-39:6: FalseEdge: falseEdge -> [real: bb56, imaginary: bb55]"><span class="annotation">@54</span></span><span class="code even" style="--layer: 13" title="bb55: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6: + 37:5-39:6: Goto: goto -> bb57"><span class="annotation">56⦊</span></span><span class="code even" style="--layer: 12" title="bb54: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6: + 37:5-39:6: FalseEdge: falseEdge -> [real: bb56, imaginary: bb55]"><span class="annotation">54⦊</span></span><span class="code even" style="--layer: 13" title="bb55: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6: 37:5-39:6: Assign: _42 = const () - 37:5-39:6: Goto: goto -> bb57"><span class="annotation">@55:</span> if </span><span class="code even" style="--layer: 14" title="bb53: ../instrument-coverage/coverage_of_if_else.rs:37:8: 37:12: + 37:5-39:6: Goto: goto -> bb57"><span class="annotation">55⦊</span>if </span><span class="code even" style="--layer: 14" title="bb53: ../instrument-coverage/coverage_of_if_else.rs:37:8: 37:12: 34:5-34:6: StorageDead: StorageDead(_25) 34:5-34:6: StorageDead: StorageDead(_24) 36:9-36:22: StorageLive: StorageLive(_41) @@ -418,21 +554,25 @@ 37:8-37:12: StorageLive: StorageLive(_43) 37:8-37:12: Assign: _43 = const true 37:8-37:12: FakeRead: FakeRead(ForMatchedPlace, _43) - 37:5-39:6: SwitchInt: switchInt(_43) -> [false: bb55, otherwise: bb54]"><span class="annotation">@53:</span> true</span><span class="code even" style="--layer: 13" title="bb55: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6: + 37:5-39:6: SwitchInt: switchInt(_43) -> [false: bb55, otherwise: bb54]"><span class="annotation">53⦊</span>true<span class="annotation">⦉53</span></span><span class="code even" style="--layer: 13" title="bb55: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6: 37:5-39:6: Assign: _42 = const () - 37:5-39:6: Goto: goto -> bb57"><span class="annotation">@55:</span> {</span></span> + 37:5-39:6: Goto: goto -> bb57"> {</span></span> <span class="line"><span class="code even" style="--layer: 13" title="bb55: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6: 37:5-39:6: Assign: _42 = const () 37:5-39:6: Goto: goto -> bb57"> countdown = 10;</span></span> <span class="line"><span class="code even" style="--layer: 13" title="bb55: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6: 37:5-39:6: Assign: _42 = const () - 37:5-39:6: Goto: goto -> bb57"> }</span><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2: + 37:5-39:6: Goto: goto -> bb57"> }<span class="annotation">⦉55</span></span><span class="code even" style="--layer: 12" title="bb54: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6: + 37:5-39:6: FalseEdge: falseEdge -> [real: bb56, imaginary: bb55]"><span class="annotation">⦉54</span></span><span class="code even" style="--layer: 11" title="bb56: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6: + 38:9-38:23: Assign: _41 = const 10_i32 + 37:13-39:6: Assign: _42 = const () + 37:5-39:6: Goto: goto -> bb57"><span class="annotation">⦉56</span></span><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2: 33:9-33:15: Assign: _0 = const () 34:5-34:6: StorageDead: StorageDead(_28) 34:5-34:6: StorageDead: StorageDead(_25) 34:5-34:6: StorageDead: StorageDead(_24) 51:1-51:2: StorageDead: StorageDead(_21) - 33:9-33:15: Goto: goto -> bb27"><span class="annotation">@38:</span> </span></span> + 33:9-33:15: Goto: goto -> bb27"></span></span> <span class="line"><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2: 33:9-33:15: Assign: _0 = const () 34:5-34:6: StorageDead: StorageDead(_28) @@ -449,12 +589,12 @@ 33:9-33:15: Goto: goto -> bb27"> </span><span class="code odd" style="--layer: 11" title="bb61: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6: 42:9-42:23: Assign: _41 = move (_46.0: i32) 41:22-43:6: Assign: _0 = const () - 41:5-50:6: Goto: goto -> bb78"><span class="annotation">@61</span></span><span class="code even" style="--layer: 12" title="bb58: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6: - 41:5-50:6: FalseEdge: falseEdge -> [real: bb60, imaginary: bb59]"><span class="annotation">@58</span></span><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6: + 41:5-50:6: Goto: goto -> bb78"><span class="annotation">61⦊</span></span><span class="code even" style="--layer: 12" title="bb58: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6: + 41:5-50:6: FalseEdge: falseEdge -> [real: bb60, imaginary: bb59]"><span class="annotation">58⦊</span></span><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6: 47:9-47:23: Assign: _41 = move (_58.0: i32) 43:29-48:6: Assign: _0 = const () 50:5-50:6: StorageDead: StorageDead(_47) - 41:5-50:6: Goto: goto -> bb78"><span class="annotation">@77:</span> if </span><span class="code even" style="--layer: 14" title="bb57: ../instrument-coverage/coverage_of_if_else.rs:41:8: 41:21: + 41:5-50:6: Goto: goto -> bb78"><span class="annotation">77⦊</span>if </span><span class="code even" style="--layer: 14" title="bb57: ../instrument-coverage/coverage_of_if_else.rs:41:8: 41:21: 39:5-39:6: StorageDead: StorageDead(_43) 39:5-39:6: StorageDead: StorageDead(_42) 41:8-41:21: StorageLive: StorageLive(_44) @@ -463,59 +603,59 @@ 41:8-41:21: Assign: _44 = Gt(move _45, const 7_i32) 41:20-41:21: StorageDead: StorageDead(_45) 41:8-41:21: FakeRead: FakeRead(ForMatchedPlace, _44) - 41:5-50:6: SwitchInt: switchInt(_44) -> [false: bb59, otherwise: bb58]"><span class="annotation">@57:</span> countdown > 7</span><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6: + 41:5-50:6: SwitchInt: switchInt(_44) -> [false: bb59, otherwise: bb58]"><span class="annotation">57⦊</span>countdown > 7<span class="annotation">⦉57</span></span><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6: 47:9-47:23: Assign: _41 = move (_58.0: i32) 43:29-48:6: Assign: _0 = const () 50:5-50:6: StorageDead: StorageDead(_47) - 41:5-50:6: Goto: goto -> bb78"><span class="annotation">@77:</span> {</span></span> + 41:5-50:6: Goto: goto -> bb78"> {</span></span> <span class="line"><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6: 47:9-47:23: Assign: _41 = move (_58.0: i32) 43:29-48:6: Assign: _0 = const () 50:5-50:6: StorageDead: StorageDead(_47) 41:5-50:6: Goto: goto -> bb78"> </span><span class="code odd" style="--layer: 14" title="bb60: ../instrument-coverage/coverage_of_if_else.rs:42:9: 42:23: 42:9-42:23: Assign: _46 = CheckedSub(_41, const 4_i32) - 42:9-42:23: Assert: assert(!move (_46.1: bool), "attempt to compute `{} - {}` which would overflow", _41, const 4_i32) -> [success: bb61, unwind: bb1]"><span class="annotation">@60:</span> countdown -= 4</span><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6: + 42:9-42:23: Assert: assert(!move (_46.1: bool), "attempt to compute `{} - {}` which would overflow", _41, const 4_i32) -> [success: bb61, unwind: bb1]"><span class="annotation">60⦊</span>countdown -= 4<span class="annotation">⦉60</span></span><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6: 47:9-47:23: Assign: _41 = move (_58.0: i32) 43:29-48:6: Assign: _0 = const () 50:5-50:6: StorageDead: StorageDead(_47) - 41:5-50:6: Goto: goto -> bb78"><span class="annotation">@77:</span> ;</span></span> + 41:5-50:6: Goto: goto -> bb78">;</span></span> <span class="line"><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6: 47:9-47:23: Assign: _41 = move (_58.0: i32) 43:29-48:6: Assign: _0 = const () 50:5-50:6: StorageDead: StorageDead(_47) 41:5-50:6: Goto: goto -> bb78"> } else </span><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6: - 43:12-50:6: FalseEdge: falseEdge -> [real: bb64, imaginary: bb63]"><span class="annotation">@62:</span> if </span><span class="code even" style="--layer: 15" title="bb59: ../instrument-coverage/coverage_of_if_else.rs:43:15: 43:28: + 43:12-50:6: FalseEdge: falseEdge -> [real: bb64, imaginary: bb63]"><span class="annotation">62⦊</span>if </span><span class="code even" style="--layer: 15" title="bb59: ../instrument-coverage/coverage_of_if_else.rs:43:15: 43:28: 43:15-43:28: StorageLive: StorageLive(_47) 43:15-43:24: StorageLive: StorageLive(_48) 43:15-43:24: Assign: _48 = _41 43:15-43:28: Assign: _47 = Gt(move _48, const 2_i32) 43:27-43:28: StorageDead: StorageDead(_48) 43:15-43:28: FakeRead: FakeRead(ForMatchedPlace, _47) - 43:12-50:6: SwitchInt: switchInt(_47) -> [false: bb63, otherwise: bb62]"><span class="annotation">@59:</span> countdown > 2</span><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6: - 43:12-50:6: FalseEdge: falseEdge -> [real: bb64, imaginary: bb63]"><span class="annotation">@62:</span> {</span></span> + 43:12-50:6: SwitchInt: switchInt(_47) -> [false: bb63, otherwise: bb62]"><span class="annotation">59⦊</span>countdown > 2<span class="annotation">⦉59</span></span><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6: + 43:12-50:6: FalseEdge: falseEdge -> [real: bb64, imaginary: bb63]"> {</span></span> <span class="line"><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6: 43:12-50:6: FalseEdge: falseEdge -> [real: bb64, imaginary: bb63]"> </span><span class="code odd" style="--layer: 15" title="bb75: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10: 45:13-45:26: Assign: _41 = const 0_i32 44:61-46:10: Assign: _49 = const () - 44:9-46:10: Goto: goto -> bb76"><span class="annotation">@75</span></span><span class="code even" style="--layer: 16" title="bb74: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10: + 44:9-46:10: Goto: goto -> bb76"><span class="annotation">75⦊</span></span><span class="code even" style="--layer: 16" title="bb74: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10: 44:9-46:10: Assign: _49 = const () - 44:9-46:10: Goto: goto -> bb76"><span class="annotation">@74</span></span><span class="code even" style="--layer: 17" title="bb73: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10: - 44:9-46:10: FalseEdge: falseEdge -> [real: bb75, imaginary: bb74]"><span class="annotation">@73:</span> if </span><span class="code even" style="--layer: 18" title="bb67: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: + 44:9-46:10: Goto: goto -> bb76"><span class="annotation">74⦊</span></span><span class="code even" style="--layer: 17" title="bb73: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10: + 44:9-46:10: FalseEdge: falseEdge -> [real: bb75, imaginary: bb74]"><span class="annotation">73⦊</span>if </span><span class="code even" style="--layer: 18" title="bb67: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: 44:46-44:60: StorageLive: StorageLive(_56) 44:46-44:55: StorageLive: StorageLive(_57) 44:46-44:55: Assign: _57 = _41 44:46-44:60: Assign: _56 = Ne(move _57, const 9_i32) 44:59-44:60: StorageDead: StorageDead(_57) - 44:12-44:60: SwitchInt: switchInt(move _56) -> [false: bb66, otherwise: bb65]"><span class="annotation">@67</span></span><span class="code even" style="--layer: 19" title="bb68: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: + 44:12-44:60: SwitchInt: switchInt(move _56) -> [false: bb66, otherwise: bb65]"><span class="annotation">67⦊</span></span><span class="code even" style="--layer: 19" title="bb68: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: 44:59-44:60: StorageDead: StorageDead(_56) 44:59-44:60: StorageDead: StorageDead(_51) 44:12-44:60: FakeRead: FakeRead(ForMatchedPlace, _50) - 44:9-46:10: SwitchInt: switchInt(_50) -> [false: bb74, otherwise: bb73]"><span class="annotation">@68</span></span><span class="code even" style="--layer: 20" title="bb65: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: + 44:9-46:10: SwitchInt: switchInt(_50) -> [false: bb74, otherwise: bb73]"><span class="annotation">68⦊</span></span><span class="code even" style="--layer: 20" title="bb65: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: 44:12-44:60: Assign: _50 = const true - 44:12-44:60: Goto: goto -> bb68"><span class="annotation">@65</span></span><span class="code even" style="--layer: 21" title="bb72: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: + 44:12-44:60: Goto: goto -> bb68"><span class="annotation">65⦊</span></span><span class="code even" style="--layer: 21" title="bb72: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: 44:41-44:42: StorageDead: StorageDead(_54) 44:41-44:42: StorageDead: StorageDead(_52) - 44:12-44:60: SwitchInt: switchInt(move _51) -> [false: bb67, otherwise: bb65]"><span class="annotation">@72</span></span><span class="code even" style="--layer: 22" title="bb64: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: + 44:12-44:60: SwitchInt: switchInt(move _51) -> [false: bb67, otherwise: bb65]"><span class="annotation">72⦊</span></span><span class="code even" style="--layer: 22" title="bb64: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: 44:9-46:10: StorageLive: StorageLive(_49) 44:12-44:60: StorageLive: StorageLive(_50) 44:12-44:42: StorageLive: StorageLive(_51) @@ -524,22 +664,54 @@ 44:12-44:21: Assign: _53 = _41 44:12-44:25: Assign: _52 = Lt(move _53, const 1_i32) 44:24-44:25: StorageDead: StorageDead(_53) - 44:12-44:42: SwitchInt: switchInt(move _52) -> [false: bb71, otherwise: bb69]"><span class="annotation">@64</span></span><span class="code even" style="--layer: 23" title="bb66: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: + 44:12-44:42: SwitchInt: switchInt(move _52) -> [false: bb71, otherwise: bb69]"><span class="annotation">64⦊</span></span><span class="code even" style="--layer: 23" title="bb66: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: 44:12-44:60: Assign: _50 = const false - 44:12-44:60: Goto: goto -> bb68"><span class="annotation">@66</span></span><span class="code even" style="--layer: 24" title="bb69: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:42: + 44:12-44:60: Goto: goto -> bb68"><span class="annotation">66⦊</span></span><span class="code even" style="--layer: 24" title="bb69: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:42: 44:12-44:42: Assign: _51 = const true - 44:12-44:42: Goto: goto -> bb72"><span class="annotation">@69</span></span><span class="code even" style="--layer: 25" title="bb71: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:42: + 44:12-44:42: Goto: goto -> bb72"><span class="annotation">69⦊</span></span><span class="code even" style="--layer: 25" title="bb71: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:42: 44:29-44:42: StorageLive: StorageLive(_54) 44:29-44:38: StorageLive: StorageLive(_55) 44:29-44:38: Assign: _55 = _41 44:29-44:42: Assign: _54 = Gt(move _55, const 5_i32) 44:41-44:42: StorageDead: StorageDead(_55) - 44:12-44:42: SwitchInt: switchInt(move _54) -> [false: bb70, otherwise: bb69]"><span class="annotation">@71</span></span><span class="code even" style="--layer: 26" title="bb70: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:42: + 44:12-44:42: SwitchInt: switchInt(move _54) -> [false: bb70, otherwise: bb69]"><span class="annotation">71⦊</span></span><span class="code even" style="--layer: 26" title="bb70: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:42: 44:12-44:42: Assign: _51 = const false - 44:12-44:42: Goto: goto -> bb72"><span class="annotation">@70:</span> countdown < 1 || countdown > 5</span><span class="code even" style="--layer: 23" title="bb66: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: + 44:12-44:42: Goto: goto -> bb72"><span class="annotation">70⦊</span>countdown < 1 || countdown > 5<span class="annotation">⦉70</span></span><span class="code even" style="--layer: 25" title="bb71: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:42: + 44:29-44:42: StorageLive: StorageLive(_54) + 44:29-44:38: StorageLive: StorageLive(_55) + 44:29-44:38: Assign: _55 = _41 + 44:29-44:42: Assign: _54 = Gt(move _55, const 5_i32) + 44:41-44:42: StorageDead: StorageDead(_55) + 44:12-44:42: SwitchInt: switchInt(move _54) -> [false: bb70, otherwise: bb69]"><span class="annotation">⦉71</span></span><span class="code even" style="--layer: 24" title="bb69: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:42: + 44:12-44:42: Assign: _51 = const true + 44:12-44:42: Goto: goto -> bb72"><span class="annotation">⦉69</span></span><span class="code even" style="--layer: 23" title="bb66: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: 44:12-44:60: Assign: _50 = const false - 44:12-44:60: Goto: goto -> bb68"><span class="annotation">@66:</span> || countdown != 9</span><span class="code even" style="--layer: 17" title="bb73: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10: - 44:9-46:10: FalseEdge: falseEdge -> [real: bb75, imaginary: bb74]"><span class="annotation">@73:</span> {</span></span> + 44:12-44:60: Goto: goto -> bb68"> || countdown != 9<span class="annotation">⦉66</span></span><span class="code even" style="--layer: 22" title="bb64: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: + 44:9-46:10: StorageLive: StorageLive(_49) + 44:12-44:60: StorageLive: StorageLive(_50) + 44:12-44:42: StorageLive: StorageLive(_51) + 44:12-44:25: StorageLive: StorageLive(_52) + 44:12-44:21: StorageLive: StorageLive(_53) + 44:12-44:21: Assign: _53 = _41 + 44:12-44:25: Assign: _52 = Lt(move _53, const 1_i32) + 44:24-44:25: StorageDead: StorageDead(_53) + 44:12-44:42: SwitchInt: switchInt(move _52) -> [false: bb71, otherwise: bb69]"><span class="annotation">⦉64</span></span><span class="code even" style="--layer: 21" title="bb72: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: + 44:41-44:42: StorageDead: StorageDead(_54) + 44:41-44:42: StorageDead: StorageDead(_52) + 44:12-44:60: SwitchInt: switchInt(move _51) -> [false: bb67, otherwise: bb65]"><span class="annotation">⦉72</span></span><span class="code even" style="--layer: 20" title="bb65: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: + 44:12-44:60: Assign: _50 = const true + 44:12-44:60: Goto: goto -> bb68"><span class="annotation">⦉65</span></span><span class="code even" style="--layer: 19" title="bb68: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: + 44:59-44:60: StorageDead: StorageDead(_56) + 44:59-44:60: StorageDead: StorageDead(_51) + 44:12-44:60: FakeRead: FakeRead(ForMatchedPlace, _50) + 44:9-46:10: SwitchInt: switchInt(_50) -> [false: bb74, otherwise: bb73]"><span class="annotation">⦉68</span></span><span class="code even" style="--layer: 18" title="bb67: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: + 44:46-44:60: StorageLive: StorageLive(_56) + 44:46-44:55: StorageLive: StorageLive(_57) + 44:46-44:55: Assign: _57 = _41 + 44:46-44:60: Assign: _56 = Ne(move _57, const 9_i32) + 44:59-44:60: StorageDead: StorageDead(_57) + 44:12-44:60: SwitchInt: switchInt(move _56) -> [false: bb66, otherwise: bb65]"><span class="annotation">⦉67</span></span><span class="code even" style="--layer: 17" title="bb73: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10: + 44:9-46:10: FalseEdge: falseEdge -> [real: bb75, imaginary: bb74]"> {</span></span> <span class="line"><span class="code even" style="--layer: 17" title="bb73: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10: 44:9-46:10: FalseEdge: falseEdge -> [real: bb75, imaginary: bb74]"> countdown = 0;</span></span> <span class="line"><span class="code even" style="--layer: 17" title="bb73: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10: @@ -547,13 +719,24 @@ 46:9-46:10: StorageDead: StorageDead(_50) 46:9-46:10: StorageDead: StorageDead(_49) 47:9-47:23: Assign: _58 = CheckedSub(_41, const 5_i32) - 47:9-47:23: Assert: assert(!move (_58.1: bool), "attempt to compute `{} - {}` which would overflow", _41, const 5_i32) -> [success: bb77, unwind: bb1]"><span class="annotation">@76:</span> }</span></span> + 47:9-47:23: Assert: assert(!move (_58.1: bool), "attempt to compute `{} - {}` which would overflow", _41, const 5_i32) -> [success: bb77, unwind: bb1]"><span class="annotation">76⦊</span>}</span><span class="code odd" style="--layer: 15" title="bb75: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10: + 45:13-45:26: Assign: _41 = const 0_i32 + 44:61-46:10: Assign: _49 = const () + 44:9-46:10: Goto: goto -> bb76"><span class="annotation">⦉75</span></span><span class="code even" style="--layer: 16" title="bb74: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10: + 44:9-46:10: Assign: _49 = const () + 44:9-46:10: Goto: goto -> bb76"><span class="annotation">⦉74</span></span><span class="code even" style="--layer: 17" title="bb73: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10: + 44:9-46:10: FalseEdge: falseEdge -> [real: bb75, imaginary: bb74]"><span class="annotation">⦉73</span></span><span class="code even" style="--layer: 17" title="bb73: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10: + 44:9-46:10: FalseEdge: falseEdge -> [real: bb75, imaginary: bb74]"><span class="annotation">⦉73</span></span><span class="code odd" style="--layer: 18" title="bb76: ../instrument-coverage/coverage_of_if_else.rs:46:9: 47:23: + 46:9-46:10: StorageDead: StorageDead(_50) + 46:9-46:10: StorageDead: StorageDead(_49) + 47:9-47:23: Assign: _58 = CheckedSub(_41, const 5_i32) + 47:9-47:23: Assert: assert(!move (_58.1: bool), "attempt to compute `{} - {}` which would overflow", _41, const 5_i32) -> [success: bb77, unwind: bb1]"></span></span> <span class="line"><span class="code odd" style="--layer: 18" title="bb76: ../instrument-coverage/coverage_of_if_else.rs:46:9: 47:23: 46:9-46:10: StorageDead: StorageDead(_50) 46:9-46:10: StorageDead: StorageDead(_49) 47:9-47:23: Assign: _58 = CheckedSub(_41, const 5_i32) - 47:9-47:23: Assert: assert(!move (_58.1: bool), "attempt to compute `{} - {}` which would overflow", _41, const 5_i32) -> [success: bb77, unwind: bb1]"> countdown -= 5</span><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6: - 43:12-50:6: FalseEdge: falseEdge -> [real: bb64, imaginary: bb63]"><span class="annotation">@62:</span> ;</span></span> + 47:9-47:23: Assert: assert(!move (_58.1: bool), "attempt to compute `{} - {}` which would overflow", _41, const 5_i32) -> [success: bb77, unwind: bb1]"> countdown -= 5<span class="annotation">⦉76</span></span><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6: + 43:12-50:6: FalseEdge: falseEdge -> [real: bb64, imaginary: bb63]">;</span></span> <span class="line"><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6: 43:12-50:6: FalseEdge: falseEdge -> [real: bb64, imaginary: bb63]"> } else {</span></span> <span class="line"><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6: @@ -564,7 +747,7 @@ 51:1-51:2: StorageDead: StorageDead(_21) 51:1-51:2: StorageDead: StorageDead(_1) 51:1-51:2: StorageDead: StorageDead(_44) - 49:9-49:15: Goto: goto -> bb26"><span class="annotation">@63:</span> return;</span></span> + 49:9-49:15: Goto: goto -> bb26"><span class="annotation">63⦊</span>return;</span></span> <span class="line"><span class="code even" style="--layer: 15" title="bb63: ../instrument-coverage/coverage_of_if_else.rs:49:9: 51:2: 49:9-49:15: Assign: _0 = const () 50:5-50:6: StorageDead: StorageDead(_47) @@ -572,12 +755,54 @@ 51:1-51:2: StorageDead: StorageDead(_21) 51:1-51:2: StorageDead: StorageDead(_1) 51:1-51:2: StorageDead: StorageDead(_44) - 49:9-49:15: Goto: goto -> bb26"> }</span><span class="code even" style="--layer: 16" title="bb78: ../instrument-coverage/coverage_of_if_else.rs:51:1: 51:2: + 49:9-49:15: Goto: goto -> bb26"> }</span><span class="code odd" style="--layer: 11" title="bb61: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6: + 42:9-42:23: Assign: _41 = move (_46.0: i32) + 41:22-43:6: Assign: _0 = const () + 41:5-50:6: Goto: goto -> bb78"><span class="annotation">⦉61</span></span><span class="code even" style="--layer: 12" title="bb58: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6: + 41:5-50:6: FalseEdge: falseEdge -> [real: bb60, imaginary: bb59]"><span class="annotation">⦉58</span></span><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6: + 47:9-47:23: Assign: _41 = move (_58.0: i32) + 43:29-48:6: Assign: _0 = const () + 50:5-50:6: StorageDead: StorageDead(_47) + 41:5-50:6: Goto: goto -> bb78"><span class="annotation">⦉77</span></span><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6: + 47:9-47:23: Assign: _41 = move (_58.0: i32) + 43:29-48:6: Assign: _0 = const () + 50:5-50:6: StorageDead: StorageDead(_47) + 41:5-50:6: Goto: goto -> bb78"><span class="annotation">⦉77</span></span><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6: + 47:9-47:23: Assign: _41 = move (_58.0: i32) + 43:29-48:6: Assign: _0 = const () + 50:5-50:6: StorageDead: StorageDead(_47) + 41:5-50:6: Goto: goto -> bb78"><span class="annotation">⦉77</span></span><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6: + 43:12-50:6: FalseEdge: falseEdge -> [real: bb64, imaginary: bb63]"><span class="annotation">⦉62</span></span><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6: + 43:12-50:6: FalseEdge: falseEdge -> [real: bb64, imaginary: bb63]"><span class="annotation">⦉62</span></span><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6: + 43:12-50:6: FalseEdge: falseEdge -> [real: bb64, imaginary: bb63]"><span class="annotation">⦉62</span></span><span class="code even" style="--layer: 15" title="bb63: ../instrument-coverage/coverage_of_if_else.rs:49:9: 51:2: + 49:9-49:15: Assign: _0 = const () + 50:5-50:6: StorageDead: StorageDead(_47) + 51:1-51:2: StorageDead: StorageDead(_41) + 51:1-51:2: StorageDead: StorageDead(_21) + 51:1-51:2: StorageDead: StorageDead(_1) + 51:1-51:2: StorageDead: StorageDead(_44) + 49:9-49:15: Goto: goto -> bb26"></span></span> +<span class="line"><span class="code even" style="--layer: 16" title="bb78: ../instrument-coverage/coverage_of_if_else.rs:51:1: 51:2: 51:1-51:2: StorageDead: StorageDead(_41) 51:1-51:2: StorageDead: StorageDead(_21) 51:1-51:2: StorageDead: StorageDead(_1) 51:1-51:2: StorageDead: StorageDead(_44) - 51:2-51:2: Goto: goto -> bb26"><span class="annotation">@78:</span> }</span><span><span class="code even" style="--layer: 1" title="bb26: ../instrument-coverage/coverage_of_if_else.rs:51:2: 51:2: - 51:2-51:2: Return: return"><span class="annotation">@26</span></span></span></span></div> + 51:2-51:2: Goto: goto -> bb26"><span class="annotation">78⦊</span>}<span class="annotation">⦉78</span></span><span class="code even" style="--layer: 15" title="bb63: ../instrument-coverage/coverage_of_if_else.rs:49:9: 51:2: + 49:9-49:15: Assign: _0 = const () + 50:5-50:6: StorageDead: StorageDead(_47) + 51:1-51:2: StorageDead: StorageDead(_41) + 51:1-51:2: StorageDead: StorageDead(_21) + 51:1-51:2: StorageDead: StorageDead(_1) + 51:1-51:2: StorageDead: StorageDead(_44) + 49:9-49:15: Goto: goto -> bb26"><span class="annotation">⦉63</span></span><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2: + 33:9-33:15: Assign: _0 = const () + 34:5-34:6: StorageDead: StorageDead(_28) + 34:5-34:6: StorageDead: StorageDead(_25) + 34:5-34:6: StorageDead: StorageDead(_24) + 51:1-51:2: StorageDead: StorageDead(_21) + 33:9-33:15: Goto: goto -> bb27"><span class="annotation">⦉38</span></span><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2: + 51:1-51:2: StorageDead: StorageDead(_1) + 17:9-17:15: Goto: goto -> bb26"><span class="annotation">⦉27</span></span><span><span class="code even" style="--layer: 1" title="bb26: ../instrument-coverage/coverage_of_if_else.rs:51:2: 51:2: + 51:2-51:2: Return: return"><span class="annotation">26⦊</span>‸<span class="annotation">⦉26</span></span></span></span></div> </body> </html> diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html index faa5d65e7e7..1ea9aba488e 100644 --- a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html @@ -62,12 +62,12 @@ <div class="code" style="counter-reset: line 2"><span class="line"><span class="code" style="--layer: 0">fn main() {</span></span> <span class="line"><span class="code" style="--layer: 0"> let mut countdown = 0;</span></span> <span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="bb2: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6: - 5:5-7:6: FalseEdge: falseEdge -> [real: bb4, imaginary: bb3]"><span class="annotation">@2</span></span></span><span class="code even" style="--layer: 2" title="bb4: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6: + 5:5-7:6: FalseEdge: falseEdge -> [real: bb4, imaginary: bb3]"><span class="annotation">2⦊</span></span></span><span class="code even" style="--layer: 2" title="bb4: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6: 6:9-6:23: Assign: _1 = const 10_i32 5:13-7:6: Assign: _2 = const () - 5:5-7:6: Goto: goto -> bb5"><span class="annotation">@4</span></span><span class="code even" style="--layer: 3" title="bb3: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6: + 5:5-7:6: Goto: goto -> bb5"><span class="annotation">4⦊</span></span><span class="code even" style="--layer: 3" title="bb3: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6: 5:5-7:6: Assign: _2 = const () - 5:5-7:6: Goto: goto -> bb5"><span class="annotation">@3:</span> if </span><span class="code even" style="--layer: 4" title="bb0: ../instrument-coverage/coverage_of_if_else.rs:5:8: 5:12: + 5:5-7:6: Goto: goto -> bb5"><span class="annotation">3⦊</span>if </span><span class="code even" style="--layer: 4" title="bb0: ../instrument-coverage/coverage_of_if_else.rs:5:8: 5:12: 4:9-4:22: StorageLive: StorageLive(_1) 4:25-4:26: Assign: _1 = const 0_i32 4:9-4:22: FakeRead: FakeRead(ForLet, _1) @@ -75,25 +75,29 @@ 5:8-5:12: StorageLive: StorageLive(_3) 5:8-5:12: Assign: _3 = const true 5:8-5:12: FakeRead: FakeRead(ForMatchedPlace, _3) - 5:5-7:6: SwitchInt: switchInt(_3) -> [false: bb3, otherwise: bb2]"><span class="annotation">@0:</span> true</span><span class="code even" style="--layer: 3" title="bb3: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6: + 5:5-7:6: SwitchInt: switchInt(_3) -> [false: bb3, otherwise: bb2]"><span class="annotation">0⦊</span>true<span class="annotation">⦉0</span></span><span class="code even" style="--layer: 3" title="bb3: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6: 5:5-7:6: Assign: _2 = const () - 5:5-7:6: Goto: goto -> bb5"><span class="annotation">@3:</span> {</span></span> + 5:5-7:6: Goto: goto -> bb5"> {</span></span> <span class="line"><span class="code even" style="--layer: 3" title="bb3: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6: 5:5-7:6: Assign: _2 = const () 5:5-7:6: Goto: goto -> bb5"> countdown = 10;</span></span> <span class="line"><span class="code even" style="--layer: 3" title="bb3: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6: 5:5-7:6: Assign: _2 = const () - 5:5-7:6: Goto: goto -> bb5"> }</span><span class="code" style="--layer: 0"></span></span> + 5:5-7:6: Goto: goto -> bb5"> }<span class="annotation">⦉3</span></span><span class="code even" style="--layer: 2" title="bb4: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6: + 6:9-6:23: Assign: _1 = const 10_i32 + 5:13-7:6: Assign: _2 = const () + 5:5-7:6: Goto: goto -> bb5"><span class="annotation">⦉4</span></span><span><span class="code even" style="--layer: 1" title="bb2: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6: + 5:5-7:6: FalseEdge: falseEdge -> [real: bb4, imaginary: bb3]"><span class="annotation">⦉2</span></span></span><span class="code" style="--layer: 0"></span></span> <span class="line"><span class="code" style="--layer: 0"></span></span> -<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="bb6: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: - 9:5-18:6: FalseEdge: falseEdge -> [real: bb8, imaginary: bb7]"><span class="annotation">@6</span></span></span><span class="code even" style="--layer: 2" title="bb9: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: +<span class="line"><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="bb6: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: + 9:5-18:6: FalseEdge: falseEdge -> [real: bb8, imaginary: bb7]"><span class="annotation">6⦊</span></span></span><span class="code even" style="--layer: 2" title="bb9: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: 10:9-10:23: Assign: _1 = move (_7.0: i32) 9:22-11:6: Assign: _4 = const () - 9:5-18:6: Goto: goto -> bb28"><span class="annotation">@9</span></span><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: + 9:5-18:6: Goto: goto -> bb28"><span class="annotation">9⦊</span></span><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: 15:9-15:23: Assign: _1 = move (_19.0: i32) 11:29-16:6: Assign: _4 = const () 18:5-18:6: StorageDead: StorageDead(_8) - 9:5-18:6: Goto: goto -> bb28"><span class="annotation">@25:</span> if </span><span class="code even" style="--layer: 4" title="bb5: ../instrument-coverage/coverage_of_if_else.rs:9:8: 9:21: + 9:5-18:6: Goto: goto -> bb28"><span class="annotation">25⦊</span>if </span><span class="code even" style="--layer: 4" title="bb5: ../instrument-coverage/coverage_of_if_else.rs:9:8: 9:21: 7:5-7:6: StorageDead: StorageDead(_3) 7:5-7:6: StorageDead: StorageDead(_2) 9:5-18:6: StorageLive: StorageLive(_4) @@ -103,61 +107,61 @@ 9:8-9:21: Assign: _5 = Gt(move _6, const 7_i32) 9:20-9:21: StorageDead: StorageDead(_6) 9:8-9:21: FakeRead: FakeRead(ForMatchedPlace, _5) - 9:5-18:6: SwitchInt: switchInt(_5) -> [false: bb7, otherwise: bb6]"><span class="annotation">@5:</span> countdown > 7</span><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: + 9:5-18:6: SwitchInt: switchInt(_5) -> [false: bb7, otherwise: bb6]"><span class="annotation">5⦊</span>countdown > 7<span class="annotation">⦉5</span></span><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: 15:9-15:23: Assign: _1 = move (_19.0: i32) 11:29-16:6: Assign: _4 = const () 18:5-18:6: StorageDead: StorageDead(_8) - 9:5-18:6: Goto: goto -> bb28"><span class="annotation">@25:</span> {</span></span> + 9:5-18:6: Goto: goto -> bb28"> {</span></span> <span class="line"><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: 15:9-15:23: Assign: _1 = move (_19.0: i32) 11:29-16:6: Assign: _4 = const () 18:5-18:6: StorageDead: StorageDead(_8) 9:5-18:6: Goto: goto -> bb28"> </span><span class="code odd" style="--layer: 4" title="bb8: ../instrument-coverage/coverage_of_if_else.rs:10:9: 10:23: 10:9-10:23: Assign: _7 = CheckedSub(_1, const 4_i32) - 10:9-10:23: Assert: assert(!move (_7.1: bool), "attempt to compute `{} - {}` which would overflow", _1, const 4_i32) -> [success: bb9, unwind: bb1]"><span class="annotation">@8:</span> countdown -= 4</span><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: + 10:9-10:23: Assert: assert(!move (_7.1: bool), "attempt to compute `{} - {}` which would overflow", _1, const 4_i32) -> [success: bb9, unwind: bb1]"><span class="annotation">8⦊</span>countdown -= 4<span class="annotation">⦉8</span></span><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: 15:9-15:23: Assign: _1 = move (_19.0: i32) 11:29-16:6: Assign: _4 = const () 18:5-18:6: StorageDead: StorageDead(_8) - 9:5-18:6: Goto: goto -> bb28"><span class="annotation">@25:</span> ;</span></span> + 9:5-18:6: Goto: goto -> bb28">;</span></span> <span class="line"><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: 15:9-15:23: Assign: _1 = move (_19.0: i32) 11:29-16:6: Assign: _4 = const () 18:5-18:6: StorageDead: StorageDead(_8) 9:5-18:6: Goto: goto -> bb28"> } else </span><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6: - 11:12-18:6: FalseEdge: falseEdge -> [real: bb12, imaginary: bb11]"><span class="annotation">@10:</span> if </span><span class="code even" style="--layer: 5" title="bb7: ../instrument-coverage/coverage_of_if_else.rs:11:15: 11:28: + 11:12-18:6: FalseEdge: falseEdge -> [real: bb12, imaginary: bb11]"><span class="annotation">10⦊</span>if </span><span class="code even" style="--layer: 5" title="bb7: ../instrument-coverage/coverage_of_if_else.rs:11:15: 11:28: 11:15-11:28: StorageLive: StorageLive(_8) 11:15-11:24: StorageLive: StorageLive(_9) 11:15-11:24: Assign: _9 = _1 11:15-11:28: Assign: _8 = Gt(move _9, const 2_i32) 11:27-11:28: StorageDead: StorageDead(_9) 11:15-11:28: FakeRead: FakeRead(ForMatchedPlace, _8) - 11:12-18:6: SwitchInt: switchInt(_8) -> [false: bb11, otherwise: bb10]"><span class="annotation">@7:</span> countdown > 2</span><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6: - 11:12-18:6: FalseEdge: falseEdge -> [real: bb12, imaginary: bb11]"><span class="annotation">@10:</span> {</span></span> + 11:12-18:6: SwitchInt: switchInt(_8) -> [false: bb11, otherwise: bb10]"><span class="annotation">7⦊</span>countdown > 2<span class="annotation">⦉7</span></span><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6: + 11:12-18:6: FalseEdge: falseEdge -> [real: bb12, imaginary: bb11]"> {</span></span> <span class="line"><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6: 11:12-18:6: FalseEdge: falseEdge -> [real: bb12, imaginary: bb11]"> </span><span class="code odd" style="--layer: 5" title="bb22: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10: 12:9-14:10: Assign: _10 = const () - 12:9-14:10: Goto: goto -> bb24"><span class="annotation">@22</span></span><span class="code even" style="--layer: 6" title="bb23: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10: + 12:9-14:10: Goto: goto -> bb24"><span class="annotation">22⦊</span></span><span class="code even" style="--layer: 6" title="bb23: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10: 13:13-13:26: Assign: _1 = const 0_i32 12:61-14:10: Assign: _10 = const () - 12:9-14:10: Goto: goto -> bb24"><span class="annotation">@23</span></span><span class="code even" style="--layer: 7" title="bb21: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10: - 12:9-14:10: FalseEdge: falseEdge -> [real: bb23, imaginary: bb22]"><span class="annotation">@21:</span> if </span><span class="code even" style="--layer: 8" title="bb14: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: + 12:9-14:10: Goto: goto -> bb24"><span class="annotation">23⦊</span></span><span class="code even" style="--layer: 7" title="bb21: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10: + 12:9-14:10: FalseEdge: falseEdge -> [real: bb23, imaginary: bb22]"><span class="annotation">21⦊</span>if </span><span class="code even" style="--layer: 8" title="bb14: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: 12:12-12:60: Assign: _11 = const false - 12:12-12:60: Goto: goto -> bb16"><span class="annotation">@14</span></span><span class="code even" style="--layer: 9" title="bb15: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: + 12:12-12:60: Goto: goto -> bb16"><span class="annotation">14⦊</span></span><span class="code even" style="--layer: 9" title="bb15: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: 12:46-12:60: StorageLive: StorageLive(_17) 12:46-12:55: StorageLive: StorageLive(_18) 12:46-12:55: Assign: _18 = _1 12:46-12:60: Assign: _17 = Ne(move _18, const 9_i32) 12:59-12:60: StorageDead: StorageDead(_18) - 12:12-12:60: SwitchInt: switchInt(move _17) -> [false: bb14, otherwise: bb13]"><span class="annotation">@15</span></span><span class="code even" style="--layer: 10" title="bb16: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: + 12:12-12:60: SwitchInt: switchInt(move _17) -> [false: bb14, otherwise: bb13]"><span class="annotation">15⦊</span></span><span class="code even" style="--layer: 10" title="bb16: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: 12:59-12:60: StorageDead: StorageDead(_17) 12:59-12:60: StorageDead: StorageDead(_12) 12:12-12:60: FakeRead: FakeRead(ForMatchedPlace, _11) - 12:9-14:10: SwitchInt: switchInt(_11) -> [false: bb22, otherwise: bb21]"><span class="annotation">@16</span></span><span class="code even" style="--layer: 11" title="bb13: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: + 12:9-14:10: SwitchInt: switchInt(_11) -> [false: bb22, otherwise: bb21]"><span class="annotation">16⦊</span></span><span class="code even" style="--layer: 11" title="bb13: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: 12:12-12:60: Assign: _11 = const true - 12:12-12:60: Goto: goto -> bb16"><span class="annotation">@13</span></span><span class="code even" style="--layer: 12" title="bb20: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: + 12:12-12:60: Goto: goto -> bb16"><span class="annotation">13⦊</span></span><span class="code even" style="--layer: 12" title="bb20: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: 12:41-12:42: StorageDead: StorageDead(_15) 12:41-12:42: StorageDead: StorageDead(_13) - 12:12-12:60: SwitchInt: switchInt(move _12) -> [false: bb15, otherwise: bb13]"><span class="annotation">@20</span></span><span class="code even" style="--layer: 13" title="bb12: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: + 12:12-12:60: SwitchInt: switchInt(move _12) -> [false: bb15, otherwise: bb13]"><span class="annotation">20⦊</span></span><span class="code even" style="--layer: 13" title="bb12: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: 12:9-14:10: StorageLive: StorageLive(_10) 12:12-12:60: StorageLive: StorageLive(_11) 12:12-12:42: StorageLive: StorageLive(_12) @@ -166,17 +170,25 @@ 12:12-12:21: Assign: _14 = _1 12:12-12:25: Assign: _13 = Lt(move _14, const 1_i32) 12:24-12:25: StorageDead: StorageDead(_14) - 12:12-12:42: SwitchInt: switchInt(move _13) -> [false: bb19, otherwise: bb17]"><span class="annotation">@12</span></span><span class="code even" style="--layer: 14" title="bb18: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:42: + 12:12-12:42: SwitchInt: switchInt(move _13) -> [false: bb19, otherwise: bb17]"><span class="annotation">12⦊</span></span><span class="code even" style="--layer: 14" title="bb18: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:42: 12:12-12:42: Assign: _12 = const false - 12:12-12:42: Goto: goto -> bb20"><span class="annotation">@18</span></span><span class="code even" style="--layer: 15" title="bb19: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:42: + 12:12-12:42: Goto: goto -> bb20"><span class="annotation">18⦊</span></span><span class="code even" style="--layer: 15" title="bb19: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:42: 12:29-12:42: StorageLive: StorageLive(_15) 12:29-12:38: StorageLive: StorageLive(_16) 12:29-12:38: Assign: _16 = _1 12:29-12:42: Assign: _15 = Gt(move _16, const 5_i32) 12:41-12:42: StorageDead: StorageDead(_16) - 12:12-12:42: SwitchInt: switchInt(move _15) -> [false: bb18, otherwise: bb17]"><span class="annotation">@19</span></span><span class="code even" style="--layer: 16" title="bb17: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:42: + 12:12-12:42: SwitchInt: switchInt(move _15) -> [false: bb18, otherwise: bb17]"><span class="annotation">19⦊</span></span><span class="code even" style="--layer: 16" title="bb17: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:42: 12:12-12:42: Assign: _12 = const true - 12:12-12:42: Goto: goto -> bb20"><span class="annotation">@17:</span> countdown < 1 || countdown > 5</span><span class="code even" style="--layer: 13" title="bb12: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: + 12:12-12:42: Goto: goto -> bb20"><span class="annotation">17⦊</span>countdown < 1 || countdown > 5<span class="annotation">⦉17</span></span><span class="code even" style="--layer: 15" title="bb19: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:42: + 12:29-12:42: StorageLive: StorageLive(_15) + 12:29-12:38: StorageLive: StorageLive(_16) + 12:29-12:38: Assign: _16 = _1 + 12:29-12:42: Assign: _15 = Gt(move _16, const 5_i32) + 12:41-12:42: StorageDead: StorageDead(_16) + 12:12-12:42: SwitchInt: switchInt(move _15) -> [false: bb18, otherwise: bb17]"><span class="annotation">⦉19</span></span><span class="code even" style="--layer: 14" title="bb18: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:42: + 12:12-12:42: Assign: _12 = const false + 12:12-12:42: Goto: goto -> bb20"><span class="annotation">⦉18</span></span><span class="code even" style="--layer: 13" title="bb12: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: 12:9-14:10: StorageLive: StorageLive(_10) 12:12-12:60: StorageLive: StorageLive(_11) 12:12-12:42: StorageLive: StorageLive(_12) @@ -185,8 +197,25 @@ 12:12-12:21: Assign: _14 = _1 12:12-12:25: Assign: _13 = Lt(move _14, const 1_i32) 12:24-12:25: StorageDead: StorageDead(_14) - 12:12-12:42: SwitchInt: switchInt(move _13) -> [false: bb19, otherwise: bb17]"><span class="annotation">@12:</span> || countdown != 9</span><span class="code even" style="--layer: 7" title="bb21: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10: - 12:9-14:10: FalseEdge: falseEdge -> [real: bb23, imaginary: bb22]"><span class="annotation">@21:</span> {</span></span> + 12:12-12:42: SwitchInt: switchInt(move _13) -> [false: bb19, otherwise: bb17]"> || countdown != 9<span class="annotation">⦉12</span></span><span class="code even" style="--layer: 12" title="bb20: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: + 12:41-12:42: StorageDead: StorageDead(_15) + 12:41-12:42: StorageDead: StorageDead(_13) + 12:12-12:60: SwitchInt: switchInt(move _12) -> [false: bb15, otherwise: bb13]"><span class="annotation">⦉20</span></span><span class="code even" style="--layer: 11" title="bb13: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: + 12:12-12:60: Assign: _11 = const true + 12:12-12:60: Goto: goto -> bb16"><span class="annotation">⦉13</span></span><span class="code even" style="--layer: 10" title="bb16: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: + 12:59-12:60: StorageDead: StorageDead(_17) + 12:59-12:60: StorageDead: StorageDead(_12) + 12:12-12:60: FakeRead: FakeRead(ForMatchedPlace, _11) + 12:9-14:10: SwitchInt: switchInt(_11) -> [false: bb22, otherwise: bb21]"><span class="annotation">⦉16</span></span><span class="code even" style="--layer: 9" title="bb15: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: + 12:46-12:60: StorageLive: StorageLive(_17) + 12:46-12:55: StorageLive: StorageLive(_18) + 12:46-12:55: Assign: _18 = _1 + 12:46-12:60: Assign: _17 = Ne(move _18, const 9_i32) + 12:59-12:60: StorageDead: StorageDead(_18) + 12:12-12:60: SwitchInt: switchInt(move _17) -> [false: bb14, otherwise: bb13]"><span class="annotation">⦉15</span></span><span class="code even" style="--layer: 8" title="bb14: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60: + 12:12-12:60: Assign: _11 = const false + 12:12-12:60: Goto: goto -> bb16"><span class="annotation">⦉14</span></span><span class="code even" style="--layer: 7" title="bb21: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10: + 12:9-14:10: FalseEdge: falseEdge -> [real: bb23, imaginary: bb22]"> {</span></span> <span class="line"><span class="code even" style="--layer: 7" title="bb21: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10: 12:9-14:10: FalseEdge: falseEdge -> [real: bb23, imaginary: bb22]"> countdown = 0;</span></span> <span class="line"><span class="code even" style="--layer: 7" title="bb21: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10: @@ -194,32 +223,67 @@ 14:9-14:10: StorageDead: StorageDead(_11) 14:9-14:10: StorageDead: StorageDead(_10) 15:9-15:23: Assign: _19 = CheckedSub(_1, const 5_i32) - 15:9-15:23: Assert: assert(!move (_19.1: bool), "attempt to compute `{} - {}` which would overflow", _1, const 5_i32) -> [success: bb25, unwind: bb1]"><span class="annotation">@24:</span> }</span></span> + 15:9-15:23: Assert: assert(!move (_19.1: bool), "attempt to compute `{} - {}` which would overflow", _1, const 5_i32) -> [success: bb25, unwind: bb1]"><span class="annotation">24⦊</span>}</span><span class="code odd" style="--layer: 5" title="bb22: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10: + 12:9-14:10: Assign: _10 = const () + 12:9-14:10: Goto: goto -> bb24"><span class="annotation">⦉22</span></span><span class="code even" style="--layer: 6" title="bb23: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10: + 13:13-13:26: Assign: _1 = const 0_i32 + 12:61-14:10: Assign: _10 = const () + 12:9-14:10: Goto: goto -> bb24"><span class="annotation">⦉23</span></span><span class="code even" style="--layer: 7" title="bb21: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10: + 12:9-14:10: FalseEdge: falseEdge -> [real: bb23, imaginary: bb22]"><span class="annotation">⦉21</span></span><span class="code even" style="--layer: 7" title="bb21: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10: + 12:9-14:10: FalseEdge: falseEdge -> [real: bb23, imaginary: bb22]"><span class="annotation">⦉21</span></span><span class="code odd" style="--layer: 8" title="bb24: ../instrument-coverage/coverage_of_if_else.rs:14:9: 15:23: + 14:9-14:10: StorageDead: StorageDead(_11) + 14:9-14:10: StorageDead: StorageDead(_10) + 15:9-15:23: Assign: _19 = CheckedSub(_1, const 5_i32) + 15:9-15:23: Assert: assert(!move (_19.1: bool), "attempt to compute `{} - {}` which would overflow", _1, const 5_i32) -> [success: bb25, unwind: bb1]"></span></span> <span class="line"><span class="code odd" style="--layer: 8" title="bb24: ../instrument-coverage/coverage_of_if_else.rs:14:9: 15:23: 14:9-14:10: StorageDead: StorageDead(_11) 14:9-14:10: StorageDead: StorageDead(_10) 15:9-15:23: Assign: _19 = CheckedSub(_1, const 5_i32) - 15:9-15:23: Assert: assert(!move (_19.1: bool), "attempt to compute `{} - {}` which would overflow", _1, const 5_i32) -> [success: bb25, unwind: bb1]"> countdown -= 5</span><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6: - 11:12-18:6: FalseEdge: falseEdge -> [real: bb12, imaginary: bb11]"><span class="annotation">@10:</span> ;</span></span> + 15:9-15:23: Assert: assert(!move (_19.1: bool), "attempt to compute `{} - {}` which would overflow", _1, const 5_i32) -> [success: bb25, unwind: bb1]"> countdown -= 5<span class="annotation">⦉24</span></span><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6: + 11:12-18:6: FalseEdge: falseEdge -> [real: bb12, imaginary: bb11]">;</span></span> <span class="line"><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6: 11:12-18:6: FalseEdge: falseEdge -> [real: bb12, imaginary: bb11]"> } else {</span></span> <span class="line"><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6: 11:12-18:6: FalseEdge: falseEdge -> [real: bb12, imaginary: bb11]"> </span><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2: 51:1-51:2: StorageDead: StorageDead(_1) - 17:9-17:15: Goto: goto -> bb26"><span class="annotation">@27</span></span><span class="code even" style="--layer: 6" title="bb11: ../instrument-coverage/coverage_of_if_else.rs:17:9: 18:6: + 17:9-17:15: Goto: goto -> bb26"><span class="annotation">27⦊</span></span><span class="code even" style="--layer: 6" title="bb11: ../instrument-coverage/coverage_of_if_else.rs:17:9: 18:6: 17:9-17:15: Assign: _0 = const () 18:5-18:6: StorageDead: StorageDead(_8) 18:5-18:6: StorageDead: StorageDead(_5) 18:5-18:6: StorageDead: StorageDead(_4) - 17:9-17:15: Goto: goto -> bb27"><span class="annotation">@11:</span> return;</span></span> + 17:9-17:15: Goto: goto -> bb27"><span class="annotation">11⦊</span>return;</span></span> <span class="line"><span class="code even" style="--layer: 6" title="bb11: ../instrument-coverage/coverage_of_if_else.rs:17:9: 18:6: 17:9-17:15: Assign: _0 = const () 18:5-18:6: StorageDead: StorageDead(_8) 18:5-18:6: StorageDead: StorageDead(_5) 18:5-18:6: StorageDead: StorageDead(_4) - 17:9-17:15: Goto: goto -> bb27"> }</span><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2: + 17:9-17:15: Goto: goto -> bb27"> }<span class="annotation">⦉11</span></span><span><span class="code odd" style="--layer: 1" title="bb6: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: + 9:5-18:6: FalseEdge: falseEdge -> [real: bb8, imaginary: bb7]"><span class="annotation">⦉6</span></span></span><span class="code even" style="--layer: 2" title="bb9: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: + 10:9-10:23: Assign: _1 = move (_7.0: i32) + 9:22-11:6: Assign: _4 = const () + 9:5-18:6: Goto: goto -> bb28"><span class="annotation">⦉9</span></span><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: + 15:9-15:23: Assign: _1 = move (_19.0: i32) + 11:29-16:6: Assign: _4 = const () + 18:5-18:6: StorageDead: StorageDead(_8) + 9:5-18:6: Goto: goto -> bb28"><span class="annotation">⦉25</span></span><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: + 15:9-15:23: Assign: _1 = move (_19.0: i32) + 11:29-16:6: Assign: _4 = const () + 18:5-18:6: StorageDead: StorageDead(_8) + 9:5-18:6: Goto: goto -> bb28"><span class="annotation">⦉25</span></span><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6: + 15:9-15:23: Assign: _1 = move (_19.0: i32) + 11:29-16:6: Assign: _4 = const () + 18:5-18:6: StorageDead: StorageDead(_8) + 9:5-18:6: Goto: goto -> bb28"><span class="annotation">⦉25</span></span><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6: + 11:12-18:6: FalseEdge: falseEdge -> [real: bb12, imaginary: bb11]"><span class="annotation">⦉10</span></span><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6: + 11:12-18:6: FalseEdge: falseEdge -> [real: bb12, imaginary: bb11]"><span class="annotation">⦉10</span></span><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6: + 11:12-18:6: FalseEdge: falseEdge -> [real: bb12, imaginary: bb11]"><span class="annotation">⦉10</span></span><span class="code even" style="--layer: 6" title="bb11: ../instrument-coverage/coverage_of_if_else.rs:17:9: 18:6: + 17:9-17:15: Assign: _0 = const () + 18:5-18:6: StorageDead: StorageDead(_8) + 18:5-18:6: StorageDead: StorageDead(_5) + 18:5-18:6: StorageDead: StorageDead(_4) + 17:9-17:15: Goto: goto -> bb27"><span class="annotation">⦉11</span></span><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2: 51:1-51:2: StorageDead: StorageDead(_1) - 17:9-17:15: Goto: goto -> bb26"><span class="annotation">@27:</span> </span></span> + 17:9-17:15: Goto: goto -> bb26"></span></span> <span class="line"><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2: 51:1-51:2: StorageDead: StorageDead(_1) 17:9-17:15: Goto: goto -> bb26"></span></span> @@ -230,11 +294,11 @@ 51:1-51:2: StorageDead: StorageDead(_1) 17:9-17:15: Goto: goto -> bb26"> </span><span class="code odd" style="--layer: 6" title="bb30: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6: 21:5-23:6: Assign: _22 = const () - 21:5-23:6: Goto: goto -> bb32"><span class="annotation">@30</span></span><span class="code even" style="--layer: 7" title="bb31: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6: + 21:5-23:6: Goto: goto -> bb32"><span class="annotation">30⦊</span></span><span class="code even" style="--layer: 7" title="bb31: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6: 22:9-22:23: Assign: _21 = const 10_i32 21:13-23:6: Assign: _22 = const () - 21:5-23:6: Goto: goto -> bb32"><span class="annotation">@31</span></span><span class="code even" style="--layer: 8" title="bb29: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6: - 21:5-23:6: FalseEdge: falseEdge -> [real: bb31, imaginary: bb30]"><span class="annotation">@29:</span> if </span><span class="code even" style="--layer: 9" title="bb28: ../instrument-coverage/coverage_of_if_else.rs:21:8: 21:12: + 21:5-23:6: Goto: goto -> bb32"><span class="annotation">31⦊</span></span><span class="code even" style="--layer: 8" title="bb29: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6: + 21:5-23:6: FalseEdge: falseEdge -> [real: bb31, imaginary: bb30]"><span class="annotation">29⦊</span>if </span><span class="code even" style="--layer: 9" title="bb28: ../instrument-coverage/coverage_of_if_else.rs:21:8: 21:12: 18:5-18:6: StorageDead: StorageDead(_5) 18:5-18:6: StorageDead: StorageDead(_4) 20:9-20:22: StorageLive: StorageLive(_21) @@ -244,28 +308,33 @@ 21:8-21:12: StorageLive: StorageLive(_23) 21:8-21:12: Assign: _23 = const true 21:8-21:12: FakeRead: FakeRead(ForMatchedPlace, _23) - 21:5-23:6: SwitchInt: switchInt(_23) -> [false: bb30, otherwise: bb29]"><span class="annotation">@28:</span> true</span><span class="code even" style="--layer: 8" title="bb29: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6: - 21:5-23:6: FalseEdge: falseEdge -> [real: bb31, imaginary: bb30]"><span class="annotation">@29:</span> {</span></span> + 21:5-23:6: SwitchInt: switchInt(_23) -> [false: bb30, otherwise: bb29]"><span class="annotation">28⦊</span>true<span class="annotation">⦉28</span></span><span class="code even" style="--layer: 8" title="bb29: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6: + 21:5-23:6: FalseEdge: falseEdge -> [real: bb31, imaginary: bb30]"> {</span></span> <span class="line"><span class="code even" style="--layer: 8" title="bb29: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6: 21:5-23:6: FalseEdge: falseEdge -> [real: bb31, imaginary: bb30]"> countdown = 10;</span></span> <span class="line"><span class="code even" style="--layer: 8" title="bb29: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6: - 21:5-23:6: FalseEdge: falseEdge -> [real: bb31, imaginary: bb30]"> }</span><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2: + 21:5-23:6: FalseEdge: falseEdge -> [real: bb31, imaginary: bb30]"> }<span class="annotation">⦉29</span></span><span class="code even" style="--layer: 7" title="bb31: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6: + 22:9-22:23: Assign: _21 = const 10_i32 + 21:13-23:6: Assign: _22 = const () + 21:5-23:6: Goto: goto -> bb32"><span class="annotation">⦉31</span></span><span class="code odd" style="--layer: 6" title="bb30: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6: + 21:5-23:6: Assign: _22 = const () + 21:5-23:6: Goto: goto -> bb32"><span class="annotation">⦉30</span></span><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2: 51:1-51:2: StorageDead: StorageDead(_1) - 17:9-17:15: Goto: goto -> bb26"><span class="annotation">@27:</span> </span></span> + 17:9-17:15: Goto: goto -> bb26"></span></span> <span class="line"><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2: 51:1-51:2: StorageDead: StorageDead(_1) 17:9-17:15: Goto: goto -> bb26"></span></span> <span class="line"><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2: 51:1-51:2: StorageDead: StorageDead(_1) 17:9-17:15: Goto: goto -> bb26"> </span><span class="code even" style="--layer: 6" title="bb33: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6: - 25:5-34:6: FalseEdge: falseEdge -> [real: bb35, imaginary: bb34]"><span class="annotation">@33</span></span><span class="code even" style="--layer: 7" title="bb52: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6: + 25:5-34:6: FalseEdge: falseEdge -> [real: bb35, imaginary: bb34]"><span class="annotation">33⦊</span></span><span class="code even" style="--layer: 7" title="bb52: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6: 31:9-31:23: Assign: _21 = move (_39.0: i32) 27:29-32:6: Assign: _24 = const () 34:5-34:6: StorageDead: StorageDead(_28) - 25:5-34:6: Goto: goto -> bb53"><span class="annotation">@52</span></span><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6: + 25:5-34:6: Goto: goto -> bb53"><span class="annotation">52⦊</span></span><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6: 26:9-26:23: Assign: _21 = move (_27.0: i32) 25:22-27:6: Assign: _24 = const () - 25:5-34:6: Goto: goto -> bb53"><span class="annotation">@36:</span> if </span><span class="code even" style="--layer: 9" title="bb32: ../instrument-coverage/coverage_of_if_else.rs:25:8: 25:21: + 25:5-34:6: Goto: goto -> bb53"><span class="annotation">36⦊</span>if </span><span class="code even" style="--layer: 9" title="bb32: ../instrument-coverage/coverage_of_if_else.rs:25:8: 25:21: 23:5-23:6: StorageDead: StorageDead(_23) 23:5-23:6: StorageDead: StorageDead(_22) 25:5-34:6: StorageLive: StorageLive(_24) @@ -275,40 +344,40 @@ 25:8-25:21: Assign: _25 = Gt(move _26, const 7_i32) 25:20-25:21: StorageDead: StorageDead(_26) 25:8-25:21: FakeRead: FakeRead(ForMatchedPlace, _25) - 25:5-34:6: SwitchInt: switchInt(_25) -> [false: bb34, otherwise: bb33]"><span class="annotation">@32:</span> countdown > 7</span><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6: + 25:5-34:6: SwitchInt: switchInt(_25) -> [false: bb34, otherwise: bb33]"><span class="annotation">32⦊</span>countdown > 7<span class="annotation">⦉32</span></span><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6: 26:9-26:23: Assign: _21 = move (_27.0: i32) 25:22-27:6: Assign: _24 = const () - 25:5-34:6: Goto: goto -> bb53"><span class="annotation">@36:</span> {</span></span> + 25:5-34:6: Goto: goto -> bb53"> {</span></span> <span class="line"><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6: 26:9-26:23: Assign: _21 = move (_27.0: i32) 25:22-27:6: Assign: _24 = const () 25:5-34:6: Goto: goto -> bb53"> </span><span class="code odd" style="--layer: 9" title="bb35: ../instrument-coverage/coverage_of_if_else.rs:26:9: 26:23: 26:9-26:23: Assign: _27 = CheckedSub(_21, const 4_i32) - 26:9-26:23: Assert: assert(!move (_27.1: bool), "attempt to compute `{} - {}` which would overflow", _21, const 4_i32) -> [success: bb36, unwind: bb1]"><span class="annotation">@35:</span> countdown -= 4</span><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6: + 26:9-26:23: Assert: assert(!move (_27.1: bool), "attempt to compute `{} - {}` which would overflow", _21, const 4_i32) -> [success: bb36, unwind: bb1]"><span class="annotation">35⦊</span>countdown -= 4<span class="annotation">⦉35</span></span><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6: 26:9-26:23: Assign: _21 = move (_27.0: i32) 25:22-27:6: Assign: _24 = const () - 25:5-34:6: Goto: goto -> bb53"><span class="annotation">@36:</span> ;</span></span> + 25:5-34:6: Goto: goto -> bb53">;</span></span> <span class="line"><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6: 26:9-26:23: Assign: _21 = move (_27.0: i32) 25:22-27:6: Assign: _24 = const () 25:5-34:6: Goto: goto -> bb53"> } else </span><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6: - 27:12-34:6: FalseEdge: falseEdge -> [real: bb39, imaginary: bb38]"><span class="annotation">@37:</span> if </span><span class="code even" style="--layer: 10" title="bb34: ../instrument-coverage/coverage_of_if_else.rs:27:15: 27:28: + 27:12-34:6: FalseEdge: falseEdge -> [real: bb39, imaginary: bb38]"><span class="annotation">37⦊</span>if </span><span class="code even" style="--layer: 10" title="bb34: ../instrument-coverage/coverage_of_if_else.rs:27:15: 27:28: 27:15-27:28: StorageLive: StorageLive(_28) 27:15-27:24: StorageLive: StorageLive(_29) 27:15-27:24: Assign: _29 = _21 27:15-27:28: Assign: _28 = Gt(move _29, const 2_i32) 27:27-27:28: StorageDead: StorageDead(_29) 27:15-27:28: FakeRead: FakeRead(ForMatchedPlace, _28) - 27:12-34:6: SwitchInt: switchInt(_28) -> [false: bb38, otherwise: bb37]"><span class="annotation">@34:</span> countdown > 2</span><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6: - 27:12-34:6: FalseEdge: falseEdge -> [real: bb39, imaginary: bb38]"><span class="annotation">@37:</span> {</span></span> + 27:12-34:6: SwitchInt: switchInt(_28) -> [false: bb38, otherwise: bb37]"><span class="annotation">34⦊</span>countdown > 2<span class="annotation">⦉34</span></span><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6: + 27:12-34:6: FalseEdge: falseEdge -> [real: bb39, imaginary: bb38]"> {</span></span> <span class="line"><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6: 27:12-34:6: FalseEdge: falseEdge -> [real: bb39, imaginary: bb38]"> </span><span class="code odd" style="--layer: 10" title="bb48: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10: - 28:9-30:10: FalseEdge: falseEdge -> [real: bb50, imaginary: bb49]"><span class="annotation">@48</span></span><span class="code even" style="--layer: 11" title="bb50: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10: + 28:9-30:10: FalseEdge: falseEdge -> [real: bb50, imaginary: bb49]"><span class="annotation">48⦊</span></span><span class="code even" style="--layer: 11" title="bb50: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10: 29:13-29:26: Assign: _21 = const 0_i32 28:61-30:10: Assign: _30 = const () - 28:9-30:10: Goto: goto -> bb51"><span class="annotation">@50</span></span><span class="code even" style="--layer: 12" title="bb49: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10: + 28:9-30:10: Goto: goto -> bb51"><span class="annotation">50⦊</span></span><span class="code even" style="--layer: 12" title="bb49: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10: 28:9-30:10: Assign: _30 = const () - 28:9-30:10: Goto: goto -> bb51"><span class="annotation">@49:</span> if </span><span class="code even" style="--layer: 13" title="bb39: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: + 28:9-30:10: Goto: goto -> bb51"><span class="annotation">49⦊</span>if </span><span class="code even" style="--layer: 13" title="bb39: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: 28:9-30:10: StorageLive: StorageLive(_30) 28:12-28:60: StorageLive: StorageLive(_31) 28:12-28:42: StorageLive: StorageLive(_32) @@ -317,38 +386,70 @@ 28:12-28:21: Assign: _34 = _21 28:12-28:25: Assign: _33 = Lt(move _34, const 1_i32) 28:24-28:25: StorageDead: StorageDead(_34) - 28:12-28:42: SwitchInt: switchInt(move _33) -> [false: bb46, otherwise: bb44]"><span class="annotation">@39</span></span><span class="code even" style="--layer: 14" title="bb47: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: + 28:12-28:42: SwitchInt: switchInt(move _33) -> [false: bb46, otherwise: bb44]"><span class="annotation">39⦊</span></span><span class="code even" style="--layer: 14" title="bb47: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: 28:41-28:42: StorageDead: StorageDead(_35) 28:41-28:42: StorageDead: StorageDead(_33) - 28:12-28:60: SwitchInt: switchInt(move _32) -> [false: bb42, otherwise: bb40]"><span class="annotation">@47</span></span><span class="code even" style="--layer: 15" title="bb40: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: + 28:12-28:60: SwitchInt: switchInt(move _32) -> [false: bb42, otherwise: bb40]"><span class="annotation">47⦊</span></span><span class="code even" style="--layer: 15" title="bb40: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: 28:12-28:60: Assign: _31 = const true - 28:12-28:60: Goto: goto -> bb43"><span class="annotation">@40</span></span><span class="code even" style="--layer: 16" title="bb43: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: + 28:12-28:60: Goto: goto -> bb43"><span class="annotation">40⦊</span></span><span class="code even" style="--layer: 16" title="bb43: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: 28:59-28:60: StorageDead: StorageDead(_37) 28:59-28:60: StorageDead: StorageDead(_32) 28:12-28:60: FakeRead: FakeRead(ForMatchedPlace, _31) - 28:9-30:10: SwitchInt: switchInt(_31) -> [false: bb49, otherwise: bb48]"><span class="annotation">@43</span></span><span class="code even" style="--layer: 17" title="bb42: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: + 28:9-30:10: SwitchInt: switchInt(_31) -> [false: bb49, otherwise: bb48]"><span class="annotation">43⦊</span></span><span class="code even" style="--layer: 17" title="bb42: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: 28:46-28:60: StorageLive: StorageLive(_37) 28:46-28:55: StorageLive: StorageLive(_38) 28:46-28:55: Assign: _38 = _21 28:46-28:60: Assign: _37 = Ne(move _38, const 9_i32) 28:59-28:60: StorageDead: StorageDead(_38) - 28:12-28:60: SwitchInt: switchInt(move _37) -> [false: bb41, otherwise: bb40]"><span class="annotation">@42</span></span><span class="code even" style="--layer: 18" title="bb41: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: + 28:12-28:60: SwitchInt: switchInt(move _37) -> [false: bb41, otherwise: bb40]"><span class="annotation">42⦊</span></span><span class="code even" style="--layer: 18" title="bb41: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: 28:12-28:60: Assign: _31 = const false - 28:12-28:60: Goto: goto -> bb43"><span class="annotation">@41</span></span><span class="code even" style="--layer: 19" title="bb46: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:42: + 28:12-28:60: Goto: goto -> bb43"><span class="annotation">41⦊</span></span><span class="code even" style="--layer: 19" title="bb46: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:42: 28:29-28:42: StorageLive: StorageLive(_35) 28:29-28:38: StorageLive: StorageLive(_36) 28:29-28:38: Assign: _36 = _21 28:29-28:42: Assign: _35 = Gt(move _36, const 5_i32) 28:41-28:42: StorageDead: StorageDead(_36) - 28:12-28:42: SwitchInt: switchInt(move _35) -> [false: bb45, otherwise: bb44]"><span class="annotation">@46</span></span><span class="code even" style="--layer: 20" title="bb45: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:42: + 28:12-28:42: SwitchInt: switchInt(move _35) -> [false: bb45, otherwise: bb44]"><span class="annotation">46⦊</span></span><span class="code even" style="--layer: 20" title="bb45: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:42: 28:12-28:42: Assign: _32 = const false - 28:12-28:42: Goto: goto -> bb47"><span class="annotation">@45</span></span><span class="code even" style="--layer: 21" title="bb44: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:42: + 28:12-28:42: Goto: goto -> bb47"><span class="annotation">45⦊</span></span><span class="code even" style="--layer: 21" title="bb44: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:42: 28:12-28:42: Assign: _32 = const true - 28:12-28:42: Goto: goto -> bb47"><span class="annotation">@44:</span> countdown < 1 || countdown > 5</span><span class="code even" style="--layer: 18" title="bb41: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: + 28:12-28:42: Goto: goto -> bb47"><span class="annotation">44⦊</span>countdown < 1 || countdown > 5<span class="annotation">⦉44</span></span><span class="code even" style="--layer: 20" title="bb45: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:42: + 28:12-28:42: Assign: _32 = const false + 28:12-28:42: Goto: goto -> bb47"><span class="annotation">⦉45</span></span><span class="code even" style="--layer: 19" title="bb46: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:42: + 28:29-28:42: StorageLive: StorageLive(_35) + 28:29-28:38: StorageLive: StorageLive(_36) + 28:29-28:38: Assign: _36 = _21 + 28:29-28:42: Assign: _35 = Gt(move _36, const 5_i32) + 28:41-28:42: StorageDead: StorageDead(_36) + 28:12-28:42: SwitchInt: switchInt(move _35) -> [false: bb45, otherwise: bb44]"><span class="annotation">⦉46</span></span><span class="code even" style="--layer: 18" title="bb41: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: 28:12-28:60: Assign: _31 = const false - 28:12-28:60: Goto: goto -> bb43"><span class="annotation">@41:</span> || countdown != 9</span><span class="code even" style="--layer: 12" title="bb49: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10: + 28:12-28:60: Goto: goto -> bb43"> || countdown != 9<span class="annotation">⦉41</span></span><span class="code even" style="--layer: 17" title="bb42: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: + 28:46-28:60: StorageLive: StorageLive(_37) + 28:46-28:55: StorageLive: StorageLive(_38) + 28:46-28:55: Assign: _38 = _21 + 28:46-28:60: Assign: _37 = Ne(move _38, const 9_i32) + 28:59-28:60: StorageDead: StorageDead(_38) + 28:12-28:60: SwitchInt: switchInt(move _37) -> [false: bb41, otherwise: bb40]"><span class="annotation">⦉42</span></span><span class="code even" style="--layer: 16" title="bb43: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: + 28:59-28:60: StorageDead: StorageDead(_37) + 28:59-28:60: StorageDead: StorageDead(_32) + 28:12-28:60: FakeRead: FakeRead(ForMatchedPlace, _31) + 28:9-30:10: SwitchInt: switchInt(_31) -> [false: bb49, otherwise: bb48]"><span class="annotation">⦉43</span></span><span class="code even" style="--layer: 15" title="bb40: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: + 28:12-28:60: Assign: _31 = const true + 28:12-28:60: Goto: goto -> bb43"><span class="annotation">⦉40</span></span><span class="code even" style="--layer: 14" title="bb47: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: + 28:41-28:42: StorageDead: StorageDead(_35) + 28:41-28:42: StorageDead: StorageDead(_33) + 28:12-28:60: SwitchInt: switchInt(move _32) -> [false: bb42, otherwise: bb40]"><span class="annotation">⦉47</span></span><span class="code even" style="--layer: 13" title="bb39: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60: + 28:9-30:10: StorageLive: StorageLive(_30) + 28:12-28:60: StorageLive: StorageLive(_31) + 28:12-28:42: StorageLive: StorageLive(_32) + 28:12-28:25: StorageLive: StorageLive(_33) + 28:12-28:21: StorageLive: StorageLive(_34) + 28:12-28:21: Assign: _34 = _21 + 28:12-28:25: Assign: _33 = Lt(move _34, const 1_i32) + 28:24-28:25: StorageDead: StorageDead(_34) + 28:12-28:42: SwitchInt: switchInt(move _33) -> [false: bb46, otherwise: bb44]"><span class="annotation">⦉39</span></span><span class="code even" style="--layer: 12" title="bb49: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10: 28:9-30:10: Assign: _30 = const () - 28:9-30:10: Goto: goto -> bb51"><span class="annotation">@49:</span> {</span></span> + 28:9-30:10: Goto: goto -> bb51"> {</span></span> <span class="line"><span class="code even" style="--layer: 12" title="bb49: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10: 28:9-30:10: Assign: _30 = const () 28:9-30:10: Goto: goto -> bb51"> countdown = 0;</span></span> @@ -358,13 +459,25 @@ 30:9-30:10: StorageDead: StorageDead(_31) 30:9-30:10: StorageDead: StorageDead(_30) 31:9-31:23: Assign: _39 = CheckedSub(_21, const 5_i32) - 31:9-31:23: Assert: assert(!move (_39.1: bool), "attempt to compute `{} - {}` which would overflow", _21, const 5_i32) -> [success: bb52, unwind: bb1]"><span class="annotation">@51:</span> }</span></span> + 31:9-31:23: Assert: assert(!move (_39.1: bool), "attempt to compute `{} - {}` which would overflow", _21, const 5_i32) -> [success: bb52, unwind: bb1]"><span class="annotation">51⦊</span>}</span><span class="code odd" style="--layer: 10" title="bb48: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10: + 28:9-30:10: FalseEdge: falseEdge -> [real: bb50, imaginary: bb49]"><span class="annotation">⦉48</span></span><span class="code even" style="--layer: 11" title="bb50: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10: + 29:13-29:26: Assign: _21 = const 0_i32 + 28:61-30:10: Assign: _30 = const () + 28:9-30:10: Goto: goto -> bb51"><span class="annotation">⦉50</span></span><span class="code even" style="--layer: 12" title="bb49: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10: + 28:9-30:10: Assign: _30 = const () + 28:9-30:10: Goto: goto -> bb51"><span class="annotation">⦉49</span></span><span class="code even" style="--layer: 12" title="bb49: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10: + 28:9-30:10: Assign: _30 = const () + 28:9-30:10: Goto: goto -> bb51"><span class="annotation">⦉49</span></span><span class="code odd" style="--layer: 13" title="bb51: ../instrument-coverage/coverage_of_if_else.rs:30:9: 31:23: + 30:9-30:10: StorageDead: StorageDead(_31) + 30:9-30:10: StorageDead: StorageDead(_30) + 31:9-31:23: Assign: _39 = CheckedSub(_21, const 5_i32) + 31:9-31:23: Assert: assert(!move (_39.1: bool), "attempt to compute `{} - {}` which would overflow", _21, const 5_i32) -> [success: bb52, unwind: bb1]"></span></span> <span class="line"><span class="code odd" style="--layer: 13" title="bb51: ../instrument-coverage/coverage_of_if_else.rs:30:9: 31:23: 30:9-30:10: StorageDead: StorageDead(_31) 30:9-30:10: StorageDead: StorageDead(_30) 31:9-31:23: Assign: _39 = CheckedSub(_21, const 5_i32) - 31:9-31:23: Assert: assert(!move (_39.1: bool), "attempt to compute `{} - {}` which would overflow", _21, const 5_i32) -> [success: bb52, unwind: bb1]"> countdown -= 5</span><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6: - 27:12-34:6: FalseEdge: falseEdge -> [real: bb39, imaginary: bb38]"><span class="annotation">@37:</span> ;</span></span> + 31:9-31:23: Assert: assert(!move (_39.1: bool), "attempt to compute `{} - {}` which would overflow", _21, const 5_i32) -> [success: bb52, unwind: bb1]"> countdown -= 5<span class="annotation">⦉51</span></span><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6: + 27:12-34:6: FalseEdge: falseEdge -> [real: bb39, imaginary: bb38]">;</span></span> <span class="line"><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6: 27:12-34:6: FalseEdge: falseEdge -> [real: bb39, imaginary: bb38]"> } else {</span></span> <span class="line"><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6: @@ -374,14 +487,37 @@ 34:5-34:6: StorageDead: StorageDead(_25) 34:5-34:6: StorageDead: StorageDead(_24) 51:1-51:2: StorageDead: StorageDead(_21) - 33:9-33:15: Goto: goto -> bb27"><span class="annotation">@38:</span> return;</span></span> + 33:9-33:15: Goto: goto -> bb27"><span class="annotation">38⦊</span>return;</span></span> <span class="line"><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2: 33:9-33:15: Assign: _0 = const () 34:5-34:6: StorageDead: StorageDead(_28) 34:5-34:6: StorageDead: StorageDead(_25) 34:5-34:6: StorageDead: StorageDead(_24) 51:1-51:2: StorageDead: StorageDead(_21) - 33:9-33:15: Goto: goto -> bb27"> }</span></span> + 33:9-33:15: Goto: goto -> bb27"> }</span><span class="code even" style="--layer: 6" title="bb33: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6: + 25:5-34:6: FalseEdge: falseEdge -> [real: bb35, imaginary: bb34]"><span class="annotation">⦉33</span></span><span class="code even" style="--layer: 7" title="bb52: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6: + 31:9-31:23: Assign: _21 = move (_39.0: i32) + 27:29-32:6: Assign: _24 = const () + 34:5-34:6: StorageDead: StorageDead(_28) + 25:5-34:6: Goto: goto -> bb53"><span class="annotation">⦉52</span></span><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6: + 26:9-26:23: Assign: _21 = move (_27.0: i32) + 25:22-27:6: Assign: _24 = const () + 25:5-34:6: Goto: goto -> bb53"><span class="annotation">⦉36</span></span><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6: + 26:9-26:23: Assign: _21 = move (_27.0: i32) + 25:22-27:6: Assign: _24 = const () + 25:5-34:6: Goto: goto -> bb53"><span class="annotation">⦉36</span></span><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6: + 26:9-26:23: Assign: _21 = move (_27.0: i32) + 25:22-27:6: Assign: _24 = const () + 25:5-34:6: Goto: goto -> bb53"><span class="annotation">⦉36</span></span><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6: + 27:12-34:6: FalseEdge: falseEdge -> [real: bb39, imaginary: bb38]"><span class="annotation">⦉37</span></span><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6: + 27:12-34:6: FalseEdge: falseEdge -> [real: bb39, imaginary: bb38]"><span class="annotation">⦉37</span></span><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6: + 27:12-34:6: FalseEdge: falseEdge -> [real: bb39, imaginary: bb38]"><span class="annotation">⦉37</span></span><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2: + 33:9-33:15: Assign: _0 = const () + 34:5-34:6: StorageDead: StorageDead(_28) + 34:5-34:6: StorageDead: StorageDead(_25) + 34:5-34:6: StorageDead: StorageDead(_24) + 51:1-51:2: StorageDead: StorageDead(_21) + 33:9-33:15: Goto: goto -> bb27"></span></span> <span class="line"><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2: 33:9-33:15: Assign: _0 = const () 34:5-34:6: StorageDead: StorageDead(_28) @@ -405,10 +541,10 @@ 33:9-33:15: Goto: goto -> bb27"> </span><span class="code even" style="--layer: 11" title="bb56: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6: 38:9-38:23: Assign: _41 = const 10_i32 37:13-39:6: Assign: _42 = const () - 37:5-39:6: Goto: goto -> bb57"><span class="annotation">@56</span></span><span class="code even" style="--layer: 12" title="bb54: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6: - 37:5-39:6: FalseEdge: falseEdge -> [real: bb56, imaginary: bb55]"><span class="annotation">@54</span></span><span class="code even" style="--layer: 13" title="bb55: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6: + 37:5-39:6: Goto: goto -> bb57"><span class="annotation">56⦊</span></span><span class="code even" style="--layer: 12" title="bb54: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6: + 37:5-39:6: FalseEdge: falseEdge -> [real: bb56, imaginary: bb55]"><span class="annotation">54⦊</span></span><span class="code even" style="--layer: 13" title="bb55: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6: 37:5-39:6: Assign: _42 = const () - 37:5-39:6: Goto: goto -> bb57"><span class="annotation">@55:</span> if </span><span class="code even" style="--layer: 14" title="bb53: ../instrument-coverage/coverage_of_if_else.rs:37:8: 37:12: + 37:5-39:6: Goto: goto -> bb57"><span class="annotation">55⦊</span>if </span><span class="code even" style="--layer: 14" title="bb53: ../instrument-coverage/coverage_of_if_else.rs:37:8: 37:12: 34:5-34:6: StorageDead: StorageDead(_25) 34:5-34:6: StorageDead: StorageDead(_24) 36:9-36:22: StorageLive: StorageLive(_41) @@ -418,21 +554,25 @@ 37:8-37:12: StorageLive: StorageLive(_43) 37:8-37:12: Assign: _43 = const true 37:8-37:12: FakeRead: FakeRead(ForMatchedPlace, _43) - 37:5-39:6: SwitchInt: switchInt(_43) -> [false: bb55, otherwise: bb54]"><span class="annotation">@53:</span> true</span><span class="code even" style="--layer: 13" title="bb55: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6: + 37:5-39:6: SwitchInt: switchInt(_43) -> [false: bb55, otherwise: bb54]"><span class="annotation">53⦊</span>true<span class="annotation">⦉53</span></span><span class="code even" style="--layer: 13" title="bb55: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6: 37:5-39:6: Assign: _42 = const () - 37:5-39:6: Goto: goto -> bb57"><span class="annotation">@55:</span> {</span></span> + 37:5-39:6: Goto: goto -> bb57"> {</span></span> <span class="line"><span class="code even" style="--layer: 13" title="bb55: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6: 37:5-39:6: Assign: _42 = const () 37:5-39:6: Goto: goto -> bb57"> countdown = 10;</span></span> <span class="line"><span class="code even" style="--layer: 13" title="bb55: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6: 37:5-39:6: Assign: _42 = const () - 37:5-39:6: Goto: goto -> bb57"> }</span><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2: + 37:5-39:6: Goto: goto -> bb57"> }<span class="annotation">⦉55</span></span><span class="code even" style="--layer: 12" title="bb54: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6: + 37:5-39:6: FalseEdge: falseEdge -> [real: bb56, imaginary: bb55]"><span class="annotation">⦉54</span></span><span class="code even" style="--layer: 11" title="bb56: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6: + 38:9-38:23: Assign: _41 = const 10_i32 + 37:13-39:6: Assign: _42 = const () + 37:5-39:6: Goto: goto -> bb57"><span class="annotation">⦉56</span></span><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2: 33:9-33:15: Assign: _0 = const () 34:5-34:6: StorageDead: StorageDead(_28) 34:5-34:6: StorageDead: StorageDead(_25) 34:5-34:6: StorageDead: StorageDead(_24) 51:1-51:2: StorageDead: StorageDead(_21) - 33:9-33:15: Goto: goto -> bb27"><span class="annotation">@38:</span> </span></span> + 33:9-33:15: Goto: goto -> bb27"></span></span> <span class="line"><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2: 33:9-33:15: Assign: _0 = const () 34:5-34:6: StorageDead: StorageDead(_28) @@ -449,12 +589,12 @@ 33:9-33:15: Goto: goto -> bb27"> </span><span class="code odd" style="--layer: 11" title="bb61: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6: 42:9-42:23: Assign: _41 = move (_46.0: i32) 41:22-43:6: Assign: _0 = const () - 41:5-50:6: Goto: goto -> bb78"><span class="annotation">@61</span></span><span class="code even" style="--layer: 12" title="bb58: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6: - 41:5-50:6: FalseEdge: falseEdge -> [real: bb60, imaginary: bb59]"><span class="annotation">@58</span></span><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6: + 41:5-50:6: Goto: goto -> bb78"><span class="annotation">61⦊</span></span><span class="code even" style="--layer: 12" title="bb58: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6: + 41:5-50:6: FalseEdge: falseEdge -> [real: bb60, imaginary: bb59]"><span class="annotation">58⦊</span></span><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6: 47:9-47:23: Assign: _41 = move (_58.0: i32) 43:29-48:6: Assign: _0 = const () 50:5-50:6: StorageDead: StorageDead(_47) - 41:5-50:6: Goto: goto -> bb78"><span class="annotation">@77:</span> if </span><span class="code even" style="--layer: 14" title="bb57: ../instrument-coverage/coverage_of_if_else.rs:41:8: 41:21: + 41:5-50:6: Goto: goto -> bb78"><span class="annotation">77⦊</span>if </span><span class="code even" style="--layer: 14" title="bb57: ../instrument-coverage/coverage_of_if_else.rs:41:8: 41:21: 39:5-39:6: StorageDead: StorageDead(_43) 39:5-39:6: StorageDead: StorageDead(_42) 41:8-41:21: StorageLive: StorageLive(_44) @@ -463,59 +603,59 @@ 41:8-41:21: Assign: _44 = Gt(move _45, const 7_i32) 41:20-41:21: StorageDead: StorageDead(_45) 41:8-41:21: FakeRead: FakeRead(ForMatchedPlace, _44) - 41:5-50:6: SwitchInt: switchInt(_44) -> [false: bb59, otherwise: bb58]"><span class="annotation">@57:</span> countdown > 7</span><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6: + 41:5-50:6: SwitchInt: switchInt(_44) -> [false: bb59, otherwise: bb58]"><span class="annotation">57⦊</span>countdown > 7<span class="annotation">⦉57</span></span><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6: 47:9-47:23: Assign: _41 = move (_58.0: i32) 43:29-48:6: Assign: _0 = const () 50:5-50:6: StorageDead: StorageDead(_47) - 41:5-50:6: Goto: goto -> bb78"><span class="annotation">@77:</span> {</span></span> + 41:5-50:6: Goto: goto -> bb78"> {</span></span> <span class="line"><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6: 47:9-47:23: Assign: _41 = move (_58.0: i32) 43:29-48:6: Assign: _0 = const () 50:5-50:6: StorageDead: StorageDead(_47) 41:5-50:6: Goto: goto -> bb78"> </span><span class="code odd" style="--layer: 14" title="bb60: ../instrument-coverage/coverage_of_if_else.rs:42:9: 42:23: 42:9-42:23: Assign: _46 = CheckedSub(_41, const 4_i32) - 42:9-42:23: Assert: assert(!move (_46.1: bool), "attempt to compute `{} - {}` which would overflow", _41, const 4_i32) -> [success: bb61, unwind: bb1]"><span class="annotation">@60:</span> countdown -= 4</span><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6: + 42:9-42:23: Assert: assert(!move (_46.1: bool), "attempt to compute `{} - {}` which would overflow", _41, const 4_i32) -> [success: bb61, unwind: bb1]"><span class="annotation">60⦊</span>countdown -= 4<span class="annotation">⦉60</span></span><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6: 47:9-47:23: Assign: _41 = move (_58.0: i32) 43:29-48:6: Assign: _0 = const () 50:5-50:6: StorageDead: StorageDead(_47) - 41:5-50:6: Goto: goto -> bb78"><span class="annotation">@77:</span> ;</span></span> + 41:5-50:6: Goto: goto -> bb78">;</span></span> <span class="line"><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6: 47:9-47:23: Assign: _41 = move (_58.0: i32) 43:29-48:6: Assign: _0 = const () 50:5-50:6: StorageDead: StorageDead(_47) 41:5-50:6: Goto: goto -> bb78"> } else </span><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6: - 43:12-50:6: FalseEdge: falseEdge -> [real: bb64, imaginary: bb63]"><span class="annotation">@62:</span> if </span><span class="code even" style="--layer: 15" title="bb59: ../instrument-coverage/coverage_of_if_else.rs:43:15: 43:28: + 43:12-50:6: FalseEdge: falseEdge -> [real: bb64, imaginary: bb63]"><span class="annotation">62⦊</span>if </span><span class="code even" style="--layer: 15" title="bb59: ../instrument-coverage/coverage_of_if_else.rs:43:15: 43:28: 43:15-43:28: StorageLive: StorageLive(_47) 43:15-43:24: StorageLive: StorageLive(_48) 43:15-43:24: Assign: _48 = _41 43:15-43:28: Assign: _47 = Gt(move _48, const 2_i32) 43:27-43:28: StorageDead: StorageDead(_48) 43:15-43:28: FakeRead: FakeRead(ForMatchedPlace, _47) - 43:12-50:6: SwitchInt: switchInt(_47) -> [false: bb63, otherwise: bb62]"><span class="annotation">@59:</span> countdown > 2</span><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6: - 43:12-50:6: FalseEdge: falseEdge -> [real: bb64, imaginary: bb63]"><span class="annotation">@62:</span> {</span></span> + 43:12-50:6: SwitchInt: switchInt(_47) -> [false: bb63, otherwise: bb62]"><span class="annotation">59⦊</span>countdown > 2<span class="annotation">⦉59</span></span><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6: + 43:12-50:6: FalseEdge: falseEdge -> [real: bb64, imaginary: bb63]"> {</span></span> <span class="line"><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6: 43:12-50:6: FalseEdge: falseEdge -> [real: bb64, imaginary: bb63]"> </span><span class="code odd" style="--layer: 15" title="bb75: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10: 45:13-45:26: Assign: _41 = const 0_i32 44:61-46:10: Assign: _49 = const () - 44:9-46:10: Goto: goto -> bb76"><span class="annotation">@75</span></span><span class="code even" style="--layer: 16" title="bb74: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10: + 44:9-46:10: Goto: goto -> bb76"><span class="annotation">75⦊</span></span><span class="code even" style="--layer: 16" title="bb74: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10: 44:9-46:10: Assign: _49 = const () - 44:9-46:10: Goto: goto -> bb76"><span class="annotation">@74</span></span><span class="code even" style="--layer: 17" title="bb73: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10: - 44:9-46:10: FalseEdge: falseEdge -> [real: bb75, imaginary: bb74]"><span class="annotation">@73:</span> if </span><span class="code even" style="--layer: 18" title="bb67: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: + 44:9-46:10: Goto: goto -> bb76"><span class="annotation">74⦊</span></span><span class="code even" style="--layer: 17" title="bb73: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10: + 44:9-46:10: FalseEdge: falseEdge -> [real: bb75, imaginary: bb74]"><span class="annotation">73⦊</span>if </span><span class="code even" style="--layer: 18" title="bb67: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: 44:46-44:60: StorageLive: StorageLive(_56) 44:46-44:55: StorageLive: StorageLive(_57) 44:46-44:55: Assign: _57 = _41 44:46-44:60: Assign: _56 = Ne(move _57, const 9_i32) 44:59-44:60: StorageDead: StorageDead(_57) - 44:12-44:60: SwitchInt: switchInt(move _56) -> [false: bb66, otherwise: bb65]"><span class="annotation">@67</span></span><span class="code even" style="--layer: 19" title="bb68: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: + 44:12-44:60: SwitchInt: switchInt(move _56) -> [false: bb66, otherwise: bb65]"><span class="annotation">67⦊</span></span><span class="code even" style="--layer: 19" title="bb68: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: 44:59-44:60: StorageDead: StorageDead(_56) 44:59-44:60: StorageDead: StorageDead(_51) 44:12-44:60: FakeRead: FakeRead(ForMatchedPlace, _50) - 44:9-46:10: SwitchInt: switchInt(_50) -> [false: bb74, otherwise: bb73]"><span class="annotation">@68</span></span><span class="code even" style="--layer: 20" title="bb65: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: + 44:9-46:10: SwitchInt: switchInt(_50) -> [false: bb74, otherwise: bb73]"><span class="annotation">68⦊</span></span><span class="code even" style="--layer: 20" title="bb65: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: 44:12-44:60: Assign: _50 = const true - 44:12-44:60: Goto: goto -> bb68"><span class="annotation">@65</span></span><span class="code even" style="--layer: 21" title="bb72: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: + 44:12-44:60: Goto: goto -> bb68"><span class="annotation">65⦊</span></span><span class="code even" style="--layer: 21" title="bb72: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: 44:41-44:42: StorageDead: StorageDead(_54) 44:41-44:42: StorageDead: StorageDead(_52) - 44:12-44:60: SwitchInt: switchInt(move _51) -> [false: bb67, otherwise: bb65]"><span class="annotation">@72</span></span><span class="code even" style="--layer: 22" title="bb64: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: + 44:12-44:60: SwitchInt: switchInt(move _51) -> [false: bb67, otherwise: bb65]"><span class="annotation">72⦊</span></span><span class="code even" style="--layer: 22" title="bb64: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: 44:9-46:10: StorageLive: StorageLive(_49) 44:12-44:60: StorageLive: StorageLive(_50) 44:12-44:42: StorageLive: StorageLive(_51) @@ -524,22 +664,54 @@ 44:12-44:21: Assign: _53 = _41 44:12-44:25: Assign: _52 = Lt(move _53, const 1_i32) 44:24-44:25: StorageDead: StorageDead(_53) - 44:12-44:42: SwitchInt: switchInt(move _52) -> [false: bb71, otherwise: bb69]"><span class="annotation">@64</span></span><span class="code even" style="--layer: 23" title="bb66: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: + 44:12-44:42: SwitchInt: switchInt(move _52) -> [false: bb71, otherwise: bb69]"><span class="annotation">64⦊</span></span><span class="code even" style="--layer: 23" title="bb66: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: 44:12-44:60: Assign: _50 = const false - 44:12-44:60: Goto: goto -> bb68"><span class="annotation">@66</span></span><span class="code even" style="--layer: 24" title="bb69: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:42: + 44:12-44:60: Goto: goto -> bb68"><span class="annotation">66⦊</span></span><span class="code even" style="--layer: 24" title="bb69: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:42: 44:12-44:42: Assign: _51 = const true - 44:12-44:42: Goto: goto -> bb72"><span class="annotation">@69</span></span><span class="code even" style="--layer: 25" title="bb71: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:42: + 44:12-44:42: Goto: goto -> bb72"><span class="annotation">69⦊</span></span><span class="code even" style="--layer: 25" title="bb71: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:42: 44:29-44:42: StorageLive: StorageLive(_54) 44:29-44:38: StorageLive: StorageLive(_55) 44:29-44:38: Assign: _55 = _41 44:29-44:42: Assign: _54 = Gt(move _55, const 5_i32) 44:41-44:42: StorageDead: StorageDead(_55) - 44:12-44:42: SwitchInt: switchInt(move _54) -> [false: bb70, otherwise: bb69]"><span class="annotation">@71</span></span><span class="code even" style="--layer: 26" title="bb70: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:42: + 44:12-44:42: SwitchInt: switchInt(move _54) -> [false: bb70, otherwise: bb69]"><span class="annotation">71⦊</span></span><span class="code even" style="--layer: 26" title="bb70: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:42: 44:12-44:42: Assign: _51 = const false - 44:12-44:42: Goto: goto -> bb72"><span class="annotation">@70:</span> countdown < 1 || countdown > 5</span><span class="code even" style="--layer: 23" title="bb66: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: + 44:12-44:42: Goto: goto -> bb72"><span class="annotation">70⦊</span>countdown < 1 || countdown > 5<span class="annotation">⦉70</span></span><span class="code even" style="--layer: 25" title="bb71: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:42: + 44:29-44:42: StorageLive: StorageLive(_54) + 44:29-44:38: StorageLive: StorageLive(_55) + 44:29-44:38: Assign: _55 = _41 + 44:29-44:42: Assign: _54 = Gt(move _55, const 5_i32) + 44:41-44:42: StorageDead: StorageDead(_55) + 44:12-44:42: SwitchInt: switchInt(move _54) -> [false: bb70, otherwise: bb69]"><span class="annotation">⦉71</span></span><span class="code even" style="--layer: 24" title="bb69: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:42: + 44:12-44:42: Assign: _51 = const true + 44:12-44:42: Goto: goto -> bb72"><span class="annotation">⦉69</span></span><span class="code even" style="--layer: 23" title="bb66: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: 44:12-44:60: Assign: _50 = const false - 44:12-44:60: Goto: goto -> bb68"><span class="annotation">@66:</span> || countdown != 9</span><span class="code even" style="--layer: 17" title="bb73: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10: - 44:9-46:10: FalseEdge: falseEdge -> [real: bb75, imaginary: bb74]"><span class="annotation">@73:</span> {</span></span> + 44:12-44:60: Goto: goto -> bb68"> || countdown != 9<span class="annotation">⦉66</span></span><span class="code even" style="--layer: 22" title="bb64: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: + 44:9-46:10: StorageLive: StorageLive(_49) + 44:12-44:60: StorageLive: StorageLive(_50) + 44:12-44:42: StorageLive: StorageLive(_51) + 44:12-44:25: StorageLive: StorageLive(_52) + 44:12-44:21: StorageLive: StorageLive(_53) + 44:12-44:21: Assign: _53 = _41 + 44:12-44:25: Assign: _52 = Lt(move _53, const 1_i32) + 44:24-44:25: StorageDead: StorageDead(_53) + 44:12-44:42: SwitchInt: switchInt(move _52) -> [false: bb71, otherwise: bb69]"><span class="annotation">⦉64</span></span><span class="code even" style="--layer: 21" title="bb72: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: + 44:41-44:42: StorageDead: StorageDead(_54) + 44:41-44:42: StorageDead: StorageDead(_52) + 44:12-44:60: SwitchInt: switchInt(move _51) -> [false: bb67, otherwise: bb65]"><span class="annotation">⦉72</span></span><span class="code even" style="--layer: 20" title="bb65: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: + 44:12-44:60: Assign: _50 = const true + 44:12-44:60: Goto: goto -> bb68"><span class="annotation">⦉65</span></span><span class="code even" style="--layer: 19" title="bb68: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: + 44:59-44:60: StorageDead: StorageDead(_56) + 44:59-44:60: StorageDead: StorageDead(_51) + 44:12-44:60: FakeRead: FakeRead(ForMatchedPlace, _50) + 44:9-46:10: SwitchInt: switchInt(_50) -> [false: bb74, otherwise: bb73]"><span class="annotation">⦉68</span></span><span class="code even" style="--layer: 18" title="bb67: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60: + 44:46-44:60: StorageLive: StorageLive(_56) + 44:46-44:55: StorageLive: StorageLive(_57) + 44:46-44:55: Assign: _57 = _41 + 44:46-44:60: Assign: _56 = Ne(move _57, const 9_i32) + 44:59-44:60: StorageDead: StorageDead(_57) + 44:12-44:60: SwitchInt: switchInt(move _56) -> [false: bb66, otherwise: bb65]"><span class="annotation">⦉67</span></span><span class="code even" style="--layer: 17" title="bb73: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10: + 44:9-46:10: FalseEdge: falseEdge -> [real: bb75, imaginary: bb74]"> {</span></span> <span class="line"><span class="code even" style="--layer: 17" title="bb73: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10: 44:9-46:10: FalseEdge: falseEdge -> [real: bb75, imaginary: bb74]"> countdown = 0;</span></span> <span class="line"><span class="code even" style="--layer: 17" title="bb73: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10: @@ -547,13 +719,24 @@ 46:9-46:10: StorageDead: StorageDead(_50) 46:9-46:10: StorageDead: StorageDead(_49) 47:9-47:23: Assign: _58 = CheckedSub(_41, const 5_i32) - 47:9-47:23: Assert: assert(!move (_58.1: bool), "attempt to compute `{} - {}` which would overflow", _41, const 5_i32) -> [success: bb77, unwind: bb1]"><span class="annotation">@76:</span> }</span></span> + 47:9-47:23: Assert: assert(!move (_58.1: bool), "attempt to compute `{} - {}` which would overflow", _41, const 5_i32) -> [success: bb77, unwind: bb1]"><span class="annotation">76⦊</span>}</span><span class="code odd" style="--layer: 15" title="bb75: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10: + 45:13-45:26: Assign: _41 = const 0_i32 + 44:61-46:10: Assign: _49 = const () + 44:9-46:10: Goto: goto -> bb76"><span class="annotation">⦉75</span></span><span class="code even" style="--layer: 16" title="bb74: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10: + 44:9-46:10: Assign: _49 = const () + 44:9-46:10: Goto: goto -> bb76"><span class="annotation">⦉74</span></span><span class="code even" style="--layer: 17" title="bb73: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10: + 44:9-46:10: FalseEdge: falseEdge -> [real: bb75, imaginary: bb74]"><span class="annotation">⦉73</span></span><span class="code even" style="--layer: 17" title="bb73: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10: + 44:9-46:10: FalseEdge: falseEdge -> [real: bb75, imaginary: bb74]"><span class="annotation">⦉73</span></span><span class="code odd" style="--layer: 18" title="bb76: ../instrument-coverage/coverage_of_if_else.rs:46:9: 47:23: + 46:9-46:10: StorageDead: StorageDead(_50) + 46:9-46:10: StorageDead: StorageDead(_49) + 47:9-47:23: Assign: _58 = CheckedSub(_41, const 5_i32) + 47:9-47:23: Assert: assert(!move (_58.1: bool), "attempt to compute `{} - {}` which would overflow", _41, const 5_i32) -> [success: bb77, unwind: bb1]"></span></span> <span class="line"><span class="code odd" style="--layer: 18" title="bb76: ../instrument-coverage/coverage_of_if_else.rs:46:9: 47:23: 46:9-46:10: StorageDead: StorageDead(_50) 46:9-46:10: StorageDead: StorageDead(_49) 47:9-47:23: Assign: _58 = CheckedSub(_41, const 5_i32) - 47:9-47:23: Assert: assert(!move (_58.1: bool), "attempt to compute `{} - {}` which would overflow", _41, const 5_i32) -> [success: bb77, unwind: bb1]"> countdown -= 5</span><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6: - 43:12-50:6: FalseEdge: falseEdge -> [real: bb64, imaginary: bb63]"><span class="annotation">@62:</span> ;</span></span> + 47:9-47:23: Assert: assert(!move (_58.1: bool), "attempt to compute `{} - {}` which would overflow", _41, const 5_i32) -> [success: bb77, unwind: bb1]"> countdown -= 5<span class="annotation">⦉76</span></span><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6: + 43:12-50:6: FalseEdge: falseEdge -> [real: bb64, imaginary: bb63]">;</span></span> <span class="line"><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6: 43:12-50:6: FalseEdge: falseEdge -> [real: bb64, imaginary: bb63]"> } else {</span></span> <span class="line"><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6: @@ -564,7 +747,7 @@ 51:1-51:2: StorageDead: StorageDead(_21) 51:1-51:2: StorageDead: StorageDead(_1) 51:1-51:2: StorageDead: StorageDead(_44) - 49:9-49:15: Goto: goto -> bb26"><span class="annotation">@63:</span> return;</span></span> + 49:9-49:15: Goto: goto -> bb26"><span class="annotation">63⦊</span>return;</span></span> <span class="line"><span class="code even" style="--layer: 15" title="bb63: ../instrument-coverage/coverage_of_if_else.rs:49:9: 51:2: 49:9-49:15: Assign: _0 = const () 50:5-50:6: StorageDead: StorageDead(_47) @@ -572,12 +755,54 @@ 51:1-51:2: StorageDead: StorageDead(_21) 51:1-51:2: StorageDead: StorageDead(_1) 51:1-51:2: StorageDead: StorageDead(_44) - 49:9-49:15: Goto: goto -> bb26"> }</span><span class="code even" style="--layer: 16" title="bb78: ../instrument-coverage/coverage_of_if_else.rs:51:1: 51:2: + 49:9-49:15: Goto: goto -> bb26"> }</span><span class="code odd" style="--layer: 11" title="bb61: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6: + 42:9-42:23: Assign: _41 = move (_46.0: i32) + 41:22-43:6: Assign: _0 = const () + 41:5-50:6: Goto: goto -> bb78"><span class="annotation">⦉61</span></span><span class="code even" style="--layer: 12" title="bb58: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6: + 41:5-50:6: FalseEdge: falseEdge -> [real: bb60, imaginary: bb59]"><span class="annotation">⦉58</span></span><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6: + 47:9-47:23: Assign: _41 = move (_58.0: i32) + 43:29-48:6: Assign: _0 = const () + 50:5-50:6: StorageDead: StorageDead(_47) + 41:5-50:6: Goto: goto -> bb78"><span class="annotation">⦉77</span></span><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6: + 47:9-47:23: Assign: _41 = move (_58.0: i32) + 43:29-48:6: Assign: _0 = const () + 50:5-50:6: StorageDead: StorageDead(_47) + 41:5-50:6: Goto: goto -> bb78"><span class="annotation">⦉77</span></span><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6: + 47:9-47:23: Assign: _41 = move (_58.0: i32) + 43:29-48:6: Assign: _0 = const () + 50:5-50:6: StorageDead: StorageDead(_47) + 41:5-50:6: Goto: goto -> bb78"><span class="annotation">⦉77</span></span><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6: + 43:12-50:6: FalseEdge: falseEdge -> [real: bb64, imaginary: bb63]"><span class="annotation">⦉62</span></span><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6: + 43:12-50:6: FalseEdge: falseEdge -> [real: bb64, imaginary: bb63]"><span class="annotation">⦉62</span></span><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6: + 43:12-50:6: FalseEdge: falseEdge -> [real: bb64, imaginary: bb63]"><span class="annotation">⦉62</span></span><span class="code even" style="--layer: 15" title="bb63: ../instrument-coverage/coverage_of_if_else.rs:49:9: 51:2: + 49:9-49:15: Assign: _0 = const () + 50:5-50:6: StorageDead: StorageDead(_47) + 51:1-51:2: StorageDead: StorageDead(_41) + 51:1-51:2: StorageDead: StorageDead(_21) + 51:1-51:2: StorageDead: StorageDead(_1) + 51:1-51:2: StorageDead: StorageDead(_44) + 49:9-49:15: Goto: goto -> bb26"></span></span> +<span class="line"><span class="code even" style="--layer: 16" title="bb78: ../instrument-coverage/coverage_of_if_else.rs:51:1: 51:2: 51:1-51:2: StorageDead: StorageDead(_41) 51:1-51:2: StorageDead: StorageDead(_21) 51:1-51:2: StorageDead: StorageDead(_1) 51:1-51:2: StorageDead: StorageDead(_44) - 51:2-51:2: Goto: goto -> bb26"><span class="annotation">@78:</span> }</span><span><span class="code even" style="--layer: 1" title="bb26: ../instrument-coverage/coverage_of_if_else.rs:51:2: 51:2: - 51:2-51:2: Return: return"><span class="annotation">@26</span></span></span></span></div> + 51:2-51:2: Goto: goto -> bb26"><span class="annotation">78⦊</span>}<span class="annotation">⦉78</span></span><span class="code even" style="--layer: 15" title="bb63: ../instrument-coverage/coverage_of_if_else.rs:49:9: 51:2: + 49:9-49:15: Assign: _0 = const () + 50:5-50:6: StorageDead: StorageDead(_47) + 51:1-51:2: StorageDead: StorageDead(_41) + 51:1-51:2: StorageDead: StorageDead(_21) + 51:1-51:2: StorageDead: StorageDead(_1) + 51:1-51:2: StorageDead: StorageDead(_44) + 49:9-49:15: Goto: goto -> bb26"><span class="annotation">⦉63</span></span><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2: + 33:9-33:15: Assign: _0 = const () + 34:5-34:6: StorageDead: StorageDead(_28) + 34:5-34:6: StorageDead: StorageDead(_25) + 34:5-34:6: StorageDead: StorageDead(_24) + 51:1-51:2: StorageDead: StorageDead(_21) + 33:9-33:15: Goto: goto -> bb27"><span class="annotation">⦉38</span></span><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2: + 51:1-51:2: StorageDead: StorageDead(_1) + 17:9-17:15: Goto: goto -> bb26"><span class="annotation">⦉27</span></span><span><span class="code even" style="--layer: 1" title="bb26: ../instrument-coverage/coverage_of_if_else.rs:51:2: 51:2: + 51:2-51:2: Return: return"><span class="annotation">26⦊</span>‸<span class="annotation">⦉26</span></span></span></span></div> </body> </html> diff --git a/src/test/run-make-fulldeps/pgo-branch-weights/Makefile b/src/test/run-make-fulldeps/pgo-branch-weights/Makefile index c13297b3a61..18828b66ce8 100644 --- a/src/test/run-make-fulldeps/pgo-branch-weights/Makefile +++ b/src/test/run-make-fulldeps/pgo-branch-weights/Makefile @@ -1,4 +1,8 @@ # needs-profiler-support +# ignore-windows-gnu + +# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works +# properly. Since we only have GCC on the CI ignore the test for now. -include ../tools.mk diff --git a/src/test/run-make-fulldeps/pgo-gen-lto/Makefile b/src/test/run-make-fulldeps/pgo-gen-lto/Makefile index 6c70d951c35..f1ac39aa0ea 100644 --- a/src/test/run-make-fulldeps/pgo-gen-lto/Makefile +++ b/src/test/run-make-fulldeps/pgo-gen-lto/Makefile @@ -1,4 +1,8 @@ # needs-profiler-support +# ignore-windows-gnu + +# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works +# properly. Since we only have GCC on the CI ignore the test for now. -include ../tools.mk diff --git a/src/test/run-make-fulldeps/pgo-gen/Makefile b/src/test/run-make-fulldeps/pgo-gen/Makefile index 3b66427c14c..69b19801bf0 100644 --- a/src/test/run-make-fulldeps/pgo-gen/Makefile +++ b/src/test/run-make-fulldeps/pgo-gen/Makefile @@ -1,4 +1,8 @@ # needs-profiler-support +# ignore-windows-gnu + +# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works +# properly. Since we only have GCC on the CI ignore the test for now. -include ../tools.mk diff --git a/src/test/run-make-fulldeps/pgo-indirect-call-promotion/Makefile b/src/test/run-make-fulldeps/pgo-indirect-call-promotion/Makefile index e61018752c3..876a9b2c439 100644 --- a/src/test/run-make-fulldeps/pgo-indirect-call-promotion/Makefile +++ b/src/test/run-make-fulldeps/pgo-indirect-call-promotion/Makefile @@ -1,4 +1,8 @@ # needs-profiler-support +# ignore-windows-gnu + +# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works +# properly. Since we only have GCC on the CI ignore the test for now. -include ../tools.mk diff --git a/src/test/run-make-fulldeps/pgo-use/Makefile b/src/test/run-make-fulldeps/pgo-use/Makefile index 61a73587759..cb5e9e9a455 100644 --- a/src/test/run-make-fulldeps/pgo-use/Makefile +++ b/src/test/run-make-fulldeps/pgo-use/Makefile @@ -1,4 +1,8 @@ # needs-profiler-support +# ignore-windows-gnu + +# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works +# properly. Since we only have GCC on the CI ignore the test for now. -include ../tools.mk diff --git a/src/test/run-make-fulldeps/tools.mk b/src/test/run-make-fulldeps/tools.mk index f9b6d342295..634c9ece3f5 100644 --- a/src/test/run-make-fulldeps/tools.mk +++ b/src/test/run-make-fulldeps/tools.mk @@ -11,8 +11,8 @@ BARE_RUSTDOC := $(HOST_RPATH_ENV) '$(RUSTDOC)' RUSTC := $(BARE_RUSTC) --out-dir $(TMPDIR) -L $(TMPDIR) $(RUSTFLAGS) RUSTDOC := $(BARE_RUSTDOC) -L $(TARGET_RPATH_DIR) ifdef RUSTC_LINKER -RUSTC := $(RUSTC) -Clinker=$(RUSTC_LINKER) -RUSTDOC := $(RUSTDOC) -Clinker=$(RUSTC_LINKER) +RUSTC := $(RUSTC) -Clinker='$(RUSTC_LINKER)' +RUSTDOC := $(RUSTDOC) -Clinker='$(RUSTC_LINKER)' endif #CC := $(CC) -L $(TMPDIR) HTMLDOCCK := '$(PYTHON)' '$(S)/src/etc/htmldocck.py' diff --git a/src/test/rustdoc-ui/assoc-item-not-in-scope.stderr b/src/test/rustdoc-ui/assoc-item-not-in-scope.stderr index 8827c9351a6..92d27179e8c 100644 --- a/src/test/rustdoc-ui/assoc-item-not-in-scope.stderr +++ b/src/test/rustdoc-ui/assoc-item-not-in-scope.stderr @@ -2,14 +2,13 @@ error: unresolved link to `S::fmt` --> $DIR/assoc-item-not-in-scope.rs:4:14 | LL | /// Link to [`S::fmt`] - | ^^^^^^^^ unresolved link + | ^^^^^^^^ the struct `S` has no field or associated item named `fmt` | note: the lint level is defined here --> $DIR/assoc-item-not-in-scope.rs:1:9 | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: aborting due to previous error diff --git a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr index 7530e3ad0f5..5020b97b2f2 100644 --- a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr +++ b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr @@ -2,7 +2,7 @@ error: unresolved link to `v2` --> $DIR/deny-intra-link-resolution-failure.rs:3:6 | LL | /// [v2] - | ^^ unresolved link + | ^^ no item named `v2` in `deny_intra_link_resolution_failure` | note: the lint level is defined here --> $DIR/deny-intra-link-resolution-failure.rs:1:9 diff --git a/src/test/rustdoc-ui/failed-doctest-output.rs b/src/test/rustdoc-ui/failed-doctest-output.rs index fcbd7cabc69..90cdb5127be 100644 --- a/src/test/rustdoc-ui/failed-doctest-output.rs +++ b/src/test/rustdoc-ui/failed-doctest-output.rs @@ -2,7 +2,7 @@ // FIXME: if/when the output of the test harness can be tested on its own, this test should be // adapted to use that, and that normalize line can go away -// compile-flags:--test +// compile-flags:--test --test-args --test-threads=1 // rustc-env:RUST_BACKTRACE=0 // normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" // failure-status: 101 diff --git a/src/test/rustdoc-ui/intra-doc-alias-ice.stderr b/src/test/rustdoc-ui/intra-doc-alias-ice.stderr index f1c07e31cd7..771fc2204f5 100644 --- a/src/test/rustdoc-ui/intra-doc-alias-ice.stderr +++ b/src/test/rustdoc-ui/intra-doc-alias-ice.stderr @@ -2,14 +2,13 @@ error: unresolved link to `TypeAlias::hoge` --> $DIR/intra-doc-alias-ice.rs:5:30 | LL | /// [broken cross-reference](TypeAlias::hoge) - | ^^^^^^^^^^^^^^^ unresolved link + | ^^^^^^^^^^^^^^^ the type alias `TypeAlias` has no associated item named `hoge` | note: the lint level is defined here --> $DIR/intra-doc-alias-ice.rs:1:9 | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: aborting due to previous error diff --git a/src/test/rustdoc-ui/intra-link-errors.rs b/src/test/rustdoc-ui/intra-link-errors.rs new file mode 100644 index 00000000000..26b629b1313 --- /dev/null +++ b/src/test/rustdoc-ui/intra-link-errors.rs @@ -0,0 +1,88 @@ +#![deny(broken_intra_doc_links)] +//~^ NOTE lint level is defined + +// FIXME: this should say that it was skipped (maybe an allowed by default lint?) +/// [<invalid syntax>] + +/// [path::to::nonexistent::module] +//~^ ERROR unresolved link +//~| NOTE no item named `path` in `intra_link_errors` + +/// [path::to::nonexistent::macro!] +//~^ ERROR unresolved link +//~| NOTE no item named `path` in `intra_link_errors` + +/// [type@path::to::nonexistent::type] +//~^ ERROR unresolved link +//~| NOTE no item named `path` in `intra_link_errors` + +/// [std::io::not::here] +//~^ ERROR unresolved link +//~| NOTE the module `io` has no inner item + +/// [std::io::Error::x] +//~^ ERROR unresolved link +//~| NOTE the struct `Error` has no field + +/// [std::io::ErrorKind::x] +//~^ ERROR unresolved link +//~| NOTE the enum `ErrorKind` has no variant + +/// [f::A] +//~^ ERROR unresolved link +//~| NOTE `f` is a function, not a module + +/// [S::A] +//~^ ERROR unresolved link +//~| NOTE struct `S` has no field or associated item + +/// [S::fmt] +//~^ ERROR unresolved link +//~| NOTE struct `S` has no field or associated item + +/// [E::D] +//~^ ERROR unresolved link +//~| NOTE enum `E` has no variant or associated item + +/// [u8::not_found] +//~^ ERROR unresolved link +//~| NOTE the builtin type `u8` does not have an associated item named `not_found` + +/// [S!] +//~^ ERROR unresolved link +//~| HELP to link to the struct, prefix with `struct@` +//~| NOTE this link resolves to the struct `S` +pub fn f() {} +#[derive(Debug)] +pub struct S; + +pub enum E { A, B, C } + +/// [type@S::h] +//~^ ERROR unresolved link +//~| HELP to link to the associated function +//~| NOTE not in the type namespace +impl S { + pub fn h() {} +} + +/// [type@T::g] +//~^ ERROR unresolved link +//~| HELP to link to the associated function +//~| NOTE not in the type namespace + +/// [T::h!] +//~^ ERROR unresolved link +//~| NOTE `T` has no macro named `h` +pub trait T { + fn g() {} +} + +/// [m()] +//~^ ERROR unresolved link +//~| HELP to link to the macro +//~| NOTE not in the value namespace +#[macro_export] +macro_rules! m { + () => {}; +} diff --git a/src/test/rustdoc-ui/intra-link-errors.stderr b/src/test/rustdoc-ui/intra-link-errors.stderr new file mode 100644 index 00000000000..fbf3dcbbec2 --- /dev/null +++ b/src/test/rustdoc-ui/intra-link-errors.stderr @@ -0,0 +1,116 @@ +error: unresolved link to `path::to::nonexistent::module` + --> $DIR/intra-link-errors.rs:7:6 + | +LL | /// [path::to::nonexistent::module] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `path` in `intra_link_errors` + | +note: the lint level is defined here + --> $DIR/intra-link-errors.rs:1:9 + | +LL | #![deny(broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: unresolved link to `path::to::nonexistent::macro` + --> $DIR/intra-link-errors.rs:11:6 + | +LL | /// [path::to::nonexistent::macro!] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `path` in `intra_link_errors` + +error: unresolved link to `path::to::nonexistent::type` + --> $DIR/intra-link-errors.rs:15:6 + | +LL | /// [type@path::to::nonexistent::type] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `path` in `intra_link_errors` + +error: unresolved link to `std::io::not::here` + --> $DIR/intra-link-errors.rs:19:6 + | +LL | /// [std::io::not::here] + | ^^^^^^^^^^^^^^^^^^ the module `io` has no inner item named `not` + +error: unresolved link to `std::io::Error::x` + --> $DIR/intra-link-errors.rs:23:6 + | +LL | /// [std::io::Error::x] + | ^^^^^^^^^^^^^^^^^ the struct `Error` has no field or associated item named `x` + +error: unresolved link to `std::io::ErrorKind::x` + --> $DIR/intra-link-errors.rs:27:6 + | +LL | /// [std::io::ErrorKind::x] + | ^^^^^^^^^^^^^^^^^^^^^ the enum `ErrorKind` has no variant or associated item named `x` + +error: unresolved link to `f::A` + --> $DIR/intra-link-errors.rs:31:6 + | +LL | /// [f::A] + | ^^^^ `f` is a function, not a module or type, and cannot have associated items + +error: unresolved link to `S::A` + --> $DIR/intra-link-errors.rs:35:6 + | +LL | /// [S::A] + | ^^^^ the struct `S` has no field or associated item named `A` + +error: unresolved link to `S::fmt` + --> $DIR/intra-link-errors.rs:39:6 + | +LL | /// [S::fmt] + | ^^^^^^ the struct `S` has no field or associated item named `fmt` + +error: unresolved link to `E::D` + --> $DIR/intra-link-errors.rs:43:6 + | +LL | /// [E::D] + | ^^^^ the enum `E` has no variant or associated item named `D` + +error: unresolved link to `u8::not_found` + --> $DIR/intra-link-errors.rs:47:6 + | +LL | /// [u8::not_found] + | ^^^^^^^^^^^^^ the builtin type `u8` does not have an associated item named `not_found` + +error: unresolved link to `S` + --> $DIR/intra-link-errors.rs:51:6 + | +LL | /// [S!] + | ^^ + | | + | this link resolves to the struct `S`, which is not in the macro namespace + | help: to link to the struct, prefix with `struct@`: `struct@S` + +error: unresolved link to `T::g` + --> $DIR/intra-link-errors.rs:69:6 + | +LL | /// [type@T::g] + | ^^^^^^^^^ + | | + | this link resolves to the associated function `g`, which is not in the type namespace + | help: to link to the associated function, add parentheses: `T::g()` + +error: unresolved link to `T::h` + --> $DIR/intra-link-errors.rs:74:6 + | +LL | /// [T::h!] + | ^^^^^ the trait `T` has no macro named `h` + +error: unresolved link to `S::h` + --> $DIR/intra-link-errors.rs:61:6 + | +LL | /// [type@S::h] + | ^^^^^^^^^ + | | + | this link resolves to the associated function `h`, which is not in the type namespace + | help: to link to the associated function, add parentheses: `S::h()` + +error: unresolved link to `m` + --> $DIR/intra-link-errors.rs:81:6 + | +LL | /// [m()] + | ^^^ + | | + | this link resolves to the macro `m`, which is not in the value namespace + | help: to link to the macro, add an exclamation mark: `m!` + +error: aborting due to 16 previous errors + diff --git a/src/test/rustdoc-ui/intra-link-prim-conflict.rs b/src/test/rustdoc-ui/intra-link-prim-conflict.rs index 548d3e2544a..85738ceae8e 100644 --- a/src/test/rustdoc-ui/intra-link-prim-conflict.rs +++ b/src/test/rustdoc-ui/intra-link-prim-conflict.rs @@ -18,13 +18,13 @@ /// [struct@char] //~^ ERROR incompatible link -//~| HELP prefix with the item kind +//~| HELP prefix with `mod@` //~| NOTE resolved to a module pub mod char {} pub mod inner { //! [struct@char] //~^ ERROR incompatible link - //~| HELP prefix with the item kind + //~| HELP prefix with `prim@` //~| NOTE resolved to a builtin type } diff --git a/src/test/rustdoc-ui/intra-link-prim-conflict.stderr b/src/test/rustdoc-ui/intra-link-prim-conflict.stderr index 53dccfbf1a2..43587a80021 100644 --- a/src/test/rustdoc-ui/intra-link-prim-conflict.stderr +++ b/src/test/rustdoc-ui/intra-link-prim-conflict.stderr @@ -9,11 +9,11 @@ note: the lint level is defined here | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ -help: to link to the module, prefix with the item kind +help: to link to the module, prefix with `mod@` | LL | /// [mod@char] | ^^^^^^^^ -help: to link to the builtin type, prefix with the item kind +help: to link to the builtin type, prefix with `prim@` | LL | /// [prim@char] | ^^^^^^^^^ @@ -24,11 +24,11 @@ error: `char` is both a module and a builtin type LL | /// [type@char] | ^^^^^^^^^ ambiguous link | -help: to link to the module, prefix with the item kind +help: to link to the module, prefix with `mod@` | LL | /// [mod@char] | ^^^^^^^^ -help: to link to the builtin type, prefix with the item kind +help: to link to the builtin type, prefix with `prim@` | LL | /// [prim@char] | ^^^^^^^^^ @@ -37,25 +37,17 @@ error: incompatible link kind for `char` --> $DIR/intra-link-prim-conflict.rs:19:6 | LL | /// [struct@char] - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ help: to link to the module, prefix with `mod@`: `mod@char` | = note: this link resolved to a module, which is not a struct -help: to link to the module, prefix with the item kind - | -LL | /// [mod@char] - | ^^^^^^^^ error: incompatible link kind for `char` --> $DIR/intra-link-prim-conflict.rs:26:10 | LL | //! [struct@char] - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ help: to link to the builtin type, prefix with `prim@`: `prim@char` | = note: this link resolved to a builtin type, which is not a struct -help: to link to the builtin type, prefix with the item kind - | -LL | //! [prim@char] - | ^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr b/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr index 6b0ff8f1162..3c13df20588 100644 --- a/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr +++ b/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr @@ -2,7 +2,7 @@ error: unresolved link to `i` --> $DIR/intra-link-span-ice-55723.rs:9:10 | LL | /// (arr[i]) - | ^ unresolved link + | ^ no item named `i` in `intra_link_span_ice_55723` | note: the lint level is defined here --> $DIR/intra-link-span-ice-55723.rs:1:9 diff --git a/src/test/rustdoc-ui/intra-links-ambiguity.stderr b/src/test/rustdoc-ui/intra-links-ambiguity.stderr index 7912c046f1c..17891ca05ef 100644 --- a/src/test/rustdoc-ui/intra-links-ambiguity.stderr +++ b/src/test/rustdoc-ui/intra-links-ambiguity.stderr @@ -9,7 +9,7 @@ note: the lint level is defined here | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ -help: to link to the struct, prefix with the item kind +help: to link to the struct, prefix with `struct@` | LL | /// [`struct@ambiguous`] is ambiguous. | ^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ error: `ambiguous` is both a struct and a function LL | /// [ambiguous] is ambiguous. | ^^^^^^^^^ ambiguous link | -help: to link to the struct, prefix with the item kind +help: to link to the struct, prefix with `struct@` | LL | /// [struct@ambiguous] is ambiguous. | ^^^^^^^^^^^^^^^^ @@ -39,7 +39,7 @@ error: `multi_conflict` is a struct, a function, and a macro LL | /// [`multi_conflict`] is a three-way conflict. | ^^^^^^^^^^^^^^^^ ambiguous link | -help: to link to the struct, prefix with the item kind +help: to link to the struct, prefix with `struct@` | LL | /// [`struct@multi_conflict`] is a three-way conflict. | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -58,11 +58,11 @@ error: `type_and_value` is both a module and a constant LL | /// Ambiguous [type_and_value]. | ^^^^^^^^^^^^^^ ambiguous link | -help: to link to the module, prefix with the item kind +help: to link to the module, prefix with `mod@` | LL | /// Ambiguous [mod@type_and_value]. | ^^^^^^^^^^^^^^^^^^ -help: to link to the constant, prefix with the item kind +help: to link to the constant, prefix with `const@` | LL | /// Ambiguous [const@type_and_value]. | ^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ error: `foo::bar` is both an enum and a function LL | /// Ambiguous non-implied shortcut link [`foo::bar`]. | ^^^^^^^^^^ ambiguous link | -help: to link to the enum, prefix with the item kind +help: to link to the enum, prefix with `enum@` | LL | /// Ambiguous non-implied shortcut link [`enum@foo::bar`]. | ^^^^^^^^^^^^^^^ diff --git a/src/test/rustdoc-ui/intra-links-anchors.stderr b/src/test/rustdoc-ui/intra-links-anchors.stderr index e737b84320d..1825a4ad1fa 100644 --- a/src/test/rustdoc-ui/intra-links-anchors.stderr +++ b/src/test/rustdoc-ui/intra-links-anchors.stderr @@ -1,4 +1,4 @@ -error: `Foo::f#hola` contains an anchor, but links to struct fields are already anchored +error: `Foo::f#hola` contains an anchor, but links to fields are already anchored --> $DIR/intra-links-anchors.rs:25:15 | LL | /// Or maybe [Foo::f#hola]. @@ -16,13 +16,13 @@ error: `hello#people#!` contains multiple anchors LL | /// Another anchor error: [hello#people#!]. | ^^^^^^^^^^^^^^ contains invalid anchor -error: `Enum::A#whatever` contains an anchor, but links to enum variants are already anchored +error: `Enum::A#whatever` contains an anchor, but links to variants are already anchored --> $DIR/intra-links-anchors.rs:37:28 | LL | /// Damn enum's variants: [Enum::A#whatever]. | ^^^^^^^^^^^^^^^^ contains invalid anchor -error: `u32#hello` contains an anchor, but links to primitive types are already anchored +error: `u32#hello` contains an anchor, but links to builtin types are already anchored --> $DIR/intra-links-anchors.rs:43:6 | LL | /// [u32#hello] diff --git a/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.rs b/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.rs index 54e507adfe5..b9c8e033b1b 100644 --- a/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.rs +++ b/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.rs @@ -14,27 +14,27 @@ trait T {} /// Link to [struct@S] //~^ ERROR incompatible link kind for `S` //~| NOTE this link resolved -//~| HELP prefix with the item kind +//~| HELP prefix with `enum@` /// Link to [mod@S] //~^ ERROR incompatible link kind for `S` //~| NOTE this link resolved -//~| HELP prefix with the item kind +//~| HELP prefix with `enum@` /// Link to [union@S] //~^ ERROR incompatible link kind for `S` //~| NOTE this link resolved -//~| HELP prefix with the item kind +//~| HELP prefix with `enum@` /// Link to [trait@S] //~^ ERROR incompatible link kind for `S` //~| NOTE this link resolved -//~| HELP prefix with the item kind +//~| HELP prefix with `enum@` /// Link to [struct@T] //~^ ERROR incompatible link kind for `T` //~| NOTE this link resolved -//~| HELP prefix with the item kind +//~| HELP prefix with `trait@` /// Link to [derive@m] //~^ ERROR incompatible link kind for `m` @@ -44,22 +44,22 @@ trait T {} /// Link to [const@s] //~^ ERROR incompatible link kind for `s` //~| NOTE this link resolved -//~| HELP prefix with the item kind +//~| HELP prefix with `static@` /// Link to [static@c] //~^ ERROR incompatible link kind for `c` //~| NOTE this link resolved -//~| HELP prefix with the item kind +//~| HELP prefix with `const@` /// Link to [fn@c] //~^ ERROR incompatible link kind for `c` //~| NOTE this link resolved -//~| HELP prefix with the item kind +//~| HELP prefix with `const@` /// Link to [c()] //~^ ERROR incompatible link kind for `c` //~| NOTE this link resolved -//~| HELP prefix with the item kind +//~| HELP prefix with `const@` /// Link to [const@f] //~^ ERROR incompatible link kind for `f` diff --git a/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.stderr b/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.stderr index 27b94af0378..2e732baf6e0 100644 --- a/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.stderr +++ b/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.stderr @@ -2,7 +2,7 @@ error: incompatible link kind for `S` --> $DIR/intra-links-disambiguator-mismatch.rs:14:14 | LL | /// Link to [struct@S] - | ^^^^^^^^ + | ^^^^^^^^ help: to link to the enum, prefix with `enum@`: `enum@S` | note: the lint level is defined here --> $DIR/intra-links-disambiguator-mismatch.rs:1:9 @@ -10,58 +10,38 @@ note: the lint level is defined here LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ = note: this link resolved to an enum, which is not a struct -help: to link to the enum, prefix with the item kind - | -LL | /// Link to [enum@S] - | ^^^^^^ error: incompatible link kind for `S` --> $DIR/intra-links-disambiguator-mismatch.rs:19:14 | LL | /// Link to [mod@S] - | ^^^^^ + | ^^^^^ help: to link to the enum, prefix with `enum@`: `enum@S` | = note: this link resolved to an enum, which is not a module -help: to link to the enum, prefix with the item kind - | -LL | /// Link to [enum@S] - | ^^^^^^ error: incompatible link kind for `S` --> $DIR/intra-links-disambiguator-mismatch.rs:24:14 | LL | /// Link to [union@S] - | ^^^^^^^ + | ^^^^^^^ help: to link to the enum, prefix with `enum@`: `enum@S` | = note: this link resolved to an enum, which is not a union -help: to link to the enum, prefix with the item kind - | -LL | /// Link to [enum@S] - | ^^^^^^ error: incompatible link kind for `S` --> $DIR/intra-links-disambiguator-mismatch.rs:29:14 | LL | /// Link to [trait@S] - | ^^^^^^^ + | ^^^^^^^ help: to link to the enum, prefix with `enum@`: `enum@S` | = note: this link resolved to an enum, which is not a trait -help: to link to the enum, prefix with the item kind - | -LL | /// Link to [enum@S] - | ^^^^^^ error: incompatible link kind for `T` --> $DIR/intra-links-disambiguator-mismatch.rs:34:14 | LL | /// Link to [struct@T] - | ^^^^^^^^ + | ^^^^^^^^ help: to link to the trait, prefix with `trait@`: `trait@T` | = note: this link resolved to a trait, which is not a struct -help: to link to the trait, prefix with the item kind - | -LL | /// Link to [trait@T] - | ^^^^^^^ error: incompatible link kind for `m` --> $DIR/intra-links-disambiguator-mismatch.rs:39:14 @@ -75,49 +55,33 @@ error: incompatible link kind for `s` --> $DIR/intra-links-disambiguator-mismatch.rs:44:14 | LL | /// Link to [const@s] - | ^^^^^^^ + | ^^^^^^^ help: to link to the static, prefix with `static@`: `static@s` | = note: this link resolved to a static, which is not a constant -help: to link to the static, prefix with the item kind - | -LL | /// Link to [static@s] - | ^^^^^^^^ error: incompatible link kind for `c` --> $DIR/intra-links-disambiguator-mismatch.rs:49:14 | LL | /// Link to [static@c] - | ^^^^^^^^ + | ^^^^^^^^ help: to link to the constant, prefix with `const@`: `const@c` | = note: this link resolved to a constant, which is not a static -help: to link to the constant, prefix with the item kind - | -LL | /// Link to [const@c] - | ^^^^^^^ error: incompatible link kind for `c` --> $DIR/intra-links-disambiguator-mismatch.rs:54:14 | LL | /// Link to [fn@c] - | ^^^^ + | ^^^^ help: to link to the constant, prefix with `const@`: `const@c` | = note: this link resolved to a constant, which is not a function -help: to link to the constant, prefix with the item kind - | -LL | /// Link to [const@c] - | ^^^^^^^ error: incompatible link kind for `c` --> $DIR/intra-links-disambiguator-mismatch.rs:59:14 | LL | /// Link to [c()] - | ^^^ + | ^^^ help: to link to the constant, prefix with `const@`: `const@c` | = note: this link resolved to a constant, which is not a function -help: to link to the constant, prefix with the item kind - | -LL | /// Link to [const@c] - | ^^^^^^^ error: incompatible link kind for `f` --> $DIR/intra-links-disambiguator-mismatch.rs:64:14 diff --git a/src/test/rustdoc-ui/intra-links-warning-crlf.stderr b/src/test/rustdoc-ui/intra-links-warning-crlf.stderr index 1e3a26fadfa..351f8fafa64 100644 --- a/src/test/rustdoc-ui/intra-links-warning-crlf.stderr +++ b/src/test/rustdoc-ui/intra-links-warning-crlf.stderr @@ -2,7 +2,7 @@ warning: unresolved link to `error` --> $DIR/intra-links-warning-crlf.rs:7:6 | LL | /// [error] - | ^^^^^ unresolved link + | ^^^^^ no item named `error` in `intra_links_warning_crlf` | = note: `#[warn(broken_intra_doc_links)]` on by default = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -11,7 +11,7 @@ warning: unresolved link to `error1` --> $DIR/intra-links-warning-crlf.rs:12:11 | LL | /// docs [error1] - | ^^^^^^ unresolved link + | ^^^^^^ no item named `error1` in `intra_links_warning_crlf` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -19,7 +19,7 @@ warning: unresolved link to `error2` --> $DIR/intra-links-warning-crlf.rs:15:11 | LL | /// docs [error2] - | ^^^^^^ unresolved link + | ^^^^^^ no item named `error2` in `intra_links_warning_crlf` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -27,7 +27,7 @@ warning: unresolved link to `error` --> $DIR/intra-links-warning-crlf.rs:23:20 | LL | * It also has an [error]. - | ^^^^^ unresolved link + | ^^^^^ no item named `error` in `intra_links_warning_crlf` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` diff --git a/src/test/rustdoc-ui/intra-links-warning.stderr b/src/test/rustdoc-ui/intra-links-warning.stderr index 53f2476295e..0832e00d35a 100644 --- a/src/test/rustdoc-ui/intra-links-warning.stderr +++ b/src/test/rustdoc-ui/intra-links-warning.stderr @@ -2,56 +2,45 @@ warning: unresolved link to `Foo::baz` --> $DIR/intra-links-warning.rs:3:23 | LL | //! Test with [Foo::baz], [Bar::foo], ... - | ^^^^^^^^ unresolved link + | ^^^^^^^^ the struct `Foo` has no field or associated item named `baz` | = note: `#[warn(broken_intra_doc_links)]` on by default - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `Bar::foo` --> $DIR/intra-links-warning.rs:3:35 | LL | //! Test with [Foo::baz], [Bar::foo], ... - | ^^^^^^^^ unresolved link - | - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + | ^^^^^^^^ no item named `Bar` in `intra_links_warning` warning: unresolved link to `Uniooon::X` --> $DIR/intra-links-warning.rs:6:13 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^^^^^ unresolved link - | - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + | ^^^^^^^^^^ no item named `Uniooon` in `intra_links_warning` warning: unresolved link to `Qux::Z` --> $DIR/intra-links-warning.rs:6:30 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^ unresolved link - | - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + | ^^^^^^ no item named `Qux` in `intra_links_warning` warning: unresolved link to `Uniooon::X` --> $DIR/intra-links-warning.rs:10:14 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^^^^^ unresolved link - | - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + | ^^^^^^^^^^ no item named `Uniooon` in `intra_links_warning` warning: unresolved link to `Qux::Z` --> $DIR/intra-links-warning.rs:10:31 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^ unresolved link - | - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + | ^^^^^^ no item named `Qux` in `intra_links_warning` warning: unresolved link to `Qux:Y` --> $DIR/intra-links-warning.rs:14:13 | LL | /// [Qux:Y] - | ^^^^^ unresolved link + | ^^^^^ no item named `Qux:Y` in `intra_links_warning` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -59,7 +48,7 @@ warning: unresolved link to `error` --> $DIR/intra-links-warning.rs:58:30 | LL | * time to introduce a link [error]*/ - | ^^^^^ unresolved link + | ^^^^^ no item named `error` in `intra_links_warning` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -67,7 +56,7 @@ warning: unresolved link to `error` --> $DIR/intra-links-warning.rs:64:30 | LL | * time to introduce a link [error] - | ^^^^^ unresolved link + | ^^^^^ no item named `error` in `intra_links_warning` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -81,6 +70,7 @@ LL | #[doc = "single line [error]"] single line [error] ^^^^^ + = note: no item named `error` in `intra_links_warning` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error` @@ -93,6 +83,7 @@ LL | #[doc = "single line with \"escaping\" [error]"] single line with "escaping" [error] ^^^^^ + = note: no item named `error` in `intra_links_warning` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error` @@ -107,13 +98,14 @@ LL | | /// [error] [error] ^^^^^ + = note: no item named `error` in `intra_links_warning` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error1` --> $DIR/intra-links-warning.rs:80:11 | LL | /// docs [error1] - | ^^^^^^ unresolved link + | ^^^^^^ no item named `error1` in `intra_links_warning` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -121,7 +113,7 @@ warning: unresolved link to `error2` --> $DIR/intra-links-warning.rs:82:11 | LL | /// docs [error2] - | ^^^^^^ unresolved link + | ^^^^^^ no item named `error2` in `intra_links_warning` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -129,7 +121,7 @@ warning: unresolved link to `BarA` --> $DIR/intra-links-warning.rs:21:10 | LL | /// bar [BarA] bar - | ^^^^ unresolved link + | ^^^^ no item named `BarA` in `intra_links_warning` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -137,7 +129,7 @@ warning: unresolved link to `BarB` --> $DIR/intra-links-warning.rs:27:9 | LL | * bar [BarB] bar - | ^^^^ unresolved link + | ^^^^ no item named `BarB` in `intra_links_warning` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -145,7 +137,7 @@ warning: unresolved link to `BarC` --> $DIR/intra-links-warning.rs:34:6 | LL | bar [BarC] bar - | ^^^^ unresolved link + | ^^^^ no item named `BarC` in `intra_links_warning` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -159,6 +151,7 @@ LL | #[doc = "Foo\nbar [BarD] bar\nbaz"] bar [BarD] bar ^^^^ + = note: no item named `BarD` in `intra_links_warning` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `BarF` @@ -174,6 +167,7 @@ LL | f!("Foo\nbar [BarF] bar\nbaz"); bar [BarF] bar ^^^^ + = note: no item named `BarF` in `intra_links_warning` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/rustdoc-ui/lint-group.stderr b/src/test/rustdoc-ui/lint-group.stderr index 04296d2e44a..550b79f6e89 100644 --- a/src/test/rustdoc-ui/lint-group.stderr +++ b/src/test/rustdoc-ui/lint-group.stderr @@ -32,7 +32,7 @@ error: unresolved link to `error` --> $DIR/lint-group.rs:9:29 | LL | /// what up, let's make an [error] - | ^^^^^ unresolved link + | ^^^^^ no item named `error` in `lint_group` | note: the lint level is defined here --> $DIR/lint-group.rs:7:9 diff --git a/src/test/rustdoc/auxiliary/intra-link-pub-use.rs b/src/test/rustdoc/auxiliary/intra-link-pub-use.rs new file mode 100644 index 00000000000..a4db2ffc445 --- /dev/null +++ b/src/test/rustdoc/auxiliary/intra-link-pub-use.rs @@ -0,0 +1,4 @@ +#![crate_name = "inner"] + +/// Documentation, including a link to [std::ptr] +pub fn f() {} diff --git a/src/test/rustdoc/const-generics/type-alias.rs b/src/test/rustdoc/const-generics/type-alias.rs new file mode 100644 index 00000000000..3064d0701e3 --- /dev/null +++ b/src/test/rustdoc/const-generics/type-alias.rs @@ -0,0 +1,6 @@ +// ignore-tidy-linelength +#![feature(min_const_generics)] +#![crate_name = "foo"] + +// @has foo/type.CellIndex.html '//pre[@class="rust typedef"]' 'type CellIndex<const D: usize> = [i64; D];' +pub type CellIndex<const D: usize> = [i64; D]; diff --git a/src/test/rustdoc/intra-link-disambiguators-removed.rs b/src/test/rustdoc/intra-link-disambiguators-removed.rs new file mode 100644 index 00000000000..26d05b484b9 --- /dev/null +++ b/src/test/rustdoc/intra-link-disambiguators-removed.rs @@ -0,0 +1,51 @@ +// ignore-tidy-linelength +#![deny(intra_doc_link_resolution_failure)] +// first try backticks +/// Trait: [`trait@Name`], fn: [`fn@Name`], [`Name`][`macro@Name`] +// @has intra_link_disambiguators_removed/struct.AtDisambiguator.html +// @has - '//a[@href="../intra_link_disambiguators_removed/trait.Name.html"][code]' "Name" +// @has - '//a[@href="../intra_link_disambiguators_removed/fn.Name.html"][code]' "Name" +// @has - '//a[@href="../intra_link_disambiguators_removed/macro.Name.html"][code]' "Name" +pub struct AtDisambiguator; + +/// fn: [`Name()`], macro: [`Name!`] +// @has intra_link_disambiguators_removed/struct.SymbolDisambiguator.html +// @has - '//a[@href="../intra_link_disambiguators_removed/fn.Name.html"][code]' "Name()" +// @has - '//a[@href="../intra_link_disambiguators_removed/macro.Name.html"][code]' "Name!" +pub struct SymbolDisambiguator; + +// Now make sure that backticks aren't added if they weren't already there +/// [fn@Name] +// @has intra_link_disambiguators_removed/trait.Name.html +// @has - '//a[@href="../intra_link_disambiguators_removed/fn.Name.html"]' "Name" +// @!has - '//a[@href="../intra_link_disambiguators_removed/fn.Name.html"][code]' "Name" + +// FIXME: this will turn !() into ! alone +/// [Name!()] +// @has - '//a[@href="../intra_link_disambiguators_removed/macro.Name.html"]' "Name!" +pub trait Name {} + +#[allow(non_snake_case)] + +// Try collapsed reference links +/// [macro@Name][] +// @has intra_link_disambiguators_removed/fn.Name.html +// @has - '//a[@href="../intra_link_disambiguators_removed/macro.Name.html"]' "Name" + +// Try links that have the same text as a generated URL +/// Weird URL aligned [../intra_link_disambiguators_removed/macro.Name.html][trait@Name] +// @has - '//a[@href="../intra_link_disambiguators_removed/trait.Name.html"]' "../intra_link_disambiguators_removed/macro.Name.html" +pub fn Name() {} + +#[macro_export] +// Rustdoc doesn't currently handle links that have weird interspersing of inline code blocks. +/// [fn@Na`m`e] +// @has intra_link_disambiguators_removed/macro.Name.html +// @has - '//a[@href="../intra_link_disambiguators_removed/fn.Name.html"]' "fn@Name" + +// It also doesn't handle any case where the code block isn't the whole link text: +/// [trait@`Name`] +// @has - '//a[@href="../intra_link_disambiguators_removed/trait.Name.html"]' "trait@Name" +macro_rules! Name { + () => () +} diff --git a/src/test/rustdoc/intra-link-pub-use.rs b/src/test/rustdoc/intra-link-pub-use.rs new file mode 100644 index 00000000000..dd52249abc6 --- /dev/null +++ b/src/test/rustdoc/intra-link-pub-use.rs @@ -0,0 +1,27 @@ +// aux-build: intra-link-pub-use.rs +#![deny(broken_intra_doc_links)] +#![crate_name = "outer"] + +extern crate inner; + +/// [mod@std::env] [g] + +// FIXME: This can't be tested because rustdoc doesn't show documentation on pub re-exports. +// Until then, comment out the `htmldocck` test. +// This test still does something; namely check that no incorrect errors are emitted when +// documenting the re-export. + +// @has outer/index.html +// @ has - '//a[@href="https://doc.rust-lang.org/nightly/std/env/fn.var.html"]' "std::env" +// @ has - '//a[@href="../outer/fn.f.html"]' "g" +pub use f as g; + +// FIXME: same as above +/// [std::env] +extern crate self as _; + +// Make sure the documentation is actually correct by documenting an inlined re-export +/// [mod@std::env] +// @has outer/fn.f.html +// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/env/index.html"]' "std::env" +pub use inner::f; diff --git a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs index 633d153e391..caf55bec53d 100644 --- a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs @@ -62,7 +62,7 @@ fn expr(kind: ExprKind) -> P<Expr> { fn make_x() -> P<Expr> { let seg = PathSegment::from_ident(Ident::from_str("x")); - let path = Path { segments: vec![seg], span: DUMMY_SP }; + let path = Path { segments: vec![seg], span: DUMMY_SP, tokens: None }; expr(ExprKind::Path(None, path)) } @@ -113,6 +113,7 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) { id: DUMMY_NODE_ID, rules: BlockCheckMode::Default, span: DUMMY_SP, + tokens: None, }); iter_exprs(depth - 1, &mut |e| g(ExprKind::If(e, block.clone(), None))); }, diff --git a/src/test/ui-fulldeps/session-derive-errors.rs b/src/test/ui-fulldeps/session-derive-errors.rs new file mode 100644 index 00000000000..7967b32a4a4 --- /dev/null +++ b/src/test/ui-fulldeps/session-derive-errors.rs @@ -0,0 +1,260 @@ +// check-fail +// Tests error conditions for specifying diagnostics using #[derive(SessionDiagnostic)] + +#![feature(rustc_private)] +#![crate_type = "lib"] + +extern crate rustc_span; +use rustc_span::Span; +use rustc_span::symbol::Ident; + +extern crate rustc_macros; +use rustc_macros::SessionDiagnostic; + +extern crate rustc_middle; +use rustc_middle::ty::Ty; + +extern crate rustc_errors; +use rustc_errors::Applicability; + +extern crate rustc_session; + +#[derive(SessionDiagnostic)] +#[message = "Hello, world!"] +#[error = "E0123"] +struct Hello {} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +//~^ ERROR `#[derive(SessionDiagnostic)]` can only be used on structs +enum SessionDiagnosticOnEnum { + Foo, + Bar, +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +#[label = "This is in the wrong place"] +//~^ ERROR `#[label = ...]` is not a valid SessionDiagnostic struct attribute +struct WrongPlace {} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct WrongPlaceField { + #[suggestion = "this is the wrong kind of attribute"] +//~^ ERROR `#[suggestion = ...]` is not a valid SessionDiagnostic field attribute + sp: Span, +} + +#[derive(SessionDiagnostic)] +#[message = "Hello, world!"] +#[error = "E0123"] +#[error = "E0456"] //~ ERROR `error` specified multiple times +struct ErrorSpecifiedTwice {} + +#[derive(SessionDiagnostic)] +#[message = "Hello, world!"] +#[error = "E0123"] +#[lint = "some_useful_lint"] //~ ERROR `lint` specified when `error` was already specified +struct LintSpecifiedAfterError {} + +#[derive(SessionDiagnostic)] +#[message = "Some lint message"] +#[error = "E0123"] +struct LintButHasErrorCode {} + +#[derive(SessionDiagnostic)] +struct ErrorCodeNotProvided {} //~ ERROR `code` not specified + +// FIXME: Uncomment when emitting lints is supported. +/* +#[derive(SessionDiagnostic)] +#[message = "Hello, world!"] +#[lint = "clashing_extern_declarations"] +#[lint = "improper_ctypes"] // FIXME: ERROR `lint` specified multiple times +struct LintSpecifiedTwice {} + +#[derive(SessionDiagnostic)] +#[lint = "Some lint message"] +#[message = "Some error message"] +#[error = "E0123"] // ERROR `error` specified when `lint` was already specified +struct ErrorSpecifiedAfterLint {} +*/ + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct ErrorWithField { + name: String, + #[message = "This error has a field, and references {name}"] + span: Span +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct ErrorWithMessageAppliedToField { + #[message = "this message is applied to a String field"] + //~^ ERROR the `#[message = "..."]` attribute can only be applied to fields of type Span + name: String, +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +#[message = "This error has a field, and references {name}"] +//~^ ERROR `name` doesn't refer to a field on this type +struct ErrorWithNonexistentField { + span: Span +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +#[message = "This is missing a closing brace: {name"] +//~^ ERROR invalid format string: expected `'}'` +struct ErrorMissingClosingBrace { + name: String, + span: Span +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +#[message = "This is missing an opening brace: name}"] +//~^ ERROR invalid format string: unmatched `}` +struct ErrorMissingOpeningBrace { + name: String, + span: Span +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +#[message = "Something something"] +struct LabelOnSpan { + #[label = "See here"] + sp: Span +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +#[message = "Something something"] +struct LabelOnNonSpan { + #[label = "See here"] + //~^ ERROR The `#[label = ...]` attribute can only be applied to fields of type Span + id: u32, +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct Suggest { + #[suggestion(message = "This is a suggestion", code = "This is the suggested code")] + #[suggestion_short(message = "This is a suggestion", code = "This is the suggested code")] + #[suggestion_hidden(message = "This is a suggestion", code = "This is the suggested code")] + #[suggestion_verbose(message = "This is a suggestion", code = "This is the suggested code")] + suggestion: (Span, Applicability), +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct SuggestWithoutCode { + #[suggestion(message = "This is a suggestion")] + suggestion: (Span, Applicability), +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct SuggestWithBadKey { + #[suggestion(nonsense = "This is nonsense")] + //~^ ERROR `nonsense` is not a valid key for `#[suggestion(...)]` + suggestion: (Span, Applicability), +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct SuggestWithShorthandMsg { + #[suggestion(msg = "This is a suggestion")] + //~^ ERROR `msg` is not a valid key for `#[suggestion(...)]` + suggestion: (Span, Applicability), +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct SuggestWithoutMsg { + #[suggestion(code = "This is suggested code")] + //~^ ERROR missing suggestion message + suggestion: (Span, Applicability), +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct SuggestWithTypesSwapped { + #[suggestion(message = "This is a message", code = "This is suggested code")] + suggestion: (Applicability, Span), +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct SuggestWithWrongTypeApplicabilityOnly { + #[suggestion(message = "This is a message", code = "This is suggested code")] + //~^ ERROR wrong field type for suggestion + suggestion: Applicability, +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct SuggestWithSpanOnly{ + #[suggestion(message = "This is a message", code = "This is suggested code")] + suggestion: Span, +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct SuggestWithDuplicateSpanAndApplicability { + #[suggestion(message = "This is a message", code = "This is suggested code")] + //~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one Span + suggestion: (Span, Span, Applicability), +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct SuggestWithDuplicateApplicabilityAndSpan { + #[suggestion(message = "This is a message", code = "This is suggested code")] + //~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one + suggestion: (Applicability, Applicability, Span), +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct WrongKindOfAnnotation { + #[label("wrong kind of annotation for label")] + //~^ ERROR invalid annotation list `#[label(...)]` + z: Span, +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +#[message = "Something something else"] +struct OptionsInErrors { + #[label = "Label message"] + label: Option<Span>, + #[suggestion(message = "suggestion message")] + opt_sugg: Option<(Span, Applicability)>, +} + +#[derive(SessionDiagnostic)] +#[error = "E0456"] +struct MoveOutOfBorrowError<'tcx> { + name: Ident, + ty: Ty<'tcx>, + #[message = "cannot move {ty} out of borrow"] + #[label = "cannot move out of borrow"] + span: Span, + #[label = "`{ty}` first borrowed here"] + other_span: Span, + #[suggestion(message = "consider cloning here", code = "{name}.clone()")] + opt_sugg: Option<(Span, Applicability)>, +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct ErrorWithLifetime<'a> { + #[message = "Some message that references {name}"] + span: Span, + name: &'a str, +} diff --git a/src/test/ui-fulldeps/session-derive-errors.stderr b/src/test/ui-fulldeps/session-derive-errors.stderr new file mode 100644 index 00000000000..c1be151f1c1 --- /dev/null +++ b/src/test/ui-fulldeps/session-derive-errors.stderr @@ -0,0 +1,135 @@ +error: `#[derive(SessionDiagnostic)]` can only be used on structs + --> $DIR/session-derive-errors.rs:28:1 + | +LL | / #[error = "E0123"] +LL | | +LL | | enum SessionDiagnosticOnEnum { +LL | | Foo, +LL | | Bar, +LL | | } + | |_^ + +error: `#[label = ...]` is not a valid SessionDiagnostic struct attribute + --> $DIR/session-derive-errors.rs:37:1 + | +LL | #[label = "This is in the wrong place"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `#[suggestion = ...]` is not a valid SessionDiagnostic field attribute + --> $DIR/session-derive-errors.rs:44:5 + | +LL | #[suggestion = "this is the wrong kind of attribute"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `error` specified multiple times + --> $DIR/session-derive-errors.rs:52:11 + | +LL | #[error = "E0456"] + | ^^^^^^^ + +error: `lint` specified when `error` was already specified + --> $DIR/session-derive-errors.rs:58:10 + | +LL | #[lint = "some_useful_lint"] + | ^^^^^^^^^^^^^^^^^^ + +error: `code` not specified + --> $DIR/session-derive-errors.rs:67:1 + | +LL | struct ErrorCodeNotProvided {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use the [code = "..."] attribute to set this diagnostic's error code + +error: the `#[message = "..."]` attribute can only be applied to fields of type Span + --> $DIR/session-derive-errors.rs:95:5 + | +LL | #[message = "this message is applied to a String field"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `name` doesn't refer to a field on this type + --> $DIR/session-derive-errors.rs:102:1 + | +LL | #[message = "This error has a field, and references {name}"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: invalid format string: expected `'}'` but string was terminated + --> $DIR/session-derive-errors.rs:110:1 + | +LL | #[error = "E0123"] + | - because of this opening brace +LL | #[message = "This is missing a closing brace: {name"] + | ^ expected `'}'` in format string + | + = note: if you intended to print `{`, you can escape it using `{{` + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: invalid format string: unmatched `}` found + --> $DIR/session-derive-errors.rs:119:1 + | +LL | #[message = "This is missing an opening brace: name}"] + | ^ unmatched `}` in format string + | + = note: if you intended to print `}`, you can escape it using `}}` + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: The `#[label = ...]` attribute can only be applied to fields of type Span + --> $DIR/session-derive-errors.rs:138:5 + | +LL | #[label = "See here"] + | ^^^^^^^^^^^^^^^^^^^^^ + +error: `nonsense` is not a valid key for `#[suggestion(...)]` + --> $DIR/session-derive-errors.rs:163:18 + | +LL | #[suggestion(nonsense = "This is nonsense")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `msg` is not a valid key for `#[suggestion(...)]` + --> $DIR/session-derive-errors.rs:171:18 + | +LL | #[suggestion(msg = "This is a suggestion")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: missing suggestion message + --> $DIR/session-derive-errors.rs:179:7 + | +LL | #[suggestion(code = "This is suggested code")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: provide a suggestion message using #[suggestion(message = "...")] + +error: wrong field type for suggestion + --> $DIR/session-derive-errors.rs:194:5 + | +LL | / #[suggestion(message = "This is a message", code = "This is suggested code")] +LL | | +LL | | suggestion: Applicability, + | |_____________________________^ + | + = help: #[suggestion(...)] should be applied to fields of type Span or (Span, Applicability) + +error: type of field annotated with `#[suggestion(...)]` contains more than one Span + --> $DIR/session-derive-errors.rs:209:5 + | +LL | / #[suggestion(message = "This is a message", code = "This is suggested code")] +LL | | +LL | | suggestion: (Span, Span, Applicability), + | |___________________________________________^ + +error: type of field annotated with `#[suggestion(...)]` contains more than one Applicability + --> $DIR/session-derive-errors.rs:217:5 + | +LL | / #[suggestion(message = "This is a message", code = "This is suggested code")] +LL | | +LL | | suggestion: (Applicability, Applicability, Span), + | |____________________________________________________^ + +error: invalid annotation list `#[label(...)]` + --> $DIR/session-derive-errors.rs:225:7 + | +LL | #[label("wrong kind of annotation for label")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 18 previous errors + diff --git a/src/test/ui/array-slice-vec/slice-2.rs b/src/test/ui/array-slice-vec/slice-2.rs deleted file mode 100644 index 01733f48234..00000000000 --- a/src/test/ui/array-slice-vec/slice-2.rs +++ /dev/null @@ -1,62 +0,0 @@ -// run-pass - -// Test slicing expressions on slices and Vecs. - - -fn main() { - let x: &[isize] = &[1, 2, 3, 4, 5]; - let cmp: &[isize] = &[1, 2, 3, 4, 5]; - assert_eq!(&x[..], cmp); - let cmp: &[isize] = &[3, 4, 5]; - assert_eq!(&x[2..], cmp); - let cmp: &[isize] = &[1, 2, 3]; - assert_eq!(&x[..3], cmp); - let cmp: &[isize] = &[2, 3, 4]; - assert_eq!(&x[1..4], cmp); - - let x: Vec<isize> = vec![1, 2, 3, 4, 5]; - let cmp: &[isize] = &[1, 2, 3, 4, 5]; - assert_eq!(&x[..], cmp); - let cmp: &[isize] = &[3, 4, 5]; - assert_eq!(&x[2..], cmp); - let cmp: &[isize] = &[1, 2, 3]; - assert_eq!(&x[..3], cmp); - let cmp: &[isize] = &[2, 3, 4]; - assert_eq!(&x[1..4], cmp); - - let x: &mut [isize] = &mut [1, 2, 3, 4, 5]; - { - let cmp: &mut [isize] = &mut [1, 2, 3, 4, 5]; - assert_eq!(&mut x[..], cmp); - } - { - let cmp: &mut [isize] = &mut [3, 4, 5]; - assert_eq!(&mut x[2..], cmp); - } - { - let cmp: &mut [isize] = &mut [1, 2, 3]; - assert_eq!(&mut x[..3], cmp); - } - { - let cmp: &mut [isize] = &mut [2, 3, 4]; - assert_eq!(&mut x[1..4], cmp); - } - - let mut x: Vec<isize> = vec![1, 2, 3, 4, 5]; - { - let cmp: &mut [isize] = &mut [1, 2, 3, 4, 5]; - assert_eq!(&mut x[..], cmp); - } - { - let cmp: &mut [isize] = &mut [3, 4, 5]; - assert_eq!(&mut x[2..], cmp); - } - { - let cmp: &mut [isize] = &mut [1, 2, 3]; - assert_eq!(&mut x[..3], cmp); - } - { - let cmp: &mut [isize] = &mut [2, 3, 4]; - assert_eq!(&mut x[1..4], cmp); - } -} diff --git a/src/test/ui/array-slice-vec/vec-concat.rs b/src/test/ui/array-slice-vec/vec-concat.rs deleted file mode 100644 index 1f493679b79..00000000000 --- a/src/test/ui/array-slice-vec/vec-concat.rs +++ /dev/null @@ -1,14 +0,0 @@ -// run-pass - -use std::vec; - -pub fn main() { - let a: Vec<isize> = vec![1, 2, 3, 4, 5]; - let b: Vec<isize> = vec![6, 7, 8, 9, 0]; - let mut v: Vec<isize> = a; - v.extend_from_slice(&b); - println!("{}", v[9]); - assert_eq!(v[0], 1); - assert_eq!(v[7], 8); - assert_eq!(v[9], 0); -} diff --git a/src/test/ui/array-slice-vec/vec-growth.rs b/src/test/ui/array-slice-vec/vec-growth.rs deleted file mode 100644 index b09f08bb85a..00000000000 --- a/src/test/ui/array-slice-vec/vec-growth.rs +++ /dev/null @@ -1,16 +0,0 @@ -// run-pass - - - -pub fn main() { - let mut v = vec![1]; - v.push(2); - v.push(3); - v.push(4); - v.push(5); - assert_eq!(v[0], 1); - assert_eq!(v[1], 2); - assert_eq!(v[2], 3); - assert_eq!(v[3], 4); - assert_eq!(v[4], 5); -} diff --git a/src/test/ui/array-slice-vec/vec-push.rs b/src/test/ui/array-slice-vec/vec-push.rs deleted file mode 100644 index 466ab3fab1c..00000000000 --- a/src/test/ui/array-slice-vec/vec-push.rs +++ /dev/null @@ -1,3 +0,0 @@ -// run-pass - -pub fn main() { let mut v = vec![1, 2, 3]; v.push(1); } diff --git a/src/test/ui/array-slice-vec/vec-slice.rs b/src/test/ui/array-slice-vec/vec-slice.rs deleted file mode 100644 index 1f090ddd9c9..00000000000 --- a/src/test/ui/array-slice-vec/vec-slice.rs +++ /dev/null @@ -1,9 +0,0 @@ -// run-pass - - -pub fn main() { - let v = vec![1,2,3,4,5]; - let v2 = &v[1..3]; - assert_eq!(v2[0], 2); - assert_eq!(v2[1], 3); -} diff --git a/src/test/ui/array-slice-vec/vec-to_str.rs b/src/test/ui/array-slice-vec/vec-to_str.rs deleted file mode 100644 index a11cfc8e9b5..00000000000 --- a/src/test/ui/array-slice-vec/vec-to_str.rs +++ /dev/null @@ -1,12 +0,0 @@ -// run-pass - - -pub fn main() { - assert_eq!(format!("{:?}", vec![0, 1]), "[0, 1]".to_string()); - - let foo = vec![3, 4]; - let bar: &[isize] = &[4, 5]; - - assert_eq!(format!("{:?}", foo), "[3, 4]"); - assert_eq!(format!("{:?}", bar), "[4, 5]"); -} diff --git a/src/test/ui/array-slice-vec/vec.rs b/src/test/ui/array-slice-vec/vec.rs deleted file mode 100644 index e76c1ab440e..00000000000 --- a/src/test/ui/array-slice-vec/vec.rs +++ /dev/null @@ -1,15 +0,0 @@ -// run-pass - - - -pub fn main() { - let v: Vec<isize> = vec![10, 20]; - assert_eq!(v[0], 10); - assert_eq!(v[1], 20); - let mut x: usize = 0; - assert_eq!(v[x], 10); - assert_eq!(v[x + 1], 20); - x = x + 1; - assert_eq!(v[x], 20); - assert_eq!(v[x - 1], 10); -} diff --git a/src/test/ui/ast-json/ast-json-noexpand-output.stdout b/src/test/ui/ast-json/ast-json-noexpand-output.stdout index d0942f78bb8..3d7d476cf6c 100644 --- a/src/test/ui/ast-json/ast-json-noexpand-output.stdout +++ b/src/test/ui/ast-json/ast-json-noexpand-output.stdout @@ -1 +1 @@ -{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"NonJoint"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} +{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"tokens":null}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} diff --git a/src/test/ui/ast-json/ast-json-output.stdout b/src/test/ui/ast-json/ast-json-output.stdout index dc06fd74a4b..a4ce6061b4c 100644 --- a/src/test/ui/ast-json/ast-json-output.stdout +++ b/src/test/ui/ast-json/ast-json-output.stdout @@ -1 +1 @@ -{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"NonJoint"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} +{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"tokens":null}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} diff --git a/src/test/ui/attributes/register-attr-tool-prelude.rs b/src/test/ui/attributes/register-attr-tool-prelude.rs index a491773f5eb..d217a8146d2 100644 --- a/src/test/ui/attributes/register-attr-tool-prelude.rs +++ b/src/test/ui/attributes/register-attr-tool-prelude.rs @@ -7,7 +7,7 @@ #[no_implicit_prelude] mod m { #[attr] //~ ERROR cannot find attribute `attr` in this scope - #[tool::attr] //~ ERROR failed to resolve: use of undeclared type or module `tool` + #[tool::attr] //~ ERROR failed to resolve: use of undeclared crate or module `tool` fn check() {} } diff --git a/src/test/ui/attributes/register-attr-tool-prelude.stderr b/src/test/ui/attributes/register-attr-tool-prelude.stderr index 66a4eeb6aa4..905b661206a 100644 --- a/src/test/ui/attributes/register-attr-tool-prelude.stderr +++ b/src/test/ui/attributes/register-attr-tool-prelude.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `tool` +error[E0433]: failed to resolve: use of undeclared crate or module `tool` --> $DIR/register-attr-tool-prelude.rs:10:7 | LL | #[tool::attr] - | ^^^^ use of undeclared type or module `tool` + | ^^^^ use of undeclared crate or module `tool` error: cannot find attribute `attr` in this scope --> $DIR/register-attr-tool-prelude.rs:9:7 diff --git a/src/test/ui/bad/bad-module.rs b/src/test/ui/bad/bad-module.rs index a496c816e94..b23e97c2cf6 100644 --- a/src/test/ui/bad/bad-module.rs +++ b/src/test/ui/bad/bad-module.rs @@ -1,7 +1,7 @@ fn main() { let foo = thing::len(Vec::new()); - //~^ ERROR failed to resolve: use of undeclared type or module `thing` + //~^ ERROR failed to resolve: use of undeclared crate or module `thing` let foo = foo::bar::baz(); - //~^ ERROR failed to resolve: use of undeclared type or module `foo` + //~^ ERROR failed to resolve: use of undeclared crate or module `foo` } diff --git a/src/test/ui/bad/bad-module.stderr b/src/test/ui/bad/bad-module.stderr index 45d4c5abd93..581a6619814 100644 --- a/src/test/ui/bad/bad-module.stderr +++ b/src/test/ui/bad/bad-module.stderr @@ -1,14 +1,14 @@ -error[E0433]: failed to resolve: use of undeclared type or module `thing` +error[E0433]: failed to resolve: use of undeclared crate or module `thing` --> $DIR/bad-module.rs:2:15 | LL | let foo = thing::len(Vec::new()); - | ^^^^^ use of undeclared type or module `thing` + | ^^^^^ use of undeclared crate or module `thing` -error[E0433]: failed to resolve: use of undeclared type or module `foo` +error[E0433]: failed to resolve: use of undeclared crate or module `foo` --> $DIR/bad-module.rs:5:15 | LL | let foo = foo::bar::baz(); - | ^^^ use of undeclared type or module `foo` + | ^^^ use of undeclared crate or module `foo` error: aborting due to 2 previous errors diff --git a/src/test/ui/coherence/conflicting-impl-with-err.stderr b/src/test/ui/coherence/conflicting-impl-with-err.stderr index a8a5730accd..3009b452dc7 100644 --- a/src/test/ui/coherence/conflicting-impl-with-err.stderr +++ b/src/test/ui/coherence/conflicting-impl-with-err.stderr @@ -1,14 +1,14 @@ -error[E0433]: failed to resolve: use of undeclared type or module `nope` +error[E0433]: failed to resolve: use of undeclared crate or module `nope` --> $DIR/conflicting-impl-with-err.rs:4:11 | LL | impl From<nope::Thing> for Error { - | ^^^^ use of undeclared type or module `nope` + | ^^^^ use of undeclared crate or module `nope` -error[E0433]: failed to resolve: use of undeclared type or module `nope` +error[E0433]: failed to resolve: use of undeclared crate or module `nope` --> $DIR/conflicting-impl-with-err.rs:5:16 | LL | fn from(_: nope::Thing) -> Self { - | ^^^^ use of undeclared type or module `nope` + | ^^^^ use of undeclared crate or module `nope` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/auxiliary/const_generic_lib.rs b/src/test/ui/const-generics/auxiliary/const_generic_lib.rs index 901fb5dd054..899a5a1836c 100644 --- a/src/test/ui/const-generics/auxiliary/const_generic_lib.rs +++ b/src/test/ui/const-generics/auxiliary/const_generic_lib.rs @@ -1,4 +1,6 @@ -#![feature(const_generics)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] pub struct Struct<const N: usize>(pub [u8; N]); diff --git a/src/test/ui/const-generics/auxiliary/impl-const.rs b/src/test/ui/const-generics/auxiliary/impl-const.rs index fc993d63927..2e25dadf119 100644 --- a/src/test/ui/const-generics/auxiliary/impl-const.rs +++ b/src/test/ui/const-generics/auxiliary/impl-const.rs @@ -1,4 +1,6 @@ -#![feature(const_generics)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] pub struct Num<const N: usize>; diff --git a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.full.stderr index aefd514f7a6..a35c3abc113 100644 --- a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr +++ b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.full.stderr @@ -1,11 +1,11 @@ error[E0308]: mismatched types - --> $DIR/const-argument-cross-crate-mismatch.rs:6:67 + --> $DIR/const-argument-cross-crate-mismatch.rs:7:67 | LL | let _ = const_generic_lib::function(const_generic_lib::Struct([0u8, 1u8])); | ^^^^^^^^^^ expected an array with a fixed size of 3 elements, found one with 2 elements error[E0308]: mismatched types - --> $DIR/const-argument-cross-crate-mismatch.rs:8:65 + --> $DIR/const-argument-cross-crate-mismatch.rs:9:65 | LL | let _: const_generic_lib::Alias = const_generic_lib::Struct([0u8, 1u8, 2u8]); | ^^^^^^^^^^^^^^^ expected an array with a fixed size of 2 elements, found one with 3 elements diff --git a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.min.stderr b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.min.stderr new file mode 100644 index 00000000000..a35c3abc113 --- /dev/null +++ b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.min.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> $DIR/const-argument-cross-crate-mismatch.rs:7:67 + | +LL | let _ = const_generic_lib::function(const_generic_lib::Struct([0u8, 1u8])); + | ^^^^^^^^^^ expected an array with a fixed size of 3 elements, found one with 2 elements + +error[E0308]: mismatched types + --> $DIR/const-argument-cross-crate-mismatch.rs:9:65 + | +LL | let _: const_generic_lib::Alias = const_generic_lib::Struct([0u8, 1u8, 2u8]); + | ^^^^^^^^^^^^^^^ expected an array with a fixed size of 2 elements, found one with 3 elements + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.rs b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.rs index d863d097d5c..9ae2ae50ba0 100644 --- a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.rs +++ b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.rs @@ -1,4 +1,5 @@ // aux-build:const_generic_lib.rs +// revisions: full min extern crate const_generic_lib; diff --git a/src/test/ui/const-generics/const-argument-cross-crate.rs b/src/test/ui/const-generics/const-argument-cross-crate.rs index 98cf39a7ee1..fda3ec3eef7 100644 --- a/src/test/ui/const-generics/const-argument-cross-crate.rs +++ b/src/test/ui/const-generics/const-argument-cross-crate.rs @@ -1,4 +1,5 @@ // run-pass +// revisions: full min // aux-build:const_generic_lib.rs extern crate const_generic_lib; diff --git a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.full.stderr b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.full.stderr new file mode 100644 index 00000000000..b2816367ea1 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.full.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/feature-gate-const_evaluatable_checked.rs:9:30 + | +LL | fn test<const N: usize>() -> Arr<N> where Arr<N>: Default { + | ^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr new file mode 100644 index 00000000000..269710db164 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/feature-gate-const_evaluatable_checked.rs:6:33 + | +LL | type Arr<const N: usize> = [u8; N - 1]; + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs new file mode 100644 index 00000000000..af3090115f2 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs @@ -0,0 +1,17 @@ +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] + +type Arr<const N: usize> = [u8; N - 1]; +//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values + +fn test<const N: usize>() -> Arr<N> where Arr<N>: Default { + //[full]~^ ERROR constant expression depends + Default::default() +} + +fn main() { + let x = test::<33>(); + assert_eq!(x, [0; 32]); +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr new file mode 100644 index 00000000000..da8ccdaee41 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/simple.rs:8:33 + | +LL | type Arr<const N: usize> = [u8; N - 1]; + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple.rs b/src/test/ui/const-generics/const_evaluatable_checked/simple.rs new file mode 100644 index 00000000000..27dc6b10320 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple.rs @@ -0,0 +1,18 @@ +// [full] run-pass +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(min, feature(min_const_generics))] +#![feature(const_evaluatable_checked)] +#![allow(incomplete_features)] + +type Arr<const N: usize> = [u8; N - 1]; +//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values + +fn test<const N: usize>() -> Arr<N> where Arr<N>: Default { + Default::default() +} + +fn main() { + let x = test::<33>(); + assert_eq!(x, [0; 32]); +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr new file mode 100644 index 00000000000..104cab8667c --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/simple_fail.rs:7:33 + | +LL | type Arr<const N: usize> = [u8; N - 1]; + | ^^^^^ attempt to compute `0_usize - 1_usize` which would overflow + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr new file mode 100644 index 00000000000..042710f1327 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/simple_fail.rs:7:33 + | +LL | type Arr<const N: usize> = [u8; N - 1]; + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs new file mode 100644 index 00000000000..b15e0ff1839 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs @@ -0,0 +1,16 @@ +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(min, feature(min_const_generics))] +#![feature(const_evaluatable_checked)] +#![allow(incomplete_features)] + +type Arr<const N: usize> = [u8; N - 1]; //[full]~ ERROR evaluation of constant +//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values + +fn test<const N: usize>() -> Arr<N> where Arr<N>: Sized { + todo!() +} + +fn main() { + test::<0>(); +} diff --git a/src/test/ui/const-generics/defaults/complex-unord-param.min.stderr b/src/test/ui/const-generics/defaults/complex-unord-param.min.stderr new file mode 100644 index 00000000000..0574ddfb255 --- /dev/null +++ b/src/test/ui/const-generics/defaults/complex-unord-param.min.stderr @@ -0,0 +1,8 @@ +error: type parameters must be declared prior to const parameters + --> $DIR/complex-unord-param.rs:9:41 + | +LL | struct NestedArrays<'a, const N: usize, A: 'a, const M: usize, T:'a =u32> { + | ---------------------^----------------------^--------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, A: 'a, T: 'a, const N: usize, const M: usize>` + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/defaults/complex-unord-param.rs b/src/test/ui/const-generics/defaults/complex-unord-param.rs index 72967640a8e..e83a96388c1 100644 --- a/src/test/ui/const-generics/defaults/complex-unord-param.rs +++ b/src/test/ui/const-generics/defaults/complex-unord-param.rs @@ -1,11 +1,13 @@ -// run-pass +// [full] run-pass +// revisions: full min // Checks a complicated usage of unordered params - -#![feature(const_generics)] -#![allow(incomplete_features)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] #![allow(dead_code)] struct NestedArrays<'a, const N: usize, A: 'a, const M: usize, T:'a =u32> { + //[min]~^ ERROR type parameters must be declared prior to const parameters args: &'a [&'a [T; M]; N], specifier: A, } diff --git a/src/test/ui/const-generics/defaults/intermixed-lifetime.stderr b/src/test/ui/const-generics/defaults/intermixed-lifetime.full.stderr index 0f6d7f1065a..9cc3e9c0da6 100644 --- a/src/test/ui/const-generics/defaults/intermixed-lifetime.stderr +++ b/src/test/ui/const-generics/defaults/intermixed-lifetime.full.stderr @@ -1,11 +1,11 @@ error: lifetime parameters must be declared prior to const parameters - --> $DIR/intermixed-lifetime.rs:6:28 + --> $DIR/intermixed-lifetime.rs:7:28 | LL | struct Foo<const N: usize, 'a, T = u32>(&'a (), T); | -----------------^^---------- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T>` error: lifetime parameters must be declared prior to type parameters - --> $DIR/intermixed-lifetime.rs:9:37 + --> $DIR/intermixed-lifetime.rs:11:37 | LL | struct Bar<const N: usize, T = u32, 'a>(&'a (), T); | --------------------------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T>` diff --git a/src/test/ui/const-generics/defaults/intermixed-lifetime.min.stderr b/src/test/ui/const-generics/defaults/intermixed-lifetime.min.stderr new file mode 100644 index 00000000000..4d80fdb5bcb --- /dev/null +++ b/src/test/ui/const-generics/defaults/intermixed-lifetime.min.stderr @@ -0,0 +1,26 @@ +error: lifetime parameters must be declared prior to const parameters + --> $DIR/intermixed-lifetime.rs:7:28 + | +LL | struct Foo<const N: usize, 'a, T = u32>(&'a (), T); + | -----------------^^---------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>` + +error: type parameters must be declared prior to const parameters + --> $DIR/intermixed-lifetime.rs:7:32 + | +LL | struct Foo<const N: usize, 'a, T = u32>(&'a (), T); + | ---------------------^------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>` + +error: lifetime parameters must be declared prior to const parameters + --> $DIR/intermixed-lifetime.rs:11:37 + | +LL | struct Bar<const N: usize, T = u32, 'a>(&'a (), T); + | --------------------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>` + +error: type parameters must be declared prior to const parameters + --> $DIR/intermixed-lifetime.rs:11:28 + | +LL | struct Bar<const N: usize, T = u32, 'a>(&'a (), T); + | -----------------^----------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>` + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/const-generics/defaults/intermixed-lifetime.rs b/src/test/ui/const-generics/defaults/intermixed-lifetime.rs index ea3a8c14b98..cc0d1c6c0c9 100644 --- a/src/test/ui/const-generics/defaults/intermixed-lifetime.rs +++ b/src/test/ui/const-generics/defaults/intermixed-lifetime.rs @@ -1,12 +1,16 @@ +// revisions: full min // Checks that lifetimes cannot be interspersed between consts and types. - -#![feature(const_generics)] -#![allow(incomplete_features)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct Foo<const N: usize, 'a, T = u32>(&'a (), T); //~^ Error lifetime parameters must be declared prior to const parameters +//[min]~^^ Error type parameters must be declared prior to const parameters struct Bar<const N: usize, T = u32, 'a>(&'a (), T); -//~^ Error lifetime parameters must be declared prior to type parameters +//[full]~^ Error lifetime parameters must be declared prior to type parameters +//[min]~^^ Error type parameters must be declared prior to const parameters +//[min]~| Error lifetime parameters must be declared prior to const parameters fn main() {} diff --git a/src/test/ui/const-generics/defaults/simple-defaults.min.stderr b/src/test/ui/const-generics/defaults/simple-defaults.min.stderr new file mode 100644 index 00000000000..59cc6f28af8 --- /dev/null +++ b/src/test/ui/const-generics/defaults/simple-defaults.min.stderr @@ -0,0 +1,8 @@ +error: type parameters must be declared prior to const parameters + --> $DIR/simple-defaults.rs:9:40 + | +LL | struct FixedOutput<'a, const N: usize, T=u32> { + | ---------------------^----- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>` + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/defaults/simple-defaults.rs b/src/test/ui/const-generics/defaults/simple-defaults.rs index b282dfd37cc..78abe351998 100644 --- a/src/test/ui/const-generics/defaults/simple-defaults.rs +++ b/src/test/ui/const-generics/defaults/simple-defaults.rs @@ -1,10 +1,13 @@ -// run-pass +// [full] run-pass +// revisions: min full // Checks some basic test cases for defaults. -#![feature(const_generics)] -#![allow(incomplete_features)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] #![allow(dead_code)] struct FixedOutput<'a, const N: usize, T=u32> { + //[min]~^ ERROR type parameters must be declared prior to const parameters out: &'a [T; N], } diff --git a/src/test/ui/const-generics/invalid-enum.rs b/src/test/ui/const-generics/invalid-enum.rs new file mode 100644 index 00000000000..ceb188a0d3d --- /dev/null +++ b/src/test/ui/const-generics/invalid-enum.rs @@ -0,0 +1,39 @@ +#![feature(const_generics)] +#![allow(incomplete_features)] + +#[derive(PartialEq, Eq)] +enum CompileFlag { + A, + B, +} + +pub fn test_1<const CF: CompileFlag>() {} +pub fn test_2<T, const CF: CompileFlag>(x: T) {} +pub struct Example<const CF: CompileFlag, T=u32>{ + x: T, +} + +impl<const CF: CompileFlag, T> Example<CF, T> { + const ASSOC_FLAG: CompileFlag = CompileFlag::A; +} + +pub fn main() { + test_1::<CompileFlag::A>(); + //~^ ERROR: expected type, found variant + //~| ERROR: wrong number of const arguments + //~| ERROR: wrong number of type arguments + + test_2::<_, CompileFlag::A>(0); + //~^ ERROR: expected type, found variant + //~| ERROR: wrong number of const arguments + //~| ERROR: wrong number of type arguments + + let _: Example<CompileFlag::A, _> = Example { x: 0 }; + //~^ ERROR: expected type, found variant + //~| ERROR: wrong number of const arguments + //~| ERROR: wrong number of type arguments + + let _: Example<Example::ASSOC_FLAG, _> = Example { x: 0 }; + //~^ ERROR: wrong number of const arguments + //~| ERROR: wrong number of type arguments +} diff --git a/src/test/ui/const-generics/invalid-enum.stderr b/src/test/ui/const-generics/invalid-enum.stderr new file mode 100644 index 00000000000..965abbc9cb7 --- /dev/null +++ b/src/test/ui/const-generics/invalid-enum.stderr @@ -0,0 +1,99 @@ +error[E0573]: expected type, found variant `CompileFlag::A` + --> $DIR/invalid-enum.rs:21:12 + | +LL | test_1::<CompileFlag::A>(); + | ^^^^^^^^^^^^^^ + | | + | not a type + | help: try using the variant's enum: `CompileFlag` + +error[E0573]: expected type, found variant `CompileFlag::A` + --> $DIR/invalid-enum.rs:26:15 + | +LL | test_2::<_, CompileFlag::A>(0); + | ^^^^^^^^^^^^^^ + | | + | not a type + | help: try using the variant's enum: `CompileFlag` + +error[E0573]: expected type, found variant `CompileFlag::A` + --> $DIR/invalid-enum.rs:31:18 + | +LL | let _: Example<CompileFlag::A, _> = Example { x: 0 }; + | ^^^^^^^^^^^^^^ + | | + | not a type + | help: try using the variant's enum: `CompileFlag` + +error[E0107]: wrong number of const arguments: expected 1, found 0 + --> $DIR/invalid-enum.rs:31:10 + | +LL | let _: Example<CompileFlag::A, _> = Example { x: 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument + +error[E0107]: wrong number of type arguments: expected at most 1, found 2 + --> $DIR/invalid-enum.rs:31:10 + | +LL | let _: Example<CompileFlag::A, _> = Example { x: 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected at most 1 type argument + | +help: If this generic argument was intended as a const parameter, try surrounding it with braces: + | +LL | let _: Example<{ CompileFlag::A }, _> = Example { x: 0 }; + | ^ ^ + +error[E0107]: wrong number of const arguments: expected 1, found 0 + --> $DIR/invalid-enum.rs:36:10 + | +LL | let _: Example<Example::ASSOC_FLAG, _> = Example { x: 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument + +error[E0107]: wrong number of type arguments: expected at most 1, found 2 + --> $DIR/invalid-enum.rs:36:10 + | +LL | let _: Example<Example::ASSOC_FLAG, _> = Example { x: 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected at most 1 type argument + | +help: If this generic argument was intended as a const parameter, try surrounding it with braces: + | +LL | let _: Example<{ Example::ASSOC_FLAG }, _> = Example { x: 0 }; + | ^ ^ + +error[E0107]: wrong number of const arguments: expected 1, found 0 + --> $DIR/invalid-enum.rs:21:3 + | +LL | test_1::<CompileFlag::A>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument + +error[E0107]: wrong number of type arguments: expected 0, found 1 + --> $DIR/invalid-enum.rs:21:12 + | +LL | test_1::<CompileFlag::A>(); + | ^^^^^^^^^^^^^^ unexpected type argument + | +help: If this generic argument was intended as a const parameter, try surrounding it with braces: + | +LL | test_1::<{ CompileFlag::A }>(); + | ^ ^ + +error[E0107]: wrong number of const arguments: expected 1, found 0 + --> $DIR/invalid-enum.rs:26:3 + | +LL | test_2::<_, CompileFlag::A>(0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument + +error[E0107]: wrong number of type arguments: expected 1, found 2 + --> $DIR/invalid-enum.rs:26:15 + | +LL | test_2::<_, CompileFlag::A>(0); + | ^^^^^^^^^^^^^^ unexpected type argument + | +help: If this generic argument was intended as a const parameter, try surrounding it with braces: + | +LL | test_2::<_, { CompileFlag::A }>(0); + | ^ ^ + +error: aborting due to 11 previous errors + +Some errors have detailed explanations: E0107, E0573. +For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/const-generics/issues/auxiliary/const_generic_issues_lib.rs b/src/test/ui/const-generics/issues/auxiliary/const_generic_issues_lib.rs index 59a4d345cbc..7ea8d936d61 100644 --- a/src/test/ui/const-generics/issues/auxiliary/const_generic_issues_lib.rs +++ b/src/test/ui/const-generics/issues/auxiliary/const_generic_issues_lib.rs @@ -1,4 +1,6 @@ -#![feature(const_generics)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] // All of these three items must be in `lib2` to reproduce the error diff --git a/src/test/ui/const-generics/issues/issue-61935.full.stderr b/src/test/ui/const-generics/issues/issue-61935.full.stderr new file mode 100644 index 00000000000..b805bc0db7e --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-61935.full.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-61935.rs:10:14 + | +LL | Self:FooImpl<{N==0}> + | ^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-61935.min.stderr b/src/test/ui/const-generics/issues/issue-61935.min.stderr new file mode 100644 index 00000000000..e5715ec658c --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-61935.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-61935.rs:10:23 + | +LL | Self:FooImpl<{N==0}> + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-61935.rs b/src/test/ui/const-generics/issues/issue-61935.rs index 0d42ff1895c..64257da0309 100644 --- a/src/test/ui/const-generics/issues/issue-61935.rs +++ b/src/test/ui/const-generics/issues/issue-61935.rs @@ -1,12 +1,15 @@ -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] trait Foo {} impl<const N: usize> Foo for [(); N] where Self:FooImpl<{N==0}> -//~^ERROR constant expression depends on a generic parameter +//[full]~^ERROR constant expression depends on a generic parameter +//[min]~^^ERROR generic parameters must not be used inside of non trivial constant values {} trait FooImpl<const IS_ZERO: bool>{} diff --git a/src/test/ui/const-generics/issues/issue-61935.stderr b/src/test/ui/const-generics/issues/issue-61935.stderr deleted file mode 100644 index a785af5f008..00000000000 --- a/src/test/ui/const-generics/issues/issue-61935.stderr +++ /dev/null @@ -1,19 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-61935.rs:1:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information - -error: constant expression depends on a generic parameter - --> $DIR/issue-61935.rs:8:14 - | -LL | Self:FooImpl<{N==0}> - | ^^^^^^^^^^^^^^^ - | - = note: this may fail depending on what value the parameter takes - -error: aborting due to previous error; 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs index 2f3b5c5dc5b..a8fa3780356 100644 --- a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs +++ b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs @@ -1,7 +1,9 @@ // run-pass -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] pub trait BitLen: Sized { const BIT_LEN: usize; @@ -12,5 +14,5 @@ impl<const L: usize> BitLen for [u8; L] { } fn main() { - let foo = <[u8; 2]>::BIT_LEN; //~ WARN unused variable + let _foo = <[u8; 2]>::BIT_LEN; } diff --git a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.stderr b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.stderr deleted file mode 100644 index a9abb877c09..00000000000 --- a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.stderr +++ /dev/null @@ -1,19 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-62187-encountered-polymorphic-const.rs:3:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information - -warning: unused variable: `foo` - --> $DIR/issue-62187-encountered-polymorphic-const.rs:15:9 - | -LL | let foo = <[u8; 2]>::BIT_LEN; - | ^^^ help: if this is intentional, prefix it with an underscore: `_foo` - | - = note: `#[warn(unused_variables)]` on by default - -warning: 2 warnings emitted - diff --git a/src/test/ui/const-generics/issues/issue-62220.stderr b/src/test/ui/const-generics/issues/issue-62220.full.stderr index d91d2bb326f..120aa8e4af5 100644 --- a/src/test/ui/const-generics/issues/issue-62220.stderr +++ b/src/test/ui/const-generics/issues/issue-62220.full.stderr @@ -1,5 +1,5 @@ error: constant expression depends on a generic parameter - --> $DIR/issue-62220.rs:10:27 + --> $DIR/issue-62220.rs:13:27 | LL | pub fn trunc(self) -> (TruncatedVector<T, { N }>, T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/const-generics/issues/issue-62220.min.stderr b/src/test/ui/const-generics/issues/issue-62220.min.stderr new file mode 100644 index 00000000000..943b689bf61 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62220.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-62220.rs:8:59 + | +LL | pub type TruncatedVector<T, const N: usize> = Vector<T, { N - 1 }>; + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-62220.rs b/src/test/ui/const-generics/issues/issue-62220.rs index 5c4a0d31a89..acb13ad1170 100644 --- a/src/test/ui/const-generics/issues/issue-62220.rs +++ b/src/test/ui/const-generics/issues/issue-62220.rs @@ -1,14 +1,17 @@ -#![allow(incomplete_features)] -#![feature(const_generics)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] pub struct Vector<T, const N: usize>([T; N]); pub type TruncatedVector<T, const N: usize> = Vector<T, { N - 1 }>; +//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values impl<T, const N: usize> Vector<T, { N }> { /// Drop the last component and return the vector with one fewer dimension. pub fn trunc(self) -> (TruncatedVector<T, { N }>, T) { - //~^ ERROR constant expression depends on a generic parameter + //[full]~^ ERROR constant expression depends on a generic parameter unimplemented!() } } diff --git a/src/test/ui/const-generics/issues/issue-62456.full.stderr b/src/test/ui/const-generics/issues/issue-62456.full.stderr new file mode 100644 index 00000000000..a8d44074db9 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62456.full.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-62456.rs:7:20 + | +LL | let _ = [0u64; N + 1]; + | ^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-62456.min.stderr b/src/test/ui/const-generics/issues/issue-62456.min.stderr new file mode 100644 index 00000000000..335f0ead278 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62456.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-62456.rs:7:20 + | +LL | let _ = [0u64; N + 1]; + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-62456.rs b/src/test/ui/const-generics/issues/issue-62456.rs index 37947ad1b33..c96868c00a3 100644 --- a/src/test/ui/const-generics/issues/issue-62456.rs +++ b/src/test/ui/const-generics/issues/issue-62456.rs @@ -1,9 +1,12 @@ -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] fn foo<const N: usize>() { let _ = [0u64; N + 1]; - //~^ ERROR constant expression depends on a generic parameter + //[full]~^ ERROR constant expression depends on a generic parameter + //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values } fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-62456.stderr b/src/test/ui/const-generics/issues/issue-62456.stderr deleted file mode 100644 index 0454fed6705..00000000000 --- a/src/test/ui/const-generics/issues/issue-62456.stderr +++ /dev/null @@ -1,19 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-62456.rs:1:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information - -error: constant expression depends on a generic parameter - --> $DIR/issue-62456.rs:5:20 - | -LL | let _ = [0u64; N + 1]; - | ^^^^^ - | - = note: this may fail depending on what value the parameter takes - -error: aborting due to previous error; 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-62504.stderr b/src/test/ui/const-generics/issues/issue-62504.full.stderr index f09af76325e..9c84f06ce9f 100644 --- a/src/test/ui/const-generics/issues/issue-62504.stderr +++ b/src/test/ui/const-generics/issues/issue-62504.full.stderr @@ -1,5 +1,5 @@ error: constant expression depends on a generic parameter - --> $DIR/issue-62504.rs:18:25 + --> $DIR/issue-62504.rs:19:25 | LL | ArrayHolder([0; Self::SIZE]) | ^^^^^^^^^^ diff --git a/src/test/ui/const-generics/issues/issue-62504.min.stderr b/src/test/ui/const-generics/issues/issue-62504.min.stderr new file mode 100644 index 00000000000..752df17aad6 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62504.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-62504.rs:19:25 + | +LL | ArrayHolder([0; Self::SIZE]) + | ^^^^^^^^^^ non-trivial anonymous constants must not depend on the parameter `Self` + | + = help: it is currently only allowed to use either `Self` or `{ Self }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-62504.rs b/src/test/ui/const-generics/issues/issue-62504.rs index 4e05aadd393..b520dbe4e80 100644 --- a/src/test/ui/const-generics/issues/issue-62504.rs +++ b/src/test/ui/const-generics/issues/issue-62504.rs @@ -1,7 +1,8 @@ -// Regression test for #62504 - -#![feature(const_generics)] +// revisions: full min #![allow(incomplete_features)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] trait HasSize { const SIZE: usize; @@ -16,7 +17,8 @@ struct ArrayHolder<const X: usize>([u32; X]); impl<const X: usize> ArrayHolder<X> { pub const fn new() -> Self { ArrayHolder([0; Self::SIZE]) - //~^ ERROR constant expression depends on a generic parameter + //[full]~^ ERROR constant expression depends on a generic parameter + //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values } } diff --git a/src/test/ui/const-generics/issues/issue-62579-no-match.min.stderr b/src/test/ui/const-generics/issues/issue-62579-no-match.min.stderr new file mode 100644 index 00000000000..6903b20fad6 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62579-no-match.min.stderr @@ -0,0 +1,11 @@ +error: `NoMatch` is forbidden as the type of a const generic parameter + --> $DIR/issue-62579-no-match.rs:10:17 + | +LL | fn foo<const T: NoMatch>() -> bool { + | ^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-62579-no-match.rs b/src/test/ui/const-generics/issues/issue-62579-no-match.rs index 7eaf5eea078..c9853aa9162 100644 --- a/src/test/ui/const-generics/issues/issue-62579-no-match.rs +++ b/src/test/ui/const-generics/issues/issue-62579-no-match.rs @@ -1,12 +1,14 @@ -// run-pass - -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// [full] run-pass +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] #[derive(PartialEq, Eq)] struct NoMatch; fn foo<const T: NoMatch>() -> bool { + //[min]~^ ERROR `NoMatch` is forbidden as the type of a const generic parameter true } diff --git a/src/test/ui/const-generics/issues/issue-62579-no-match.stderr b/src/test/ui/const-generics/issues/issue-62579-no-match.stderr deleted file mode 100644 index 9fb9b5b13d8..00000000000 --- a/src/test/ui/const-generics/issues/issue-62579-no-match.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-62579-no-match.rs:3:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information - -warning: 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-62878.stderr b/src/test/ui/const-generics/issues/issue-62878.full.stderr index fe0990d8241..c8b9db89410 100644 --- a/src/test/ui/const-generics/issues/issue-62878.stderr +++ b/src/test/ui/const-generics/issues/issue-62878.full.stderr @@ -1,37 +1,28 @@ error[E0770]: the type of const parameters must not depend on other generic parameters - --> $DIR/issue-62878.rs:3:38 + --> $DIR/issue-62878.rs:6:38 | LL | fn foo<const N: usize, const A: [u8; N]>() {} | ^ the type must not depend on the parameter `N` -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-62878.rs:1:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information - error[E0107]: wrong number of const arguments: expected 2, found 1 - --> $DIR/issue-62878.rs:7:5 + --> $DIR/issue-62878.rs:11:5 | LL | foo::<_, {[1]}>(); | ^^^^^^^^^^^^^^^ expected 2 const arguments error[E0107]: wrong number of type arguments: expected 0, found 1 - --> $DIR/issue-62878.rs:7:11 + --> $DIR/issue-62878.rs:11:11 | LL | foo::<_, {[1]}>(); | ^ unexpected type argument error[E0308]: mismatched types - --> $DIR/issue-62878.rs:7:15 + --> $DIR/issue-62878.rs:11:15 | LL | foo::<_, {[1]}>(); | ^^^ expected `usize`, found array `[{integer}; 1]` -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 4 previous errors Some errors have detailed explanations: E0107, E0308, E0770. For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/const-generics/issues/issue-62878.min.stderr b/src/test/ui/const-generics/issues/issue-62878.min.stderr new file mode 100644 index 00000000000..34edd09b515 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62878.min.stderr @@ -0,0 +1,18 @@ +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/issue-62878.rs:6:38 + | +LL | fn foo<const N: usize, const A: [u8; N]>() {} + | ^ the type must not depend on the parameter `N` + +error: `[u8; _]` is forbidden as the type of a const generic parameter + --> $DIR/issue-62878.rs:6:33 + | +LL | fn foo<const N: usize, const A: [u8; N]>() {} + | ^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0770`. diff --git a/src/test/ui/const-generics/issues/issue-62878.rs b/src/test/ui/const-generics/issues/issue-62878.rs index ccc05fdf100..0487dda2fe8 100644 --- a/src/test/ui/const-generics/issues/issue-62878.rs +++ b/src/test/ui/const-generics/issues/issue-62878.rs @@ -1,11 +1,15 @@ -#![feature(const_generics)] //~ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] fn foo<const N: usize, const A: [u8; N]>() {} //~^ ERROR the type of const parameters must not +//[min]~| ERROR `[u8; _]` is forbidden as the type of a const generic parameter fn main() { foo::<_, {[1]}>(); - //~^ ERROR wrong number of const arguments - //~| ERROR wrong number of type arguments - //~| ERROR mismatched types + //[full]~^ ERROR wrong number of const arguments + //[full]~| ERROR wrong number of type arguments + //[full]~| ERROR mismatched types } diff --git a/src/test/ui/const-generics/issues/issue-67185-2.stderr b/src/test/ui/const-generics/issues/issue-67185-2.full.stderr index 7d947a907a0..78c7ebff059 100644 --- a/src/test/ui/const-generics/issues/issue-67185-2.stderr +++ b/src/test/ui/const-generics/issues/issue-67185-2.full.stderr @@ -1,14 +1,5 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-67185-2.rs:1:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information - error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied - --> $DIR/issue-67185-2.rs:15:1 + --> $DIR/issue-67185-2.rs:17:1 | LL | / trait Foo LL | | @@ -26,7 +17,7 @@ LL | | } = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied - --> $DIR/issue-67185-2.rs:15:1 + --> $DIR/issue-67185-2.rs:17:1 | LL | / trait Foo LL | | @@ -44,7 +35,7 @@ LL | | } = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied - --> $DIR/issue-67185-2.rs:25:6 + --> $DIR/issue-67185-2.rs:27:6 | LL | trait Foo | --- required by a bound in this @@ -60,7 +51,7 @@ LL | impl Foo for FooImpl {} <[u16; 4] as Bar> error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied - --> $DIR/issue-67185-2.rs:25:6 + --> $DIR/issue-67185-2.rs:27:6 | LL | trait Foo | --- required by a bound in this @@ -76,7 +67,7 @@ LL | impl Foo for FooImpl {} <[u16; 4] as Bar> error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied - --> $DIR/issue-67185-2.rs:29:14 + --> $DIR/issue-67185-2.rs:31:14 | LL | trait Foo | --- required by a bound in this @@ -92,7 +83,7 @@ LL | fn f(_: impl Foo) {} <[u16; 4] as Bar> error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied - --> $DIR/issue-67185-2.rs:29:14 + --> $DIR/issue-67185-2.rs:31:14 | LL | trait Foo | --- required by a bound in this @@ -107,6 +98,6 @@ LL | fn f(_: impl Foo) {} <[[u16; 3]; 3] as Bar> <[u16; 4] as Bar> -error: aborting due to 6 previous errors; 1 warning emitted +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/const-generics/issues/issue-67185-2.min.stderr b/src/test/ui/const-generics/issues/issue-67185-2.min.stderr new file mode 100644 index 00000000000..78c7ebff059 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-67185-2.min.stderr @@ -0,0 +1,103 @@ +error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:17:1 + | +LL | / trait Foo +LL | | +LL | | where +LL | | [<u8 as Baz>::Quaks; 2]: Bar, +LL | | <u8 as Baz>::Quaks: Bar, +LL | | { +LL | | } + | |_^ the trait `Bar` is not implemented for `[u16; 3]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + +error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:17:1 + | +LL | / trait Foo +LL | | +LL | | where +LL | | [<u8 as Baz>::Quaks; 2]: Bar, +LL | | <u8 as Baz>::Quaks: Bar, +LL | | { +LL | | } + | |_^ the trait `Bar` is not implemented for `[[u16; 3]; 2]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + +error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:27:6 + | +LL | trait Foo + | --- required by a bound in this +... +LL | <u8 as Baz>::Quaks: Bar, + | --- required by this bound in `Foo` +... +LL | impl Foo for FooImpl {} + | ^^^ the trait `Bar` is not implemented for `[u16; 3]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + +error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:27:6 + | +LL | trait Foo + | --- required by a bound in this +... +LL | [<u8 as Baz>::Quaks; 2]: Bar, + | --- required by this bound in `Foo` +... +LL | impl Foo for FooImpl {} + | ^^^ the trait `Bar` is not implemented for `[[u16; 3]; 2]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + +error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:31:14 + | +LL | trait Foo + | --- required by a bound in this +... +LL | [<u8 as Baz>::Quaks; 2]: Bar, + | --- required by this bound in `Foo` +... +LL | fn f(_: impl Foo) {} + | ^^^ the trait `Bar` is not implemented for `[[u16; 3]; 2]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + +error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:31:14 + | +LL | trait Foo + | --- required by a bound in this +... +LL | <u8 as Baz>::Quaks: Bar, + | --- required by this bound in `Foo` +... +LL | fn f(_: impl Foo) {} + | ^^^ the trait `Bar` is not implemented for `[u16; 3]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/const-generics/issues/issue-67185-2.rs b/src/test/ui/const-generics/issues/issue-67185-2.rs index 111b718dd5e..1176d0c6904 100644 --- a/src/test/ui/const-generics/issues/issue-67185-2.rs +++ b/src/test/ui/const-generics/issues/issue-67185-2.rs @@ -1,5 +1,7 @@ -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] trait Baz { type Quaks; diff --git a/src/test/ui/const-generics/issues/issue-67739.stderr b/src/test/ui/const-generics/issues/issue-67739.full.stderr index 27a56b8eb02..27a56b8eb02 100644 --- a/src/test/ui/const-generics/issues/issue-67739.stderr +++ b/src/test/ui/const-generics/issues/issue-67739.full.stderr diff --git a/src/test/ui/const-generics/issues/issue-67739.min.stderr b/src/test/ui/const-generics/issues/issue-67739.min.stderr new file mode 100644 index 00000000000..1254ee7239d --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-67739.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-67739.rs:12:30 + | +LL | [0u8; mem::size_of::<Self::Associated>()]; + | ^^^^^^^^^^^^^^^^ non-trivial anonymous constants must not depend on the parameter `Self` + | + = help: it is currently only allowed to use either `Self` or `{ Self }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-67739.rs b/src/test/ui/const-generics/issues/issue-67739.rs index c8ee1821239..72bf3ee9602 100644 --- a/src/test/ui/const-generics/issues/issue-67739.rs +++ b/src/test/ui/const-generics/issues/issue-67739.rs @@ -1,7 +1,7 @@ -// Regression test for #67739 - -#![allow(incomplete_features)] -#![feature(const_generics)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] use std::mem; @@ -10,7 +10,8 @@ pub trait Trait { fn associated_size(&self) -> usize { [0u8; mem::size_of::<Self::Associated>()]; - //~^ ERROR constant expression depends on a generic parameter + //[full]~^ ERROR constant expression depends on a generic parameter + //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values 0 } } diff --git a/src/test/ui/const-generics/issues/issue-68366.full.stderr b/src/test/ui/const-generics/issues/issue-68366.full.stderr new file mode 100644 index 00000000000..ac774f50c74 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-68366.full.stderr @@ -0,0 +1,21 @@ +error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates + --> $DIR/issue-68366.rs:12:13 + | +LL | impl <const N: usize> Collatz<{Some(N)}> {} + | ^ unconstrained const parameter + | + = note: expressions using a const parameter must map each value to a distinct output value + = note: proving the result of expressions other than the parameter are unique is not supported + +error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates + --> $DIR/issue-68366.rs:18:12 + | +LL | impl<const N: usize> Foo {} + | ^ unconstrained const parameter + | + = note: expressions using a const parameter must map each value to a distinct output value + = note: proving the result of expressions other than the parameter are unique is not supported + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0207`. diff --git a/src/test/ui/const-generics/issues/issue-68366.min.stderr b/src/test/ui/const-generics/issues/issue-68366.min.stderr new file mode 100644 index 00000000000..8d34bdc6ea0 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-68366.min.stderr @@ -0,0 +1,29 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-68366.rs:12:37 + | +LL | impl <const N: usize> Collatz<{Some(N)}> {} + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates + --> $DIR/issue-68366.rs:12:13 + | +LL | impl <const N: usize> Collatz<{Some(N)}> {} + | ^ unconstrained const parameter + | + = note: expressions using a const parameter must map each value to a distinct output value + = note: proving the result of expressions other than the parameter are unique is not supported + +error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates + --> $DIR/issue-68366.rs:18:12 + | +LL | impl<const N: usize> Foo {} + | ^ unconstrained const parameter + | + = note: expressions using a const parameter must map each value to a distinct output value + = note: proving the result of expressions other than the parameter are unique is not supported + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0207`. diff --git a/src/test/ui/const-generics/issues/issue-68366.rs b/src/test/ui/const-generics/issues/issue-68366.rs new file mode 100644 index 00000000000..819fcaffea1 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-68366.rs @@ -0,0 +1,21 @@ +// Checks that const expressions have a useful note explaining why they can't be evaluated. +// The note should relate to the fact that it cannot be shown forall N that it maps 1-1 to a new +// type. + +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] + +struct Collatz<const N: Option<usize>>; + +impl <const N: usize> Collatz<{Some(N)}> {} +//~^ ERROR the const parameter +//[min]~^^ generic parameters must not be used inside of non trivial constant values + +struct Foo; + +impl<const N: usize> Foo {} +//~^ ERROR the const parameter + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-72787.stderr b/src/test/ui/const-generics/issues/issue-72787.full.stderr index ed892e46bbb..b4c79d4171b 100644 --- a/src/test/ui/const-generics/issues/issue-72787.stderr +++ b/src/test/ui/const-generics/issues/issue-72787.full.stderr @@ -1,5 +1,5 @@ error: constant expression depends on a generic parameter - --> $DIR/issue-72787.rs:9:32 + --> $DIR/issue-72787.rs:11:32 | LL | Condition<{ LHS <= RHS }>: True | ^^^^ @@ -7,7 +7,7 @@ LL | Condition<{ LHS <= RHS }>: True = note: this may fail depending on what value the parameter takes error: constant expression depends on a generic parameter - --> $DIR/issue-72787.rs:20:42 + --> $DIR/issue-72787.rs:26:42 | LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | ^^^^ @@ -15,7 +15,7 @@ LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, = note: this may fail depending on what value the parameter takes error: constant expression depends on a generic parameter - --> $DIR/issue-72787.rs:20:42 + --> $DIR/issue-72787.rs:26:42 | LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | ^^^^ @@ -23,7 +23,7 @@ LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, = note: this may fail depending on what value the parameter takes error: constant expression depends on a generic parameter - --> $DIR/issue-72787.rs:20:42 + --> $DIR/issue-72787.rs:26:42 | LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | ^^^^ @@ -31,7 +31,7 @@ LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, = note: this may fail depending on what value the parameter takes error: constant expression depends on a generic parameter - --> $DIR/issue-72787.rs:20:42 + --> $DIR/issue-72787.rs:26:42 | LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | ^^^^ diff --git a/src/test/ui/const-generics/issues/issue-72787.min.stderr b/src/test/ui/const-generics/issues/issue-72787.min.stderr new file mode 100644 index 00000000000..d3e9887fe20 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-72787.min.stderr @@ -0,0 +1,57 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-72787.rs:11:17 + | +LL | Condition<{ LHS <= RHS }>: True + | ^^^ non-trivial anonymous constants must not depend on the parameter `LHS` + | + = help: it is currently only allowed to use either `LHS` or `{ LHS }` as generic constants + +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-72787.rs:11:24 + | +LL | Condition<{ LHS <= RHS }>: True + | ^^^ non-trivial anonymous constants must not depend on the parameter `RHS` + | + = help: it is currently only allowed to use either `RHS` or `{ RHS }` as generic constants + +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-72787.rs:26:25 + | +LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, + | ^ non-trivial anonymous constants must not depend on the parameter `I` + | + = help: it is currently only allowed to use either `I` or `{ I }` as generic constants + +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-72787.rs:26:36 + | +LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, + | ^ non-trivial anonymous constants must not depend on the parameter `J` + | + = help: it is currently only allowed to use either `J` or `{ J }` as generic constants + +error[E0283]: type annotations needed + --> $DIR/issue-72787.rs:22:26 + | +LL | pub trait True {} + | -------------- required by this bound in `True` +... +LL | IsLessOrEqual<I, 8>: True, + | ^^^^ cannot infer type for struct `IsLessOrEqual<I, 8_u32>` + | + = note: cannot satisfy `IsLessOrEqual<I, 8_u32>: True` + +error[E0283]: type annotations needed + --> $DIR/issue-72787.rs:22:26 + | +LL | pub trait True {} + | -------------- required by this bound in `True` +... +LL | IsLessOrEqual<I, 8>: True, + | ^^^^ cannot infer type for struct `IsLessOrEqual<I, 8_u32>` + | + = note: cannot satisfy `IsLessOrEqual<I, 8_u32>: True` + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0283`. diff --git a/src/test/ui/const-generics/issues/issue-72787.rs b/src/test/ui/const-generics/issues/issue-72787.rs index a368c226ec3..45c20191c88 100644 --- a/src/test/ui/const-generics/issues/issue-72787.rs +++ b/src/test/ui/const-generics/issues/issue-72787.rs @@ -1,5 +1,7 @@ -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] pub struct IsLessOrEqual<const LHS: u32, const RHS: u32>; pub struct Condition<const CONDITION: bool>; @@ -7,7 +9,9 @@ pub trait True {} impl<const LHS: u32, const RHS: u32> True for IsLessOrEqual<LHS, RHS> where Condition<{ LHS <= RHS }>: True -//~^ Error constant expression depends on a generic parameter +//[full]~^ Error constant expression depends on a generic parameter +//[min]~^^ Error generic parameters must not be used inside of non trivial constant values +//[min]~| Error generic parameters must not be used inside of non trivial constant values { } impl True for Condition<true> {} @@ -16,12 +20,16 @@ struct S<const I: u32, const J: u32>; impl<const I: u32, const J: u32> S<I, J> where IsLessOrEqual<I, 8>: True, +//[min]~^ Error type annotations needed [E0283] +//[min]~| Error type annotations needed [E0283] IsLessOrEqual<J, 8>: True, IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, -//~^ Error constant expression depends on a generic parameter -//~| Error constant expression depends on a generic parameter -//~| Error constant expression depends on a generic parameter -//~| Error constant expression depends on a generic parameter +//[full]~^ constant expression depends on a generic parameter +//[full]~| constant expression depends on a generic parameter +//[full]~| constant expression depends on a generic parameter +//[full]~| constant expression depends on a generic parameter +//[min]~^^^^^ Error generic parameters must not be used inside of non trivial constant values +//[min]~| Error generic parameters must not be used inside of non trivial constant values // Condition<{ 8 - I <= 8 - J }>: True, { fn print() { diff --git a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.stderr b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.full.stderr index a9f664d0ac8..e4105a3df1c 100644 --- a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.stderr +++ b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.full.stderr @@ -1,5 +1,5 @@ error: constant expression depends on a generic parameter - --> $DIR/issue-72819-generic-in-const-eval.rs:7:47 + --> $DIR/issue-72819-generic-in-const-eval.rs:9:47 | LL | where Assert::<{N < usize::max_value() / 2}>: IsTrue, | ^^^^^^ diff --git a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr new file mode 100644 index 00000000000..48a1f0bd19c --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-72819-generic-in-const-eval.rs:9:17 + | +LL | where Assert::<{N < usize::max_value() / 2}>: IsTrue, + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs index 225593c3178..b653b91d99d 100644 --- a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs +++ b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs @@ -1,11 +1,14 @@ // Regression test for #72819: ICE due to failure in resolving the const generic in `Arr`'s type // bounds. +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] -#![feature(const_generics)] -#![allow(incomplete_features)] struct Arr<const N: usize> where Assert::<{N < usize::max_value() / 2}>: IsTrue, -//~^ ERROR constant expression depends on a generic parameter +//[full]~^ ERROR constant expression depends on a generic parameter +//[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values { } diff --git a/src/test/ui/const-generics/issues/issue-73120.rs b/src/test/ui/const-generics/issues/issue-73120.rs index aea4de39f79..c153a93cdef 100644 --- a/src/test/ui/const-generics/issues/issue-73120.rs +++ b/src/test/ui/const-generics/issues/issue-73120.rs @@ -1,3 +1,4 @@ +// revisions: full min // check-pass // aux-build:const_generic_issues_lib.rs extern crate const_generic_issues_lib as lib2; diff --git a/src/test/ui/const-generics/min-and-full-same-time.rs b/src/test/ui/const-generics/min-and-full-same-time.rs new file mode 100644 index 00000000000..2365adc3a86 --- /dev/null +++ b/src/test/ui/const-generics/min-and-full-same-time.rs @@ -0,0 +1,7 @@ +#![feature(const_generics)] +//~^ ERROR features `const_generics` and `min_const_generics` are incompatible +#![allow(incomplete_features)] +#![feature(min_const_generics)] + + +fn main() {} diff --git a/src/test/ui/const-generics/min-and-full-same-time.stderr b/src/test/ui/const-generics/min-and-full-same-time.stderr new file mode 100644 index 00000000000..907fec9bbe1 --- /dev/null +++ b/src/test/ui/const-generics/min-and-full-same-time.stderr @@ -0,0 +1,13 @@ +error: features `const_generics` and `min_const_generics` are incompatible, using them at the same time is not allowed + --> $DIR/min-and-full-same-time.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ +... +LL | #![feature(min_const_generics)] + | ^^^^^^^^^^^^^^^^^^ + | + = help: remove one of these features + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/type-dependent/auxiliary/type_dependent_lib.rs b/src/test/ui/const-generics/type-dependent/auxiliary/type_dependent_lib.rs index c8db91b62b5..aa85376bf0d 100644 --- a/src/test/ui/const-generics/type-dependent/auxiliary/type_dependent_lib.rs +++ b/src/test/ui/const-generics/type-dependent/auxiliary/type_dependent_lib.rs @@ -1,5 +1,6 @@ -#![feature(const_generics)] -#![allow(incomplete_features)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] pub struct Struct<const N: usize>(()); diff --git a/src/test/ui/const_evaluatable/associated-const.rs b/src/test/ui/const_evaluatable/associated-const.rs new file mode 100644 index 00000000000..a6777632254 --- /dev/null +++ b/src/test/ui/const_evaluatable/associated-const.rs @@ -0,0 +1,11 @@ +// check-pass +struct Foo<T>(T); +impl<T> Foo<T> { + const VALUE: usize = std::mem::size_of::<T>(); +} + +fn test<T>() { + let _ = [0; Foo::<u8>::VALUE]; +} + +fn main() {} diff --git a/src/test/ui/const_evaluatable/function-call.rs b/src/test/ui/const_evaluatable/function-call.rs new file mode 100644 index 00000000000..b5de66621c5 --- /dev/null +++ b/src/test/ui/const_evaluatable/function-call.rs @@ -0,0 +1,19 @@ +// check-pass + +const fn foo<T>() -> usize { + // We might instead branch on `std::mem::size_of::<*mut T>() < 8` here, + // which would cause this function to fail on 32 bit systems. + if false { + std::mem::size_of::<T>() + } else { + 8 + } +} + +fn test<T>() { + let _ = [0; foo::<T>()]; + //~^ WARN cannot use constants which depend on generic parameters in types + //~| WARN this was previously accepted by the compiler but is being phased out +} + +fn main() {} diff --git a/src/test/ui/const_evaluatable/function-call.stderr b/src/test/ui/const_evaluatable/function-call.stderr new file mode 100644 index 00000000000..0d8463714e8 --- /dev/null +++ b/src/test/ui/const_evaluatable/function-call.stderr @@ -0,0 +1,12 @@ +warning: cannot use constants which depend on generic parameters in types + --> $DIR/function-call.rs:14:17 + | +LL | let _ = [0; foo::<T>()]; + | ^^^^^^^^^^ + | + = note: `#[warn(const_evaluatable_unchecked)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #76200 <https://github.com/rust-lang/rust/issues/76200> + +warning: 1 warning emitted + diff --git a/src/test/ui/consts/const-nonzero.rs b/src/test/ui/consts/const-nonzero.rs deleted file mode 100644 index cf6f8c8d69a..00000000000 --- a/src/test/ui/consts/const-nonzero.rs +++ /dev/null @@ -1,16 +0,0 @@ -// run-pass - -use std::num::NonZeroU8; - -const X: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(5) }; -const Y: u8 = X.get(); - -const ZERO: Option<NonZeroU8> = NonZeroU8::new(0); -const ONE: Option<NonZeroU8> = NonZeroU8::new(1); - -fn main() { - assert_eq!(Y, 5); - - assert!(ZERO.is_none()); - assert_eq!(ONE.unwrap().get(), 1); -} diff --git a/src/test/ui/consts/cow-is-borrowed.rs b/src/test/ui/consts/cow-is-borrowed.rs deleted file mode 100644 index adebe20f5a2..00000000000 --- a/src/test/ui/consts/cow-is-borrowed.rs +++ /dev/null @@ -1,15 +0,0 @@ -// run-pass - -#![feature(cow_is_borrowed)] - -use std::borrow::Cow; - -fn main() { - const COW: Cow<str> = Cow::Borrowed("moo"); - - const IS_BORROWED: bool = COW.is_borrowed(); - assert!(IS_BORROWED); - - const IS_OWNED: bool = COW.is_owned(); - assert!(!IS_OWNED); -} diff --git a/src/test/ui/consts/duration-consts-2.rs b/src/test/ui/consts/duration-consts-2.rs index c8b39399331..bc0969e4f1f 100644 --- a/src/test/ui/consts/duration-consts-2.rs +++ b/src/test/ui/consts/duration-consts-2.rs @@ -3,6 +3,7 @@ #![feature(const_panic)] #![feature(duration_consts_2)] #![feature(div_duration)] +#![feature(duration_saturating_ops)] use std::time::Duration; @@ -15,29 +16,29 @@ fn duration() { const MAX : Duration = Duration::new(u64::MAX, 1_000_000_000 - 1); - const MAX_ADD_ZERO : Option<Duration> = MAX.checked_add(ZERO); - assert_eq!(MAX_ADD_ZERO, Some(MAX)); + const MAX_CHECKED_ADD_ZERO : Option<Duration> = MAX.checked_add(ZERO); + assert_eq!(MAX_CHECKED_ADD_ZERO, Some(MAX)); - const MAX_ADD_ONE : Option<Duration> = MAX.checked_add(ONE); - assert_eq!(MAX_ADD_ONE, None); + const MAX_CHECKED_ADD_ONE : Option<Duration> = MAX.checked_add(ONE); + assert_eq!(MAX_CHECKED_ADD_ONE, None); - const ONE_SUB_ONE : Option<Duration> = ONE.checked_sub(ONE); - assert_eq!(ONE_SUB_ONE, Some(ZERO)); + const ONE_CHECKED_SUB_ONE : Option<Duration> = ONE.checked_sub(ONE); + assert_eq!(ONE_CHECKED_SUB_ONE, Some(ZERO)); - const ZERO_SUB_ONE : Option<Duration> = ZERO.checked_sub(ONE); - assert_eq!(ZERO_SUB_ONE, None); + const ZERO_CHECKED_SUB_ONE : Option<Duration> = ZERO.checked_sub(ONE); + assert_eq!(ZERO_CHECKED_SUB_ONE, None); - const ONE_MUL_ONE : Option<Duration> = ONE.checked_mul(1); - assert_eq!(ONE_MUL_ONE, Some(ONE)); + const ONE_CHECKED_MUL_ONE : Option<Duration> = ONE.checked_mul(1); + assert_eq!(ONE_CHECKED_MUL_ONE, Some(ONE)); - const MAX_MUL_TWO : Option<Duration> = MAX.checked_mul(2); - assert_eq!(MAX_MUL_TWO, None); + const MAX_CHECKED_MUL_TWO : Option<Duration> = MAX.checked_mul(2); + assert_eq!(MAX_CHECKED_MUL_TWO, None); - const ONE_DIV_ONE : Option<Duration> = ONE.checked_div(1); - assert_eq!(ONE_DIV_ONE, Some(ONE)); + const ONE_CHECKED_DIV_ONE : Option<Duration> = ONE.checked_div(1); + assert_eq!(ONE_CHECKED_DIV_ONE, Some(ONE)); - const ONE_DIV_ZERO : Option<Duration> = ONE.checked_div(0); - assert_eq!(ONE_DIV_ZERO, None); + const ONE_CHECKED_DIV_ZERO : Option<Duration> = ONE.checked_div(0); + assert_eq!(ONE_CHECKED_DIV_ZERO, None); const MAX_AS_F32 : f32 = MAX.as_secs_f32(); assert_eq!(MAX_AS_F32, 18446744000000000000.0_f32); @@ -50,6 +51,15 @@ fn duration() { const ONE_AS_F64 : f64 = ONE.div_duration_f64(ONE); assert_eq!(ONE_AS_F64, 1.0_f64); + + const MAX_SATURATING_ADD_ONE : Duration = MAX.saturating_add(ONE); + assert_eq!(MAX_SATURATING_ADD_ONE, MAX); + + const ZERO_SATURATING_SUB_ONE : Duration = ZERO.saturating_sub(ONE); + assert_eq!(ZERO_SATURATING_SUB_ONE, ZERO); + + const MAX_SATURATING_MUL_TWO : Duration = MAX.saturating_mul(2); + assert_eq!(MAX_SATURATING_MUL_TWO, MAX); } fn main() { diff --git a/src/test/ui/consts/is_ascii.rs b/src/test/ui/consts/is_ascii.rs deleted file mode 100644 index d8424549f93..00000000000 --- a/src/test/ui/consts/is_ascii.rs +++ /dev/null @@ -1,15 +0,0 @@ -// run-pass - -static X: bool = 'a'.is_ascii(); -static Y: bool = 'ä'.is_ascii(); - -static BX: bool = b'a'.is_ascii(); -static BY: bool = 192u8.is_ascii(); - -fn main() { - assert!(X); - assert!(!Y); - - assert!(BX); - assert!(!BY); -} diff --git a/src/test/ui/consts/promote-no-mut.rs b/src/test/ui/consts/promote-no-mut.rs new file mode 100644 index 00000000000..fb57c8bb934 --- /dev/null +++ b/src/test/ui/consts/promote-no-mut.rs @@ -0,0 +1,10 @@ +// ignore-tidy-linelength +// We do not promote mutable references. +static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]); //~ ERROR temporary value dropped while borrowed + +static mut TEST2: &'static mut [i32] = { + let x = &mut [1,2,3]; //~ ERROR temporary value dropped while borrowed + x +}; + +fn main() {} diff --git a/src/test/ui/consts/promote-no-mut.stderr b/src/test/ui/consts/promote-no-mut.stderr new file mode 100644 index 00000000000..49d96546ada --- /dev/null +++ b/src/test/ui/consts/promote-no-mut.stderr @@ -0,0 +1,23 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-no-mut.rs:3:50 + | +LL | static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]); + | ----------^^^^^^^^^- + | | | | + | | | temporary value is freed at the end of this statement + | | creates a temporary which is freed while still in use + | using this value as a static requires that borrow lasts for `'static` + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-no-mut.rs:6:18 + | +LL | let x = &mut [1,2,3]; + | ^^^^^^^ creates a temporary which is freed while still in use +LL | x + | - using this value as a static requires that borrow lasts for `'static` +LL | }; + | - temporary value is freed at the end of this statement + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/promotion-mutable-ref.rs b/src/test/ui/consts/promotion-mutable-ref.rs new file mode 100644 index 00000000000..d103c5a9d23 --- /dev/null +++ b/src/test/ui/consts/promotion-mutable-ref.rs @@ -0,0 +1,17 @@ +// run-pass +#![feature(const_mut_refs)] + +static mut TEST: i32 = { + // We must not promote this, as CTFE needs to be able to mutate it later. + let x = &mut [1,2,3]; + x[0] += 1; + x[0] +}; + +// This still works -- it's not done via promotion. +#[allow(unused)] +static mut TEST2: &'static mut [i32] = &mut [0,1,2]; + +fn main() { + assert_eq!(unsafe { TEST }, 2); +} diff --git a/src/test/ui/consts/std/net/ipv4.rs b/src/test/ui/consts/std/net/ipv4.rs deleted file mode 100644 index 8c676999ae7..00000000000 --- a/src/test/ui/consts/std/net/ipv4.rs +++ /dev/null @@ -1,58 +0,0 @@ -// run-pass - -#![feature(ip)] -#![feature(const_ipv4)] - -use std::net::{Ipv4Addr, Ipv6Addr}; - -fn main() { - const IP_ADDRESS: Ipv4Addr = Ipv4Addr::new(127, 0, 0, 1); - assert_eq!(IP_ADDRESS, Ipv4Addr::LOCALHOST); - - const OCTETS: [u8; 4] = IP_ADDRESS.octets(); - assert_eq!(OCTETS, [127, 0, 0, 1]); - - const IS_UNSPECIFIED : bool = IP_ADDRESS.is_unspecified(); - assert!(!IS_UNSPECIFIED); - - const IS_LOOPBACK : bool = IP_ADDRESS.is_loopback(); - assert!(IS_LOOPBACK); - - const IS_PRIVATE : bool = IP_ADDRESS.is_private(); - assert!(!IS_PRIVATE); - - const IS_LINK_LOCAL : bool = IP_ADDRESS.is_link_local(); - assert!(!IS_LINK_LOCAL); - - const IS_GLOBAL : bool = IP_ADDRESS.is_global(); - assert!(!IS_GLOBAL); - - const IS_SHARED : bool = IP_ADDRESS.is_shared(); - assert!(!IS_SHARED); - - const IS_IETF_PROTOCOL_ASSIGNMENT : bool = IP_ADDRESS.is_ietf_protocol_assignment(); - assert!(!IS_IETF_PROTOCOL_ASSIGNMENT); - - const IS_BENCHMARKING : bool = IP_ADDRESS.is_benchmarking(); - assert!(!IS_BENCHMARKING); - - const IS_RESERVED : bool = IP_ADDRESS.is_reserved(); - assert!(!IS_RESERVED); - - const IS_MULTICAST : bool = IP_ADDRESS.is_multicast(); - assert!(!IS_MULTICAST); - - const IS_BROADCAST : bool = IP_ADDRESS.is_broadcast(); - assert!(!IS_BROADCAST); - - const IS_DOCUMENTATION : bool = IP_ADDRESS.is_documentation(); - assert!(!IS_DOCUMENTATION); - - const IP_V6_COMPATIBLE : Ipv6Addr = IP_ADDRESS.to_ipv6_compatible(); - assert_eq!(IP_V6_COMPATIBLE, - Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 1])); - - const IP_V6_MAPPED : Ipv6Addr = IP_ADDRESS.to_ipv6_mapped(); - assert_eq!(IP_V6_MAPPED, - Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 127, 0, 0, 1])); -} diff --git a/src/test/ui/consts/std/net/ipv6.rs b/src/test/ui/consts/std/net/ipv6.rs deleted file mode 100644 index e3841c38c22..00000000000 --- a/src/test/ui/consts/std/net/ipv6.rs +++ /dev/null @@ -1,53 +0,0 @@ -// run-pass - -#![feature(ip)] -#![feature(const_ipv6)] - -use std::net::{Ipv4Addr, Ipv6Addr, Ipv6MulticastScope}; - -fn main() { - const IP_ADDRESS : Ipv6Addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); - assert_eq!(IP_ADDRESS, Ipv6Addr::LOCALHOST); - - const SEGMENTS : [u16; 8] = IP_ADDRESS.segments(); - assert_eq!(SEGMENTS, [0 ,0 ,0 ,0 ,0 ,0 ,0, 1]); - - const OCTETS : [u8; 16] = IP_ADDRESS.octets(); - assert_eq!(OCTETS, [0 ,0 ,0 ,0 ,0 ,0 ,0, 0 ,0 ,0 ,0 ,0 ,0 ,0, 0, 1]); - - const IS_UNSPECIFIED : bool = IP_ADDRESS.is_unspecified(); - assert!(!IS_UNSPECIFIED); - - const IS_LOOPBACK : bool = IP_ADDRESS.is_loopback(); - assert!(IS_LOOPBACK); - - const IS_GLOBAL : bool = IP_ADDRESS.is_global(); - assert!(!IS_GLOBAL); - - const IS_UNIQUE_LOCAL : bool = IP_ADDRESS.is_unique_local(); - assert!(!IS_UNIQUE_LOCAL); - - const IS_UNICAST_LINK_LOCAL_STRICT : bool = IP_ADDRESS.is_unicast_link_local_strict(); - assert!(!IS_UNICAST_LINK_LOCAL_STRICT); - - const IS_UNICAST_LINK_LOCAL : bool = IP_ADDRESS.is_unicast_link_local(); - assert!(!IS_UNICAST_LINK_LOCAL); - - const IS_UNICAST_SITE_LOCAL : bool = IP_ADDRESS.is_unicast_site_local(); - assert!(!IS_UNICAST_SITE_LOCAL); - - const IS_DOCUMENTATION : bool = IP_ADDRESS.is_documentation(); - assert!(!IS_DOCUMENTATION); - - const IS_UNICAST_GLOBAL : bool = IP_ADDRESS.is_unicast_global(); - assert!(!IS_UNICAST_GLOBAL); - - const MULTICAST_SCOPE : Option<Ipv6MulticastScope> = IP_ADDRESS.multicast_scope(); - assert_eq!(MULTICAST_SCOPE, None); - - const IS_MULTICAST : bool = IP_ADDRESS.is_multicast(); - assert!(!IS_MULTICAST); - - const IP_V4 : Option<Ipv4Addr> = IP_ADDRESS.to_ipv4(); - assert_eq!(IP_V4.unwrap(), Ipv4Addr::new(0, 0, 0, 1)); -} diff --git a/src/test/ui/derived-errors/issue-31997-1.stderr b/src/test/ui/derived-errors/issue-31997-1.stderr index 229c5c9e80f..6d177666ed0 100644 --- a/src/test/ui/derived-errors/issue-31997-1.stderr +++ b/src/test/ui/derived-errors/issue-31997-1.stderr @@ -1,4 +1,4 @@ -error[E0433]: failed to resolve: use of undeclared type or module `HashMap` +error[E0433]: failed to resolve: use of undeclared type `HashMap` --> $DIR/issue-31997-1.rs:20:19 | LL | let mut map = HashMap::new(); diff --git a/src/test/ui/derives/derive-on-trait-item-or-impl-item.stderr b/src/test/ui/derives/derive-on-trait-item-or-impl-item.stderr index b3aa886cd49..e892d3f0863 100644 --- a/src/test/ui/derives/derive-on-trait-item-or-impl-item.stderr +++ b/src/test/ui/derives/derive-on-trait-item-or-impl-item.stderr @@ -1,10 +1,10 @@ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/derive-on-trait-item-or-impl-item.rs:2:5 | LL | #[derive(Clone)] | ^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/derive-on-trait-item-or-impl-item.rs:10:5 | LL | #[derive(Clone)] @@ -12,3 +12,4 @@ LL | #[derive(Clone)] error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/derives/deriving-non-type.stderr b/src/test/ui/derives/deriving-non-type.stderr index 563e76dc609..8c9daf4d4b3 100644 --- a/src/test/ui/derives/deriving-non-type.stderr +++ b/src/test/ui/derives/deriving-non-type.stderr @@ -1,52 +1,52 @@ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:5:1 | LL | #[derive(PartialEq)] | ^^^^^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:8:1 | LL | #[derive(PartialEq)] | ^^^^^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:11:1 | LL | #[derive(PartialEq)] | ^^^^^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:14:1 | LL | #[derive(PartialEq)] | ^^^^^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:17:1 | LL | #[derive(PartialEq)] | ^^^^^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:20:1 | LL | #[derive(PartialEq)] | ^^^^^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:23:1 | LL | #[derive(PartialEq)] | ^^^^^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:26:1 | LL | #[derive(PartialEq)] | ^^^^^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:29:1 | LL | #[derive(PartialEq)] @@ -54,3 +54,4 @@ LL | #[derive(PartialEq)] error: aborting due to 9 previous errors +For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/dyn-trait-compatibility.rs b/src/test/ui/dyn-trait-compatibility.rs index 2a1cea6c348..d2b02cc2af5 100644 --- a/src/test/ui/dyn-trait-compatibility.rs +++ b/src/test/ui/dyn-trait-compatibility.rs @@ -1,7 +1,7 @@ type A0 = dyn; //~^ ERROR cannot find type `dyn` in this scope type A1 = dyn::dyn; -//~^ ERROR use of undeclared type or module `dyn` +//~^ ERROR use of undeclared crate or module `dyn` type A2 = dyn<dyn, dyn>; //~^ ERROR cannot find type `dyn` in this scope //~| ERROR cannot find type `dyn` in this scope @@ -9,6 +9,6 @@ type A2 = dyn<dyn, dyn>; type A3 = dyn<<dyn as dyn>::dyn>; //~^ ERROR cannot find type `dyn` in this scope //~| ERROR cannot find type `dyn` in this scope -//~| ERROR use of undeclared type or module `dyn` +//~| ERROR use of undeclared crate or module `dyn` fn main() {} diff --git a/src/test/ui/dyn-trait-compatibility.stderr b/src/test/ui/dyn-trait-compatibility.stderr index 8fe8ceb4d0a..9218ae9d5da 100644 --- a/src/test/ui/dyn-trait-compatibility.stderr +++ b/src/test/ui/dyn-trait-compatibility.stderr @@ -1,14 +1,14 @@ -error[E0433]: failed to resolve: use of undeclared type or module `dyn` +error[E0433]: failed to resolve: use of undeclared crate or module `dyn` --> $DIR/dyn-trait-compatibility.rs:3:11 | LL | type A1 = dyn::dyn; - | ^^^ use of undeclared type or module `dyn` + | ^^^ use of undeclared crate or module `dyn` -error[E0433]: failed to resolve: use of undeclared type or module `dyn` +error[E0433]: failed to resolve: use of undeclared crate or module `dyn` --> $DIR/dyn-trait-compatibility.rs:9:23 | LL | type A3 = dyn<<dyn as dyn>::dyn>; - | ^^^ use of undeclared type or module `dyn` + | ^^^ use of undeclared crate or module `dyn` error[E0412]: cannot find type `dyn` in this scope --> $DIR/dyn-trait-compatibility.rs:1:11 diff --git a/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs b/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs index 5a528379b04..cdc1db4c0b4 100644 --- a/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs +++ b/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs @@ -1,5 +1,4 @@ // run-pass - #![feature(arbitrary_enum_discriminant, core_intrinsics)] extern crate core; @@ -9,6 +8,8 @@ use core::intrinsics::discriminant_value; enum MyWeirdOption<T> { None = 0, Some(T) = core::mem::size_of::<*mut T>(), + //~^ WARN cannot use constants which depend on generic parameters in types + //~| WARN this was previously accepted by the compiler but is being phased out } fn main() { diff --git a/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.stderr b/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.stderr new file mode 100644 index 00000000000..906927e705e --- /dev/null +++ b/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.stderr @@ -0,0 +1,12 @@ +warning: cannot use constants which depend on generic parameters in types + --> $DIR/issue-70453-polymorphic-ctfe.rs:10:15 + | +LL | Some(T) = core::mem::size_of::<*mut T>(), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(const_evaluatable_unchecked)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #76200 <https://github.com/rust-lang/rust/issues/76200> + +warning: 1 warning emitted + diff --git a/src/test/ui/error-codes/E0017.rs b/src/test/ui/error-codes/E0017.rs index 818dec1207b..54d3cc54a84 100644 --- a/src/test/ui/error-codes/E0017.rs +++ b/src/test/ui/error-codes/E0017.rs @@ -3,9 +3,11 @@ const C: i32 = 2; static mut M: i32 = 3; const CR: &'static mut i32 = &mut C; //~ ERROR E0764 + //~| WARN taking a mutable static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0764 //~| ERROR E0019 //~| ERROR cannot borrow static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0764 + //~| WARN taking a mutable static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; //~ ERROR E0764 fn main() {} diff --git a/src/test/ui/error-codes/E0017.stderr b/src/test/ui/error-codes/E0017.stderr index c1d96de1dca..40ef6bd97b3 100644 --- a/src/test/ui/error-codes/E0017.stderr +++ b/src/test/ui/error-codes/E0017.stderr @@ -1,3 +1,18 @@ +warning: taking a mutable reference to a `const` item + --> $DIR/E0017.rs:5:30 + | +LL | const CR: &'static mut i32 = &mut C; + | ^^^^^^ + | + = note: `#[warn(const_item_mutation)]` on by default + = note: each usage of a `const` item creates a new temporary + = note: the mutable reference will refer to this temporary, not the original `const` item +note: `const` item defined here + --> $DIR/E0017.rs:2:1 + | +LL | const C: i32 = 2; + | ^^^^^^^^^^^^^^^^^ + error[E0764]: mutable references are not allowed in constants --> $DIR/E0017.rs:5:30 | @@ -5,7 +20,7 @@ LL | const CR: &'static mut i32 = &mut C; | ^^^^^^ `&mut` is only allowed in `const fn` error[E0019]: static contains unimplemented expression type - --> $DIR/E0017.rs:6:39 + --> $DIR/E0017.rs:7:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ @@ -13,30 +28,44 @@ LL | static STATIC_REF: &'static mut i32 = &mut X; = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0764]: mutable references are not allowed in statics - --> $DIR/E0017.rs:6:39 + --> $DIR/E0017.rs:7:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ `&mut` is only allowed in `const fn` error[E0596]: cannot borrow immutable static item `X` as mutable - --> $DIR/E0017.rs:6:39 + --> $DIR/E0017.rs:7:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ cannot borrow as mutable +warning: taking a mutable reference to a `const` item + --> $DIR/E0017.rs:10:38 + | +LL | static CONST_REF: &'static mut i32 = &mut C; + | ^^^^^^ + | + = note: each usage of a `const` item creates a new temporary + = note: the mutable reference will refer to this temporary, not the original `const` item +note: `const` item defined here + --> $DIR/E0017.rs:2:1 + | +LL | const C: i32 = 2; + | ^^^^^^^^^^^^^^^^^ + error[E0764]: mutable references are not allowed in statics - --> $DIR/E0017.rs:9:38 + --> $DIR/E0017.rs:10:38 | LL | static CONST_REF: &'static mut i32 = &mut C; | ^^^^^^ `&mut` is only allowed in `const fn` error[E0764]: mutable references are not allowed in statics - --> $DIR/E0017.rs:10:52 + --> $DIR/E0017.rs:12:52 | LL | static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; | ^^^^^^ `&mut` is only allowed in `const fn` -error: aborting due to 6 previous errors +error: aborting due to 6 previous errors; 2 warnings emitted Some errors have detailed explanations: E0019, E0596, E0764. For more information about an error, try `rustc --explain E0019`. diff --git a/src/test/ui/error-codes/E0388.rs b/src/test/ui/error-codes/E0388.rs index 13131017c2e..8ad586bb30f 100644 --- a/src/test/ui/error-codes/E0388.rs +++ b/src/test/ui/error-codes/E0388.rs @@ -2,9 +2,11 @@ static X: i32 = 1; const C: i32 = 2; const CR: &'static mut i32 = &mut C; //~ ERROR E0764 + //~| WARN taking a mutable static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0019 //~| ERROR cannot borrow //~| ERROR E0764 static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0764 + //~| WARN taking a mutable fn main() {} diff --git a/src/test/ui/error-codes/E0388.stderr b/src/test/ui/error-codes/E0388.stderr index f09100bac43..39bc717ceec 100644 --- a/src/test/ui/error-codes/E0388.stderr +++ b/src/test/ui/error-codes/E0388.stderr @@ -1,3 +1,18 @@ +warning: taking a mutable reference to a `const` item + --> $DIR/E0388.rs:4:30 + | +LL | const CR: &'static mut i32 = &mut C; + | ^^^^^^ + | + = note: `#[warn(const_item_mutation)]` on by default + = note: each usage of a `const` item creates a new temporary + = note: the mutable reference will refer to this temporary, not the original `const` item +note: `const` item defined here + --> $DIR/E0388.rs:2:1 + | +LL | const C: i32 = 2; + | ^^^^^^^^^^^^^^^^^ + error[E0764]: mutable references are not allowed in constants --> $DIR/E0388.rs:4:30 | @@ -5,7 +20,7 @@ LL | const CR: &'static mut i32 = &mut C; | ^^^^^^ `&mut` is only allowed in `const fn` error[E0019]: static contains unimplemented expression type - --> $DIR/E0388.rs:5:39 + --> $DIR/E0388.rs:6:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ @@ -13,24 +28,38 @@ LL | static STATIC_REF: &'static mut i32 = &mut X; = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0764]: mutable references are not allowed in statics - --> $DIR/E0388.rs:5:39 + --> $DIR/E0388.rs:6:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ `&mut` is only allowed in `const fn` error[E0596]: cannot borrow immutable static item `X` as mutable - --> $DIR/E0388.rs:5:39 + --> $DIR/E0388.rs:6:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ cannot borrow as mutable +warning: taking a mutable reference to a `const` item + --> $DIR/E0388.rs:9:38 + | +LL | static CONST_REF: &'static mut i32 = &mut C; + | ^^^^^^ + | + = note: each usage of a `const` item creates a new temporary + = note: the mutable reference will refer to this temporary, not the original `const` item +note: `const` item defined here + --> $DIR/E0388.rs:2:1 + | +LL | const C: i32 = 2; + | ^^^^^^^^^^^^^^^^^ + error[E0764]: mutable references are not allowed in statics - --> $DIR/E0388.rs:8:38 + --> $DIR/E0388.rs:9:38 | LL | static CONST_REF: &'static mut i32 = &mut C; | ^^^^^^ `&mut` is only allowed in `const fn` -error: aborting due to 5 previous errors +error: aborting due to 5 previous errors; 2 warnings emitted Some errors have detailed explanations: E0019, E0596, E0764. For more information about an error, try `rustc --explain E0019`. diff --git a/src/test/ui/error-codes/E0433.stderr b/src/test/ui/error-codes/E0433.stderr index d9555e1fcf7..265d8885c8d 100644 --- a/src/test/ui/error-codes/E0433.stderr +++ b/src/test/ui/error-codes/E0433.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `NonExistingMap` +error[E0433]: failed to resolve: use of undeclared type `NonExistingMap` --> $DIR/E0433.rs:2:15 | LL | let map = NonExistingMap::new(); - | ^^^^^^^^^^^^^^ use of undeclared type or module `NonExistingMap` + | ^^^^^^^^^^^^^^ use of undeclared type `NonExistingMap` error: aborting due to previous error diff --git a/src/test/ui/export-fully-qualified.rs b/src/test/ui/export-fully-qualified.rs index 99cb558908c..40f26c7095f 100644 --- a/src/test/ui/export-fully-qualified.rs +++ b/src/test/ui/export-fully-qualified.rs @@ -1,9 +1,11 @@ +// ignore-tidy-linelength + // In this test baz isn't resolved when called as foo.baz even though // it's called from inside foo. This is somewhat surprising and may // want to change eventually. mod foo { - pub fn bar() { foo::baz(); } //~ ERROR failed to resolve: use of undeclared type or module `foo` + pub fn bar() { foo::baz(); } //~ ERROR failed to resolve: use of undeclared crate or module `foo` fn baz() { } } diff --git a/src/test/ui/export-fully-qualified.stderr b/src/test/ui/export-fully-qualified.stderr index c2ec1600868..a8af0c7c9b8 100644 --- a/src/test/ui/export-fully-qualified.stderr +++ b/src/test/ui/export-fully-qualified.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `foo` - --> $DIR/export-fully-qualified.rs:6:20 +error[E0433]: failed to resolve: use of undeclared crate or module `foo` + --> $DIR/export-fully-qualified.rs:8:20 | LL | pub fn bar() { foo::baz(); } - | ^^^ use of undeclared type or module `foo` + | ^^^ use of undeclared crate or module `foo` error: aborting due to previous error diff --git a/src/test/ui/export2.rs b/src/test/ui/export2.rs index 811d96f26d0..64ebeddffa8 100644 --- a/src/test/ui/export2.rs +++ b/src/test/ui/export2.rs @@ -1,5 +1,5 @@ mod foo { - pub fn x() { bar::x(); } //~ ERROR failed to resolve: use of undeclared type or module `bar` + pub fn x() { bar::x(); } //~ ERROR failed to resolve: use of undeclared crate or module `bar` } mod bar { diff --git a/src/test/ui/export2.stderr b/src/test/ui/export2.stderr index e0cd4404d37..7cf47d0764b 100644 --- a/src/test/ui/export2.stderr +++ b/src/test/ui/export2.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `bar` +error[E0433]: failed to resolve: use of undeclared crate or module `bar` --> $DIR/export2.rs:2:18 | LL | pub fn x() { bar::x(); } - | ^^^ use of undeclared type or module `bar` + | ^^^ use of undeclared crate or module `bar` error: aborting due to previous error diff --git a/src/test/ui/extern-flag/multiple-opts.stderr b/src/test/ui/extern-flag/multiple-opts.stderr index 3bf73d11cfd..5088fb1c4d2 100644 --- a/src/test/ui/extern-flag/multiple-opts.stderr +++ b/src/test/ui/extern-flag/multiple-opts.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `somedep` +error[E0433]: failed to resolve: use of undeclared crate or module `somedep` --> $DIR/multiple-opts.rs:19:5 | LL | somedep::somefun(); - | ^^^^^^^ use of undeclared type or module `somedep` + | ^^^^^^^ use of undeclared crate or module `somedep` error: aborting due to previous error diff --git a/src/test/ui/extern-flag/noprelude.stderr b/src/test/ui/extern-flag/noprelude.stderr index beb9200ddda..57878721683 100644 --- a/src/test/ui/extern-flag/noprelude.stderr +++ b/src/test/ui/extern-flag/noprelude.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `somedep` +error[E0433]: failed to resolve: use of undeclared crate or module `somedep` --> $DIR/noprelude.rs:6:5 | LL | somedep::somefun(); - | ^^^^^^^ use of undeclared type or module `somedep` + | ^^^^^^^ use of undeclared crate or module `somedep` error: aborting due to previous error diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-derive.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-derive.stderr index db29a2bddd3..ffec76f409e 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-derive.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-derive.stderr @@ -1,28 +1,28 @@ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43106-gating-of-derive.rs:4:1 | LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43106-gating-of-derive.rs:7:17 | LL | mod inner { #![derive(Debug)] } | ^^^^^^^^^^^^^^^^^ help: try an outer attribute: `#[derive(Debug)]` -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43106-gating-of-derive.rs:10:5 | LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43106-gating-of-derive.rs:23:5 | LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43106-gating-of-derive.rs:27:5 | LL | #[derive(Debug)] @@ -30,3 +30,4 @@ LL | #[derive(Debug)] error: aborting due to 5 previous errors +For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/generator/static-generators.rs b/src/test/ui/generator/static-generators.rs index 3980766c428..d098bf1e688 100644 --- a/src/test/ui/generator/static-generators.rs +++ b/src/test/ui/generator/static-generators.rs @@ -12,7 +12,7 @@ fn main() { yield; assert_eq!(b as *const _, &a as *const _); }; - // Safety: We shadow the original generator variable so have no safe API to + // SAFETY: We shadow the original generator variable so have no safe API to // move it after this point. let mut generator = unsafe { Pin::new_unchecked(&mut generator) }; assert_eq!(generator.as_mut().resume(()), GeneratorState::Yielded(())); diff --git a/src/test/ui/hygiene/extern-prelude-from-opaque-fail.rs b/src/test/ui/hygiene/extern-prelude-from-opaque-fail.rs index 06d62656e95..571017df4d7 100644 --- a/src/test/ui/hygiene/extern-prelude-from-opaque-fail.rs +++ b/src/test/ui/hygiene/extern-prelude-from-opaque-fail.rs @@ -9,7 +9,7 @@ macro a() { mod u { // Late resolution. fn f() { my_core::mem::drop(0); } - //~^ ERROR failed to resolve: use of undeclared type or module `my_core` + //~^ ERROR failed to resolve: use of undeclared crate or module `my_core` } } @@ -22,7 +22,7 @@ mod v { mod u { // Late resolution. fn f() { my_core::mem::drop(0); } - //~^ ERROR failed to resolve: use of undeclared type or module `my_core` + //~^ ERROR failed to resolve: use of undeclared crate or module `my_core` } fn main() {} diff --git a/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr b/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr index b9e05c84a8a..d3e6021a1ed 100644 --- a/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr +++ b/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr @@ -18,22 +18,22 @@ LL | a!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0433]: failed to resolve: use of undeclared type or module `my_core` +error[E0433]: failed to resolve: use of undeclared crate or module `my_core` --> $DIR/extern-prelude-from-opaque-fail.rs:11:18 | LL | fn f() { my_core::mem::drop(0); } - | ^^^^^^^ use of undeclared type or module `my_core` + | ^^^^^^^ use of undeclared crate or module `my_core` ... LL | a!(); | ----- in this macro invocation | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0433]: failed to resolve: use of undeclared type or module `my_core` +error[E0433]: failed to resolve: use of undeclared crate or module `my_core` --> $DIR/extern-prelude-from-opaque-fail.rs:24:14 | LL | fn f() { my_core::mem::drop(0); } - | ^^^^^^^ use of undeclared type or module `my_core` + | ^^^^^^^ use of undeclared crate or module `my_core` error: aborting due to 4 previous errors diff --git a/src/test/ui/hygiene/no_implicit_prelude.stderr b/src/test/ui/hygiene/no_implicit_prelude.stderr index 990210ffb6b..3c0c0450774 100644 --- a/src/test/ui/hygiene/no_implicit_prelude.stderr +++ b/src/test/ui/hygiene/no_implicit_prelude.stderr @@ -6,7 +6,7 @@ LL | assert_eq!(0, 0); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0433]: failed to resolve: use of undeclared type or module `Vec` +error[E0433]: failed to resolve: use of undeclared type `Vec` --> $DIR/no_implicit_prelude.rs:11:9 | LL | fn f() { ::bar::m!(); } diff --git a/src/test/ui/impl-trait/issue-56445.rs b/src/test/ui/impl-trait/issue-56445.rs index a34d7bae3a6..6dd1648c9b8 100644 --- a/src/test/ui/impl-trait/issue-56445.rs +++ b/src/test/ui/impl-trait/issue-56445.rs @@ -5,8 +5,7 @@ use std::marker::PhantomData; -pub struct S<'a> -{ +pub struct S<'a> { pub m1: PhantomData<&'a u8>, pub m2: [u8; S::size()], } diff --git a/src/test/ui/impl-trait/issue-72911.stderr b/src/test/ui/impl-trait/issue-72911.stderr index 55fd38f7c0d..17748ae4277 100644 --- a/src/test/ui/impl-trait/issue-72911.stderr +++ b/src/test/ui/impl-trait/issue-72911.stderr @@ -1,14 +1,14 @@ -error[E0433]: failed to resolve: use of undeclared type or module `foo` +error[E0433]: failed to resolve: use of undeclared crate or module `foo` --> $DIR/issue-72911.rs:12:33 | LL | fn gather_from_file(dir_entry: &foo::MissingItem) -> impl Iterator<Item = Lint> { - | ^^^ use of undeclared type or module `foo` + | ^^^ use of undeclared crate or module `foo` -error[E0433]: failed to resolve: use of undeclared type or module `foo` +error[E0433]: failed to resolve: use of undeclared crate or module `foo` --> $DIR/issue-72911.rs:17:41 | LL | fn lint_files() -> impl Iterator<Item = foo::MissingItem> { - | ^^^ use of undeclared type or module `foo` + | ^^^ use of undeclared crate or module `foo` error[E0720]: cannot resolve opaque type --> $DIR/issue-72911.rs:7:24 diff --git a/src/test/ui/imports/extern-prelude-extern-crate-fail.rs b/src/test/ui/imports/extern-prelude-extern-crate-fail.rs index 6b70efe0c44..4a0c6120201 100644 --- a/src/test/ui/imports/extern-prelude-extern-crate-fail.rs +++ b/src/test/ui/imports/extern-prelude-extern-crate-fail.rs @@ -1,3 +1,5 @@ +// ignore-tidy-linelength + // aux-build:two_macros.rs // compile-flags:--extern non_existent @@ -7,7 +9,7 @@ mod n { mod m { fn check() { - two_macros::m!(); //~ ERROR failed to resolve: use of undeclared type or module `two_macros` + two_macros::m!(); //~ ERROR failed to resolve: use of undeclared crate or module `two_macros` } } diff --git a/src/test/ui/imports/extern-prelude-extern-crate-fail.stderr b/src/test/ui/imports/extern-prelude-extern-crate-fail.stderr index f7544306d34..2d7a1bf468e 100644 --- a/src/test/ui/imports/extern-prelude-extern-crate-fail.stderr +++ b/src/test/ui/imports/extern-prelude-extern-crate-fail.stderr @@ -1,5 +1,5 @@ error: macro-expanded `extern crate` items cannot shadow names passed with `--extern` - --> $DIR/extern-prelude-extern-crate-fail.rs:16:9 + --> $DIR/extern-prelude-extern-crate-fail.rs:18:9 | LL | extern crate std as non_existent; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -9,11 +9,11 @@ LL | define_std_as_non_existent!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0433]: failed to resolve: use of undeclared type or module `two_macros` - --> $DIR/extern-prelude-extern-crate-fail.rs:10:9 +error[E0433]: failed to resolve: use of undeclared crate or module `two_macros` + --> $DIR/extern-prelude-extern-crate-fail.rs:12:9 | LL | two_macros::m!(); - | ^^^^^^^^^^ use of undeclared type or module `two_macros` + | ^^^^^^^^^^ use of undeclared crate or module `two_macros` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/auxiliary/issue-75907.rs b/src/test/ui/issues/auxiliary/issue-75907.rs new file mode 100644 index 00000000000..0b70452a24d --- /dev/null +++ b/src/test/ui/issues/auxiliary/issue-75907.rs @@ -0,0 +1,5 @@ +pub struct Bar(pub u8, u8, u8); + +pub fn make_bar() -> Bar { + Bar(1, 12, 10) +} diff --git a/src/test/ui/issues/issue-33293.rs b/src/test/ui/issues/issue-33293.rs index d3670374284..a6ef007d51f 100644 --- a/src/test/ui/issues/issue-33293.rs +++ b/src/test/ui/issues/issue-33293.rs @@ -1,6 +1,6 @@ fn main() { match 0 { aaa::bbb(_) => () - //~^ ERROR failed to resolve: use of undeclared type or module `aaa` + //~^ ERROR failed to resolve: use of undeclared crate or module `aaa` }; } diff --git a/src/test/ui/issues/issue-33293.stderr b/src/test/ui/issues/issue-33293.stderr index 6b7333f22fe..c8450f40042 100644 --- a/src/test/ui/issues/issue-33293.stderr +++ b/src/test/ui/issues/issue-33293.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `aaa` +error[E0433]: failed to resolve: use of undeclared crate or module `aaa` --> $DIR/issue-33293.rs:3:9 | LL | aaa::bbb(_) => () - | ^^^ use of undeclared type or module `aaa` + | ^^^ use of undeclared crate or module `aaa` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-36617.stderr b/src/test/ui/issues/issue-36617.stderr index 98b41b07ea9..586dcf2cea6 100644 --- a/src/test/ui/issues/issue-36617.stderr +++ b/src/test/ui/issues/issue-36617.stderr @@ -1,4 +1,4 @@ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-36617.rs:1:1 | LL | #![derive(Copy)] @@ -22,3 +22,4 @@ LL | #![derive(Copy)] error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/issues/issue-43023.stderr b/src/test/ui/issues/issue-43023.stderr index 206a51645fe..f5f51cdcd48 100644 --- a/src/test/ui/issues/issue-43023.stderr +++ b/src/test/ui/issues/issue-43023.stderr @@ -1,16 +1,16 @@ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43023.rs:4:5 | LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43023.rs:11:5 | LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43023.rs:16:5 | LL | #[derive(Debug)] @@ -18,3 +18,4 @@ LL | #[derive(Debug)] error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/issues/issue-49934-errors.stderr b/src/test/ui/issues/issue-49934-errors.stderr index 8778d88d0eb..3befb38a208 100644 --- a/src/test/ui/issues/issue-49934-errors.stderr +++ b/src/test/ui/issues/issue-49934-errors.stderr @@ -1,4 +1,4 @@ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-49934-errors.rs:1:8 | LL | fn foo<#[derive(Debug)] T>() { @@ -10,7 +10,7 @@ error: expected an inert attribute, found a derive macro LL | fn foo<#[derive(Debug)] T>() { | ^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-49934-errors.rs:5:9 | LL | #[derive(Debug)] @@ -24,3 +24,4 @@ LL | #[derive(Debug)] error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/issues/issue-75907.rs b/src/test/ui/issues/issue-75907.rs new file mode 100644 index 00000000000..8c155d9be35 --- /dev/null +++ b/src/test/ui/issues/issue-75907.rs @@ -0,0 +1,18 @@ +// Test for for diagnostic improvement issue #75907 + +mod foo { + pub(crate) struct Foo(u8); + pub(crate) struct Bar(pub u8, u8, Foo); + + pub(crate) fn make_bar() -> Bar { + Bar(1, 12, Foo(10)) + } +} + +use foo::{make_bar, Bar, Foo}; + +fn main() { + let Bar(x, y, Foo(z)) = make_bar(); + //~^ ERROR expected tuple struct + //~| ERROR expected tuple struct +} diff --git a/src/test/ui/issues/issue-75907.stderr b/src/test/ui/issues/issue-75907.stderr new file mode 100644 index 00000000000..65b9a51e01d --- /dev/null +++ b/src/test/ui/issues/issue-75907.stderr @@ -0,0 +1,29 @@ +error[E0532]: expected tuple struct or tuple variant, found struct `Bar` + --> $DIR/issue-75907.rs:15:9 + | +LL | let Bar(x, y, Foo(z)) = make_bar(); + | ^^^ + | +note: constructor is not visible here due to private fields + --> $DIR/issue-75907.rs:15:16 + | +LL | let Bar(x, y, Foo(z)) = make_bar(); + | ^ ^^^^^^ private field + | | + | private field + +error[E0532]: expected tuple struct or tuple variant, found struct `Foo` + --> $DIR/issue-75907.rs:15:19 + | +LL | let Bar(x, y, Foo(z)) = make_bar(); + | ^^^ + | +note: constructor is not visible here due to private fields + --> $DIR/issue-75907.rs:15:23 + | +LL | let Bar(x, y, Foo(z)) = make_bar(); + | ^ private field + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0532`. diff --git a/src/test/ui/issues/issue-75907_b.rs b/src/test/ui/issues/issue-75907_b.rs new file mode 100644 index 00000000000..fdd3bc6d724 --- /dev/null +++ b/src/test/ui/issues/issue-75907_b.rs @@ -0,0 +1,11 @@ +// Test for for diagnostic improvement issue #75907, extern crate +// aux-build:issue-75907.rs + +extern crate issue_75907 as a; + +use a::{make_bar, Bar}; + +fn main() { + let Bar(x, y, z) = make_bar(); + //~^ ERROR expected tuple struct +} diff --git a/src/test/ui/issues/issue-75907_b.stderr b/src/test/ui/issues/issue-75907_b.stderr new file mode 100644 index 00000000000..cdd21de6c33 --- /dev/null +++ b/src/test/ui/issues/issue-75907_b.stderr @@ -0,0 +1,9 @@ +error[E0532]: expected tuple struct or tuple variant, found struct `Bar` + --> $DIR/issue-75907_b.rs:9:9 + | +LL | let Bar(x, y, z) = make_bar(); + | ^^^ constructor is not visible here due to private fields + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0532`. diff --git a/src/test/ui/issues/issue-76077-1.fixed b/src/test/ui/issues/issue-76077-1.fixed new file mode 100644 index 00000000000..8103a7ca47d --- /dev/null +++ b/src/test/ui/issues/issue-76077-1.fixed @@ -0,0 +1,18 @@ +// run-rustfix +#![allow(dead_code, unused_variables)] + +pub mod foo { + #[derive(Default)] + pub struct Foo { invisible: bool, } + + #[derive(Default)] + pub struct Bar { pub visible: bool, invisible: bool, } +} + +fn main() { + let foo::Foo { .. } = foo::Foo::default(); + //~^ ERROR pattern requires `..` due to inaccessible fields + + let foo::Bar { visible, .. } = foo::Bar::default(); + //~^ ERROR pattern requires `..` due to inaccessible fields +} diff --git a/src/test/ui/issues/issue-76077-1.rs b/src/test/ui/issues/issue-76077-1.rs new file mode 100644 index 00000000000..730332853c1 --- /dev/null +++ b/src/test/ui/issues/issue-76077-1.rs @@ -0,0 +1,18 @@ +// run-rustfix +#![allow(dead_code, unused_variables)] + +pub mod foo { + #[derive(Default)] + pub struct Foo { invisible: bool, } + + #[derive(Default)] + pub struct Bar { pub visible: bool, invisible: bool, } +} + +fn main() { + let foo::Foo {} = foo::Foo::default(); + //~^ ERROR pattern requires `..` due to inaccessible fields + + let foo::Bar { visible } = foo::Bar::default(); + //~^ ERROR pattern requires `..` due to inaccessible fields +} diff --git a/src/test/ui/issues/issue-76077-1.stderr b/src/test/ui/issues/issue-76077-1.stderr new file mode 100644 index 00000000000..4557595529f --- /dev/null +++ b/src/test/ui/issues/issue-76077-1.stderr @@ -0,0 +1,24 @@ +error: pattern requires `..` due to inaccessible fields + --> $DIR/issue-76077-1.rs:13:9 + | +LL | let foo::Foo {} = foo::Foo::default(); + | ^^^^^^^^^^^ + | +help: ignore the inaccessible and unused fields + | +LL | let foo::Foo { .. } = foo::Foo::default(); + | ^^^^^^ + +error: pattern requires `..` due to inaccessible fields + --> $DIR/issue-76077-1.rs:16:9 + | +LL | let foo::Bar { visible } = foo::Bar::default(); + | ^^^^^^^^^^^^^^^^^^^^ + | +help: ignore the inaccessible and unused fields + | +LL | let foo::Bar { visible, .. } = foo::Bar::default(); + | ^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/issues/issue-76077.rs b/src/test/ui/issues/issue-76077.rs new file mode 100644 index 00000000000..1ecd37de2e1 --- /dev/null +++ b/src/test/ui/issues/issue-76077.rs @@ -0,0 +1,10 @@ +pub mod foo { + pub struct Foo { + you_cant_use_this_field: bool, + } +} + +fn main() { + foo::Foo {}; + //~^ ERROR cannot construct `Foo` with struct literal syntax due to inaccessible fields +} diff --git a/src/test/ui/issues/issue-76077.stderr b/src/test/ui/issues/issue-76077.stderr new file mode 100644 index 00000000000..d834ec5e0ed --- /dev/null +++ b/src/test/ui/issues/issue-76077.stderr @@ -0,0 +1,8 @@ +error: cannot construct `Foo` with struct literal syntax due to inaccessible fields + --> $DIR/issue-76077.rs:8:5 + | +LL | foo::Foo {}; + | ^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/lazy_normalization_consts/issue-73980.rs b/src/test/ui/lazy_normalization_consts/issue-73980.rs index 339b22c0b42..e10040652c7 100644 --- a/src/test/ui/lazy_normalization_consts/issue-73980.rs +++ b/src/test/ui/lazy_normalization_consts/issue-73980.rs @@ -10,5 +10,7 @@ impl<T: ?Sized> L<T> { } impl<T> X<T, [u8; L::<T>::S]> {} +//~^ WARN cannot use constants which depend on generic parameters +//~| WARN this was previously accepted by the compiler but is being phased out fn main() {} diff --git a/src/test/ui/lazy_normalization_consts/issue-73980.stderr b/src/test/ui/lazy_normalization_consts/issue-73980.stderr new file mode 100644 index 00000000000..5ed1ca362f4 --- /dev/null +++ b/src/test/ui/lazy_normalization_consts/issue-73980.stderr @@ -0,0 +1,12 @@ +warning: cannot use constants which depend on generic parameters in types + --> $DIR/issue-73980.rs:12:9 + | +LL | impl<T> X<T, [u8; L::<T>::S]> {} + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(const_evaluatable_unchecked)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #76200 <https://github.com/rust-lang/rust/issues/76200> + +warning: 1 warning emitted + diff --git a/src/test/ui/lint/lint-const-item-mutation.rs b/src/test/ui/lint/lint-const-item-mutation.rs new file mode 100644 index 00000000000..92d29a7dae4 --- /dev/null +++ b/src/test/ui/lint/lint-const-item-mutation.rs @@ -0,0 +1,21 @@ +// check-pass + +struct MyStruct { + field: bool, + inner_array: [char; 1], +} +impl MyStruct { + fn use_mut(&mut self) {} +} + +const ARRAY: [u8; 1] = [25]; +const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'] }; + +fn main() { + ARRAY[0] = 5; //~ WARN attempting to modify + MY_STRUCT.field = false; //~ WARN attempting to modify + MY_STRUCT.inner_array[0] = 'b'; //~ WARN attempting to modify + MY_STRUCT.use_mut(); //~ WARN taking + &mut MY_STRUCT; //~ WARN taking + (&mut MY_STRUCT).use_mut(); //~ WARN taking +} diff --git a/src/test/ui/lint/lint-const-item-mutation.stderr b/src/test/ui/lint/lint-const-item-mutation.stderr new file mode 100644 index 00000000000..2d8f2c49744 --- /dev/null +++ b/src/test/ui/lint/lint-const-item-mutation.stderr @@ -0,0 +1,89 @@ +warning: attempting to modify a `const` item + --> $DIR/lint-const-item-mutation.rs:15:5 + | +LL | ARRAY[0] = 5; + | ^^^^^^^^^^^^ + | + = note: `#[warn(const_item_mutation)]` on by default + = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified +note: `const` item defined here + --> $DIR/lint-const-item-mutation.rs:11:1 + | +LL | const ARRAY: [u8; 1] = [25]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: attempting to modify a `const` item + --> $DIR/lint-const-item-mutation.rs:16:5 + | +LL | MY_STRUCT.field = false; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified +note: `const` item defined here + --> $DIR/lint-const-item-mutation.rs:12:1 + | +LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'] }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: attempting to modify a `const` item + --> $DIR/lint-const-item-mutation.rs:17:5 + | +LL | MY_STRUCT.inner_array[0] = 'b'; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified +note: `const` item defined here + --> $DIR/lint-const-item-mutation.rs:12:1 + | +LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'] }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: taking a mutable reference to a `const` item + --> $DIR/lint-const-item-mutation.rs:18:5 + | +LL | MY_STRUCT.use_mut(); + | ^^^^^^^^^^^^^^^^^^^ + | + = note: each usage of a `const` item creates a new temporary + = note: the mutable reference will refer to this temporary, not the original `const` item +note: mutable reference created due to call to this method + --> $DIR/lint-const-item-mutation.rs:8:5 + | +LL | fn use_mut(&mut self) {} + | ^^^^^^^^^^^^^^^^^^^^^ +note: `const` item defined here + --> $DIR/lint-const-item-mutation.rs:12:1 + | +LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'] }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: taking a mutable reference to a `const` item + --> $DIR/lint-const-item-mutation.rs:19:5 + | +LL | &mut MY_STRUCT; + | ^^^^^^^^^^^^^^ + | + = note: each usage of a `const` item creates a new temporary + = note: the mutable reference will refer to this temporary, not the original `const` item +note: `const` item defined here + --> $DIR/lint-const-item-mutation.rs:12:1 + | +LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'] }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: taking a mutable reference to a `const` item + --> $DIR/lint-const-item-mutation.rs:20:5 + | +LL | (&mut MY_STRUCT).use_mut(); + | ^^^^^^^^^^^^^^^^ + | + = note: each usage of a `const` item creates a new temporary + = note: the mutable reference will refer to this temporary, not the original `const` item +note: `const` item defined here + --> $DIR/lint-const-item-mutation.rs:12:1 + | +LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'] }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 6 warnings emitted + diff --git a/src/test/ui/macros/builtin-prelude-no-accidents.rs b/src/test/ui/macros/builtin-prelude-no-accidents.rs index ac82f343acc..01691a82dd7 100644 --- a/src/test/ui/macros/builtin-prelude-no-accidents.rs +++ b/src/test/ui/macros/builtin-prelude-no-accidents.rs @@ -2,7 +2,7 @@ // because macros with the same names are in prelude. fn main() { - env::current_dir; //~ ERROR use of undeclared type or module `env` - type A = panic::PanicInfo; //~ ERROR use of undeclared type or module `panic` - type B = vec::Vec<u8>; //~ ERROR use of undeclared type or module `vec` + env::current_dir; //~ ERROR use of undeclared crate or module `env` + type A = panic::PanicInfo; //~ ERROR use of undeclared crate or module `panic` + type B = vec::Vec<u8>; //~ ERROR use of undeclared crate or module `vec` } diff --git a/src/test/ui/macros/builtin-prelude-no-accidents.stderr b/src/test/ui/macros/builtin-prelude-no-accidents.stderr index 914e906df58..56af618d484 100644 --- a/src/test/ui/macros/builtin-prelude-no-accidents.stderr +++ b/src/test/ui/macros/builtin-prelude-no-accidents.stderr @@ -1,20 +1,20 @@ -error[E0433]: failed to resolve: use of undeclared type or module `env` +error[E0433]: failed to resolve: use of undeclared crate or module `env` --> $DIR/builtin-prelude-no-accidents.rs:5:5 | LL | env::current_dir; - | ^^^ use of undeclared type or module `env` + | ^^^ use of undeclared crate or module `env` -error[E0433]: failed to resolve: use of undeclared type or module `panic` +error[E0433]: failed to resolve: use of undeclared crate or module `panic` --> $DIR/builtin-prelude-no-accidents.rs:6:14 | LL | type A = panic::PanicInfo; - | ^^^^^ use of undeclared type or module `panic` + | ^^^^^ use of undeclared crate or module `panic` -error[E0433]: failed to resolve: use of undeclared type or module `vec` +error[E0433]: failed to resolve: use of undeclared crate or module `vec` --> $DIR/builtin-prelude-no-accidents.rs:7:14 | LL | type B = vec::Vec<u8>; - | ^^^ use of undeclared type or module `vec` + | ^^^ use of undeclared crate or module `vec` error: aborting due to 3 previous errors diff --git a/src/test/ui/macros/macro-inner-attributes.rs b/src/test/ui/macros/macro-inner-attributes.rs index 56a90231566..a8cda23075b 100644 --- a/src/test/ui/macros/macro-inner-attributes.rs +++ b/src/test/ui/macros/macro-inner-attributes.rs @@ -15,6 +15,6 @@ test!(b, #[rustc_dummy] fn main() { a::bar(); - //~^ ERROR failed to resolve: use of undeclared type or module `a` + //~^ ERROR failed to resolve: use of undeclared crate or module `a` b::bar(); } diff --git a/src/test/ui/macros/macro-inner-attributes.stderr b/src/test/ui/macros/macro-inner-attributes.stderr index 5e20f106a95..8223220d9a4 100644 --- a/src/test/ui/macros/macro-inner-attributes.stderr +++ b/src/test/ui/macros/macro-inner-attributes.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `a` +error[E0433]: failed to resolve: use of undeclared crate or module `a` --> $DIR/macro-inner-attributes.rs:17:5 | LL | a::bar(); - | ^ use of undeclared type or module `a` + | ^ use of undeclared crate or module `a` error: aborting due to previous error diff --git a/src/test/ui/macros/macro_path_as_generic_bound.stderr b/src/test/ui/macros/macro_path_as_generic_bound.stderr index 48c33575ad2..00d954d24f3 100644 --- a/src/test/ui/macros/macro_path_as_generic_bound.stderr +++ b/src/test/ui/macros/macro_path_as_generic_bound.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `m` +error[E0433]: failed to resolve: use of undeclared crate or module `m` --> $DIR/macro_path_as_generic_bound.rs:7:6 | LL | foo!(m::m2::A); - | ^ use of undeclared type or module `m` + | ^ use of undeclared crate or module `m` error: aborting due to previous error diff --git a/src/test/ui/macros/trace_faulty_macros.stderr b/src/test/ui/macros/trace_faulty_macros.stderr index aec9d1ab191..cecc942f470 100644 --- a/src/test/ui/macros/trace_faulty_macros.stderr +++ b/src/test/ui/macros/trace_faulty_macros.stderr @@ -60,7 +60,7 @@ LL | let a = pat_macro!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/trace_faulty_macros.rs:42:1 | LL | #[derive(Debug)] @@ -79,3 +79,4 @@ LL | let a = pat_macro!(); error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/malformed/issue-69341-malformed-derive-inert.stderr b/src/test/ui/malformed/issue-69341-malformed-derive-inert.stderr index e8f96178d10..c4532a375a7 100644 --- a/src/test/ui/malformed/issue-69341-malformed-derive-inert.stderr +++ b/src/test/ui/malformed/issue-69341-malformed-derive-inert.stderr @@ -4,7 +4,7 @@ error: traits in `#[derive(...)]` don't accept arguments LL | #[derive(parse())] | ^^ help: remove the arguments -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-69341-malformed-derive-inert.rs:8:5 | LL | path: (), @@ -24,3 +24,4 @@ LL | #[derive(parse())] error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/mir/issue-76248.rs b/src/test/ui/mir/issue-76248.rs new file mode 100644 index 00000000000..b01a9727852 --- /dev/null +++ b/src/test/ui/mir/issue-76248.rs @@ -0,0 +1,29 @@ +// This used to ICE during codegen after MIR inlining of g into f. +// The root cause was a missing fold of length constant in Rvalue::Repeat. +// Regression test for #76248. +// +// build-pass +// compile-flags: -Zmir-opt-level=2 + +const N: usize = 1; + +pub struct Elem<M> { + pub x: [usize; N], + pub m: M, +} + +pub fn f() -> Elem<()> { + g(()) +} + +#[inline] +pub fn g<M>(m: M) -> Elem<M> { + Elem { + x: [0; N], + m, + } +} + +pub fn main() { + f(); +} diff --git a/src/test/ui/mod/mod_file_disambig.rs b/src/test/ui/mod/mod_file_disambig.rs index 7b182421d34..e5958af173b 100644 --- a/src/test/ui/mod/mod_file_disambig.rs +++ b/src/test/ui/mod/mod_file_disambig.rs @@ -2,5 +2,5 @@ mod mod_file_disambig_aux; //~ ERROR file for module `mod_file_disambig_aux` fou fn main() { assert_eq!(mod_file_aux::bar(), 10); - //~^ ERROR failed to resolve: use of undeclared type or module `mod_file_aux` + //~^ ERROR failed to resolve: use of undeclared crate or module `mod_file_aux` } diff --git a/src/test/ui/mod/mod_file_disambig.stderr b/src/test/ui/mod/mod_file_disambig.stderr index 2cb99b75142..3a3d2e2dddd 100644 --- a/src/test/ui/mod/mod_file_disambig.stderr +++ b/src/test/ui/mod/mod_file_disambig.stderr @@ -6,11 +6,11 @@ LL | mod mod_file_disambig_aux; | = help: delete or rename one of them to remove the ambiguity -error[E0433]: failed to resolve: use of undeclared type or module `mod_file_aux` +error[E0433]: failed to resolve: use of undeclared crate or module `mod_file_aux` --> $DIR/mod_file_disambig.rs:4:16 | LL | assert_eq!(mod_file_aux::bar(), 10); - | ^^^^^^^^^^^^ use of undeclared type or module `mod_file_aux` + | ^^^^^^^^^^^^ use of undeclared crate or module `mod_file_aux` error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/mod_file_not_exist.rs b/src/test/ui/parser/mod_file_not_exist.rs index f4a27b52ec5..7b079eb02dc 100644 --- a/src/test/ui/parser/mod_file_not_exist.rs +++ b/src/test/ui/parser/mod_file_not_exist.rs @@ -5,5 +5,5 @@ mod not_a_real_file; //~ ERROR file not found for module `not_a_real_file` fn main() { assert_eq!(mod_file_aux::bar(), 10); - //~^ ERROR failed to resolve: use of undeclared type or module `mod_file_aux` + //~^ ERROR failed to resolve: use of undeclared crate or module `mod_file_aux` } diff --git a/src/test/ui/parser/mod_file_not_exist.stderr b/src/test/ui/parser/mod_file_not_exist.stderr index 087ae9fe3e0..4e08125625f 100644 --- a/src/test/ui/parser/mod_file_not_exist.stderr +++ b/src/test/ui/parser/mod_file_not_exist.stderr @@ -6,11 +6,11 @@ LL | mod not_a_real_file; | = help: to create the module `not_a_real_file`, create file "$DIR/not_a_real_file.rs" -error[E0433]: failed to resolve: use of undeclared type or module `mod_file_aux` +error[E0433]: failed to resolve: use of undeclared crate or module `mod_file_aux` --> $DIR/mod_file_not_exist.rs:7:16 | LL | assert_eq!(mod_file_aux::bar(), 10); - | ^^^^^^^^^^^^ use of undeclared type or module `mod_file_aux` + | ^^^^^^^^^^^^ use of undeclared crate or module `mod_file_aux` error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/mod_file_not_exist_windows.rs b/src/test/ui/parser/mod_file_not_exist_windows.rs index 4b7d7a02bbe..5db21e2bbc7 100644 --- a/src/test/ui/parser/mod_file_not_exist_windows.rs +++ b/src/test/ui/parser/mod_file_not_exist_windows.rs @@ -5,5 +5,5 @@ mod not_a_real_file; //~ ERROR file not found for module `not_a_real_file` fn main() { assert_eq!(mod_file_aux::bar(), 10); - //~^ ERROR failed to resolve: use of undeclared type or module `mod_file_aux` + //~^ ERROR failed to resolve: use of undeclared crate or module `mod_file_aux` } diff --git a/src/test/ui/parser/mod_file_not_exist_windows.stderr b/src/test/ui/parser/mod_file_not_exist_windows.stderr index d67205cfdf1..73cdf098b00 100644 --- a/src/test/ui/parser/mod_file_not_exist_windows.stderr +++ b/src/test/ui/parser/mod_file_not_exist_windows.stderr @@ -6,11 +6,11 @@ LL | mod not_a_real_file; | = help: to create the module `not_a_real_file`, create file "$DIR/not_a_real_file.rs" -error[E0433]: failed to resolve: use of undeclared type or module `mod_file_aux` +error[E0433]: failed to resolve: use of undeclared crate or module `mod_file_aux` --> $DIR/mod_file_not_exist_windows.rs:7:16 | LL | assert_eq!(mod_file_aux::bar(), 10); - | ^^^^^^^^^^^^ use of undeclared type or module `mod_file_aux` + | ^^^^^^^^^^^^ use of undeclared crate or module `mod_file_aux` error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/unsafe-foreign-mod.rs b/src/test/ui/parser/unsafe-foreign-mod.rs new file mode 100644 index 00000000000..872af95bd22 --- /dev/null +++ b/src/test/ui/parser/unsafe-foreign-mod.rs @@ -0,0 +1,9 @@ +unsafe extern { + //~^ ERROR extern block cannot be declared unsafe +} + +unsafe extern "C" { + //~^ ERROR extern block cannot be declared unsafe +} + +fn main() {} diff --git a/src/test/ui/parser/unsafe-foreign-mod.stderr b/src/test/ui/parser/unsafe-foreign-mod.stderr new file mode 100644 index 00000000000..5e10988051e --- /dev/null +++ b/src/test/ui/parser/unsafe-foreign-mod.stderr @@ -0,0 +1,14 @@ +error: extern block cannot be declared unsafe + --> $DIR/unsafe-foreign-mod.rs:1:1 + | +LL | unsafe extern { + | ^^^^^^ + +error: extern block cannot be declared unsafe + --> $DIR/unsafe-foreign-mod.rs:5:1 + | +LL | unsafe extern "C" { + | ^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/parser/unsafe-mod.rs b/src/test/ui/parser/unsafe-mod.rs new file mode 100644 index 00000000000..7916d878ea5 --- /dev/null +++ b/src/test/ui/parser/unsafe-mod.rs @@ -0,0 +1,9 @@ +unsafe mod m { + //~^ ERROR module cannot be declared unsafe +} + +unsafe mod n; +//~^ ERROR module cannot be declared unsafe +//~^^ ERROR file not found for module `n` + +fn main() {} diff --git a/src/test/ui/parser/unsafe-mod.stderr b/src/test/ui/parser/unsafe-mod.stderr new file mode 100644 index 00000000000..259b2c1d61e --- /dev/null +++ b/src/test/ui/parser/unsafe-mod.stderr @@ -0,0 +1,23 @@ +error[E0583]: file not found for module `n` + --> $DIR/unsafe-mod.rs:5:1 + | +LL | unsafe mod n; + | ^^^^^^^^^^^^^ + | + = help: to create the module `n`, create file "$DIR/n.rs" + +error: module cannot be declared unsafe + --> $DIR/unsafe-mod.rs:1:1 + | +LL | unsafe mod m { + | ^^^^^^ + +error: module cannot be declared unsafe + --> $DIR/unsafe-mod.rs:5:1 + | +LL | unsafe mod n; + | ^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0583`. diff --git a/src/test/ui/pattern/pattern-error-continue.rs b/src/test/ui/pattern/pattern-error-continue.rs index 8635622ab37..0702a9986fc 100644 --- a/src/test/ui/pattern/pattern-error-continue.rs +++ b/src/test/ui/pattern/pattern-error-continue.rs @@ -30,6 +30,6 @@ fn main() { //~| expected `char`, found `bool` match () { - E::V => {} //~ ERROR failed to resolve: use of undeclared type or module `E` + E::V => {} //~ ERROR failed to resolve: use of undeclared type `E` } } diff --git a/src/test/ui/pattern/pattern-error-continue.stderr b/src/test/ui/pattern/pattern-error-continue.stderr index 60f76796c03..497c93b2949 100644 --- a/src/test/ui/pattern/pattern-error-continue.stderr +++ b/src/test/ui/pattern/pattern-error-continue.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `E` +error[E0433]: failed to resolve: use of undeclared type `E` --> $DIR/pattern-error-continue.rs:33:9 | LL | E::V => {} - | ^ use of undeclared type or module `E` + | ^ use of undeclared type `E` error[E0532]: expected tuple struct or tuple variant, found unit variant `A::D` --> $DIR/pattern-error-continue.rs:18:9 diff --git a/src/test/ui/proc-macro/attributes-on-modules-fail.stderr b/src/test/ui/proc-macro/attributes-on-modules-fail.stderr index 97b2f22e161..7141a1b50b5 100644 --- a/src/test/ui/proc-macro/attributes-on-modules-fail.stderr +++ b/src/test/ui/proc-macro/attributes-on-modules-fail.stderr @@ -1,4 +1,4 @@ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/attributes-on-modules-fail.rs:16:1 | LL | #[derive(Copy)] @@ -64,5 +64,5 @@ LL | use m::X; error: aborting due to 7 previous errors -Some errors have detailed explanations: E0412, E0658. +Some errors have detailed explanations: E0412, E0658, E0774. For more information about an error, try `rustc --explain E0412`. diff --git a/src/test/ui/proc-macro/auxiliary/macro-only-syntax.rs b/src/test/ui/proc-macro/auxiliary/macro-only-syntax.rs new file mode 100644 index 00000000000..c72306c3d50 --- /dev/null +++ b/src/test/ui/proc-macro/auxiliary/macro-only-syntax.rs @@ -0,0 +1,89 @@ +// force-host +// no-prefer-dynamic + +// These are tests for syntax that is accepted by the Rust parser but +// unconditionally rejected semantically after macro expansion. Attribute macros +// are permitted to accept such syntax as long as they replace it with something +// that makes sense to Rust. +// +// We also inspect some of the spans to verify the syntax is not triggering the +// lossy string reparse hack (https://github.com/rust-lang/rust/issues/43081). + +#![crate_type = "proc-macro"] +#![feature(proc_macro_span)] + +extern crate proc_macro; +use proc_macro::{token_stream, Delimiter, TokenStream, TokenTree}; +use std::path::Component; + +// unsafe mod m { +// pub unsafe mod inner; +// } +#[proc_macro_attribute] +pub fn expect_unsafe_mod(_attrs: TokenStream, input: TokenStream) -> TokenStream { + let tokens = &mut input.into_iter(); + expect(tokens, "unsafe"); + expect(tokens, "mod"); + expect(tokens, "m"); + let tokens = &mut expect_brace(tokens); + expect(tokens, "pub"); + expect(tokens, "unsafe"); + expect(tokens, "mod"); + let ident = expect(tokens, "inner"); + expect(tokens, ";"); + check_useful_span(ident, "unsafe-mod.rs"); + TokenStream::new() +} + +// unsafe extern { +// type T; +// } +#[proc_macro_attribute] +pub fn expect_unsafe_foreign_mod(_attrs: TokenStream, input: TokenStream) -> TokenStream { + let tokens = &mut input.into_iter(); + expect(tokens, "unsafe"); + expect(tokens, "extern"); + let tokens = &mut expect_brace(tokens); + expect(tokens, "type"); + let ident = expect(tokens, "T"); + expect(tokens, ";"); + check_useful_span(ident, "unsafe-foreign-mod.rs"); + TokenStream::new() +} + +// unsafe extern "C++" {} +#[proc_macro_attribute] +pub fn expect_unsafe_extern_cpp_mod(_attrs: TokenStream, input: TokenStream) -> TokenStream { + let tokens = &mut input.into_iter(); + expect(tokens, "unsafe"); + expect(tokens, "extern"); + let abi = expect(tokens, "\"C++\""); + expect_brace(tokens); + check_useful_span(abi, "unsafe-foreign-mod.rs"); + TokenStream::new() +} + +fn expect(tokens: &mut token_stream::IntoIter, expected: &str) -> TokenTree { + match tokens.next() { + Some(token) if token.to_string() == expected => token, + wrong => panic!("unexpected token: {:?}, expected `{}`", wrong, expected), + } +} + +fn expect_brace(tokens: &mut token_stream::IntoIter) -> token_stream::IntoIter { + match tokens.next() { + Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Brace => { + group.stream().into_iter() + } + wrong => panic!("unexpected token: {:?}, expected `{{`", wrong), + } +} + +fn check_useful_span(token: TokenTree, expected_filename: &str) { + let span = token.span(); + assert!(span.start().column < span.end().column); + + let source_path = span.source_file().path(); + let filename = source_path.components().last().unwrap(); + assert_eq!(filename, Component::Normal(expected_filename.as_ref())); +} diff --git a/src/test/ui/proc-macro/capture-macro-rules-invoke.rs b/src/test/ui/proc-macro/capture-macro-rules-invoke.rs index 2ff6ad6d68f..de008a3708a 100644 --- a/src/test/ui/proc-macro/capture-macro-rules-invoke.rs +++ b/src/test/ui/proc-macro/capture-macro-rules-invoke.rs @@ -1,10 +1,20 @@ // aux-build:test-macros.rs // check-pass // compile-flags: -Z span-debug -// normalize-stdout-test "#\d+" -> "#CTXT" + +#![no_std] // Don't load unnecessary hygiene information from std +extern crate std; extern crate test_macros; -use test_macros::print_bang; +use test_macros::{print_bang, print_bang_consume}; + +macro_rules! test_matchers { + ($expr:expr, $block:block, $stmt:stmt, $ty:ty, $ident:ident, $lifetime:lifetime, + $meta:meta, $path:path, $vis:vis, $tt:tt, $lit:literal) => { + print_bang_consume!($expr, $block, $stmt, $ty, $ident, + $lifetime, $meta, $path, $vis, $tt, $lit) + } +} macro_rules! use_expr { ($expr:expr) => { @@ -24,10 +34,23 @@ impl Foo { #[allow(dead_code)] fn use_self(self) { drop(use_expr!(self)); + test_matchers!( + 1 + 1, + { "a" }, + let a = 1, + String, + my_name, + 'a, + my_val = 30, + std::option::Option, + pub(in some::path), + [ a b c ], + -30 + ); } fn with_pat(use_pat!((a, b)): (u32, u32)) { - println!("Args: {} {}", a, b); + let _ = (a, b); } } diff --git a/src/test/ui/proc-macro/capture-macro-rules-invoke.stdout b/src/test/ui/proc-macro/capture-macro-rules-invoke.stdout index 28812e20548..652bf6b6b22 100644 --- a/src/test/ui/proc-macro/capture-macro-rules-invoke.stdout +++ b/src/test/ui/proc-macro/capture-macro-rules-invoke.stdout @@ -5,10 +5,299 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ stream: TokenStream [ Ident { ident: "self", - span: $DIR/capture-macro-rules-invoke.rs:26:24: 26:28 (#CTXT), + span: $DIR/capture-macro-rules-invoke.rs:36:24: 36:28 (#0), }, ], - span: $DIR/capture-macro-rules-invoke.rs:11:21: 11:26 (#CTXT), + span: $DIR/capture-macro-rules-invoke.rs:21:21: 21:26 (#3), + }, +] +PRINT-BANG INPUT (DISPLAY): 1 + 1, { "a" }, let a = 1;, String, my_name, 'a, my_val = 30, +std::option::Option, pub(in some::path) , [a b c], -30 +PRINT-BANG RE-COLLECTED (DISPLAY): 1 + 1, { "a" }, let a = 1, String, my_name, 'a, my_val = 30, +std :: option :: Option, pub(in some :: path), [a b c], - 30 +PRINT-BANG INPUT (DEBUG): TokenStream [ + Group { + delimiter: None, + stream: TokenStream [ + Literal { + kind: Integer, + symbol: "1", + suffix: None, + span: $DIR/capture-macro-rules-invoke.rs:38:13: 38:14 (#0), + }, + Punct { + ch: '+', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:38:15: 38:16 (#0), + }, + Literal { + kind: Integer, + symbol: "1", + suffix: None, + span: $DIR/capture-macro-rules-invoke.rs:38:17: 38:18 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:14:29: 14:34 (#7), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:14:34: 14:35 (#7), + }, + Group { + delimiter: None, + stream: TokenStream [ + Group { + delimiter: Brace, + stream: TokenStream [ + Literal { + kind: Str, + symbol: "a", + suffix: None, + span: $DIR/capture-macro-rules-invoke.rs:39:15: 39:18 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:39:13: 39:20 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:14:36: 14:42 (#7), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:14:42: 14:43 (#7), + }, + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "let", + span: $DIR/capture-macro-rules-invoke.rs:40:13: 40:16 (#0), + }, + Ident { + ident: "a", + span: $DIR/capture-macro-rules-invoke.rs:40:17: 40:18 (#0), + }, + Punct { + ch: '=', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:40:19: 40:20 (#0), + }, + Literal { + kind: Integer, + symbol: "1", + suffix: None, + span: $DIR/capture-macro-rules-invoke.rs:40:21: 40:22 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:14:44: 14:49 (#7), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:14:49: 14:50 (#7), + }, + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "String", + span: $DIR/capture-macro-rules-invoke.rs:41:13: 41:19 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:14:51: 14:54 (#7), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:14:54: 14:55 (#7), + }, + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "my_name", + span: $DIR/capture-macro-rules-invoke.rs:42:13: 42:20 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:14:56: 14:62 (#7), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:14:62: 14:63 (#7), + }, + Group { + delimiter: None, + stream: TokenStream [ + Punct { + ch: '\'', + spacing: Joint, + span: $DIR/capture-macro-rules-invoke.rs:43:13: 43:15 (#0), + }, + Ident { + ident: "a", + span: $DIR/capture-macro-rules-invoke.rs:43:13: 43:15 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:15:29: 15:38 (#7), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:15:38: 15:39 (#7), + }, + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "my_val", + span: $DIR/capture-macro-rules-invoke.rs:44:13: 44:19 (#0), + }, + Punct { + ch: '=', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:44:20: 44:21 (#0), + }, + Literal { + kind: Integer, + symbol: "30", + suffix: None, + span: $DIR/capture-macro-rules-invoke.rs:44:22: 44:24 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:15:40: 15:45 (#7), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:15:45: 15:46 (#7), + }, + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "std", + span: $DIR/capture-macro-rules-invoke.rs:45:13: 45:16 (#0), + }, + Punct { + ch: ':', + spacing: Joint, + span: $DIR/capture-macro-rules-invoke.rs:45:16: 45:18 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:45:16: 45:18 (#0), + }, + Ident { + ident: "option", + span: $DIR/capture-macro-rules-invoke.rs:45:18: 45:24 (#0), + }, + Punct { + ch: ':', + spacing: Joint, + span: $DIR/capture-macro-rules-invoke.rs:45:24: 45:26 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:45:24: 45:26 (#0), + }, + Ident { + ident: "Option", + span: $DIR/capture-macro-rules-invoke.rs:45:26: 45:32 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:15:47: 15:52 (#7), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:15:52: 15:53 (#7), + }, + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "pub", + span: $DIR/capture-macro-rules-invoke.rs:46:13: 46:16 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "in", + span: $DIR/capture-macro-rules-invoke.rs:46:17: 46:19 (#0), + }, + Ident { + ident: "some", + span: $DIR/capture-macro-rules-invoke.rs:46:20: 46:24 (#0), + }, + Punct { + ch: ':', + spacing: Joint, + span: $DIR/capture-macro-rules-invoke.rs:46:24: 46:26 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:46:24: 46:26 (#0), + }, + Ident { + ident: "path", + span: $DIR/capture-macro-rules-invoke.rs:46:26: 46:30 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:46:16: 46:31 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:15:54: 15:58 (#7), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:15:58: 15:59 (#7), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "a", + span: $DIR/capture-macro-rules-invoke.rs:47:15: 47:16 (#0), + }, + Ident { + ident: "b", + span: $DIR/capture-macro-rules-invoke.rs:47:17: 47:18 (#0), + }, + Ident { + ident: "c", + span: $DIR/capture-macro-rules-invoke.rs:47:19: 47:20 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:47:13: 47:22 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:15:63: 15:64 (#7), + }, + Group { + delimiter: None, + stream: TokenStream [ + Punct { + ch: '-', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:48:13: 48:14 (#0), + }, + Literal { + kind: Integer, + symbol: "30", + suffix: None, + span: $DIR/capture-macro-rules-invoke.rs:48:14: 48:16 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:15:65: 15:69 (#7), }, ] PRINT-BANG INPUT (DISPLAY): (a, b) @@ -21,21 +310,21 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ stream: TokenStream [ Ident { ident: "a", - span: $DIR/capture-macro-rules-invoke.rs:29:27: 29:28 (#CTXT), + span: $DIR/capture-macro-rules-invoke.rs:52:27: 52:28 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/capture-macro-rules-invoke.rs:29:28: 29:29 (#CTXT), + span: $DIR/capture-macro-rules-invoke.rs:52:28: 52:29 (#0), }, Ident { ident: "b", - span: $DIR/capture-macro-rules-invoke.rs:29:30: 29:31 (#CTXT), + span: $DIR/capture-macro-rules-invoke.rs:52:30: 52:31 (#0), }, ], - span: $DIR/capture-macro-rules-invoke.rs:29:26: 29:32 (#CTXT), + span: $DIR/capture-macro-rules-invoke.rs:52:26: 52:32 (#0), }, ], - span: $DIR/capture-macro-rules-invoke.rs:17:21: 17:25 (#CTXT), + span: $DIR/capture-macro-rules-invoke.rs:27:21: 27:25 (#11), }, ] diff --git a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs index 35c101587de..bc82a2ff196 100644 --- a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs +++ b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs @@ -13,18 +13,37 @@ extern crate std; // place of a `None`-delimited group. This allows us to maintain // backwards compatibility for older versions of these crates. -include!("js-sys/src/lib.rs"); -include!("time-macros-impl/src/lib.rs"); +mod no_version { + include!("js-sys/src/lib.rs"); + include!("time-macros-impl/src/lib.rs"); -macro_rules! other { - ($name:ident) => { - #[my_macro] struct Three($name); + macro_rules! other { + ($name:ident) => { + #[my_macro] struct Three($name); + } } + + struct Foo; + impl_macros!(Foo); + arrays!(Foo); + other!(Foo); } -fn main() { +mod with_version { + include!("js-sys-0.3.17/src/lib.rs"); + include!("time-macros-impl-0.1.0/src/lib.rs"); + + macro_rules! other { + ($name:ident) => { + #[my_macro] struct Three($name); + } + } + struct Foo; impl_macros!(Foo); arrays!(Foo); other!(Foo); } + + +fn main() {} diff --git a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout index d519daab1f2..e7645280a75 100644 --- a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout +++ b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout @@ -1,3 +1,6 @@ Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl/src/lib.rs:5:21: 5:27 (#5) }, Ident { ident: "One", span: $DIR/time-macros-impl/src/lib.rs:5:28: 5:31 (#5) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:27:18: 27:21 (#0) }], span: $DIR/time-macros-impl/src/lib.rs:5:31: 5:38 (#5) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl/src/lib.rs:5:38: 5:39 (#5) }] Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys/src/lib.rs:5:21: 5:27 (#9) }, Ident { ident: "Two", span: $DIR/js-sys/src/lib.rs:5:28: 5:31 (#9) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:28:13: 28:16 (#0) }], span: $DIR/js-sys/src/lib.rs:5:31: 5:38 (#9) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys/src/lib.rs:5:38: 5:39 (#9) }] -Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:21:21: 21:27 (#13) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:21:28: 21:33 (#13) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:29:12: 29:15 (#0) }], span: $DIR/group-compat-hack.rs:21:34: 21:39 (#13) }], span: $DIR/group-compat-hack.rs:21:33: 21:40 (#13) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:21:40: 21:41 (#13) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:22:25: 22:31 (#13) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:22:32: 22:37 (#13) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:29:12: 29:15 (#0) }], span: $DIR/group-compat-hack.rs:22:38: 22:43 (#13) }], span: $DIR/group-compat-hack.rs:22:37: 22:44 (#13) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:22:44: 22:45 (#13) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:21: 5:27 (#19) }, Ident { ident: "One", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:28: 5:31 (#19) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:43:18: 43:21 (#0) }], span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:31: 5:38 (#19) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:38: 5:39 (#19) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys-0.3.17/src/lib.rs:5:21: 5:27 (#23) }, Ident { ident: "Two", span: $DIR/js-sys-0.3.17/src/lib.rs:5:28: 5:31 (#23) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:44:13: 44:16 (#0) }], span: $DIR/js-sys-0.3.17/src/lib.rs:5:31: 5:38 (#23) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys-0.3.17/src/lib.rs:5:38: 5:39 (#23) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:38:25: 38:31 (#27) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:38:32: 38:37 (#27) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:45:12: 45:15 (#0) }], span: $DIR/group-compat-hack.rs:38:38: 38:43 (#27) }], span: $DIR/group-compat-hack.rs:38:37: 38:44 (#27) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:38:44: 38:45 (#27) }] diff --git a/src/test/ui/proc-macro/group-compat-hack/js-sys-0.3.17/src/lib.rs b/src/test/ui/proc-macro/group-compat-hack/js-sys-0.3.17/src/lib.rs new file mode 100644 index 00000000000..d1a66940ebf --- /dev/null +++ b/src/test/ui/proc-macro/group-compat-hack/js-sys-0.3.17/src/lib.rs @@ -0,0 +1,7 @@ +// ignore-test this is not a test + +macro_rules! arrays { + ($name:ident) => { + #[my_macro] struct Two($name); + } +} diff --git a/src/test/ui/proc-macro/group-compat-hack/time-macros-impl-0.1.0/src/lib.rs b/src/test/ui/proc-macro/group-compat-hack/time-macros-impl-0.1.0/src/lib.rs new file mode 100644 index 00000000000..c94c3579209 --- /dev/null +++ b/src/test/ui/proc-macro/group-compat-hack/time-macros-impl-0.1.0/src/lib.rs @@ -0,0 +1,7 @@ +// ignore-test this is not a test + +macro_rules! impl_macros { + ($name:ident) => { + #[my_macro] struct One($name); + } +} diff --git a/src/test/ui/proc-macro/macros-in-extern-derive.stderr b/src/test/ui/proc-macro/macros-in-extern-derive.stderr index e2afb7d34c1..6b737449209 100644 --- a/src/test/ui/proc-macro/macros-in-extern-derive.stderr +++ b/src/test/ui/proc-macro/macros-in-extern-derive.stderr @@ -1,4 +1,4 @@ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/macros-in-extern-derive.rs:2:5 | LL | #[derive(Copy)] @@ -6,3 +6,4 @@ LL | #[derive(Copy)] error: aborting due to previous error +For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/proc-macro/unsafe-foreign-mod.rs b/src/test/ui/proc-macro/unsafe-foreign-mod.rs new file mode 100644 index 00000000000..7bdfa93c21f --- /dev/null +++ b/src/test/ui/proc-macro/unsafe-foreign-mod.rs @@ -0,0 +1,14 @@ +// run-pass +// aux-build:macro-only-syntax.rs + +extern crate macro_only_syntax; + +#[macro_only_syntax::expect_unsafe_foreign_mod] +unsafe extern { + type T; +} + +#[macro_only_syntax::expect_unsafe_extern_cpp_mod] +unsafe extern "C++" {} + +fn main() {} diff --git a/src/test/ui/proc-macro/unsafe-mod.rs b/src/test/ui/proc-macro/unsafe-mod.rs new file mode 100644 index 00000000000..8ff6e352c53 --- /dev/null +++ b/src/test/ui/proc-macro/unsafe-mod.rs @@ -0,0 +1,13 @@ +// run-pass +// aux-build:macro-only-syntax.rs + +#![feature(proc_macro_hygiene)] + +extern crate macro_only_syntax; + +#[macro_only_syntax::expect_unsafe_mod] +unsafe mod m { + pub unsafe mod inner; +} + +fn main() {} diff --git a/src/test/ui/resolve/use_suggestion.stderr b/src/test/ui/resolve/use_suggestion.stderr index 72dda940729..4fff179b1fe 100644 --- a/src/test/ui/resolve/use_suggestion.stderr +++ b/src/test/ui/resolve/use_suggestion.stderr @@ -1,10 +1,10 @@ -error[E0433]: failed to resolve: use of undeclared type or module `GooMap` +error[E0433]: failed to resolve: use of undeclared type `GooMap` --> $DIR/use_suggestion.rs:3:14 | LL | let x2 = GooMap::new(); - | ^^^^^^ use of undeclared type or module `GooMap` + | ^^^^^^ use of undeclared type `GooMap` -error[E0433]: failed to resolve: use of undeclared type or module `HashMap` +error[E0433]: failed to resolve: use of undeclared type `HashMap` --> $DIR/use_suggestion.rs:2:14 | LL | let x1 = HashMap::new(); diff --git a/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-1.stderr b/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-1.stderr index 64b920e9aa7..81891572179 100644 --- a/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-1.stderr +++ b/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-1.stderr @@ -2,7 +2,7 @@ error[E0432]: unresolved import `xcrate` --> $DIR/non-existent-1.rs:3:5 | LL | use xcrate::S; - | ^^^^^^ use of undeclared type or module `xcrate` + | ^^^^^^ use of undeclared crate or module `xcrate` error: aborting due to previous error diff --git a/src/test/ui/span/issue-43927-non-ADT-derive.stderr b/src/test/ui/span/issue-43927-non-ADT-derive.stderr index b68681c5297..b160a4e5877 100644 --- a/src/test/ui/span/issue-43927-non-ADT-derive.stderr +++ b/src/test/ui/span/issue-43927-non-ADT-derive.stderr @@ -1,4 +1,4 @@ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43927-non-ADT-derive.rs:3:1 | LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute! @@ -54,3 +54,4 @@ LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute! error: aborting due to 7 previous errors +For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/str-concat.rs b/src/test/ui/str-concat.rs deleted file mode 100644 index fa2fc97d7b8..00000000000 --- a/src/test/ui/str-concat.rs +++ /dev/null @@ -1,9 +0,0 @@ -// run-pass - -pub fn main() { - let a: String = "hello".to_string(); - let b: String = "world".to_string(); - let s: String = format!("{}{}", a, b); - println!("{}", s.clone()); - assert_eq!(s.as_bytes()[9], 'd' as u8); -} diff --git a/src/test/ui/str/str-idx.stderr b/src/test/ui/str/str-idx.stderr index ef7ce735868..f323ba03c01 100644 --- a/src/test/ui/str/str-idx.stderr +++ b/src/test/ui/str/str-idx.stderr @@ -6,7 +6,7 @@ LL | let _: u8 = s[4]; | = help: the trait `SliceIndex<str>` is not implemented for `{integer}` = note: you can use `.chars().nth()` or `.bytes().nth()` - see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings> + for more information, see chapter 8 in The Book: <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings> = note: required because of the requirements on the impl of `Index<{integer}>` for `str` error[E0277]: the type `str` cannot be indexed by `{integer}` @@ -17,7 +17,7 @@ LL | let _ = s.get(4); | = help: the trait `SliceIndex<str>` is not implemented for `{integer}` = note: you can use `.chars().nth()` or `.bytes().nth()` - see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings> + for more information, see chapter 8 in The Book: <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings> error[E0277]: the type `str` cannot be indexed by `{integer}` --> $DIR/str-idx.rs:5:29 @@ -27,7 +27,7 @@ LL | let _ = s.get_unchecked(4); | = help: the trait `SliceIndex<str>` is not implemented for `{integer}` = note: you can use `.chars().nth()` or `.bytes().nth()` - see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings> + for more information, see chapter 8 in The Book: <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings> error[E0277]: the type `str` cannot be indexed by `char` --> $DIR/str-idx.rs:6:17 diff --git a/src/test/ui/str/str-mut-idx.stderr b/src/test/ui/str/str-mut-idx.stderr index abb9b09cf38..405542820a3 100644 --- a/src/test/ui/str/str-mut-idx.stderr +++ b/src/test/ui/str/str-mut-idx.stderr @@ -39,7 +39,7 @@ LL | s.get_mut(1); | = help: the trait `SliceIndex<str>` is not implemented for `{integer}` = note: you can use `.chars().nth()` or `.bytes().nth()` - see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings> + for more information, see chapter 8 in The Book: <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings> error[E0277]: the type `str` cannot be indexed by `{integer}` --> $DIR/str-mut-idx.rs:11:25 @@ -49,7 +49,7 @@ LL | s.get_unchecked_mut(1); | = help: the trait `SliceIndex<str>` is not implemented for `{integer}` = note: you can use `.chars().nth()` or `.bytes().nth()` - see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings> + for more information, see chapter 8 in The Book: <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings> error[E0277]: the type `str` cannot be indexed by `char` --> $DIR/str-mut-idx.rs:13:5 diff --git a/src/test/ui/suggestions/type-ascription-instead-of-path.rs b/src/test/ui/suggestions/type-ascription-instead-of-path.rs index e92087e2947..ce40b55f1ee 100644 --- a/src/test/ui/suggestions/type-ascription-instead-of-path.rs +++ b/src/test/ui/suggestions/type-ascription-instead-of-path.rs @@ -1,5 +1,5 @@ fn main() { std:io::stdin(); - //~^ ERROR failed to resolve: use of undeclared type or module `io` + //~^ ERROR failed to resolve: use of undeclared crate or module `io` //~| ERROR expected value, found crate } diff --git a/src/test/ui/suggestions/type-ascription-instead-of-path.stderr b/src/test/ui/suggestions/type-ascription-instead-of-path.stderr index fd2fedc7640..518660cfa16 100644 --- a/src/test/ui/suggestions/type-ascription-instead-of-path.stderr +++ b/src/test/ui/suggestions/type-ascription-instead-of-path.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `io` +error[E0433]: failed to resolve: use of undeclared crate or module `io` --> $DIR/type-ascription-instead-of-path.rs:2:9 | LL | std:io::stdin(); - | ^^ use of undeclared type or module `io` + | ^^ use of undeclared crate or module `io` error[E0423]: expected value, found crate `std` --> $DIR/type-ascription-instead-of-path.rs:2:5 diff --git a/src/test/ui/try-block/try-block-in-return.rs b/src/test/ui/try-block/try-block-in-return.rs new file mode 100644 index 00000000000..a15bfeef1c1 --- /dev/null +++ b/src/test/ui/try-block/try-block-in-return.rs @@ -0,0 +1,12 @@ +// run-pass +// compile-flags: --edition 2018 + +#![feature(try_blocks)] + +fn issue_76271() -> Option<i32> { + return try { 4 } +} + +fn main() { + assert_eq!(issue_76271(), Some(4)); +} diff --git a/src/test/ui/type-alias-impl-trait/issue-72793.rs b/src/test/ui/type-alias-impl-trait/issue-72793.rs new file mode 100644 index 00000000000..e643a8cab5b --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-72793.rs @@ -0,0 +1,27 @@ +// build-pass + +// Regression test for #72793. +// FIXME: This still shows ICE with `-Zmir-opt-level=2`. + +#![feature(type_alias_impl_trait)] + +trait T { type Item; } + +type Alias<'a> = impl T<Item = &'a ()>; + +struct S; +impl<'a> T for &'a S { + type Item = &'a (); +} + +fn filter_positive<'a>() -> Alias<'a> { + &S +} + +fn with_positive(fun: impl Fn(Alias<'_>)) { + fun(filter_positive()); +} + +fn main() { + with_positive(|_| ()); +} diff --git a/src/test/ui/type-alias/issue-62263-self-in-atb.rs b/src/test/ui/type-alias/issue-62263-self-in-atb.rs index 5e812db4d23..1f64b4cfe5c 100644 --- a/src/test/ui/type-alias/issue-62263-self-in-atb.rs +++ b/src/test/ui/type-alias/issue-62263-self-in-atb.rs @@ -3,6 +3,6 @@ pub trait Trait { } pub type Alias = dyn Trait<A = Self::A>; -//~^ ERROR failed to resolve: use of undeclared type or module `Self` [E0433] +//~^ ERROR failed to resolve: use of undeclared type `Self` [E0433] fn main() {} diff --git a/src/test/ui/type-alias/issue-62263-self-in-atb.stderr b/src/test/ui/type-alias/issue-62263-self-in-atb.stderr index a642d029f93..d34b6ed5038 100644 --- a/src/test/ui/type-alias/issue-62263-self-in-atb.stderr +++ b/src/test/ui/type-alias/issue-62263-self-in-atb.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `Self` +error[E0433]: failed to resolve: use of undeclared type `Self` --> $DIR/issue-62263-self-in-atb.rs:5:32 | LL | pub type Alias = dyn Trait<A = Self::A>; - | ^^^^ use of undeclared type or module `Self` + | ^^^^ use of undeclared type `Self` error: aborting due to previous error diff --git a/src/test/ui/type-alias/issue-62305-self-assoc-ty.rs b/src/test/ui/type-alias/issue-62305-self-assoc-ty.rs index 0b95ddeb19e..999902fb18b 100644 --- a/src/test/ui/type-alias/issue-62305-self-assoc-ty.rs +++ b/src/test/ui/type-alias/issue-62305-self-assoc-ty.rs @@ -1,4 +1,4 @@ type Alias = Self::Target; -//~^ ERROR failed to resolve: use of undeclared type or module `Self` [E0433] +//~^ ERROR failed to resolve: use of undeclared type `Self` [E0433] fn main() {} diff --git a/src/test/ui/type-alias/issue-62305-self-assoc-ty.stderr b/src/test/ui/type-alias/issue-62305-self-assoc-ty.stderr index 6eb445e9dbc..823a5fa50fc 100644 --- a/src/test/ui/type-alias/issue-62305-self-assoc-ty.stderr +++ b/src/test/ui/type-alias/issue-62305-self-assoc-ty.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `Self` +error[E0433]: failed to resolve: use of undeclared type `Self` --> $DIR/issue-62305-self-assoc-ty.rs:1:14 | LL | type Alias = Self::Target; - | ^^^^ use of undeclared type or module `Self` + | ^^^^ use of undeclared type `Self` error: aborting due to previous error diff --git a/src/test/ui/type/type-path-err-node-types.rs b/src/test/ui/type/type-path-err-node-types.rs index 15adfebb334..b3795772e6f 100644 --- a/src/test/ui/type/type-path-err-node-types.rs +++ b/src/test/ui/type/type-path-err-node-types.rs @@ -12,7 +12,7 @@ fn ufcs_trait() { } fn ufcs_item() { - NonExistent::Assoc::<u8>; //~ ERROR undeclared type or module `NonExistent` + NonExistent::Assoc::<u8>; //~ ERROR undeclared type `NonExistent` } fn method() { diff --git a/src/test/ui/type/type-path-err-node-types.stderr b/src/test/ui/type/type-path-err-node-types.stderr index ea9cca2bfaa..baf218243c4 100644 --- a/src/test/ui/type/type-path-err-node-types.stderr +++ b/src/test/ui/type/type-path-err-node-types.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `NonExistent` +error[E0433]: failed to resolve: use of undeclared type `NonExistent` --> $DIR/type-path-err-node-types.rs:15:5 | LL | NonExistent::Assoc::<u8>; - | ^^^^^^^^^^^ use of undeclared type or module `NonExistent` + | ^^^^^^^^^^^ use of undeclared type `NonExistent` error[E0412]: cannot find type `Nonexistent` in this scope --> $DIR/type-path-err-node-types.rs:7:12 diff --git a/src/test/ui/union/union-deref.rs b/src/test/ui/union/union-deref.rs new file mode 100644 index 00000000000..df598eea9ef --- /dev/null +++ b/src/test/ui/union/union-deref.rs @@ -0,0 +1,28 @@ +// ignore-tidy-linelength +//! Test the part of RFC 2514 that is about not applying `DerefMut` coercions +//! of union fields. +#![feature(untagged_unions)] + +use std::mem::ManuallyDrop; + +union U1<T> { x:(), f: ManuallyDrop<(T,)> } + +union U2<T> { x:(), f: (ManuallyDrop<(T,)>,) } + +fn main() { + let mut u : U1<Vec<i32>> = U1 { x: () }; + unsafe { (*u.f).0 = Vec::new() }; // explicit deref, this compiles + unsafe { u.f.0 = Vec::new() }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field + unsafe { &mut (*u.f).0 }; // explicit deref, this compiles + unsafe { &mut u.f.0 }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field + unsafe { (*u.f).0.push(0) }; // explicit deref, this compiles + unsafe { u.f.0.push(0) }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field + + let mut u : U2<Vec<i32>> = U2 { x: () }; + unsafe { (*u.f.0).0 = Vec::new() }; // explicit deref, this compiles + unsafe { u.f.0.0 = Vec::new() }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field + unsafe { &mut (*u.f.0).0 }; // explicit deref, this compiles + unsafe { &mut u.f.0.0 }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field + unsafe { (*u.f.0).0.push(0) }; // explicit deref, this compiles + unsafe { u.f.0.0.push(0) }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field +} diff --git a/src/test/ui/union/union-deref.stderr b/src/test/ui/union/union-deref.stderr new file mode 100644 index 00000000000..fb16649767f --- /dev/null +++ b/src/test/ui/union/union-deref.stderr @@ -0,0 +1,56 @@ +error: not automatically applying `DerefMut` on `ManuallyDrop` union field + --> $DIR/union-deref.rs:15:14 + | +LL | unsafe { u.f.0 = Vec::new() }; + | ^^^ + | + = help: writing to this reference calls the destructor for the old value + = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor + +error: not automatically applying `DerefMut` on `ManuallyDrop` union field + --> $DIR/union-deref.rs:17:19 + | +LL | unsafe { &mut u.f.0 }; + | ^^^ + | + = help: writing to this reference calls the destructor for the old value + = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor + +error: not automatically applying `DerefMut` on `ManuallyDrop` union field + --> $DIR/union-deref.rs:19:14 + | +LL | unsafe { u.f.0.push(0) }; + | ^^^ + | + = help: writing to this reference calls the destructor for the old value + = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor + +error: not automatically applying `DerefMut` on `ManuallyDrop` union field + --> $DIR/union-deref.rs:23:14 + | +LL | unsafe { u.f.0.0 = Vec::new() }; + | ^^^^^^^ + | + = help: writing to this reference calls the destructor for the old value + = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor + +error: not automatically applying `DerefMut` on `ManuallyDrop` union field + --> $DIR/union-deref.rs:25:19 + | +LL | unsafe { &mut u.f.0.0 }; + | ^^^^^^^ + | + = help: writing to this reference calls the destructor for the old value + = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor + +error: not automatically applying `DerefMut` on `ManuallyDrop` union field + --> $DIR/union-deref.rs:27:14 + | +LL | unsafe { u.f.0.0.push(0) }; + | ^^^^^^^ + | + = help: writing to this reference calls the destructor for the old value + = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/unknown-tool-name.rs b/src/test/ui/unknown-tool-name.rs index 05f99ced687..73fca61c65d 100644 --- a/src/test/ui/unknown-tool-name.rs +++ b/src/test/ui/unknown-tool-name.rs @@ -1,2 +1,2 @@ -#[foo::bar] //~ ERROR failed to resolve: use of undeclared type or module `foo` +#[foo::bar] //~ ERROR failed to resolve: use of undeclared crate or module `foo` fn main() {} diff --git a/src/test/ui/unknown-tool-name.stderr b/src/test/ui/unknown-tool-name.stderr index 7a6ed57bda6..4a1370ba80a 100644 --- a/src/test/ui/unknown-tool-name.stderr +++ b/src/test/ui/unknown-tool-name.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `foo` +error[E0433]: failed to resolve: use of undeclared crate or module `foo` --> $DIR/unknown-tool-name.rs:1:3 | LL | #[foo::bar] - | ^^^ use of undeclared type or module `foo` + | ^^^ use of undeclared crate or module `foo` error: aborting due to previous error diff --git a/src/test/ui/use/use-self-type.rs b/src/test/ui/use/use-self-type.rs index 3e5c7bf3cca..370593b2eb2 100644 --- a/src/test/ui/use/use-self-type.rs +++ b/src/test/ui/use/use-self-type.rs @@ -4,7 +4,7 @@ impl S { fn f() {} fn g() { use Self::f; //~ ERROR unresolved import - pub(in Self::f) struct Z; //~ ERROR use of undeclared type or module `Self` + pub(in Self::f) struct Z; //~ ERROR use of undeclared type `Self` } } diff --git a/src/test/ui/use/use-self-type.stderr b/src/test/ui/use/use-self-type.stderr index 0dd0e04267c..d1469fb3490 100644 --- a/src/test/ui/use/use-self-type.stderr +++ b/src/test/ui/use/use-self-type.stderr @@ -1,14 +1,14 @@ -error[E0433]: failed to resolve: use of undeclared type or module `Self` +error[E0433]: failed to resolve: use of undeclared type `Self` --> $DIR/use-self-type.rs:7:16 | LL | pub(in Self::f) struct Z; - | ^^^^ use of undeclared type or module `Self` + | ^^^^ use of undeclared type `Self` error[E0432]: unresolved import `Self` --> $DIR/use-self-type.rs:6:13 | LL | use Self::f; - | ^^^^ use of undeclared type or module `Self` + | ^^^^ use of undeclared type `Self` error: aborting due to 2 previous errors diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 126907a7cfccbe93778530e6a6bbaa3adb6c515 +Subproject 875e0123259b0b6299903fe4aea0a12ecde9324 diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index 137b561028a..64f9379b303 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -6,11 +6,113 @@ document. ## Unreleased / In Rust Nightly -[c2c07fa...master](https://github.com/rust-lang/rust-clippy/compare/c2c07fa...master) +[09bd400...master](https://github.com/rust-lang/rust-clippy/compare/09bd400...master) + +## Rust 1.47 + +Current beta, release 2020-10-08 + +[c2c07fa...09bd400](https://github.com/rust-lang/rust-clippy/compare/c2c07fa...09bd400) + +### New lints + +* [`derive_ord_xor_partial_ord`] [#5848](https://github.com/rust-lang/rust-clippy/pull/5848) +* [`trait_duplication_in_bounds`] [#5852](https://github.com/rust-lang/rust-clippy/pull/5852) +* [`map_identity`] [#5694](https://github.com/rust-lang/rust-clippy/pull/5694) +* [`unit_return_expecting_ord`] [#5737](https://github.com/rust-lang/rust-clippy/pull/5737) +* [`pattern_type_mismatch`] [#4841](https://github.com/rust-lang/rust-clippy/pull/4841) +* [`repeat_once`] [#5773](https://github.com/rust-lang/rust-clippy/pull/5773) +* [`same_item_push`] [#5825](https://github.com/rust-lang/rust-clippy/pull/5825) +* [`needless_arbitrary_self_type`] [#5869](https://github.com/rust-lang/rust-clippy/pull/5869) +* [`match_like_matches_macro`] [#5769](https://github.com/rust-lang/rust-clippy/pull/5769) +* [`stable_sort_primitive`] [#5809](https://github.com/rust-lang/rust-clippy/pull/5809) +* [`blanket_clippy_restriction_lints`] [#5750](https://github.com/rust-lang/rust-clippy/pull/5750) +* [`option_if_let_else`] [#5301](https://github.com/rust-lang/rust-clippy/pull/5301) + +### Moves and Deprecations + +* Deprecate [`regex_macro`] lint + [#5760](https://github.com/rust-lang/rust-clippy/pull/5760) +* Move [`range_minus_one`] to `pedantic` + [#5752](https://github.com/rust-lang/rust-clippy/pull/5752) + +### Enhancements + +* Improve [`needless_collect`] by catching `collect` calls followed by `iter` or `into_iter` calls + [#5837](https://github.com/rust-lang/rust-clippy/pull/5837) +* [`panic`], [`todo`], [`unimplemented`] and [`unreachable`] now detect calls with formatting + [#5811](https://github.com/rust-lang/rust-clippy/pull/5811) +* Detect more cases of [`suboptimal_flops`] and [`imprecise_flops`] + [#5443](https://github.com/rust-lang/rust-clippy/pull/5443) +* Handle asymmetrical implementations of `PartialEq` in [`cmp_owned`] + [#5701](https://github.com/rust-lang/rust-clippy/pull/5701) +* Make it possible to allow [`unsafe_derive_deserialize`] + [#5870](https://github.com/rust-lang/rust-clippy/pull/5870) +* Catch `ord.min(a).max(b)` where a < b in [`min_max`] + [#5871](https://github.com/rust-lang/rust-clippy/pull/5871) +* Make [`clone_on_copy`] suggestion machine applicable + [#5745](https://github.com/rust-lang/rust-clippy/pull/5745) +* Enable [`len_zero`] on ranges now that `is_empty` is stable on them + [#5961](https://github.com/rust-lang/rust-clippy/pull/5961) + +### False Positive Fixes + +* Avoid triggering [`or_fun_call`] with const fns that take no arguments + [#5889](https://github.com/rust-lang/rust-clippy/pull/5889) +* Fix [`redundant_closure_call`] false positive for closures that have multiple calls + [#5800](https://github.com/rust-lang/rust-clippy/pull/5800) +* Don't lint cases involving `ManuallyDrop` in [`redundant_clone`] + [#5824](https://github.com/rust-lang/rust-clippy/pull/5824) +* Treat a single expression the same as a single statement in the 2nd arm of a match in [`single_match_else`] + [#5771](https://github.com/rust-lang/rust-clippy/pull/5771) +* Don't trigger [`unnested_or_patterns`] if the feature `or_patterns` is not enabled + [#5758](https://github.com/rust-lang/rust-clippy/pull/5758) +* Avoid linting if key borrows in [`unnecessary_sort_by`] + [#5756](https://github.com/rust-lang/rust-clippy/pull/5756) +* Consider `Try` impl for `Poll` when generating suggestions in [`try_err`] + [#5857](https://github.com/rust-lang/rust-clippy/pull/5857) +* Take input lifetimes into account in `manual_async_fn` + [#5859](https://github.com/rust-lang/rust-clippy/pull/5859) +* Fix multiple false positives in [`type_repetition_in_bounds`] and add a configuration option + [#5761](https://github.com/rust-lang/rust-clippy/pull/5761) +* Limit the [`suspicious_arithmetic_impl`] lint to one binary operation + [#5820](https://github.com/rust-lang/rust-clippy/pull/5820) + +### Suggestion Fixes/Improvements + +* Improve readability of [`shadow_unrelated`] suggestion by truncating the RHS snippet + [#5788](https://github.com/rust-lang/rust-clippy/pull/5788) +* Suggest `filter_map` instead of `flat_map` when mapping to `Option` in [`map_flatten`] + [#5846](https://github.com/rust-lang/rust-clippy/pull/5846) +* Ensure suggestion is shown correctly for long method call chains in [`iter_nth_zero`] + [#5793](https://github.com/rust-lang/rust-clippy/pull/5793) +* Drop borrow operator in suggestions of [`redundant_pattern_matching`] + [#5815](https://github.com/rust-lang/rust-clippy/pull/5815) +* Add suggestion for [`iter_skip_next`] + [#5843](https://github.com/rust-lang/rust-clippy/pull/5843) +* Improve [`collapsible_if`] fix suggestion + [#5732](https://github.com/rust-lang/rust-clippy/pull/5732) + +### ICE Fixes + +* Fix ICE caused by [`needless_collect`] + [#5877](https://github.com/rust-lang/rust-clippy/pull/5877) +* Fix ICE caused by [`unnested_or_patterns`] + [#5784](https://github.com/rust-lang/rust-clippy/pull/5784) + +### Documentation Improvements + +* Fix grammar of [`await_holding_lock`] documentation + [#5748](https://github.com/rust-lang/rust-clippy/pull/5748) + +### Others + +* Make lints adhere to the rustc dev guide + [#5888](https://github.com/rust-lang/rust-clippy/pull/5888) ## Rust 1.46 -Current beta, release 2020-08-27 +Current stable, released 2020-08-27 [7ea7cd1...c2c07fa](https://github.com/rust-lang/rust-clippy/compare/7ea7cd1...c2c07fa) @@ -72,7 +174,7 @@ Current beta, release 2020-08-27 ## Rust 1.45 -Current stable, released 2020-07-16 +Released 2020-07-16 [891e1a8...7ea7cd1](https://github.com/rust-lang/rust-clippy/compare/891e1a8...7ea7cd1) @@ -1410,6 +1512,7 @@ Released 2018-09-13 [`assertions_on_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_constants [`assign_op_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_op_pattern [`assign_ops`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_ops +[`async_yields_async`]: https://rust-lang.github.io/rust-clippy/master/index.html#async_yields_async [`await_holding_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_lock [`bad_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#bad_bit_mask [`bind_instead_of_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#bind_instead_of_map @@ -1444,6 +1547,7 @@ Released 2018-09-13 [`collapsible_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if [`comparison_chain`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain [`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator +[`create_dir`]: https://rust-lang.github.io/rust-clippy/master/index.html#create_dir [`crosspointer_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#crosspointer_transmute [`dbg_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro [`debug_assert_with_mut_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#debug_assert_with_mut_call diff --git a/src/tools/clippy/clippy_lints/src/async_yields_async.rs b/src/tools/clippy/clippy_lints/src/async_yields_async.rs new file mode 100644 index 00000000000..88d9d3b5a26 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/async_yields_async.rs @@ -0,0 +1,86 @@ +use crate::utils::{implements_trait, snippet, span_lint_and_then}; +use rustc_errors::Applicability; +use rustc_hir::{AsyncGeneratorKind, Body, BodyId, ExprKind, GeneratorKind, QPath}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// **What it does:** Checks for async blocks that yield values of types + /// that can themselves be awaited. + /// + /// **Why is this bad?** An await is likely missing. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// async fn foo() {} + /// + /// fn bar() { + /// let x = async { + /// foo() + /// }; + /// } + /// ``` + /// Use instead: + /// ```rust + /// async fn foo() {} + /// + /// fn bar() { + /// let x = async { + /// foo().await + /// }; + /// } + /// ``` + pub ASYNC_YIELDS_ASYNC, + correctness, + "async blocks that return a type that can be awaited" +} + +declare_lint_pass!(AsyncYieldsAsync => [ASYNC_YIELDS_ASYNC]); + +impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync { + fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) { + use AsyncGeneratorKind::{Block, Closure}; + // For functions, with explicitly defined types, don't warn. + // XXXkhuey maybe we should? + if let Some(GeneratorKind::Async(Block | Closure)) = body.generator_kind { + if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() { + let body_id = BodyId { + hir_id: body.value.hir_id, + }; + let def_id = cx.tcx.hir().body_owner_def_id(body_id); + let typeck_results = cx.tcx.typeck(def_id); + let expr_ty = typeck_results.expr_ty(&body.value); + + if implements_trait(cx, expr_ty, future_trait_def_id, &[]) { + let return_expr_span = match &body.value.kind { + // XXXkhuey there has to be a better way. + ExprKind::Block(block, _) => block.expr.map(|e| e.span), + ExprKind::Path(QPath::Resolved(_, path)) => Some(path.span), + _ => None, + }; + if let Some(return_expr_span) = return_expr_span { + span_lint_and_then( + cx, + ASYNC_YIELDS_ASYNC, + return_expr_span, + "an async construct yields a type which is itself awaitable", + |db| { + db.span_label(body.value.span, "outer async construct"); + db.span_label(return_expr_span, "awaitable value not awaited"); + db.span_suggestion( + return_expr_span, + "consider awaiting this value", + format!("{}.await", snippet(cx, return_expr_span, "..")), + Applicability::MaybeIncorrect, + ); + }, + ); + } + } + } + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs index cfcc1b3c5f3..c8f153e7201 100644 --- a/src/tools/clippy/clippy_lints/src/attrs.rs +++ b/src/tools/clippy/clippy_lints/src/attrs.rs @@ -71,8 +71,9 @@ declare_clippy_lint! { /// **What it does:** Checks for `extern crate` and `use` items annotated with /// lint attributes. /// - /// This lint permits `#[allow(unused_imports)]`, `#[allow(deprecated)]` and - /// `#[allow(unreachable_pub)]` on `use` items and `#[allow(unused_imports)]` on + /// This lint permits `#[allow(unused_imports)]`, `#[allow(deprecated)]`, + /// `#[allow(unreachable_pub)]`, `#[allow(clippy::wildcard_imports)]` and + /// `#[allow(clippy::enum_glob_use)]` on `use` items and `#[allow(unused_imports)]` on /// `extern crate` items with a `#[macro_use]` attribute. /// /// **Why is this bad?** Lint attributes have no effect on crate imports. Most @@ -318,7 +319,8 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { if let Some(ident) = attr.ident() { match &*ident.as_str() { "allow" | "warn" | "deny" | "forbid" => { - // permit `unused_imports`, `deprecated` and `unreachable_pub` for `use` items + // permit `unused_imports`, `deprecated`, `unreachable_pub`, + // `clippy::wildcard_imports`, and `clippy::enum_glob_use` for `use` items // and `unused_imports` for `extern crate` items with `macro_use` for lint in lint_list { match item.kind { @@ -327,6 +329,9 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { || is_word(lint, sym!(deprecated)) || is_word(lint, sym!(unreachable_pub)) || is_word(lint, sym!(unused)) + || extract_clippy_lint(lint) + .map_or(false, |s| s == "wildcard_imports") + || extract_clippy_lint(lint).map_or(false, |s| s == "enum_glob_use") { return; } @@ -387,24 +392,25 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { } } -fn check_clippy_lint_names(cx: &LateContext<'_>, ident: &str, items: &[NestedMetaItem]) { - fn extract_name(lint: &NestedMetaItem) -> Option<SymbolStr> { - if_chain! { - if let Some(meta_item) = lint.meta_item(); - if meta_item.path.segments.len() > 1; - if let tool_name = meta_item.path.segments[0].ident; - if tool_name.as_str() == "clippy"; - let lint_name = meta_item.path.segments.last().unwrap().ident.name; - then { - return Some(lint_name.as_str()); - } +/// Returns the lint name if it is clippy lint. +fn extract_clippy_lint(lint: &NestedMetaItem) -> Option<SymbolStr> { + if_chain! { + if let Some(meta_item) = lint.meta_item(); + if meta_item.path.segments.len() > 1; + if let tool_name = meta_item.path.segments[0].ident; + if tool_name.as_str() == "clippy"; + let lint_name = meta_item.path.segments.last().unwrap().ident.name; + then { + return Some(lint_name.as_str()); } - None } + None +} +fn check_clippy_lint_names(cx: &LateContext<'_>, ident: &str, items: &[NestedMetaItem]) { let lint_store = cx.lints(); for lint in items { - if let Some(lint_name) = extract_name(lint) { + if let Some(lint_name) = extract_clippy_lint(lint) { if let CheckLintNameResult::Tool(Err((None, _))) = lint_store.check_lint_name(&lint_name, Some(sym!(clippy))) { diff --git a/src/tools/clippy/clippy_lints/src/create_dir.rs b/src/tools/clippy/clippy_lints/src/create_dir.rs new file mode 100644 index 00000000000..4002fb655a5 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/create_dir.rs @@ -0,0 +1,51 @@ +use crate::utils::{match_def_path, paths, snippet, span_lint_and_sugg}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// **What it does:** Checks usage of `std::fs::create_dir` and suggest using `std::fs::create_dir_all` instead. + /// + /// **Why is this bad?** Sometimes `std::fs::crate_dir` is mistakenly chosen over `std::fs::create_dir_all`. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// std::fs::create_dir("foo"); + /// ``` + /// Use instead: + /// ```rust + /// std::fs::create_dir_all("foo"); + /// ``` + pub CREATE_DIR, + restriction, + "calling `std::fs::create_dir` instead of `std::fs::create_dir_all`" +} + +declare_lint_pass!(CreateDir => [CREATE_DIR]); + +impl LateLintPass<'_> for CreateDir { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + if_chain! { + if let ExprKind::Call(ref func, ref args) = expr.kind; + if let ExprKind::Path(ref path) = func.kind; + if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id(); + if match_def_path(cx, def_id, &paths::STD_FS_CREATE_DIR); + then { + span_lint_and_sugg( + cx, + CREATE_DIR, + expr.span, + "calling `std::fs::create_dir` where there may be a better way", + "consider calling `std::fs::create_dir_all` instead", + format!("create_dir_all({})", snippet(cx, args[0].span, "..")), + Applicability::MaybeIncorrect, + ) + } + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/default_trait_access.rs b/src/tools/clippy/clippy_lints/src/default_trait_access.rs index 1654df56a9a..3048436d9a7 100644 --- a/src/tools/clippy/clippy_lints/src/default_trait_access.rs +++ b/src/tools/clippy/clippy_lints/src/default_trait_access.rs @@ -38,37 +38,23 @@ impl<'tcx> LateLintPass<'tcx> for DefaultTraitAccess { if let ExprKind::Path(ref qpath) = path.kind; if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id(); if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD); + // Detect and ignore <Foo as Default>::default() because these calls do explicitly name the type. + if let QPath::Resolved(None, _path) = qpath; then { - match qpath { - QPath::Resolved(..) => { - if_chain! { - // Detect and ignore <Foo as Default>::default() because these calls do - // explicitly name the type. - if let ExprKind::Call(ref method, ref _args) = expr.kind; - if let ExprKind::Path(ref p) = method.kind; - if let QPath::Resolved(Some(_ty), _path) = p; - then { - return; - } - } - - // TODO: Work out a way to put "whatever the imported way of referencing - // this type in this file" rather than a fully-qualified type. - let expr_ty = cx.typeck_results().expr_ty(expr); - if let ty::Adt(..) = expr_ty.kind() { - let replacement = format!("{}::default()", expr_ty); - span_lint_and_sugg( - cx, - DEFAULT_TRAIT_ACCESS, - expr.span, - &format!("calling `{}` is more clear than this expression", replacement), - "try", - replacement, - Applicability::Unspecified, // First resolve the TODO above - ); - } - }, - QPath::TypeRelative(..) | QPath::LangItem(..) => {}, + let expr_ty = cx.typeck_results().expr_ty(expr); + if let ty::Adt(def, ..) = expr_ty.kind() { + // TODO: Work out a way to put "whatever the imported way of referencing + // this type in this file" rather than a fully-qualified type. + let replacement = format!("{}::default()", cx.tcx.def_path_str(def.did)); + span_lint_and_sugg( + cx, + DEFAULT_TRAIT_ACCESS, + expr.span, + &format!("calling `{}` is more clear than this expression", replacement), + "try", + replacement, + Applicability::Unspecified, // First resolve the TODO above + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/enum_variants.rs b/src/tools/clippy/clippy_lints/src/enum_variants.rs index a9294a87f15..67a46353856 100644 --- a/src/tools/clippy/clippy_lints/src/enum_variants.rs +++ b/src/tools/clippy/clippy_lints/src/enum_variants.rs @@ -285,7 +285,7 @@ impl EarlyLintPass for EnumVariantNames { ); } } - if item.vis.node.is_pub() { + if item.vis.kind.is_pub() { let matching = partial_match(mod_camel, &item_camel); let rmatching = partial_rmatch(mod_camel, &item_camel); let nchars = mod_camel.chars().count(); @@ -316,7 +316,7 @@ impl EarlyLintPass for EnumVariantNames { } } if let ItemKind::Enum(ref def, _) = item.kind { - let lint = match item.vis.node { + let lint = match item.vis.kind { VisibilityKind::Public => PUB_ENUM_VARIANT_NAMES, _ => ENUM_VARIANT_NAMES, }; diff --git a/src/tools/clippy/clippy_lints/src/functions.rs b/src/tools/clippy/clippy_lints/src/functions.rs index 89fde1d509d..50b39cf4ea7 100644 --- a/src/tools/clippy/clippy_lints/src/functions.rs +++ b/src/tools/clippy/clippy_lints/src/functions.rs @@ -374,7 +374,12 @@ impl<'tcx> Functions { } if line_count > self.max_lines { - span_lint(cx, TOO_MANY_LINES, span, "this function has a large number of lines") + span_lint( + cx, + TOO_MANY_LINES, + span, + &format!("this function has too many lines ({}/{})", line_count, self.max_lines), + ) } } diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 577ce6523b4..2020ef78509 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -154,6 +154,7 @@ mod arithmetic; mod as_conversions; mod assertions_on_constants; mod assign_ops; +mod async_yields_async; mod atomic_ordering; mod attrs; mod await_holding_lock; @@ -169,6 +170,7 @@ mod collapsible_if; mod comparison_chain; mod copies; mod copy_iterator; +mod create_dir; mod dbg_macro; mod default_trait_access; mod dereference; @@ -483,6 +485,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &assertions_on_constants::ASSERTIONS_ON_CONSTANTS, &assign_ops::ASSIGN_OP_PATTERN, &assign_ops::MISREFACTORED_ASSIGN_OP, + &async_yields_async::ASYNC_YIELDS_ASYNC, &atomic_ordering::INVALID_ATOMIC_ORDERING, &attrs::BLANKET_CLIPPY_RESTRICTION_LINTS, &attrs::DEPRECATED_CFG_ATTR, @@ -511,6 +514,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &copies::MATCH_SAME_ARMS, &copies::SAME_FUNCTIONS_IN_IF_CONDITION, ©_iterator::COPY_ITERATOR, + &create_dir::CREATE_DIR, &dbg_macro::DBG_MACRO, &default_trait_access::DEFAULT_TRAIT_ACCESS, &dereference::EXPLICIT_DEREF_METHODS, @@ -1042,6 +1046,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| box items_after_statements::ItemsAfterStatements); store.register_early_pass(|| box precedence::Precedence); store.register_early_pass(|| box needless_continue::NeedlessContinue); + store.register_late_pass(|| box create_dir::CreateDir); store.register_early_pass(|| box needless_arbitrary_self_type::NeedlessArbitrarySelfType); store.register_early_pass(|| box redundant_static_lifetimes::RedundantStaticLifetimes); store.register_late_pass(|| box cargo_common_metadata::CargoCommonMetadata); @@ -1099,11 +1104,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box unwrap_in_result::UnwrapInResult); store.register_late_pass(|| box self_assignment::SelfAssignment); store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs); + store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), LintId::of(&arithmetic::INTEGER_ARITHMETIC), LintId::of(&as_conversions::AS_CONVERSIONS), + LintId::of(&create_dir::CREATE_DIR), LintId::of(&dbg_macro::DBG_MACRO), LintId::of(&else_if_without_else::ELSE_IF_WITHOUT_ELSE), LintId::of(&exit::EXIT), @@ -1232,6 +1239,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&assertions_on_constants::ASSERTIONS_ON_CONSTANTS), LintId::of(&assign_ops::ASSIGN_OP_PATTERN), LintId::of(&assign_ops::MISREFACTORED_ASSIGN_OP), + LintId::of(&async_yields_async::ASYNC_YIELDS_ASYNC), LintId::of(&atomic_ordering::INVALID_ATOMIC_ORDERING), LintId::of(&attrs::BLANKET_CLIPPY_RESTRICTION_LINTS), LintId::of(&attrs::DEPRECATED_CFG_ATTR), @@ -1675,6 +1683,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_group(true, "clippy::correctness", Some("clippy_correctness"), vec![ LintId::of(&approx_const::APPROX_CONSTANT), + LintId::of(&async_yields_async::ASYNC_YIELDS_ASYNC), LintId::of(&atomic_ordering::INVALID_ATOMIC_ORDERING), LintId::of(&attrs::DEPRECATED_SEMVER), LintId::of(&attrs::MISMATCHED_TARGET_OS), diff --git a/src/tools/clippy/clippy_lints/src/loops.rs b/src/tools/clippy/clippy_lints/src/loops.rs index 604a97e3c08..6c54c07869a 100644 --- a/src/tools/clippy/clippy_lints/src/loops.rs +++ b/src/tools/clippy/clippy_lints/src/loops.rs @@ -1131,6 +1131,27 @@ fn detect_same_item_push<'tcx>( body: &'tcx Expr<'_>, _: &'tcx Expr<'_>, ) { + fn emit_lint(cx: &LateContext<'_>, vec: &Expr<'_>, pushed_item: &Expr<'_>) { + let vec_str = snippet_with_macro_callsite(cx, vec.span, ""); + let item_str = snippet_with_macro_callsite(cx, pushed_item.span, ""); + + span_lint_and_help( + cx, + SAME_ITEM_PUSH, + vec.span, + "it looks like the same item is being pushed into this Vec", + None, + &format!( + "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})", + item_str, vec_str, item_str + ), + ) + } + + if !matches!(pat.kind, PatKind::Wild) { + return; + } + // Determine whether it is safe to lint the body let mut same_item_push_visitor = SameItemPushVisitor { should_lint: true, @@ -1140,43 +1161,50 @@ fn detect_same_item_push<'tcx>( walk_expr(&mut same_item_push_visitor, body); if same_item_push_visitor.should_lint { if let Some((vec, pushed_item)) = same_item_push_visitor.vec_push { - // Make sure that the push does not involve possibly mutating values - if let PatKind::Wild = pat.kind { - let vec_str = snippet_with_macro_callsite(cx, vec.span, ""); - let item_str = snippet_with_macro_callsite(cx, pushed_item.span, ""); - if let ExprKind::Path(ref qpath) = pushed_item.kind { - if_chain! { - if let Res::Local(hir_id) = qpath_res(cx, qpath, pushed_item.hir_id); - let node = cx.tcx.hir().get(hir_id); - if let Node::Binding(pat) = node; - if let PatKind::Binding(bind_ann, ..) = pat.kind; - if !matches!(bind_ann, BindingAnnotation::RefMut | BindingAnnotation::Mutable); - then { - span_lint_and_help( - cx, - SAME_ITEM_PUSH, - vec.span, - "it looks like the same item is being pushed into this Vec", - None, - &format!( - "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})", - item_str, vec_str, item_str - ), - ) + let vec_ty = cx.typeck_results().expr_ty(vec); + let ty = vec_ty.walk().nth(1).unwrap().expect_ty(); + if cx + .tcx + .lang_items() + .clone_trait() + .map_or(false, |id| implements_trait(cx, ty, id, &[])) + { + // Make sure that the push does not involve possibly mutating values + match pushed_item.kind { + ExprKind::Path(ref qpath) => { + match qpath_res(cx, qpath, pushed_item.hir_id) { + // immutable bindings that are initialized with literal or constant + Res::Local(hir_id) => { + if_chain! { + let node = cx.tcx.hir().get(hir_id); + if let Node::Binding(pat) = node; + if let PatKind::Binding(bind_ann, ..) = pat.kind; + if !matches!(bind_ann, BindingAnnotation::RefMut | BindingAnnotation::Mutable); + let parent_node = cx.tcx.hir().get_parent_node(hir_id); + if let Some(Node::Local(parent_let_expr)) = cx.tcx.hir().find(parent_node); + if let Some(init) = parent_let_expr.init; + then { + match init.kind { + // immutable bindings that are initialized with literal + ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item), + // immutable bindings that are initialized with constant + ExprKind::Path(ref path) => { + if let Res::Def(DefKind::Const, ..) = qpath_res(cx, path, init.hir_id) { + emit_lint(cx, vec, pushed_item); + } + } + _ => {}, + } + } + } + }, + // constant + Res::Def(DefKind::Const, ..) => emit_lint(cx, vec, pushed_item), + _ => {}, } - } - } else if mutated_variables(pushed_item, cx).map_or(false, |mutvars| mutvars.is_empty()) { - span_lint_and_help( - cx, - SAME_ITEM_PUSH, - vec.span, - "it looks like the same item is being pushed into this Vec", - None, - &format!( - "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})", - item_str, vec_str, item_str - ), - ) + }, + ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item), + _ => {}, } } } diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs index 4e49bdbdd21..9c623821fdd 100644 --- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs +++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs @@ -122,7 +122,7 @@ fn check_manual_non_exhaustive_enum(cx: &EarlyContext<'_>, item: &Item, variants fn check_manual_non_exhaustive_struct(cx: &EarlyContext<'_>, item: &Item, data: &VariantData) { fn is_private(field: &StructField) -> bool { - matches!(field.vis.node, VisibilityKind::Inherited) + matches!(field.vis.kind, VisibilityKind::Inherited) } fn is_non_exhaustive_marker(field: &StructField) -> bool { @@ -141,7 +141,7 @@ fn check_manual_non_exhaustive_struct(cx: &EarlyContext<'_>, item: &Item, data: let fields = data.fields(); let private_fields = fields.iter().filter(|f| is_private(f)).count(); - let public_fields = fields.iter().filter(|f| f.vis.node.is_pub()).count(); + let public_fields = fields.iter().filter(|f| f.vis.kind.is_pub()).count(); if_chain! { if private_fields == 1 && public_fields >= 1 && public_fields == fields.len() - 1; diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs index 1f9ae8c931a..076ef235b8b 100644 --- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs +++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs @@ -9,7 +9,7 @@ use rustc_span::source_map::Span; declare_clippy_lint! { /// **What it does:** Checks for usage of `option.map(f)` where f is a function - /// or closure that returns the unit type. + /// or closure that returns the unit type `()`. /// /// **Why is this bad?** Readability, this can be written more clearly with /// an if let statement @@ -51,7 +51,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// **What it does:** Checks for usage of `result.map(f)` where f is a function - /// or closure that returns the unit type. + /// or closure that returns the unit type `()`. /// /// **Why is this bad?** Readability, this can be written more clearly with /// an if let statement @@ -197,7 +197,7 @@ fn let_binding_name(cx: &LateContext<'_>, var_arg: &hir::Expr<'_>) -> String { #[must_use] fn suggestion_msg(function_type: &str, map_type: &str) -> String { format!( - "called `map(f)` on an `{0}` value where `f` is a {1} that returns the unit type", + "called `map(f)` on an `{0}` value where `f` is a {1} that returns the unit type `()`", map_type, function_type ) } diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index a7a3d675156..ba69c8266b1 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -1324,20 +1324,20 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Warns when using push_str with a single-character string literal, - /// and push with a char would work fine. + /// **What it does:** Warns when using `push_str` with a single-character string literal, + /// and `push` with a `char` would work fine. /// - /// **Why is this bad?** It's less clear that we are pushing a single character + /// **Why is this bad?** It's less clear that we are pushing a single character. /// /// **Known problems:** None /// /// **Example:** - /// ``` + /// ```rust /// let mut string = String::new(); /// string.push_str("R"); /// ``` /// Could be written as - /// ``` + /// ```rust /// let mut string = String::new(); /// string.push('R'); /// ``` diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs index 4773731e327..57a45e628db 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs @@ -14,7 +14,6 @@ use rustc_middle::mir::{ visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor as _}, }; use rustc_middle::ty::{self, fold::TypeVisitor, Ty}; -use rustc_mir::dataflow::BottomValue; use rustc_mir::dataflow::{Analysis, AnalysisDomain, GenKill, GenKillAnalysis, ResultsCursor}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::{BytePos, Span}; @@ -411,14 +410,15 @@ impl<'tcx> mir::visit::Visitor<'tcx> for LocalUseVisitor { struct MaybeStorageLive; impl<'tcx> AnalysisDomain<'tcx> for MaybeStorageLive { - type Idx = mir::Local; + type Domain = BitSet<mir::Local>; const NAME: &'static str = "maybe_storage_live"; - fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize { - body.local_decls.len() + fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { + // bottom = dead + BitSet::new_empty(body.local_decls.len()) } - fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>) { + fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain) { for arg in body.args_iter() { state.insert(arg); } @@ -426,6 +426,8 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeStorageLive { } impl<'tcx> GenKillAnalysis<'tcx> for MaybeStorageLive { + type Idx = mir::Local; + fn statement_effect(&self, trans: &mut impl GenKill<Self::Idx>, stmt: &mir::Statement<'tcx>, _: mir::Location) { match stmt.kind { mir::StatementKind::StorageLive(l) => trans.gen(l), @@ -454,11 +456,6 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeStorageLive { } } -impl BottomValue for MaybeStorageLive { - /// bottom = dead - const BOTTOM_VALUE: bool = false; -} - /// Collects the possible borrowers of each local. /// For example, `b = &a; c = &a;` will make `b` and (transitively) `c` /// possible borrowers of `a`. diff --git a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs index 58bfd0bc553..35b38eca14d 100644 --- a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs +++ b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs @@ -41,7 +41,7 @@ impl EarlyLintPass for SingleComponentPathImports { if_chain! { if !in_macro(item.span); if cx.sess.opts.edition == Edition::Edition2018; - if !item.vis.node.is_pub(); + if !item.vis.kind.is_pub(); if let ItemKind::Use(use_tree) = &item.kind; if let segments = &use_tree.prefix.segments; if segments.len() == 1; diff --git a/src/tools/clippy/clippy_lints/src/temporary_assignment.rs b/src/tools/clippy/clippy_lints/src/temporary_assignment.rs index 1aeff1baa36..fb891866364 100644 --- a/src/tools/clippy/clippy_lints/src/temporary_assignment.rs +++ b/src/tools/clippy/clippy_lints/src/temporary_assignment.rs @@ -1,5 +1,4 @@ use crate::utils::{is_adjusted, span_lint}; -use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -22,12 +21,8 @@ declare_clippy_lint! { "assignments to temporaries" } -fn is_temporary(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - match &expr.kind { - ExprKind::Struct(..) | ExprKind::Tup(..) => true, - ExprKind::Path(qpath) => matches!(cx.qpath_res(qpath, expr.hir_id), Res::Def(DefKind::Const, ..)), - _ => false, - } +fn is_temporary(expr: &Expr<'_>) -> bool { + matches!(&expr.kind, ExprKind::Struct(..) | ExprKind::Tup(..)) } declare_lint_pass!(TemporaryAssignment => [TEMPORARY_ASSIGNMENT]); @@ -39,7 +34,7 @@ impl<'tcx> LateLintPass<'tcx> for TemporaryAssignment { while let ExprKind::Field(f, _) | ExprKind::Index(f, _) = &base.kind { base = f; } - if is_temporary(cx, base) && !is_adjusted(cx, base) { + if is_temporary(base) && !is_adjusted(cx, base) { span_lint(cx, TEMPORARY_ASSIGNMENT, expr.span, "assignment to temporary"); } } diff --git a/src/tools/clippy/clippy_lints/src/transmute.rs b/src/tools/clippy/clippy_lints/src/transmute.rs index 87c5408c785..c75adb62f25 100644 --- a/src/tools/clippy/clippy_lints/src/transmute.rs +++ b/src/tools/clippy/clippy_lints/src/transmute.rs @@ -331,8 +331,9 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { if let Some(def_id) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id(); if match_def_path(cx, def_id, &paths::TRANSMUTE); then { - // Avoid suggesting from/to bits in const contexts. + // Avoid suggesting from/to bits and dereferencing raw pointers in const contexts. // See https://github.com/rust-lang/rust/issues/73736 for progress on making them `const fn`. + // And see https://github.com/rust-lang/rust/issues/51911 for dereferencing raw pointers. let const_context = in_constant(cx, e.hir_id); let from_ty = cx.typeck_results().expr_ty(&args[0]); @@ -486,7 +487,8 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { Applicability::Unspecified, ); } else { - if cx.tcx.erase_regions(&from_ty) != cx.tcx.erase_regions(&to_ty) { + if (cx.tcx.erase_regions(&from_ty) != cx.tcx.erase_regions(&to_ty)) + && !const_context { span_lint_and_then( cx, TRANSMUTE_PTR_TO_PTR, diff --git a/src/tools/clippy/clippy_lints/src/types.rs b/src/tools/clippy/clippy_lints/src/types.rs index c82deaa43b2..6c6188d61ad 100644 --- a/src/tools/clippy/clippy_lints/src/types.rs +++ b/src/tools/clippy/clippy_lints/src/types.rs @@ -11,8 +11,8 @@ use rustc_hir as hir; use rustc_hir::intravisit::{walk_body, walk_expr, walk_ty, FnKind, NestedVisitorMap, Visitor}; use rustc_hir::{ BinOpKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, FnSig, GenericArg, GenericParamKind, HirId, ImplItem, - ImplItemKind, Item, ItemKind, Lifetime, Local, MatchSource, MutTy, Mutability, QPath, Stmt, StmtKind, TraitFn, - TraitItem, TraitItemKind, TyKind, UnOp, + ImplItemKind, Item, ItemKind, Lifetime, Local, MatchSource, MutTy, Mutability, Node, QPath, Stmt, StmtKind, + TraitFn, TraitItem, TraitItemKind, TyKind, UnOp, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; @@ -31,12 +31,13 @@ use crate::utils::paths; use crate::utils::{ clip, comparisons, differing_macro_contexts, higher, in_constant, indent_of, int_bits, is_type_diagnostic_item, last_path_segment, match_def_path, match_path, method_chain_args, multispan_sugg, numeric_literal::NumericLiteral, - qpath_res, sext, snippet, snippet_block_with_applicability, snippet_opt, snippet_with_applicability, - snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, unsext, + qpath_res, reindent_multiline, sext, snippet, snippet_opt, snippet_with_applicability, snippet_with_macro_callsite, + span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, unsext, }; declare_clippy_lint! { /// **What it does:** Checks for use of `Box<Vec<_>>` anywhere in the code. + /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information. /// /// **Why is this bad?** `Vec` already keeps its contents in a separate area on /// the heap. So if you `Box` it, you just add another level of indirection @@ -65,6 +66,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// **What it does:** Checks for use of `Vec<Box<T>>` where T: Sized anywhere in the code. + /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information. /// /// **Why is this bad?** `Vec` already keeps its contents in a separate area on /// the heap. So if you `Box` its contents, you just add another level of indirection. @@ -167,6 +169,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// **What it does:** Checks for use of `&Box<T>` anywhere in the code. + /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information. /// /// **Why is this bad?** Any `&Box<T>` can also be a `&T`, which is more /// general. @@ -802,6 +805,45 @@ impl<'tcx> LateLintPass<'tcx> for UnitArg { } } +fn fmt_stmts_and_call( + cx: &LateContext<'_>, + call_expr: &Expr<'_>, + call_snippet: &str, + args_snippets: &[impl AsRef<str>], + non_empty_block_args_snippets: &[impl AsRef<str>], +) -> String { + let call_expr_indent = indent_of(cx, call_expr.span).unwrap_or(0); + let call_snippet_with_replacements = args_snippets + .iter() + .fold(call_snippet.to_owned(), |acc, arg| acc.replacen(arg.as_ref(), "()", 1)); + + let mut stmts_and_call = non_empty_block_args_snippets + .iter() + .map(|it| it.as_ref().to_owned()) + .collect::<Vec<_>>(); + stmts_and_call.push(call_snippet_with_replacements); + stmts_and_call = stmts_and_call + .into_iter() + .map(|v| reindent_multiline(v.into(), true, Some(call_expr_indent)).into_owned()) + .collect(); + + let mut stmts_and_call_snippet = stmts_and_call.join(&format!("{}{}", ";\n", " ".repeat(call_expr_indent))); + // expr is not in a block statement or result expression position, wrap in a block + let parent_node = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(call_expr.hir_id)); + if !matches!(parent_node, Some(Node::Block(_))) && !matches!(parent_node, Some(Node::Stmt(_))) { + let block_indent = call_expr_indent + 4; + stmts_and_call_snippet = + reindent_multiline(stmts_and_call_snippet.into(), true, Some(block_indent)).into_owned(); + stmts_and_call_snippet = format!( + "{{\n{}{}\n{}}}", + " ".repeat(block_indent), + &stmts_and_call_snippet, + " ".repeat(call_expr_indent) + ); + } + stmts_and_call_snippet +} + fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Expr<'_>]) { let mut applicability = Applicability::MachineApplicable; let (singular, plural) = if args_to_recover.len() > 1 { @@ -844,43 +886,52 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp Applicability::MaybeIncorrect, ); or = "or "; + applicability = Applicability::MaybeIncorrect; }); - let sugg = args_to_recover + + let arg_snippets: Vec<String> = args_to_recover + .iter() + .filter_map(|arg| snippet_opt(cx, arg.span)) + .collect(); + let arg_snippets_without_empty_blocks: Vec<String> = args_to_recover .iter() .filter(|arg| !is_empty_block(arg)) - .enumerate() - .map(|(i, arg)| { - let indent = if i == 0 { - 0 - } else { - indent_of(cx, expr.span).unwrap_or(0) - }; - format!( - "{}{};", - " ".repeat(indent), - snippet_block_with_applicability(cx, arg.span, "..", Some(expr.span), &mut applicability) - ) - }) - .collect::<Vec<String>>(); - let mut and = ""; - if !sugg.is_empty() { - let plural = if sugg.len() > 1 { "s" } else { "" }; - db.span_suggestion( - expr.span.with_hi(expr.span.lo()), - &format!("{}move the expression{} in front of the call...", or, plural), - format!("{}\n", sugg.join("\n")), - applicability, + .filter_map(|arg| snippet_opt(cx, arg.span)) + .collect(); + + if let Some(call_snippet) = snippet_opt(cx, expr.span) { + let sugg = fmt_stmts_and_call( + cx, + expr, + &call_snippet, + &arg_snippets, + &arg_snippets_without_empty_blocks, ); - and = "...and " + + if arg_snippets_without_empty_blocks.is_empty() { + db.multipart_suggestion( + &format!("use {}unit literal{} instead", singular, plural), + args_to_recover + .iter() + .map(|arg| (arg.span, "()".to_string())) + .collect::<Vec<_>>(), + applicability, + ); + } else { + let plural = arg_snippets_without_empty_blocks.len() > 1; + let empty_or_s = if plural { "s" } else { "" }; + let it_or_them = if plural { "them" } else { "it" }; + db.span_suggestion( + expr.span, + &format!( + "{}move the expression{} in front of the call and replace {} with the unit literal `()`", + or, empty_or_s, it_or_them + ), + sugg, + applicability, + ); + } } - db.multipart_suggestion( - &format!("{}use {}unit literal{} instead", and, singular, plural), - args_to_recover - .iter() - .map(|arg| (arg.span, "()".to_string())) - .collect::<Vec<_>>(), - applicability, - ); }, ); } @@ -2055,6 +2106,7 @@ impl PartialOrd for FullInt { }) } } + impl Ord for FullInt { #[must_use] fn cmp(&self, other: &Self) -> Ordering { diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs index 8b00d29acb5..9b6a9075a29 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs @@ -1,5 +1,4 @@ use crate::utils; -use crate::utils::paths; use crate::utils::sugg::Sugg; use if_chain::if_chain; use rustc_errors::Applicability; @@ -171,12 +170,22 @@ fn mirrored_exprs( } fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintTrigger> { + // NOTE: Vectors of references are not supported. In order to avoid hitting https://github.com/rust-lang/rust/issues/34162, + // (different unnamed lifetimes for closure arg and return type) we need to make sure the suggested + // closure parameter is not a reference in case we suggest `Reverse`. Trying to destructure more + // than one level of references would add some extra complexity as we would have to compensate + // in the closure body. + if_chain! { if let ExprKind::MethodCall(name_ident, _, args, _) = &expr.kind; if let name = name_ident.ident.name.to_ident_string(); if name == "sort_by" || name == "sort_unstable_by"; if let [vec, Expr { kind: ExprKind::Closure(_, _, closure_body_id, _, _), .. }] = args; - if utils::match_type(cx, &cx.typeck_results().expr_ty(vec), &paths::VEC); + let vec_ty = cx.typeck_results().expr_ty(vec); + if utils::is_type_diagnostic_item(cx, vec_ty, sym!(vec_type)); + let ty = vec_ty.walk().nth(1).unwrap().expect_ty(); // T in Vec<T> + if !matches!(&ty.kind(), ty::Ref(..)); + if utils::is_copy(cx, ty); if let closure_body = cx.tcx.hir().body(*closure_body_id); if let &[ Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..}, diff --git a/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs b/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs index 3c3f8b26e3a..0e9feef3746 100644 --- a/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs +++ b/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs @@ -191,7 +191,9 @@ pub fn eq_stmt(l: &Stmt, r: &Stmt) -> bool { (Item(l), Item(r)) => eq_item(l, r, eq_item_kind), (Expr(l), Expr(r)) | (Semi(l), Semi(r)) => eq_expr(l, r), (Empty, Empty) => true, - (MacCall(l), MacCall(r)) => l.style == r.style && eq_mac_call(&l.mac, &r.mac) && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)), + (MacCall(l), MacCall(r)) => { + l.style == r.style && eq_mac_call(&l.mac, &r.mac) && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)) + }, _ => false, } } @@ -392,7 +394,7 @@ pub fn eq_defaultness(l: Defaultness, r: Defaultness) -> bool { pub fn eq_vis(l: &Visibility, r: &Visibility) -> bool { use VisibilityKind::*; - match (&l.node, &r.node) { + match (&l.kind, &r.kind) { (Public, Public) | (Inherited, Inherited) | (Crate(_), Crate(_)) => true, (Restricted { path: l, .. }, Restricted { path: r, .. }) => eq_path(l, r), _ => false, diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs index 292dbd7ad6b..9c5a12ea9c8 100644 --- a/src/tools/clippy/clippy_lints/src/utils/conf.rs +++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs @@ -122,7 +122,7 @@ define_Conf! { "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "NaN", "NaNs", - "OAuth", + "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "TensorFlow", diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs index 45add9ab284..3ebbfed6456 100644 --- a/src/tools/clippy/clippy_lints/src/utils/mod.rs +++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs @@ -19,6 +19,7 @@ pub mod paths; pub mod ptr; pub mod sugg; pub mod usage; + pub use self::attrs::*; pub use self::diagnostics::*; pub use self::hir_utils::{both, eq_expr_value, over, SpanlessEq, SpanlessHash}; @@ -108,6 +109,7 @@ pub fn in_macro(span: Span) -> bool { false } } + // If the snippet is empty, it's an attribute that was inserted during macro // expansion and we want to ignore those, because they could come from external // sources that the user has no control over. @@ -571,7 +573,7 @@ pub fn snippet_block<'a, T: LintContext>( ) -> Cow<'a, str> { let snip = snippet(cx, span, default); let indent = indent_relative_to.and_then(|s| indent_of(cx, s)); - trim_multiline(snip, true, indent) + reindent_multiline(snip, true, indent) } /// Same as `snippet_block`, but adapts the applicability level by the rules of @@ -585,7 +587,7 @@ pub fn snippet_block_with_applicability<'a, T: LintContext>( ) -> Cow<'a, str> { let snip = snippet_with_applicability(cx, span, default, applicability); let indent = indent_relative_to.and_then(|s| indent_of(cx, s)); - trim_multiline(snip, true, indent) + reindent_multiline(snip, true, indent) } /// Returns a new Span that extends the original Span to the first non-whitespace char of the first @@ -661,16 +663,16 @@ pub fn expr_block<'a, T: LintContext>( } } -/// Trim indentation from a multiline string with possibility of ignoring the -/// first line. -fn trim_multiline(s: Cow<'_, str>, ignore_first: bool, indent: Option<usize>) -> Cow<'_, str> { - let s_space = trim_multiline_inner(s, ignore_first, indent, ' '); - let s_tab = trim_multiline_inner(s_space, ignore_first, indent, '\t'); - trim_multiline_inner(s_tab, ignore_first, indent, ' ') +/// Reindent a multiline string with possibility of ignoring the first line. +#[allow(clippy::needless_pass_by_value)] +pub fn reindent_multiline(s: Cow<'_, str>, ignore_first: bool, indent: Option<usize>) -> Cow<'_, str> { + let s_space = reindent_multiline_inner(&s, ignore_first, indent, ' '); + let s_tab = reindent_multiline_inner(&s_space, ignore_first, indent, '\t'); + reindent_multiline_inner(&s_tab, ignore_first, indent, ' ').into() } -fn trim_multiline_inner(s: Cow<'_, str>, ignore_first: bool, indent: Option<usize>, ch: char) -> Cow<'_, str> { - let mut x = s +fn reindent_multiline_inner(s: &str, ignore_first: bool, indent: Option<usize>, ch: char) -> String { + let x = s .lines() .skip(ignore_first as usize) .filter_map(|l| { @@ -683,26 +685,20 @@ fn trim_multiline_inner(s: Cow<'_, str>, ignore_first: bool, indent: Option<usiz }) .min() .unwrap_or(0); - if let Some(indent) = indent { - x = x.saturating_sub(indent); - } - if x > 0 { - Cow::Owned( - s.lines() - .enumerate() - .map(|(i, l)| { - if (ignore_first && i == 0) || l.is_empty() { - l - } else { - l.split_at(x).1 - } - }) - .collect::<Vec<_>>() - .join("\n"), - ) - } else { - s - } + let indent = indent.unwrap_or(0); + s.lines() + .enumerate() + .map(|(i, l)| { + if (ignore_first && i == 0) || l.is_empty() { + l.to_owned() + } else if x > indent { + l.split_at(x - indent).1.to_owned() + } else { + " ".repeat(indent - x) + l + } + }) + .collect::<Vec<String>>() + .join("\n") } /// Gets the parent expression, if any –- this is useful to constrain a lint. @@ -899,7 +895,7 @@ pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_ return match res { def::Res::Def(DefKind::Variant | DefKind::Ctor(..), ..) => true, // FIXME: check the constness of the arguments, see https://github.com/rust-lang/rust-clippy/pull/5682#issuecomment-638681210 - def::Res::Def(DefKind::Fn, def_id) if has_no_arguments(cx, def_id) => { + def::Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) if has_no_arguments(cx, def_id) => { const_eval::is_const_fn(cx.tcx, def_id) }, def::Res::Def(_, def_id) => cx.tcx.is_promotable_const_fn(def_id), @@ -1432,7 +1428,7 @@ pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<S } else { unreachable!() } - } + }, _ => false, }; @@ -1474,26 +1470,26 @@ macro_rules! unwrap_cargo_metadata { #[cfg(test)] mod test { - use super::{trim_multiline, without_block_comments}; + use super::{reindent_multiline, without_block_comments}; #[test] - fn test_trim_multiline_single_line() { - assert_eq!("", trim_multiline("".into(), false, None)); - assert_eq!("...", trim_multiline("...".into(), false, None)); - assert_eq!("...", trim_multiline(" ...".into(), false, None)); - assert_eq!("...", trim_multiline("\t...".into(), false, None)); - assert_eq!("...", trim_multiline("\t\t...".into(), false, None)); + fn test_reindent_multiline_single_line() { + assert_eq!("", reindent_multiline("".into(), false, None)); + assert_eq!("...", reindent_multiline("...".into(), false, None)); + assert_eq!("...", reindent_multiline(" ...".into(), false, None)); + assert_eq!("...", reindent_multiline("\t...".into(), false, None)); + assert_eq!("...", reindent_multiline("\t\t...".into(), false, None)); } #[test] #[rustfmt::skip] - fn test_trim_multiline_block() { + fn test_reindent_multiline_block() { assert_eq!("\ if x { y } else { z - }", trim_multiline(" if x { + }", reindent_multiline(" if x { y } else { z @@ -1503,7 +1499,7 @@ mod test { \ty } else { \tz - }", trim_multiline(" if x { + }", reindent_multiline(" if x { \ty } else { \tz @@ -1512,14 +1508,14 @@ mod test { #[test] #[rustfmt::skip] - fn test_trim_multiline_empty_line() { + fn test_reindent_multiline_empty_line() { assert_eq!("\ if x { y } else { z - }", trim_multiline(" if x { + }", reindent_multiline(" if x { y } else { @@ -1528,6 +1524,22 @@ mod test { } #[test] + #[rustfmt::skip] + fn test_reindent_multiline_lines_deeper() { + assert_eq!("\ + if x { + y + } else { + z + }", reindent_multiline("\ + if x { + y + } else { + z + }".into(), true, Some(8))); + } + + #[test] fn test_without_block_comments_lines_without_block_comments() { let result = without_block_comments(vec!["/*", "", "*/"]); println!("result: {:?}", result); diff --git a/src/tools/clippy/clippy_lints/src/utils/paths.rs b/src/tools/clippy/clippy_lints/src/utils/paths.rs index d44854aefe9..65320d6a0e0 100644 --- a/src/tools/clippy/clippy_lints/src/utils/paths.rs +++ b/src/tools/clippy/clippy_lints/src/utils/paths.rs @@ -110,6 +110,7 @@ pub const SLICE_ITER: [&str; 3] = ["core", "slice", "Iter"]; pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"]; pub const STDOUT: [&str; 4] = ["std", "io", "stdio", "stdout"]; pub const STD_CONVERT_IDENTITY: [&str; 3] = ["std", "convert", "identity"]; +pub const STD_FS_CREATE_DIR: [&str; 3] = ["std", "fs", "create_dir"]; pub const STD_MEM_TRANSMUTE: [&str; 3] = ["std", "mem", "transmute"]; pub const STD_PTR_NULL: [&str; 3] = ["std", "ptr", "null"]; pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"]; diff --git a/src/tools/clippy/clippy_lints/src/utils/sugg.rs b/src/tools/clippy/clippy_lints/src/utils/sugg.rs index 2955f8d8e59..811fde388d1 100644 --- a/src/tools/clippy/clippy_lints/src/utils/sugg.rs +++ b/src/tools/clippy/clippy_lints/src/utils/sugg.rs @@ -132,7 +132,11 @@ impl<'a> Sugg<'a> { pub fn ast(cx: &EarlyContext<'_>, expr: &ast::Expr, default: &'a str) -> Self { use rustc_ast::ast::RangeLimits; - let snippet = snippet(cx, expr.span, default); + let snippet = if expr.span.from_expansion() { + snippet_with_macro_callsite(cx, expr.span, default) + } else { + snippet(cx, expr.span, default) + }; match expr.kind { ast::ExprKind::AddrOf(..) diff --git a/src/tools/clippy/src/lintlist/mod.rs b/src/tools/clippy/src/lintlist/mod.rs index 687fac7baa8..6697835e950 100644 --- a/src/tools/clippy/src/lintlist/mod.rs +++ b/src/tools/clippy/src/lintlist/mod.rs @@ -53,6 +53,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ module: "assign_ops", }, Lint { + name: "async_yields_async", + group: "correctness", + desc: "async blocks that return a type that can be awaited", + deprecation: None, + module: "async_yields_async", + }, + Lint { name: "await_holding_lock", group: "pedantic", desc: "Inside an async function, holding a MutexGuard while calling await", @@ -291,6 +298,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ module: "copy_iterator", }, Lint { + name: "create_dir", + group: "restriction", + desc: "calling `std::fs::create_dir` instead of `std::fs::create_dir_all`", + deprecation: None, + module: "create_dir", + }, + Lint { name: "crosspointer_transmute", group: "complexity", desc: "transmutes that have to or from types that are a pointer to the other", diff --git a/src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr b/src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr index fb12257021a..a27ce945ca5 100644 --- a/src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr +++ b/src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr @@ -1,4 +1,4 @@ -error: this function has a large number of lines +error: this function has too many lines (2/1) --> $DIR/test.rs:18:1 | LL | / fn too_many_lines() { @@ -9,7 +9,7 @@ LL | | } | = note: `-D clippy::too-many-lines` implied by `-D warnings` -error: this function has a large number of lines +error: this function has too many lines (2/1) --> $DIR/test.rs:38:1 | LL | / fn comment_before_code() { diff --git a/src/tools/clippy/tests/ui/async_yields_async.fixed b/src/tools/clippy/tests/ui/async_yields_async.fixed new file mode 100644 index 00000000000..9b1a7ac3ba9 --- /dev/null +++ b/src/tools/clippy/tests/ui/async_yields_async.fixed @@ -0,0 +1,68 @@ +// run-rustfix +// edition:2018 + +#![feature(async_closure)] +#![warn(clippy::async_yields_async)] + +use core::future::Future; +use core::pin::Pin; +use core::task::{Context, Poll}; + +struct CustomFutureType; + +impl Future for CustomFutureType { + type Output = u8; + + fn poll(self: Pin<&mut Self>, _: &mut Context) -> Poll<Self::Output> { + Poll::Ready(3) + } +} + +fn custom_future_type_ctor() -> CustomFutureType { + CustomFutureType +} + +async fn f() -> CustomFutureType { + // Don't warn for functions since you have to explicitly declare their + // return types. + CustomFutureType +} + +#[rustfmt::skip] +fn main() { + let _f = { + 3 + }; + let _g = async { + 3 + }; + let _h = async { + async { + 3 + }.await + }; + let _i = async { + CustomFutureType.await + }; + let _i = async || { + 3 + }; + let _j = async || { + async { + 3 + }.await + }; + let _k = async || { + CustomFutureType.await + }; + let _l = async || CustomFutureType.await; + let _m = async || { + println!("I'm bored"); + // Some more stuff + + // Finally something to await + CustomFutureType.await + }; + let _n = async || custom_future_type_ctor(); + let _o = async || f(); +} diff --git a/src/tools/clippy/tests/ui/async_yields_async.rs b/src/tools/clippy/tests/ui/async_yields_async.rs new file mode 100644 index 00000000000..731c094edb4 --- /dev/null +++ b/src/tools/clippy/tests/ui/async_yields_async.rs @@ -0,0 +1,68 @@ +// run-rustfix +// edition:2018 + +#![feature(async_closure)] +#![warn(clippy::async_yields_async)] + +use core::future::Future; +use core::pin::Pin; +use core::task::{Context, Poll}; + +struct CustomFutureType; + +impl Future for CustomFutureType { + type Output = u8; + + fn poll(self: Pin<&mut Self>, _: &mut Context) -> Poll<Self::Output> { + Poll::Ready(3) + } +} + +fn custom_future_type_ctor() -> CustomFutureType { + CustomFutureType +} + +async fn f() -> CustomFutureType { + // Don't warn for functions since you have to explicitly declare their + // return types. + CustomFutureType +} + +#[rustfmt::skip] +fn main() { + let _f = { + 3 + }; + let _g = async { + 3 + }; + let _h = async { + async { + 3 + } + }; + let _i = async { + CustomFutureType + }; + let _i = async || { + 3 + }; + let _j = async || { + async { + 3 + } + }; + let _k = async || { + CustomFutureType + }; + let _l = async || CustomFutureType; + let _m = async || { + println!("I'm bored"); + // Some more stuff + + // Finally something to await + CustomFutureType + }; + let _n = async || custom_future_type_ctor(); + let _o = async || f(); +} diff --git a/src/tools/clippy/tests/ui/async_yields_async.stderr b/src/tools/clippy/tests/ui/async_yields_async.stderr new file mode 100644 index 00000000000..17d0c375106 --- /dev/null +++ b/src/tools/clippy/tests/ui/async_yields_async.stderr @@ -0,0 +1,96 @@ +error: an async construct yields a type which is itself awaitable + --> $DIR/async_yields_async.rs:40:9 + | +LL | let _h = async { + | ____________________- +LL | | async { + | |_________^ +LL | || 3 +LL | || } + | ||_________^ awaitable value not awaited +LL | | }; + | |_____- outer async construct + | + = note: `-D clippy::async-yields-async` implied by `-D warnings` +help: consider awaiting this value + | +LL | async { +LL | 3 +LL | }.await + | + +error: an async construct yields a type which is itself awaitable + --> $DIR/async_yields_async.rs:45:9 + | +LL | let _i = async { + | ____________________- +LL | | CustomFutureType + | | ^^^^^^^^^^^^^^^^ + | | | + | | awaitable value not awaited + | | help: consider awaiting this value: `CustomFutureType.await` +LL | | }; + | |_____- outer async construct + +error: an async construct yields a type which is itself awaitable + --> $DIR/async_yields_async.rs:51:9 + | +LL | let _j = async || { + | _______________________- +LL | | async { + | |_________^ +LL | || 3 +LL | || } + | ||_________^ awaitable value not awaited +LL | | }; + | |_____- outer async construct + | +help: consider awaiting this value + | +LL | async { +LL | 3 +LL | }.await + | + +error: an async construct yields a type which is itself awaitable + --> $DIR/async_yields_async.rs:56:9 + | +LL | let _k = async || { + | _______________________- +LL | | CustomFutureType + | | ^^^^^^^^^^^^^^^^ + | | | + | | awaitable value not awaited + | | help: consider awaiting this value: `CustomFutureType.await` +LL | | }; + | |_____- outer async construct + +error: an async construct yields a type which is itself awaitable + --> $DIR/async_yields_async.rs:58:23 + | +LL | let _l = async || CustomFutureType; + | ^^^^^^^^^^^^^^^^ + | | + | outer async construct + | awaitable value not awaited + | help: consider awaiting this value: `CustomFutureType.await` + +error: an async construct yields a type which is itself awaitable + --> $DIR/async_yields_async.rs:64:9 + | +LL | let _m = async || { + | _______________________- +LL | | println!("I'm bored"); +LL | | // Some more stuff +LL | | +LL | | // Finally something to await +LL | | CustomFutureType + | | ^^^^^^^^^^^^^^^^ + | | | + | | awaitable value not awaited + | | help: consider awaiting this value: `CustomFutureType.await` +LL | | }; + | |_____- outer async construct + +error: aborting due to 6 previous errors + diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs index a414832bcd3..39f87510548 100644 --- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs +++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs @@ -1,5 +1,6 @@ #![warn(clippy::borrow_interior_mutable_const)] #![allow(clippy::declare_interior_mutable_const, clippy::ref_in_deref)] +#![allow(const_item_mutation)] use std::borrow::Cow; use std::cell::{Cell, UnsafeCell}; diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const.stderr b/src/tools/clippy/tests/ui/borrow_interior_mutable_const.stderr index 1e0b3e4d20a..5800af7e960 100644 --- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const.stderr +++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const.stderr @@ -1,5 +1,5 @@ error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:65:5 + --> $DIR/borrow_interior_mutable_const.rs:66:5 | LL | ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability | ^^^^^^ @@ -8,7 +8,7 @@ LL | ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:66:16 + --> $DIR/borrow_interior_mutable_const.rs:67:16 | LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability | ^^^^^^ @@ -16,7 +16,7 @@ LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutabi = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:69:22 + --> $DIR/borrow_interior_mutable_const.rs:70:22 | LL | let _once_ref = &ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -24,7 +24,7 @@ LL | let _once_ref = &ONCE_INIT; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:70:25 + --> $DIR/borrow_interior_mutable_const.rs:71:25 | LL | let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -32,7 +32,7 @@ LL | let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:71:27 + --> $DIR/borrow_interior_mutable_const.rs:72:27 | LL | let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -40,7 +40,7 @@ LL | let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:72:26 + --> $DIR/borrow_interior_mutable_const.rs:73:26 | LL | let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -48,7 +48,7 @@ LL | let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:83:14 + --> $DIR/borrow_interior_mutable_const.rs:84:14 | LL | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:84:14 + --> $DIR/borrow_interior_mutable_const.rs:85:14 | LL | let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:85:19 + --> $DIR/borrow_interior_mutable_const.rs:86:19 | LL | let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:86:14 + --> $DIR/borrow_interior_mutable_const.rs:87:14 | LL | let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -80,7 +80,7 @@ LL | let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:87:13 + --> $DIR/borrow_interior_mutable_const.rs:88:13 | LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -88,7 +88,7 @@ LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mu = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:93:13 + --> $DIR/borrow_interior_mutable_const.rs:94:13 | LL | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -96,7 +96,7 @@ LL | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:98:5 + --> $DIR/borrow_interior_mutable_const.rs:99:5 | LL | CELL.set(2); //~ ERROR interior mutability | ^^^^ @@ -104,7 +104,7 @@ LL | CELL.set(2); //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:99:16 + --> $DIR/borrow_interior_mutable_const.rs:100:16 | LL | assert_eq!(CELL.get(), 6); //~ ERROR interior mutability | ^^^^ @@ -112,7 +112,7 @@ LL | assert_eq!(CELL.get(), 6); //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:112:5 + --> $DIR/borrow_interior_mutable_const.rs:113:5 | LL | u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability | ^^^^^^^^^^^ @@ -120,7 +120,7 @@ LL | u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:113:16 + --> $DIR/borrow_interior_mutable_const.rs:114:16 | LL | assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability | ^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/collapsible_if.fixed b/src/tools/clippy/tests/ui/collapsible_if.fixed index 561283fc8e7..efd4187947b 100644 --- a/src/tools/clippy/tests/ui/collapsible_if.fixed +++ b/src/tools/clippy/tests/ui/collapsible_if.fixed @@ -135,4 +135,7 @@ fn main() { if truth() {} } } + + // Fix #5962 + if matches!(true, true) && matches!(true, true) {} } diff --git a/src/tools/clippy/tests/ui/collapsible_if.rs b/src/tools/clippy/tests/ui/collapsible_if.rs index dc9d9b451c0..657f32d38a3 100644 --- a/src/tools/clippy/tests/ui/collapsible_if.rs +++ b/src/tools/clippy/tests/ui/collapsible_if.rs @@ -149,4 +149,9 @@ fn main() { if truth() {} } } + + // Fix #5962 + if matches!(true, true) { + if matches!(true, true) {} + } } diff --git a/src/tools/clippy/tests/ui/collapsible_if.stderr b/src/tools/clippy/tests/ui/collapsible_if.stderr index f56dd65b9dd..acd1ec3f2ca 100644 --- a/src/tools/clippy/tests/ui/collapsible_if.stderr +++ b/src/tools/clippy/tests/ui/collapsible_if.stderr @@ -118,5 +118,13 @@ LL | println!("Hello world!"); LL | } | -error: aborting due to 7 previous errors +error: this `if` statement can be collapsed + --> $DIR/collapsible_if.rs:154:5 + | +LL | / if matches!(true, true) { +LL | | if matches!(true, true) {} +LL | | } + | |_____^ help: collapse nested if block: `if matches!(true, true) && matches!(true, true) {}` + +error: aborting due to 8 previous errors diff --git a/src/tools/clippy/tests/ui/create_dir.fixed b/src/tools/clippy/tests/ui/create_dir.fixed new file mode 100644 index 00000000000..8ed53a56ac0 --- /dev/null +++ b/src/tools/clippy/tests/ui/create_dir.fixed @@ -0,0 +1,17 @@ +// run-rustfix +#![allow(unused_must_use)] +#![warn(clippy::create_dir)] + +use std::fs::create_dir_all; + +fn create_dir() {} + +fn main() { + // Should be warned + create_dir_all("foo"); + create_dir_all("bar").unwrap(); + + // Shouldn't be warned + create_dir(); + std::fs::create_dir_all("foobar"); +} diff --git a/src/tools/clippy/tests/ui/create_dir.rs b/src/tools/clippy/tests/ui/create_dir.rs new file mode 100644 index 00000000000..19c8fc24ba2 --- /dev/null +++ b/src/tools/clippy/tests/ui/create_dir.rs @@ -0,0 +1,17 @@ +// run-rustfix +#![allow(unused_must_use)] +#![warn(clippy::create_dir)] + +use std::fs::create_dir_all; + +fn create_dir() {} + +fn main() { + // Should be warned + std::fs::create_dir("foo"); + std::fs::create_dir("bar").unwrap(); + + // Shouldn't be warned + create_dir(); + std::fs::create_dir_all("foobar"); +} diff --git a/src/tools/clippy/tests/ui/create_dir.stderr b/src/tools/clippy/tests/ui/create_dir.stderr new file mode 100644 index 00000000000..67298fc4709 --- /dev/null +++ b/src/tools/clippy/tests/ui/create_dir.stderr @@ -0,0 +1,16 @@ +error: calling `std::fs::create_dir` where there may be a better way + --> $DIR/create_dir.rs:11:5 + | +LL | std::fs::create_dir("foo"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `std::fs::create_dir_all` instead: `create_dir_all("foo")` + | + = note: `-D clippy::create-dir` implied by `-D warnings` + +error: calling `std::fs::create_dir` where there may be a better way + --> $DIR/create_dir.rs:12:5 + | +LL | std::fs::create_dir("bar").unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `std::fs::create_dir_all` instead: `create_dir_all("bar")` + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/default_trait_access.fixed b/src/tools/clippy/tests/ui/default_trait_access.fixed new file mode 100644 index 00000000000..d05567a3f82 --- /dev/null +++ b/src/tools/clippy/tests/ui/default_trait_access.fixed @@ -0,0 +1,106 @@ +// run-rustfix + +#![allow(unused_imports)] +#![deny(clippy::default_trait_access)] + +use std::default; +use std::default::Default as D2; +use std::string; + +fn main() { + let s1: String = std::string::String::default(); + + let s2 = String::default(); + + let s3: String = std::string::String::default(); + + let s4: String = std::string::String::default(); + + let s5 = string::String::default(); + + let s6: String = std::string::String::default(); + + let s7 = std::string::String::default(); + + let s8: String = DefaultFactory::make_t_badly(); + + let s9: String = DefaultFactory::make_t_nicely(); + + let s10 = DerivedDefault::default(); + + let s11: GenericDerivedDefault<String> = GenericDerivedDefault::default(); + + let s12 = GenericDerivedDefault::<String>::default(); + + let s13 = TupleDerivedDefault::default(); + + let s14: TupleDerivedDefault = TupleDerivedDefault::default(); + + let s15: ArrayDerivedDefault = ArrayDerivedDefault::default(); + + let s16 = ArrayDerivedDefault::default(); + + let s17: TupleStructDerivedDefault = TupleStructDerivedDefault::default(); + + let s18 = TupleStructDerivedDefault::default(); + + let s19 = <DerivedDefault as Default>::default(); + + println!( + "[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}], [{:?}]", + s1, + s2, + s3, + s4, + s5, + s6, + s7, + s8, + s9, + s10, + s11, + s12, + s13, + s14, + s15, + s16, + s17, + s18, + s19, + ); +} + +struct DefaultFactory; + +impl DefaultFactory { + pub fn make_t_badly<T: Default>() -> T { + Default::default() + } + + pub fn make_t_nicely<T: Default>() -> T { + T::default() + } +} + +#[derive(Debug, Default)] +struct DerivedDefault { + pub s: String, +} + +#[derive(Debug, Default)] +struct GenericDerivedDefault<T: Default + std::fmt::Debug> { + pub s: T, +} + +#[derive(Debug, Default)] +struct TupleDerivedDefault { + pub s: (String, String), +} + +#[derive(Debug, Default)] +struct ArrayDerivedDefault { + pub s: [String; 10], +} + +#[derive(Debug, Default)] +struct TupleStructDerivedDefault(String); diff --git a/src/tools/clippy/tests/ui/default_trait_access.rs b/src/tools/clippy/tests/ui/default_trait_access.rs index 2f1490a7036..447e70c0bbb 100644 --- a/src/tools/clippy/tests/ui/default_trait_access.rs +++ b/src/tools/clippy/tests/ui/default_trait_access.rs @@ -1,4 +1,7 @@ -#![warn(clippy::default_trait_access)] +// run-rustfix + +#![allow(unused_imports)] +#![deny(clippy::default_trait_access)] use std::default; use std::default::Default as D2; diff --git a/src/tools/clippy/tests/ui/default_trait_access.stderr b/src/tools/clippy/tests/ui/default_trait_access.stderr index 26b2057548b..df8a5b94ddc 100644 --- a/src/tools/clippy/tests/ui/default_trait_access.stderr +++ b/src/tools/clippy/tests/ui/default_trait_access.stderr @@ -1,49 +1,53 @@ error: calling `std::string::String::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:8:22 + --> $DIR/default_trait_access.rs:11:22 | LL | let s1: String = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` | - = note: `-D clippy::default-trait-access` implied by `-D warnings` +note: the lint level is defined here + --> $DIR/default_trait_access.rs:4:9 + | +LL | #![deny(clippy::default_trait_access)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: calling `std::string::String::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:12:22 + --> $DIR/default_trait_access.rs:15:22 | LL | let s3: String = D2::default(); | ^^^^^^^^^^^^^ help: try: `std::string::String::default()` error: calling `std::string::String::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:14:22 + --> $DIR/default_trait_access.rs:17:22 | LL | let s4: String = std::default::Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` error: calling `std::string::String::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:18:22 + --> $DIR/default_trait_access.rs:21:22 | LL | let s6: String = default::Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` -error: calling `GenericDerivedDefault<std::string::String>::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:28:46 +error: calling `GenericDerivedDefault::default()` is more clear than this expression + --> $DIR/default_trait_access.rs:31:46 | LL | let s11: GenericDerivedDefault<String> = Default::default(); - | ^^^^^^^^^^^^^^^^^^ help: try: `GenericDerivedDefault<std::string::String>::default()` + | ^^^^^^^^^^^^^^^^^^ help: try: `GenericDerivedDefault::default()` error: calling `TupleDerivedDefault::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:34:36 + --> $DIR/default_trait_access.rs:37:36 | LL | let s14: TupleDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `TupleDerivedDefault::default()` error: calling `ArrayDerivedDefault::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:36:36 + --> $DIR/default_trait_access.rs:39:36 | LL | let s15: ArrayDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `ArrayDerivedDefault::default()` error: calling `TupleStructDerivedDefault::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:40:42 + --> $DIR/default_trait_access.rs:43:42 | LL | let s17: TupleStructDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `TupleStructDerivedDefault::default()` diff --git a/src/tools/clippy/tests/ui/doc.rs b/src/tools/clippy/tests/ui/doc.rs index 77620c857e6..68c5d32846f 100644 --- a/src/tools/clippy/tests/ui/doc.rs +++ b/src/tools/clippy/tests/ui/doc.rs @@ -49,6 +49,16 @@ fn test_emphasis() { fn test_units() { } +/// This tests allowed identifiers. +/// DirectX +/// ECMAScript +/// OAuth GraphQL +/// TeX LaTeX BibTeX BibLaTeX +/// CamelCase (see also #2395) +/// be_sure_we_got_to_the_end_of_it +fn test_allowed() { +} + /// This test has [a link_with_underscores][chunked-example] inside it. See #823. /// See also [the issue tracker](https://github.com/rust-lang/rust-clippy/search?q=clippy::doc_markdown&type=Issues) /// on GitHub (which is a camel-cased word, but is OK). And here is another [inline link][inline_link]. @@ -168,9 +178,6 @@ fn issue_1920() {} /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels fn issue_1832() {} -/// Ok: CamelCase (It should not be surrounded by backticks) -fn issue_2395() {} - /// An iterator over mycrate::Collection's values. /// It should not lint a `'static` lifetime in ticks. fn issue_2210() {} diff --git a/src/tools/clippy/tests/ui/doc.stderr b/src/tools/clippy/tests/ui/doc.stderr index ae9bb394cb9..23fca43590b 100644 --- a/src/tools/clippy/tests/ui/doc.stderr +++ b/src/tools/clippy/tests/ui/doc.stderr @@ -54,131 +54,137 @@ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the doc LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation + --> $DIR/doc.rs:58:5 + | +LL | /// be_sure_we_got_to_the_end_of_it + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: you should put `link_with_underscores` between ticks in the documentation - --> $DIR/doc.rs:52:22 + --> $DIR/doc.rs:62:22 | LL | /// This test has [a link_with_underscores][chunked-example] inside it. See #823. | ^^^^^^^^^^^^^^^^^^^^^ error: you should put `inline_link2` between ticks in the documentation - --> $DIR/doc.rs:55:21 + --> $DIR/doc.rs:65:21 | LL | /// It can also be [inline_link2]. | ^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:65:5 + --> $DIR/doc.rs:75:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `CamelCaseThing` between ticks in the documentation - --> $DIR/doc.rs:73:8 + --> $DIR/doc.rs:83:8 | LL | /// ## CamelCaseThing | ^^^^^^^^^^^^^^ error: you should put `CamelCaseThing` between ticks in the documentation - --> $DIR/doc.rs:76:7 + --> $DIR/doc.rs:86:7 | LL | /// # CamelCaseThing | ^^^^^^^^^^^^^^ error: you should put `CamelCaseThing` between ticks in the documentation - --> $DIR/doc.rs:78:22 + --> $DIR/doc.rs:88:22 | LL | /// Not a title #897 CamelCaseThing | ^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:79:5 + --> $DIR/doc.rs:89:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:86:5 + --> $DIR/doc.rs:96:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:99:5 + --> $DIR/doc.rs:109:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `FooBar` between ticks in the documentation - --> $DIR/doc.rs:110:43 + --> $DIR/doc.rs:120:43 | LL | /** E.g., serialization of an empty list: FooBar | ^^^^^^ error: you should put `BarQuz` between ticks in the documentation - --> $DIR/doc.rs:115:5 + --> $DIR/doc.rs:125:5 | LL | And BarQuz too. | ^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:116:1 + --> $DIR/doc.rs:126:1 | LL | be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `FooBar` between ticks in the documentation - --> $DIR/doc.rs:121:43 + --> $DIR/doc.rs:131:43 | LL | /** E.g., serialization of an empty list: FooBar | ^^^^^^ error: you should put `BarQuz` between ticks in the documentation - --> $DIR/doc.rs:126:5 + --> $DIR/doc.rs:136:5 | LL | And BarQuz too. | ^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:127:1 + --> $DIR/doc.rs:137:1 | LL | be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:138:5 + --> $DIR/doc.rs:148:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:165:13 + --> $DIR/doc.rs:175:13 | LL | /// Not ok: http://www.unicode.org | ^^^^^^^^^^^^^^^^^^^^^^ error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:166:13 + --> $DIR/doc.rs:176:13 | LL | /// Not ok: https://www.unicode.org | ^^^^^^^^^^^^^^^^^^^^^^^ error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:167:13 + --> $DIR/doc.rs:177:13 | LL | /// Not ok: http://www.unicode.org/ | ^^^^^^^^^^^^^^^^^^^^^^ error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:168:13 + --> $DIR/doc.rs:178:13 | LL | /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `mycrate::Collection` between ticks in the documentation - --> $DIR/doc.rs:174:22 + --> $DIR/doc.rs:181:22 | LL | /// An iterator over mycrate::Collection's values. | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 30 previous errors +error: aborting due to 31 previous errors diff --git a/src/tools/clippy/tests/ui/functions_maxlines.stderr b/src/tools/clippy/tests/ui/functions_maxlines.stderr index c640c82d6d7..dc6c8ba2f15 100644 --- a/src/tools/clippy/tests/ui/functions_maxlines.stderr +++ b/src/tools/clippy/tests/ui/functions_maxlines.stderr @@ -1,4 +1,4 @@ -error: this function has a large number of lines +error: this function has too many lines (102/100) --> $DIR/functions_maxlines.rs:58:1 | LL | / fn bad_lines() { diff --git a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr index 1312c70b6d5..d7d45ef9b0b 100644 --- a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr +++ b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr @@ -1,4 +1,4 @@ -error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type +error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:38:5 | LL | x.field.map(do_nothing); @@ -8,7 +8,7 @@ LL | x.field.map(do_nothing); | = note: `-D clippy::option-map-unit-fn` implied by `-D warnings` -error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type +error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:40:5 | LL | x.field.map(do_nothing); @@ -16,7 +16,7 @@ LL | x.field.map(do_nothing); | | | help: try this: `if let Some(x_field) = x.field { do_nothing(x_field) }` -error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type +error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:42:5 | LL | x.field.map(diverge); @@ -24,7 +24,7 @@ LL | x.field.map(diverge); | | | help: try this: `if let Some(x_field) = x.field { diverge(x_field) }` -error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:48:5 | LL | x.field.map(|value| x.do_option_nothing(value + captured)); @@ -32,7 +32,7 @@ LL | x.field.map(|value| x.do_option_nothing(value + captured)); | | | help: try this: `if let Some(value) = x.field { x.do_option_nothing(value + captured) }` -error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:50:5 | LL | x.field.map(|value| { x.do_option_plus_one(value + captured); }); @@ -40,7 +40,7 @@ LL | x.field.map(|value| { x.do_option_plus_one(value + captured); }); | | | help: try this: `if let Some(value) = x.field { x.do_option_plus_one(value + captured); }` -error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:53:5 | LL | x.field.map(|value| do_nothing(value + captured)); @@ -48,7 +48,7 @@ LL | x.field.map(|value| do_nothing(value + captured)); | | | help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }` -error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:55:5 | LL | x.field.map(|value| { do_nothing(value + captured) }); @@ -56,7 +56,7 @@ LL | x.field.map(|value| { do_nothing(value + captured) }); | | | help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }` -error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:57:5 | LL | x.field.map(|value| { do_nothing(value + captured); }); @@ -64,7 +64,7 @@ LL | x.field.map(|value| { do_nothing(value + captured); }); | | | help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }` -error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:59:5 | LL | x.field.map(|value| { { do_nothing(value + captured); } }); @@ -72,7 +72,7 @@ LL | x.field.map(|value| { { do_nothing(value + captured); } }); | | | help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }` -error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:62:5 | LL | x.field.map(|value| diverge(value + captured)); @@ -80,7 +80,7 @@ LL | x.field.map(|value| diverge(value + captured)); | | | help: try this: `if let Some(value) = x.field { diverge(value + captured) }` -error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:64:5 | LL | x.field.map(|value| { diverge(value + captured) }); @@ -88,7 +88,7 @@ LL | x.field.map(|value| { diverge(value + captured) }); | | | help: try this: `if let Some(value) = x.field { diverge(value + captured) }` -error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:66:5 | LL | x.field.map(|value| { diverge(value + captured); }); @@ -96,7 +96,7 @@ LL | x.field.map(|value| { diverge(value + captured); }); | | | help: try this: `if let Some(value) = x.field { diverge(value + captured); }` -error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:68:5 | LL | x.field.map(|value| { { diverge(value + captured); } }); @@ -104,7 +104,7 @@ LL | x.field.map(|value| { { diverge(value + captured); } }); | | | help: try this: `if let Some(value) = x.field { diverge(value + captured); }` -error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:73:5 | LL | x.field.map(|value| { let y = plus_one(value + captured); }); @@ -112,7 +112,7 @@ LL | x.field.map(|value| { let y = plus_one(value + captured); }); | | | help: try this: `if let Some(value) = x.field { let y = plus_one(value + captured); }` -error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:75:5 | LL | x.field.map(|value| { plus_one(value + captured); }); @@ -120,7 +120,7 @@ LL | x.field.map(|value| { plus_one(value + captured); }); | | | help: try this: `if let Some(value) = x.field { plus_one(value + captured); }` -error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:77:5 | LL | x.field.map(|value| { { plus_one(value + captured); } }); @@ -128,7 +128,7 @@ LL | x.field.map(|value| { { plus_one(value + captured); } }); | | | help: try this: `if let Some(value) = x.field { plus_one(value + captured); }` -error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:80:5 | LL | x.field.map(|ref value| { do_nothing(value + captured) }); @@ -136,7 +136,7 @@ LL | x.field.map(|ref value| { do_nothing(value + captured) }); | | | help: try this: `if let Some(ref value) = x.field { do_nothing(value + captured) }` -error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type +error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:82:5 | LL | option().map(do_nothing);} diff --git a/src/tools/clippy/tests/ui/or_fun_call.fixed b/src/tools/clippy/tests/ui/or_fun_call.fixed index 67faa8bd4a0..5fb568672d3 100644 --- a/src/tools/clippy/tests/ui/or_fun_call.fixed +++ b/src/tools/clippy/tests/ui/or_fun_call.fixed @@ -58,12 +58,6 @@ fn or_fun_call() { let without_default = Some(Foo); without_default.unwrap_or_else(Foo::new); - let mut map = HashMap::<u64, String>::new(); - map.entry(42).or_insert_with(String::new); - - let mut btree = BTreeMap::<u64, String>::new(); - btree.entry(42).or_insert_with(String::new); - let stringy = Some(String::from("")); let _ = stringy.unwrap_or_else(|| "".to_owned()); @@ -122,6 +116,17 @@ pub fn skip_const_fn_with_no_args() { Some(42) } let _ = None.or(foo()); + + // See issue #5693. + let mut map = std::collections::HashMap::new(); + map.insert(1, vec![1]); + map.entry(1).or_insert(vec![]); + + let mut map = HashMap::<u64, String>::new(); + map.entry(42).or_insert(String::new()); + + let mut btree = BTreeMap::<u64, String>::new(); + btree.entry(42).or_insert(String::new()); } fn main() {} diff --git a/src/tools/clippy/tests/ui/or_fun_call.rs b/src/tools/clippy/tests/ui/or_fun_call.rs index 9867e2eedcf..737b0f7e55b 100644 --- a/src/tools/clippy/tests/ui/or_fun_call.rs +++ b/src/tools/clippy/tests/ui/or_fun_call.rs @@ -58,12 +58,6 @@ fn or_fun_call() { let without_default = Some(Foo); without_default.unwrap_or(Foo::new()); - let mut map = HashMap::<u64, String>::new(); - map.entry(42).or_insert(String::new()); - - let mut btree = BTreeMap::<u64, String>::new(); - btree.entry(42).or_insert(String::new()); - let stringy = Some(String::from("")); let _ = stringy.unwrap_or("".to_owned()); @@ -122,6 +116,17 @@ pub fn skip_const_fn_with_no_args() { Some(42) } let _ = None.or(foo()); + + // See issue #5693. + let mut map = std::collections::HashMap::new(); + map.insert(1, vec![1]); + map.entry(1).or_insert(vec![]); + + let mut map = HashMap::<u64, String>::new(); + map.entry(42).or_insert(String::new()); + + let mut btree = BTreeMap::<u64, String>::new(); + btree.entry(42).or_insert(String::new()); } fn main() {} diff --git a/src/tools/clippy/tests/ui/or_fun_call.stderr b/src/tools/clippy/tests/ui/or_fun_call.stderr index bc5978b538f..b8a436993f3 100644 --- a/src/tools/clippy/tests/ui/or_fun_call.stderr +++ b/src/tools/clippy/tests/ui/or_fun_call.stderr @@ -60,35 +60,23 @@ error: use of `unwrap_or` followed by a function call LL | without_default.unwrap_or(Foo::new()); | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)` -error: use of `or_insert` followed by a function call - --> $DIR/or_fun_call.rs:62:19 - | -LL | map.entry(42).or_insert(String::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)` - -error: use of `or_insert` followed by a function call - --> $DIR/or_fun_call.rs:65:21 - | -LL | btree.entry(42).or_insert(String::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)` - error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:68:21 + --> $DIR/or_fun_call.rs:62:21 | LL | let _ = stringy.unwrap_or("".to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "".to_owned())` error: use of `or` followed by a function call - --> $DIR/or_fun_call.rs:93:35 + --> $DIR/or_fun_call.rs:87:35 | LL | let _ = Some("a".to_string()).or(Some("b".to_string())); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some("b".to_string()))` error: use of `or` followed by a function call - --> $DIR/or_fun_call.rs:97:10 + --> $DIR/or_fun_call.rs:91:10 | LL | .or(Some(Bar(b, Duration::from_secs(2)))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some(Bar(b, Duration::from_secs(2))))` -error: aborting due to 15 previous errors +error: aborting due to 13 previous errors diff --git a/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.stderr b/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.stderr index 467e00263cd..4f3a8c6b792 100644 --- a/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.stderr +++ b/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.stderr @@ -1,4 +1,4 @@ -error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:35:5 | LL | x.field.map(do_nothing); @@ -8,7 +8,7 @@ LL | x.field.map(do_nothing); | = note: `-D clippy::result-map-unit-fn` implied by `-D warnings` -error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:37:5 | LL | x.field.map(do_nothing); @@ -16,7 +16,7 @@ LL | x.field.map(do_nothing); | | | help: try this: `if let Ok(x_field) = x.field { do_nothing(x_field) }` -error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:39:5 | LL | x.field.map(diverge); @@ -24,7 +24,7 @@ LL | x.field.map(diverge); | | | help: try this: `if let Ok(x_field) = x.field { diverge(x_field) }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:45:5 | LL | x.field.map(|value| x.do_result_nothing(value + captured)); @@ -32,7 +32,7 @@ LL | x.field.map(|value| x.do_result_nothing(value + captured)); | | | help: try this: `if let Ok(value) = x.field { x.do_result_nothing(value + captured) }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:47:5 | LL | x.field.map(|value| { x.do_result_plus_one(value + captured); }); @@ -40,7 +40,7 @@ LL | x.field.map(|value| { x.do_result_plus_one(value + captured); }); | | | help: try this: `if let Ok(value) = x.field { x.do_result_plus_one(value + captured); }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:50:5 | LL | x.field.map(|value| do_nothing(value + captured)); @@ -48,7 +48,7 @@ LL | x.field.map(|value| do_nothing(value + captured)); | | | help: try this: `if let Ok(value) = x.field { do_nothing(value + captured) }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:52:5 | LL | x.field.map(|value| { do_nothing(value + captured) }); @@ -56,7 +56,7 @@ LL | x.field.map(|value| { do_nothing(value + captured) }); | | | help: try this: `if let Ok(value) = x.field { do_nothing(value + captured) }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:54:5 | LL | x.field.map(|value| { do_nothing(value + captured); }); @@ -64,7 +64,7 @@ LL | x.field.map(|value| { do_nothing(value + captured); }); | | | help: try this: `if let Ok(value) = x.field { do_nothing(value + captured); }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:56:5 | LL | x.field.map(|value| { { do_nothing(value + captured); } }); @@ -72,7 +72,7 @@ LL | x.field.map(|value| { { do_nothing(value + captured); } }); | | | help: try this: `if let Ok(value) = x.field { do_nothing(value + captured); }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:59:5 | LL | x.field.map(|value| diverge(value + captured)); @@ -80,7 +80,7 @@ LL | x.field.map(|value| diverge(value + captured)); | | | help: try this: `if let Ok(value) = x.field { diverge(value + captured) }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:61:5 | LL | x.field.map(|value| { diverge(value + captured) }); @@ -88,7 +88,7 @@ LL | x.field.map(|value| { diverge(value + captured) }); | | | help: try this: `if let Ok(value) = x.field { diverge(value + captured) }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:63:5 | LL | x.field.map(|value| { diverge(value + captured); }); @@ -96,7 +96,7 @@ LL | x.field.map(|value| { diverge(value + captured); }); | | | help: try this: `if let Ok(value) = x.field { diverge(value + captured); }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:65:5 | LL | x.field.map(|value| { { diverge(value + captured); } }); @@ -104,7 +104,7 @@ LL | x.field.map(|value| { { diverge(value + captured); } }); | | | help: try this: `if let Ok(value) = x.field { diverge(value + captured); }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:70:5 | LL | x.field.map(|value| { let y = plus_one(value + captured); }); @@ -112,7 +112,7 @@ LL | x.field.map(|value| { let y = plus_one(value + captured); }); | | | help: try this: `if let Ok(value) = x.field { let y = plus_one(value + captured); }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:72:5 | LL | x.field.map(|value| { plus_one(value + captured); }); @@ -120,7 +120,7 @@ LL | x.field.map(|value| { plus_one(value + captured); }); | | | help: try this: `if let Ok(value) = x.field { plus_one(value + captured); }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:74:5 | LL | x.field.map(|value| { { plus_one(value + captured); } }); @@ -128,7 +128,7 @@ LL | x.field.map(|value| { { plus_one(value + captured); } }); | | | help: try this: `if let Ok(value) = x.field { plus_one(value + captured); }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:77:5 | LL | x.field.map(|ref value| { do_nothing(value + captured) }); diff --git a/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr b/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr index b23cc608621..88e4efdb0f0 100644 --- a/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr +++ b/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr @@ -1,4 +1,4 @@ -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_unfixable.rs:23:5 | LL | x.field.map(|value| { do_nothing(value); do_nothing(value) }); @@ -8,7 +8,7 @@ LL | x.field.map(|value| { do_nothing(value); do_nothing(value) }); | = note: `-D clippy::result-map-unit-fn` implied by `-D warnings` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_unfixable.rs:25:5 | LL | x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) }); @@ -16,7 +16,7 @@ LL | x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) | | | help: try this: `if let Ok(value) = x.field { ... }` -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_unfixable.rs:29:5 | LL | x.field.map(|value| { @@ -30,7 +30,7 @@ LL | || }); | |_______| | -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_unfixable.rs:33:5 | LL | x.field.map(|value| { do_nothing(value); do_nothing(value); }); @@ -38,7 +38,7 @@ LL | x.field.map(|value| { do_nothing(value); do_nothing(value); }); | | | help: try this: `if let Ok(value) = x.field { ... }` -error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()` --> $DIR/result_map_unit_fn_unfixable.rs:37:5 | LL | "12".parse::<i32>().map(diverge); @@ -46,7 +46,7 @@ LL | "12".parse::<i32>().map(diverge); | | | help: try this: `if let Ok(a) = "12".parse::<i32>() { diverge(a) }` -error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type +error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()` --> $DIR/result_map_unit_fn_unfixable.rs:43:5 | LL | y.map(do_nothing); diff --git a/src/tools/clippy/tests/ui/same_item_push.rs b/src/tools/clippy/tests/ui/same_item_push.rs index bfe27e02044..a37c8782ec3 100644 --- a/src/tools/clippy/tests/ui/same_item_push.rs +++ b/src/tools/clippy/tests/ui/same_item_push.rs @@ -1,5 +1,7 @@ #![warn(clippy::same_item_push)] +const VALUE: u8 = 7; + fn mutate_increment(x: &mut u8) -> u8 { *x += 1; *x @@ -9,65 +11,81 @@ fn increment(x: u8) -> u8 { x + 1 } -fn main() { - // Test for basic case - let mut spaces = Vec::with_capacity(10); - for _ in 0..10 { - spaces.push(vec![b' ']); - } +fn fun() -> usize { + 42 +} - let mut vec2: Vec<u8> = Vec::new(); +fn main() { + // ** linted cases ** + let mut vec: Vec<u8> = Vec::new(); let item = 2; for _ in 5..=20 { - vec2.push(item); + vec.push(item); } - let mut vec3: Vec<u8> = Vec::new(); + let mut vec: Vec<u8> = Vec::new(); for _ in 0..15 { let item = 2; - vec3.push(item); + vec.push(item); } - let mut vec4: Vec<u8> = Vec::new(); + let mut vec: Vec<u8> = Vec::new(); for _ in 0..15 { - vec4.push(13); + vec.push(13); + } + + let mut vec = Vec::new(); + for _ in 0..20 { + vec.push(VALUE); + } + + let mut vec = Vec::new(); + let item = VALUE; + for _ in 0..20 { + vec.push(item); + } + + // ** non-linted cases ** + let mut spaces = Vec::with_capacity(10); + for _ in 0..10 { + spaces.push(vec![b' ']); } // Suggestion should not be given as pushed variable can mutate - let mut vec5: Vec<u8> = Vec::new(); + let mut vec: Vec<u8> = Vec::new(); let mut item: u8 = 2; for _ in 0..30 { - vec5.push(mutate_increment(&mut item)); + vec.push(mutate_increment(&mut item)); } - let mut vec6: Vec<u8> = Vec::new(); + let mut vec: Vec<u8> = Vec::new(); let mut item: u8 = 2; let mut item2 = &mut mutate_increment(&mut item); for _ in 0..30 { - vec6.push(mutate_increment(item2)); + vec.push(mutate_increment(item2)); } - let mut vec7: Vec<usize> = Vec::new(); + let mut vec: Vec<usize> = Vec::new(); for (a, b) in [0, 1, 4, 9, 16].iter().enumerate() { - vec7.push(a); + vec.push(a); } - let mut vec8: Vec<u8> = Vec::new(); + let mut vec: Vec<u8> = Vec::new(); for i in 0..30 { - vec8.push(increment(i)); + vec.push(increment(i)); } - let mut vec9: Vec<u8> = Vec::new(); + let mut vec: Vec<u8> = Vec::new(); for i in 0..30 { - vec9.push(i + i * i); + vec.push(i + i * i); } // Suggestion should not be given as there are multiple pushes that are not the same - let mut vec10: Vec<u8> = Vec::new(); + let mut vec: Vec<u8> = Vec::new(); let item: u8 = 2; for _ in 0..30 { - vec10.push(item); - vec10.push(item * 2); + vec.push(item); + vec.push(item * 2); } // Suggestion should not be given as Vec is not involved @@ -82,16 +100,52 @@ fn main() { for i in 0..30 { vec_a.push(A { kind: i }); } - let mut vec12: Vec<u8> = Vec::new(); + let mut vec: Vec<u8> = Vec::new(); for a in vec_a { - vec12.push(2u8.pow(a.kind)); + vec.push(2u8.pow(a.kind)); } // Fix #5902 - let mut vec13: Vec<u8> = Vec::new(); + let mut vec: Vec<u8> = Vec::new(); let mut item = 0; for _ in 0..10 { - vec13.push(item); + vec.push(item); item += 10; } + + // Fix #5979 + let mut vec: Vec<std::fs::File> = Vec::new(); + for _ in 0..10 { + vec.push(std::fs::File::open("foobar").unwrap()); + } + // Fix #5979 + #[derive(Clone)] + struct S {} + + trait T {} + impl T for S {} + + let mut vec: Vec<Box<dyn T>> = Vec::new(); + for _ in 0..10 { + vec.push(Box::new(S {})); + } + + // Fix #5985 + let mut vec = Vec::new(); + let item = 42; + let item = fun(); + for _ in 0..20 { + vec.push(item); + } + + // Fix #5985 + let mut vec = Vec::new(); + let key = 1; + for _ in 0..20 { + let item = match key { + 1 => 10, + _ => 0, + }; + vec.push(item); + } } diff --git a/src/tools/clippy/tests/ui/same_item_push.stderr b/src/tools/clippy/tests/ui/same_item_push.stderr index ddc5d48cd41..d9ffa15780a 100644 --- a/src/tools/clippy/tests/ui/same_item_push.stderr +++ b/src/tools/clippy/tests/ui/same_item_push.stderr @@ -1,35 +1,43 @@ error: it looks like the same item is being pushed into this Vec - --> $DIR/same_item_push.rs:16:9 + --> $DIR/same_item_push.rs:23:9 | -LL | spaces.push(vec![b' ']); - | ^^^^^^ +LL | vec.push(item); + | ^^^ | = note: `-D clippy::same-item-push` implied by `-D warnings` - = help: try using vec![vec![b' '];SIZE] or spaces.resize(NEW_SIZE, vec![b' ']) + = help: try using vec![item;SIZE] or vec.resize(NEW_SIZE, item) error: it looks like the same item is being pushed into this Vec - --> $DIR/same_item_push.rs:22:9 + --> $DIR/same_item_push.rs:29:9 | -LL | vec2.push(item); - | ^^^^ +LL | vec.push(item); + | ^^^ | - = help: try using vec![item;SIZE] or vec2.resize(NEW_SIZE, item) + = help: try using vec![item;SIZE] or vec.resize(NEW_SIZE, item) error: it looks like the same item is being pushed into this Vec - --> $DIR/same_item_push.rs:28:9 + --> $DIR/same_item_push.rs:34:9 | -LL | vec3.push(item); - | ^^^^ +LL | vec.push(13); + | ^^^ | - = help: try using vec![item;SIZE] or vec3.resize(NEW_SIZE, item) + = help: try using vec![13;SIZE] or vec.resize(NEW_SIZE, 13) error: it looks like the same item is being pushed into this Vec - --> $DIR/same_item_push.rs:33:9 + --> $DIR/same_item_push.rs:39:9 | -LL | vec4.push(13); - | ^^^^ +LL | vec.push(VALUE); + | ^^^ | - = help: try using vec![13;SIZE] or vec4.resize(NEW_SIZE, 13) + = help: try using vec![VALUE;SIZE] or vec.resize(NEW_SIZE, VALUE) -error: aborting due to 4 previous errors +error: it looks like the same item is being pushed into this Vec + --> $DIR/same_item_push.rs:45:9 + | +LL | vec.push(item); + | ^^^ + | + = help: try using vec![item;SIZE] or vec.resize(NEW_SIZE, item) + +error: aborting due to 5 previous errors diff --git a/src/tools/clippy/tests/ui/temporary_assignment.rs b/src/tools/clippy/tests/ui/temporary_assignment.rs index c6c315d5fab..b4a931043b0 100644 --- a/src/tools/clippy/tests/ui/temporary_assignment.rs +++ b/src/tools/clippy/tests/ui/temporary_assignment.rs @@ -1,4 +1,5 @@ #![warn(clippy::temporary_assignment)] +#![allow(const_item_mutation)] use std::ops::{Deref, DerefMut}; @@ -53,11 +54,6 @@ fn main() { ArrayStruct { array: [0] }.array[0] = 1; (0, 0).0 = 1; - A.0 = 2; - B.field = 2; - C.structure.field = 2; - D.array[0] = 2; - // no error s.field = 1; t.0 = 1; diff --git a/src/tools/clippy/tests/ui/temporary_assignment.stderr b/src/tools/clippy/tests/ui/temporary_assignment.stderr index 4efe2d4bb67..4cc32c79f05 100644 --- a/src/tools/clippy/tests/ui/temporary_assignment.stderr +++ b/src/tools/clippy/tests/ui/temporary_assignment.stderr @@ -1,5 +1,5 @@ error: assignment to temporary - --> $DIR/temporary_assignment.rs:47:5 + --> $DIR/temporary_assignment.rs:48:5 | LL | Struct { field: 0 }.field = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | Struct { field: 0 }.field = 1; = note: `-D clippy::temporary-assignment` implied by `-D warnings` error: assignment to temporary - --> $DIR/temporary_assignment.rs:48:5 + --> $DIR/temporary_assignment.rs:49:5 | LL | / MultiStruct { LL | | structure: Struct { field: 0 }, @@ -17,40 +17,16 @@ LL | | .field = 1; | |______________^ error: assignment to temporary - --> $DIR/temporary_assignment.rs:53:5 + --> $DIR/temporary_assignment.rs:54:5 | LL | ArrayStruct { array: [0] }.array[0] = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: assignment to temporary - --> $DIR/temporary_assignment.rs:54:5 + --> $DIR/temporary_assignment.rs:55:5 | LL | (0, 0).0 = 1; | ^^^^^^^^^^^^ -error: assignment to temporary - --> $DIR/temporary_assignment.rs:56:5 - | -LL | A.0 = 2; - | ^^^^^^^ - -error: assignment to temporary - --> $DIR/temporary_assignment.rs:57:5 - | -LL | B.field = 2; - | ^^^^^^^^^^^ - -error: assignment to temporary - --> $DIR/temporary_assignment.rs:58:5 - | -LL | C.structure.field = 2; - | ^^^^^^^^^^^^^^^^^^^^^ - -error: assignment to temporary - --> $DIR/temporary_assignment.rs:59:5 - | -LL | D.array[0] = 2; - | ^^^^^^^^^^^^^^ - -error: aborting due to 8 previous errors +error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs index 0d8a322f2b2..26b03bdc740 100644 --- a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs @@ -51,4 +51,12 @@ fn transmute_ptr_to_ptr() { let _: &GenericParam<&LifetimeParam<'static>> = unsafe { std::mem::transmute(&GenericParam { t: &lp }) }; } +// dereferencing raw pointers in const contexts, should not lint as it's unstable (issue 5959) +const _: &() = { + struct ZST; + let zst = &ZST; + + unsafe { std::mem::transmute::<&'static ZST, &'static ()>(zst) } +}; + fn main() {} diff --git a/src/tools/clippy/tests/ui/unit_arg.rs b/src/tools/clippy/tests/ui/unit_arg.rs index 2992abae775..fec115ff29d 100644 --- a/src/tools/clippy/tests/ui/unit_arg.rs +++ b/src/tools/clippy/tests/ui/unit_arg.rs @@ -1,5 +1,11 @@ #![warn(clippy::unit_arg)] -#![allow(clippy::no_effect, unused_must_use, unused_variables)] +#![allow( + clippy::no_effect, + unused_must_use, + unused_variables, + clippy::unused_unit, + clippy::or_fun_call +)] use std::fmt::Debug; @@ -47,6 +53,11 @@ fn bad() { foo(3); }, ); + // here Some(foo(2)) isn't the top level statement expression, wrap the suggestion in a block + None.or(Some(foo(2))); + // in this case, the suggestion can be inlined, no need for a surrounding block + // foo(()); foo(()) instead of { foo(()); foo(()) } + foo(foo(())) } fn ok() { diff --git a/src/tools/clippy/tests/ui/unit_arg.stderr b/src/tools/clippy/tests/ui/unit_arg.stderr index 56f6a855dfa..90fee3aab23 100644 --- a/src/tools/clippy/tests/ui/unit_arg.stderr +++ b/src/tools/clippy/tests/ui/unit_arg.stderr @@ -1,5 +1,5 @@ error: passing a unit value to a function - --> $DIR/unit_arg.rs:23:5 + --> $DIR/unit_arg.rs:29:5 | LL | / foo({ LL | | 1; @@ -11,34 +11,28 @@ help: remove the semicolon from the last statement in the block | LL | 1 | -help: or move the expression in front of the call... +help: or move the expression in front of the call and replace it with the unit literal `()` | LL | { LL | 1; LL | }; - | -help: ...and use a unit literal instead - | LL | foo(()); - | ^^ + | error: passing a unit value to a function - --> $DIR/unit_arg.rs:26:5 + --> $DIR/unit_arg.rs:32:5 | LL | foo(foo(1)); | ^^^^^^^^^^^ | -help: move the expression in front of the call... +help: move the expression in front of the call and replace it with the unit literal `()` | LL | foo(1); - | -help: ...and use a unit literal instead - | LL | foo(()); - | ^^ + | error: passing a unit value to a function - --> $DIR/unit_arg.rs:27:5 + --> $DIR/unit_arg.rs:33:5 | LL | / foo({ LL | | foo(1); @@ -50,20 +44,17 @@ help: remove the semicolon from the last statement in the block | LL | foo(2) | -help: or move the expression in front of the call... +help: or move the expression in front of the call and replace it with the unit literal `()` | LL | { LL | foo(1); LL | foo(2); LL | }; - | -help: ...and use a unit literal instead - | LL | foo(()); - | ^^ + | error: passing a unit value to a function - --> $DIR/unit_arg.rs:32:5 + --> $DIR/unit_arg.rs:38:5 | LL | / b.bar({ LL | | 1; @@ -74,35 +65,29 @@ help: remove the semicolon from the last statement in the block | LL | 1 | -help: or move the expression in front of the call... +help: or move the expression in front of the call and replace it with the unit literal `()` | LL | { LL | 1; LL | }; - | -help: ...and use a unit literal instead - | LL | b.bar(()); - | ^^ + | error: passing unit values to a function - --> $DIR/unit_arg.rs:35:5 + --> $DIR/unit_arg.rs:41:5 | LL | taking_multiple_units(foo(0), foo(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: move the expressions in front of the call... +help: move the expressions in front of the call and replace them with the unit literal `()` | LL | foo(0); LL | foo(1); - | -help: ...and use unit literals instead - | LL | taking_multiple_units((), ()); - | ^^ ^^ + | error: passing unit values to a function - --> $DIR/unit_arg.rs:36:5 + --> $DIR/unit_arg.rs:42:5 | LL | / taking_multiple_units(foo(0), { LL | | foo(1); @@ -114,21 +99,18 @@ help: remove the semicolon from the last statement in the block | LL | foo(2) | -help: or move the expressions in front of the call... +help: or move the expressions in front of the call and replace them with the unit literal `()` | LL | foo(0); LL | { LL | foo(1); LL | foo(2); LL | }; - | -help: ...and use unit literals instead - | LL | taking_multiple_units((), ()); - | ^^ ^^ + | error: passing unit values to a function - --> $DIR/unit_arg.rs:40:5 + --> $DIR/unit_arg.rs:46:5 | LL | / taking_multiple_units( LL | | { @@ -147,7 +129,7 @@ help: remove the semicolon from the last statement in the block | LL | foo(3) | -help: or move the expressions in front of the call... +help: or move the expressions in front of the call and replace them with the unit literal `()` | LL | { LL | foo(0); @@ -156,26 +138,44 @@ LL | }; LL | { LL | foo(2); ... -help: ...and use unit literals instead + +error: passing a unit value to a function + --> $DIR/unit_arg.rs:57:13 + | +LL | None.or(Some(foo(2))); + | ^^^^^^^^^^^^ | -LL | (), -LL | (), +help: move the expression in front of the call and replace it with the unit literal `()` + | +LL | None.or({ +LL | foo(2); +LL | Some(()) +LL | }); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:82:5 + --> $DIR/unit_arg.rs:60:5 | -LL | Some(foo(1)) +LL | foo(foo(())) | ^^^^^^^^^^^^ | -help: move the expression in front of the call... +help: move the expression in front of the call and replace it with the unit literal `()` | -LL | foo(1); +LL | foo(()); +LL | foo(()) | -help: ...and use a unit literal instead + +error: passing a unit value to a function + --> $DIR/unit_arg.rs:93:5 | +LL | Some(foo(1)) + | ^^^^^^^^^^^^ + | +help: move the expression in front of the call and replace it with the unit literal `()` + | +LL | foo(1); LL | Some(()) - | ^^ + | -error: aborting due to 8 previous errors +error: aborting due to 10 previous errors diff --git a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr index bb58483584b..456b12a2c6b 100644 --- a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr +++ b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr @@ -22,14 +22,11 @@ error: passing unit values to a function LL | taking_two_units({}, foo(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: move the expression in front of the call... +help: move the expression in front of the call and replace it with the unit literal `()` | LL | foo(0); - | -help: ...and use unit literals instead - | LL | taking_two_units((), ()); - | ^^ ^^ + | error: passing unit values to a function --> $DIR/unit_arg_empty_blocks.rs:18:5 @@ -37,15 +34,12 @@ error: passing unit values to a function LL | taking_three_units({}, foo(0), foo(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: move the expressions in front of the call... +help: move the expressions in front of the call and replace them with the unit literal `()` | LL | foo(0); LL | foo(1); - | -help: ...and use unit literals instead - | LL | taking_three_units((), (), ()); - | ^^ ^^ ^^ + | error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed b/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed index 31c2ba0f9c5..ad0d0387db0 100644 --- a/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed @@ -25,17 +25,25 @@ fn unnecessary_sort_by() { vec.sort_by(|_, b| b.cmp(&5)); vec.sort_by(|_, b| b.cmp(c)); vec.sort_unstable_by(|a, _| a.cmp(c)); + + // Ignore vectors of references + let mut vec: Vec<&&&isize> = vec![&&&3, &&&6, &&&1, &&&2, &&&5]; + vec.sort_by(|a, b| (***a).abs().cmp(&(***b).abs())); + vec.sort_unstable_by(|a, b| (***a).abs().cmp(&(***b).abs())); + vec.sort_by(|a, b| b.cmp(a)); + vec.sort_unstable_by(|a, b| b.cmp(a)); } -// Should not be linted to avoid hitting https://github.com/rust-lang/rust/issues/34162 +// Do not suggest returning a reference to the closure parameter of `Vec::sort_by_key` mod issue_5754 { - struct Test(String); + #[derive(Clone, Copy)] + struct Test(usize); #[derive(PartialOrd, Ord, PartialEq, Eq)] - struct Wrapper<'a>(&'a str); + struct Wrapper<'a>(&'a usize); impl Test { - fn name(&self) -> &str { + fn name(&self) -> &usize { &self.0 } @@ -60,7 +68,33 @@ mod issue_5754 { } } +// `Vec::sort_by_key` closure parameter is `F: FnMut(&T) -> K` +// The suggestion is destructuring T and we know T is not a reference, so test that non-Copy T are +// not linted. +mod issue_6001 { + struct Test(String); + + impl Test { + // Return an owned type so that we don't hit the fix for 5754 + fn name(&self) -> String { + self.0.clone() + } + } + + pub fn test() { + let mut args: Vec<Test> = vec![]; + + // Forward + args.sort_by(|a, b| a.name().cmp(&b.name())); + args.sort_unstable_by(|a, b| a.name().cmp(&b.name())); + // Reverse + args.sort_by(|a, b| b.name().cmp(&a.name())); + args.sort_unstable_by(|a, b| b.name().cmp(&a.name())); + } +} + fn main() { unnecessary_sort_by(); issue_5754::test(); + issue_6001::test(); } diff --git a/src/tools/clippy/tests/ui/unnecessary_sort_by.rs b/src/tools/clippy/tests/ui/unnecessary_sort_by.rs index a3c8ae468ed..9746f6e6849 100644 --- a/src/tools/clippy/tests/ui/unnecessary_sort_by.rs +++ b/src/tools/clippy/tests/ui/unnecessary_sort_by.rs @@ -25,17 +25,25 @@ fn unnecessary_sort_by() { vec.sort_by(|_, b| b.cmp(&5)); vec.sort_by(|_, b| b.cmp(c)); vec.sort_unstable_by(|a, _| a.cmp(c)); + + // Ignore vectors of references + let mut vec: Vec<&&&isize> = vec![&&&3, &&&6, &&&1, &&&2, &&&5]; + vec.sort_by(|a, b| (***a).abs().cmp(&(***b).abs())); + vec.sort_unstable_by(|a, b| (***a).abs().cmp(&(***b).abs())); + vec.sort_by(|a, b| b.cmp(a)); + vec.sort_unstable_by(|a, b| b.cmp(a)); } -// Should not be linted to avoid hitting https://github.com/rust-lang/rust/issues/34162 +// Do not suggest returning a reference to the closure parameter of `Vec::sort_by_key` mod issue_5754 { - struct Test(String); + #[derive(Clone, Copy)] + struct Test(usize); #[derive(PartialOrd, Ord, PartialEq, Eq)] - struct Wrapper<'a>(&'a str); + struct Wrapper<'a>(&'a usize); impl Test { - fn name(&self) -> &str { + fn name(&self) -> &usize { &self.0 } @@ -60,7 +68,33 @@ mod issue_5754 { } } +// `Vec::sort_by_key` closure parameter is `F: FnMut(&T) -> K` +// The suggestion is destructuring T and we know T is not a reference, so test that non-Copy T are +// not linted. +mod issue_6001 { + struct Test(String); + + impl Test { + // Return an owned type so that we don't hit the fix for 5754 + fn name(&self) -> String { + self.0.clone() + } + } + + pub fn test() { + let mut args: Vec<Test> = vec![]; + + // Forward + args.sort_by(|a, b| a.name().cmp(&b.name())); + args.sort_unstable_by(|a, b| a.name().cmp(&b.name())); + // Reverse + args.sort_by(|a, b| b.name().cmp(&a.name())); + args.sort_unstable_by(|a, b| b.name().cmp(&a.name())); + } +} + fn main() { unnecessary_sort_by(); issue_5754::test(); + issue_6001::test(); } diff --git a/src/tools/clippy/tests/ui/useless_attribute.fixed b/src/tools/clippy/tests/ui/useless_attribute.fixed index b222e2f7976..a5fcde768f1 100644 --- a/src/tools/clippy/tests/ui/useless_attribute.fixed +++ b/src/tools/clippy/tests/ui/useless_attribute.fixed @@ -49,6 +49,14 @@ mod a { pub use self::b::C; } +// don't lint on clippy::wildcard_imports for `use` items +#[allow(clippy::wildcard_imports)] +pub use std::io::prelude::*; + +// don't lint on clippy::enum_glob_use for `use` items +#[allow(clippy::enum_glob_use)] +pub use std::cmp::Ordering::*; + fn test_indented_attr() { #![allow(clippy::almost_swapped)] use std::collections::HashSet; diff --git a/src/tools/clippy/tests/ui/useless_attribute.rs b/src/tools/clippy/tests/ui/useless_attribute.rs index 3422eace4ab..0396d39e3d5 100644 --- a/src/tools/clippy/tests/ui/useless_attribute.rs +++ b/src/tools/clippy/tests/ui/useless_attribute.rs @@ -49,6 +49,14 @@ mod a { pub use self::b::C; } +// don't lint on clippy::wildcard_imports for `use` items +#[allow(clippy::wildcard_imports)] +pub use std::io::prelude::*; + +// don't lint on clippy::enum_glob_use for `use` items +#[allow(clippy::enum_glob_use)] +pub use std::cmp::Ordering::*; + fn test_indented_attr() { #[allow(clippy::almost_swapped)] use std::collections::HashSet; diff --git a/src/tools/clippy/tests/ui/useless_attribute.stderr b/src/tools/clippy/tests/ui/useless_attribute.stderr index 57ba976730c..d0194e4bbbe 100644 --- a/src/tools/clippy/tests/ui/useless_attribute.stderr +++ b/src/tools/clippy/tests/ui/useless_attribute.stderr @@ -13,7 +13,7 @@ LL | #[cfg_attr(feature = "cargo-clippy", allow(dead_code))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if you just forgot a `!`, use: `#![cfg_attr(feature = "cargo-clippy", allow(dead_code)` error: useless lint attribute - --> $DIR/useless_attribute.rs:53:5 + --> $DIR/useless_attribute.rs:61:5 | LL | #[allow(clippy::almost_swapped)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if you just forgot a `!`, use: `#![allow(clippy::almost_swapped)]` diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 848bd3a43e8..2f832b53a90 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -261,6 +261,9 @@ pub struct Config { /// Path to / name of the Microsoft Console Debugger (CDB) executable pub cdb: Option<OsString>, + /// Version of CDB + pub cdb_version: Option<[u16; 4]>, + /// Path to / name of the GDB executable pub gdb: Option<String>, diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 0efa668ecc8..17649dfab37 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -8,8 +8,8 @@ use std::path::{Path, PathBuf}; use tracing::*; use crate::common::{CompareMode, Config, Debugger, FailMode, Mode, PassMode}; -use crate::extract_gdb_version; use crate::util; +use crate::{extract_cdb_version, extract_gdb_version}; #[cfg(test)] mod tests; @@ -105,6 +105,10 @@ impl EarlyProps { props.ignore = true; } + if config.debugger == Some(Debugger::Cdb) && ignore_cdb(config, ln) { + props.ignore = true; + } + if config.debugger == Some(Debugger::Gdb) && ignore_gdb(config, ln) { props.ignore = true; } @@ -131,6 +135,21 @@ impl EarlyProps { return props; + fn ignore_cdb(config: &Config, line: &str) -> bool { + if let Some(actual_version) = config.cdb_version { + if let Some(min_version) = line.strip_prefix("min-cdb-version:").map(str::trim) { + let min_version = extract_cdb_version(min_version).unwrap_or_else(|| { + panic!("couldn't parse version range: {:?}", min_version); + }); + + // Ignore if actual version is smaller than the minimum + // required version + return actual_version < min_version; + } + } + false + } + fn ignore_gdb(config: &Config, line: &str) -> bool { if let Some(actual_version) = config.gdb_version { if let Some(rest) = line.strip_prefix("min-gdb-version:").map(str::trim) { @@ -142,8 +161,8 @@ impl EarlyProps { if start_ver != end_ver { panic!("Expected single GDB version") } - // Ignore if actual version is smaller the minimum required - // version + // Ignore if actual version is smaller than the minimum + // required version return actual_version < start_ver; } else if let Some(rest) = line.strip_prefix("ignore-gdb-version:").map(str::trim) { let (min_version, max_version) = diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index adf2fa7fd8e..190a9c62210 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -163,7 +163,7 @@ pub fn parse_config(args: Vec<String>) -> Config { let target = opt_str2(matches.opt_str("target")); let android_cross_path = opt_path(matches, "android-cross-path"); - let cdb = analyze_cdb(matches.opt_str("cdb"), &target); + 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 @@ -216,6 +216,7 @@ pub fn parse_config(args: Vec<String>) -> Config { target, host: opt_str2(matches.opt_str("host")), cdb, + cdb_version, gdb, gdb_version, gdb_native_rust, @@ -773,8 +774,30 @@ fn find_cdb(target: &str) -> Option<OsString> { } /// Returns Path to CDB -fn analyze_cdb(cdb: Option<String>, target: &str) -> Option<OsString> { - cdb.map(OsString::from).or_else(|| find_cdb(target)) +fn analyze_cdb(cdb: Option<String>, target: &str) -> (Option<OsString>, 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) diff --git a/src/tools/miri b/src/tools/miri -Subproject c28a8eeb742d7104bc407e12212c5143439963f +Subproject 604a674ea37b302fd605df67be10a24ce94ad0a diff --git a/src/tools/rls b/src/tools/rls -Subproject 48ef96dd00b90d950a122ca180923aba77efaf7 +Subproject db6a9e01aa3453b64c05707e99e97045f971295 diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer -Subproject ac4b134c6be27642dbe915f32a41f9a21bd0c1c +Subproject 0275b08d1521606fa733f76fe5d5707717456fb diff --git a/src/tools/rustc-workspace-hack/Cargo.toml b/src/tools/rustc-workspace-hack/Cargo.toml index 351e2d4481c..11d61606ff5 100644 --- a/src/tools/rustc-workspace-hack/Cargo.toml +++ b/src/tools/rustc-workspace-hack/Cargo.toml @@ -69,7 +69,7 @@ serde = { version = "1.0.82", features = ['derive'] } serde_json = { version = "1.0.31", features = ["raw_value"] } smallvec-0_6 = { package = "smallvec", version = "0.6", features = ['union', 'may_dangle'] } smallvec = { version = "1.0", features = ['union', 'may_dangle'] } -syn = { version = "1", features = ['fold', 'full', 'extra-traits', 'visit'] } +syn = { version = "1", features = ['fold', 'full', 'extra-traits', 'visit', 'visit-mut'] } url = { version = "2.0", features = ['serde'] } [target.'cfg(not(windows))'.dependencies] diff --git a/src/tools/rustfmt b/src/tools/rustfmt -Subproject 48f6c32ec1dd370f3157a27b48a000fd8c1185a +Subproject 01f2eadccc74cf70eb11e6300ffa7e02b18b002 |
