diff options
Diffstat (limited to 'src/tools')
265 files changed, 2582 insertions, 1307 deletions
diff --git a/src/tools/build-manifest/Cargo.toml b/src/tools/build-manifest/Cargo.toml index 7e0c4bee2b3..efa99f181b3 100644 --- a/src/tools/build-manifest/Cargo.toml +++ b/src/tools/build-manifest/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -toml = "0.5" +toml = "0.7" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" anyhow = "1.0.32" diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 0520eff0fa2..8f88ab10bf7 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -205,7 +205,7 @@ static TARGETS: &[&str] = &[ /// /// The order here matters, more specific entries should be first. static DOCS_FALLBACK: &[(&str, &str)] = &[ - ("-apple-", "x86_64-apple-darwin"), + ("-apple-", "aarch64-apple-darwin"), ("aarch64", "aarch64-unknown-linux-gnu"), ("arm-", "aarch64-unknown-linux-gnu"), ("", "x86_64-unknown-linux-gnu"), diff --git a/src/tools/bump-stage0/Cargo.toml b/src/tools/bump-stage0/Cargo.toml index 6ee7a831839..b7f3625da91 100644 --- a/src/tools/bump-stage0/Cargo.toml +++ b/src/tools/bump-stage0/Cargo.toml @@ -11,4 +11,4 @@ build_helper = { path = "../../build_helper" } curl = "0.4.38" indexmap = { version = "2.0.0", features = ["serde"] } serde = { version = "1.0.125", features = ["derive"] } -toml = "0.5.7" +toml = "0.7" diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 71eb84f21aef43c07580c6aed6f806a6299f504 +Subproject 623d536836b4cde09ce38609232a024d5b25da8 diff --git a/src/tools/clippy/.github/workflows/clippy_dev.yml b/src/tools/clippy/.github/workflows/clippy_dev.yml index d6534fbaff9..d530eb6c73a 100644 --- a/src/tools/clippy/.github/workflows/clippy_dev.yml +++ b/src/tools/clippy/.github/workflows/clippy_dev.yml @@ -16,7 +16,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: # Unsetting this would make so that any malicious package could get our Github Token persist-credentials: false diff --git a/src/tools/clippy/.github/workflows/clippy_mq.yml b/src/tools/clippy/.github/workflows/clippy_mq.yml index 07d5a08304e..0bcb7135935 100644 --- a/src/tools/clippy/.github/workflows/clippy_mq.yml +++ b/src/tools/clippy/.github/workflows/clippy_mq.yml @@ -36,7 +36,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: persist-credentials: false @@ -96,7 +96,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: persist-credentials: false @@ -114,7 +114,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: persist-credentials: false @@ -170,7 +170,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: persist-credentials: false diff --git a/src/tools/clippy/.github/workflows/clippy_pr.yml b/src/tools/clippy/.github/workflows/clippy_pr.yml index 880ebd6e5d5..d91c638a8fb 100644 --- a/src/tools/clippy/.github/workflows/clippy_pr.yml +++ b/src/tools/clippy/.github/workflows/clippy_pr.yml @@ -24,7 +24,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: # Unsetting this would make so that any malicious package could get our Github Token persist-credentials: false diff --git a/src/tools/clippy/.github/workflows/deploy.yml b/src/tools/clippy/.github/workflows/deploy.yml index ede19c11257..48c5bd36dbc 100644 --- a/src/tools/clippy/.github/workflows/deploy.yml +++ b/src/tools/clippy/.github/workflows/deploy.yml @@ -25,13 +25,13 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: # Unsetting this would make so that any malicious package could get our Github Token persist-credentials: false - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: ref: ${{ env.TARGET_BRANCH }} path: 'out' diff --git a/src/tools/clippy/.github/workflows/feature_freeze.yml b/src/tools/clippy/.github/workflows/feature_freeze.yml index ec59be3e7f6..5b139e76700 100644 --- a/src/tools/clippy/.github/workflows/feature_freeze.yml +++ b/src/tools/clippy/.github/workflows/feature_freeze.yml @@ -16,7 +16,7 @@ jobs: permissions: pull-requests: write - # Do not in any case add code that runs anything coming from the the content + # Do not in any case add code that runs anything coming from the content # of the pull request, as malicious code would be able to access the private # GitHub token. steps: diff --git a/src/tools/clippy/.github/workflows/lintcheck.yml b/src/tools/clippy/.github/workflows/lintcheck.yml index 003d0395739..390d6a0f747 100644 --- a/src/tools/clippy/.github/workflows/lintcheck.yml +++ b/src/tools/clippy/.github/workflows/lintcheck.yml @@ -24,7 +24,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 2 # Unsetting this would make so that any malicious package could get our Github Token @@ -80,7 +80,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: # Unsetting this would make so that any malicious package could get our Github Token persist-credentials: false @@ -113,7 +113,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: # Unsetting this would make so that any malicious package could get our Github Token persist-credentials: false diff --git a/src/tools/clippy/.github/workflows/remark.yml b/src/tools/clippy/.github/workflows/remark.yml index 7e7e26818c0..c9d350ee0b3 100644 --- a/src/tools/clippy/.github/workflows/remark.yml +++ b/src/tools/clippy/.github/workflows/remark.yml @@ -11,7 +11,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: # Unsetting this would make so that any malicious package could get our Github Token persist-credentials: false diff --git a/src/tools/clippy/CONTRIBUTING.md b/src/tools/clippy/CONTRIBUTING.md index 42ed624ec21..f7f0a1ce249 100644 --- a/src/tools/clippy/CONTRIBUTING.md +++ b/src/tools/clippy/CONTRIBUTING.md @@ -17,7 +17,7 @@ All contributors are expected to follow the [Rust Code of Conduct]. - [High level approach](#high-level-approach) - [Finding something to fix/improve](#finding-something-to-fiximprove) - [Getting code-completion for rustc internals to work](#getting-code-completion-for-rustc-internals-to-work) - - [IntelliJ Rust](#intellij-rust) + - [RustRover](#rustrover) - [Rust Analyzer](#rust-analyzer) - [How Clippy works](#how-clippy-works) - [Issue and PR triage](#issue-and-pr-triage) @@ -92,22 +92,22 @@ an AST expression). ## Getting code-completion for rustc internals to work -### IntelliJ Rust -Unfortunately, [`IntelliJ Rust`][IntelliJ_rust_homepage] does not (yet?) understand how Clippy uses compiler-internals +### RustRover +Unfortunately, [`RustRover`][RustRover_homepage] does not (yet?) understand how Clippy uses compiler-internals using `extern crate` and it also needs to be able to read the source files of the rustc-compiler which are not available via a `rustup` component at the time of writing. To work around this, you need to have a copy of the [rustc-repo][rustc_repo] available which can be obtained via `git clone https://github.com/rust-lang/rust/`. Then you can run a `cargo dev` command to automatically make Clippy use the rustc-repo via path-dependencies -which `IntelliJ Rust` will be able to understand. +which `RustRover` will be able to understand. Run `cargo dev setup intellij --repo-path <repo-path>` where `<repo-path>` is a path to the rustc repo you just cloned. The command will add path-dependencies pointing towards rustc-crates inside the rustc repo to -Clippy's `Cargo.toml`s and should allow `IntelliJ Rust` to understand most of the types that Clippy uses. +Clippy's `Cargo.toml`s and should allow `RustRover` to understand most of the types that Clippy uses. Just make sure to remove the dependencies again before finally making a pull request! [rustc_repo]: https://github.com/rust-lang/rust/ -[IntelliJ_rust_homepage]: https://intellij-rust.github.io/ +[RustRover_homepage]: https://www.jetbrains.com/rust/ ### Rust Analyzer For [`rust-analyzer`][ra_homepage] to work correctly make sure that in the `rust-analyzer` configuration you set diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml index daf1c98cdc9..b3618932ded 100644 --- a/src/tools/clippy/Cargo.toml +++ b/src/tools/clippy/Cargo.toml @@ -64,3 +64,7 @@ harness = false [[test]] name = "dogfood" harness = false + +[lints.rust.unexpected_cfgs] +level = "warn" +check-cfg = ['cfg(bootstrap)'] diff --git a/src/tools/clippy/book/src/continuous_integration/github_actions.md b/src/tools/clippy/book/src/continuous_integration/github_actions.md index b588c8f0f02..62d32446d92 100644 --- a/src/tools/clippy/book/src/continuous_integration/github_actions.md +++ b/src/tools/clippy/book/src/continuous_integration/github_actions.md @@ -15,7 +15,7 @@ jobs: clippy_check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Run Clippy run: cargo clippy --all-targets --all-features ``` diff --git a/src/tools/clippy/book/src/development/basics.md b/src/tools/clippy/book/src/development/basics.md index fc405249bcf..19f626ab804 100644 --- a/src/tools/clippy/book/src/development/basics.md +++ b/src/tools/clippy/book/src/development/basics.md @@ -95,7 +95,7 @@ cargo dev new_lint cargo dev deprecate # automatically formatting all code before each commit cargo dev setup git-hook -# (experimental) Setup Clippy to work with IntelliJ-Rust +# (experimental) Setup Clippy to work with RustRover cargo dev setup intellij # runs the `dogfood` tests cargo dev dogfood @@ -103,7 +103,7 @@ cargo dev dogfood More about [intellij] command usage and reasons. -[intellij]: https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md#intellij-rust +[intellij]: https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md#rustrover ## lintcheck diff --git a/src/tools/clippy/book/src/development/common_tools_writing_lints.md b/src/tools/clippy/book/src/development/common_tools_writing_lints.md index e23b32039c9..3bec3ce33af 100644 --- a/src/tools/clippy/book/src/development/common_tools_writing_lints.md +++ b/src/tools/clippy/book/src/development/common_tools_writing_lints.md @@ -141,7 +141,7 @@ impl LateLintPass<'_> for MyStructLint { // we are looking for the `DefId` of `Drop` trait in lang items .drop_trait() // then we use it with our type `ty` by calling `implements_trait` from Clippy's utils - .map_or(false, |id| implements_trait(cx, ty, id, &[])) { + .is_some_and(|id| implements_trait(cx, ty, id, &[])) { // `expr` implements `Drop` trait } } diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md index 7f16f3a9810..05590ff7b1c 100644 --- a/src/tools/clippy/book/src/lint_configuration.md +++ b/src/tools/clippy/book/src/lint_configuration.md @@ -555,7 +555,7 @@ default configuration of Clippy. By default, any configuration will replace the * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. -**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "MHz", "GHz", "THz", "AccessKit", "CoAP", "CoreFoundation", "CoreGraphics", "CoreText", "DevOps", "Direct2D", "Direct3D", "DirectWrite", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PostScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenAL", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "OpenType", "WebGL", "WebGL2", "WebGPU", "WebRTC", "WebSocket", "WebTransport", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "NetBSD", "OpenBSD", "NixOS", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` +**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "MHz", "GHz", "THz", "AccessKit", "CoAP", "CoreFoundation", "CoreGraphics", "CoreText", "DevOps", "Direct2D", "Direct3D", "DirectWrite", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PostScript", "PureScript", "TypeScript", "PowerPC", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenAL", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "OpenType", "WebGL", "WebGL2", "WebGPU", "WebRTC", "WebSocket", "WebTransport", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "NetBSD", "OpenBSD", "NixOS", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` --- **Affected lints:** diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs index 8167d75583e..2ad3f2efcdd 100644 --- a/src/tools/clippy/clippy_config/src/conf.rs +++ b/src/tools/clippy/clippy_config/src/conf.rs @@ -34,7 +34,7 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[ "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PostScript", "PureScript", "TypeScript", - "WebAssembly", + "PowerPC", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", diff --git a/src/tools/clippy/clippy_dev/src/dogfood.rs b/src/tools/clippy/clippy_dev/src/dogfood.rs index 7e9d92458d0..d0fca952b93 100644 --- a/src/tools/clippy/clippy_dev/src/dogfood.rs +++ b/src/tools/clippy/clippy_dev/src/dogfood.rs @@ -1,35 +1,28 @@ -use crate::utils::exit_if_err; -use std::process::Command; +use crate::utils::{cargo_cmd, run_exit_on_err}; +use itertools::Itertools; /// # Panics /// /// Panics if unable to run the dogfood test #[allow(clippy::fn_params_excessive_bools)] pub fn dogfood(fix: bool, allow_dirty: bool, allow_staged: bool, allow_no_vcs: bool) { - let mut cmd = Command::new("cargo"); - - cmd.args(["test", "--test", "dogfood"]) - .args(["--features", "internal"]) - .args(["--", "dogfood_clippy", "--nocapture"]); - - let mut dogfood_args = Vec::new(); - if fix { - dogfood_args.push("--fix"); - } - - if allow_dirty { - dogfood_args.push("--allow-dirty"); - } - - if allow_staged { - dogfood_args.push("--allow-staged"); - } - - if allow_no_vcs { - dogfood_args.push("--allow-no-vcs"); - } - - cmd.env("__CLIPPY_DOGFOOD_ARGS", dogfood_args.join(" ")); - - exit_if_err(cmd.status()); + run_exit_on_err( + "cargo test", + cargo_cmd() + .args(["test", "--test", "dogfood"]) + .args(["--features", "internal"]) + .args(["--", "dogfood_clippy", "--nocapture"]) + .env( + "__CLIPPY_DOGFOOD_ARGS", + [ + if fix { "--fix" } else { "" }, + if allow_dirty { "--allow-dirty" } else { "" }, + if allow_staged { "--allow-staged" } else { "" }, + if allow_no_vcs { "--allow-no-vcs" } else { "" }, + ] + .iter() + .filter(|x| !x.is_empty()) + .join(" "), + ), + ); } diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs index 40aadf4589a..16f413e0c86 100644 --- a/src/tools/clippy/clippy_dev/src/lib.rs +++ b/src/tools/clippy/clippy_dev/src/lib.rs @@ -15,8 +15,7 @@ )] #![allow(clippy::missing_panics_doc)] -// The `rustc_driver` crate seems to be required in order to use the `rust_lexer` crate. -#[allow(unused_extern_crates)] +#[expect(unused_extern_crates, reason = "required to link to rustc crates")] extern crate rustc_driver; extern crate rustc_lexer; extern crate rustc_literal_escaper; @@ -32,4 +31,6 @@ pub mod serve; pub mod setup; pub mod sync; pub mod update_lints; -pub mod utils; + +mod utils; +pub use utils::{ClippyInfo, UpdateMode}; diff --git a/src/tools/clippy/clippy_dev/src/lint.rs b/src/tools/clippy/clippy_dev/src/lint.rs index 0d66f167a38..2d9f563cdae 100644 --- a/src/tools/clippy/clippy_dev/src/lint.rs +++ b/src/tools/clippy/clippy_dev/src/lint.rs @@ -1,19 +1,18 @@ -use crate::utils::{cargo_clippy_path, exit_if_err}; -use std::process::{self, Command}; +use crate::utils::{ErrAction, cargo_cmd, expect_action, run_exit_on_err}; +use std::process::Command; use std::{env, fs}; -pub fn run<'a>(path: &str, edition: &str, args: impl Iterator<Item = &'a String>) { - let is_file = match fs::metadata(path) { - Ok(metadata) => metadata.is_file(), - Err(e) => { - eprintln!("Failed to read {path}: {e:?}"); - process::exit(1); - }, - }; +#[cfg(not(windows))] +static CARGO_CLIPPY_EXE: &str = "cargo-clippy"; +#[cfg(windows)] +static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe"; +pub fn run<'a>(path: &str, edition: &str, args: impl Iterator<Item = &'a String>) { + let is_file = expect_action(fs::metadata(path), ErrAction::Read, path).is_file(); if is_file { - exit_if_err( - Command::new(env::var("CARGO").unwrap_or_else(|_| "cargo".into())) + run_exit_on_err( + "cargo run", + cargo_cmd() .args(["run", "--bin", "clippy-driver", "--"]) .args(["-L", "./target/debug"]) .args(["-Z", "no-codegen"]) @@ -21,24 +20,25 @@ pub fn run<'a>(path: &str, edition: &str, args: impl Iterator<Item = &'a String> .arg(path) .args(args) // Prevent rustc from creating `rustc-ice-*` files the console output is enough. - .env("RUSTC_ICE", "0") - .status(), + .env("RUSTC_ICE", "0"), ); } else { - exit_if_err( - Command::new(env::var("CARGO").unwrap_or_else(|_| "cargo".into())) - .arg("build") - .status(), - ); - - let status = Command::new(cargo_clippy_path()) - .arg("clippy") - .args(args) - // Prevent rustc from creating `rustc-ice-*` files the console output is enough. - .env("RUSTC_ICE", "0") - .current_dir(path) - .status(); + // Ideally this would just be `cargo run`, but the working directory needs to be + // set to clippy's directory when building, and the target project's directory + // when running clippy. `cargo` can only set a single working directory for both + // when using `run`. + run_exit_on_err("cargo build", cargo_cmd().arg("build")); - exit_if_err(status); + let mut exe = env::current_exe().expect("failed to get current executable name"); + exe.set_file_name(CARGO_CLIPPY_EXE); + run_exit_on_err( + "cargo clippy", + Command::new(exe) + .arg("clippy") + .args(args) + // Prevent rustc from creating `rustc-ice-*` files the console output is enough. + .env("RUSTC_ICE", "0") + .current_dir(path), + ); } } diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs index 26aa269fb63..5fef231f6ca 100644 --- a/src/tools/clippy/clippy_dev/src/main.rs +++ b/src/tools/clippy/clippy_dev/src/main.rs @@ -4,14 +4,15 @@ use clap::{Args, Parser, Subcommand}; use clippy_dev::{ - deprecate_lint, dogfood, fmt, lint, new_lint, release, rename_lint, serve, setup, sync, update_lints, utils, + ClippyInfo, UpdateMode, deprecate_lint, dogfood, fmt, lint, new_lint, release, rename_lint, serve, setup, sync, + update_lints, }; use std::convert::Infallible; use std::env; fn main() { let dev = Dev::parse(); - let clippy = utils::ClippyInfo::search_for_manifest(); + let clippy = ClippyInfo::search_for_manifest(); if let Err(e) = env::set_current_dir(&clippy.path) { panic!("error setting current directory to `{}`: {e}", clippy.path.display()); } @@ -26,8 +27,8 @@ fn main() { allow_staged, allow_no_vcs, } => dogfood::dogfood(fix, allow_dirty, allow_staged, allow_no_vcs), - DevCommand::Fmt { check } => fmt::run(utils::UpdateMode::from_check(check)), - DevCommand::UpdateLints { check } => update_lints::update(utils::UpdateMode::from_check(check)), + DevCommand::Fmt { check } => fmt::run(UpdateMode::from_check(check)), + DevCommand::UpdateLints { check } => update_lints::update(UpdateMode::from_check(check)), DevCommand::NewLint { pass, name, @@ -35,7 +36,7 @@ fn main() { r#type, msrv, } => match new_lint::create(clippy.version, pass, &name, &category, r#type.as_deref(), msrv) { - Ok(()) => update_lints::update(utils::UpdateMode::Change), + Ok(()) => update_lints::update(UpdateMode::Change), Err(e) => eprintln!("Unable to create lint: {e}"), }, DevCommand::Setup(SetupCommand { subcommand }) => match subcommand { diff --git a/src/tools/clippy/clippy_dev/src/serve.rs b/src/tools/clippy/clippy_dev/src/serve.rs index 498ffeba9d6..d9e01813381 100644 --- a/src/tools/clippy/clippy_dev/src/serve.rs +++ b/src/tools/clippy/clippy_dev/src/serve.rs @@ -1,7 +1,11 @@ +use crate::utils::{ErrAction, cargo_cmd, expect_action}; +use core::fmt::Display; +use core::mem; use std::path::Path; use std::process::Command; use std::time::{Duration, SystemTime}; -use std::{env, thread}; +use std::{fs, thread}; +use walkdir::WalkDir; #[cfg(windows)] const PYTHON: &str = "python"; @@ -18,56 +22,83 @@ pub fn run(port: u16, lint: Option<String>) -> ! { Some(lint) => format!("http://localhost:{port}/#{lint}"), }); + let mut last_update = mtime("util/gh-pages/index.html"); loop { - let index_time = mtime("util/gh-pages/index.html"); - let times = [ - "clippy_lints/src", - "util/gh-pages/index_template.html", - "tests/compile-test.rs", - ] - .map(mtime); - - if times.iter().any(|&time| index_time < time) { - Command::new(env::var("CARGO").unwrap_or_else(|_| "cargo".into())) - .arg("collect-metadata") - .spawn() - .unwrap() - .wait() - .unwrap(); + if is_metadata_outdated(mem::replace(&mut last_update, SystemTime::now())) { + // Ignore the command result; we'll fall back to displaying the old metadata. + let _ = expect_action( + cargo_cmd().arg("collect-metadata").status(), + ErrAction::Run, + "cargo collect-metadata", + ); + last_update = SystemTime::now(); } + + // Only start the web server the first time around. if let Some(url) = url.take() { thread::spawn(move || { - let mut child = Command::new(PYTHON) - .arg("-m") - .arg("http.server") - .arg(port.to_string()) - .current_dir("util/gh-pages") - .spawn() - .unwrap(); + let mut child = expect_action( + Command::new(PYTHON) + .args(["-m", "http.server", port.to_string().as_str()]) + .current_dir("util/gh-pages") + .spawn(), + ErrAction::Run, + "python -m http.server", + ); // Give some time for python to start thread::sleep(Duration::from_millis(500)); // Launch browser after first export.py has completed and http.server is up let _result = opener::open(url); - child.wait().unwrap(); + expect_action(child.wait(), ErrAction::Run, "python -m http.server"); }); } + + // Delay to avoid updating the metadata too aggressively. thread::sleep(Duration::from_millis(1000)); } } -fn mtime(path: impl AsRef<Path>) -> SystemTime { - let path = path.as_ref(); - if path.is_dir() { - path.read_dir() - .into_iter() - .flatten() - .flatten() - .map(|entry| mtime(entry.path())) - .max() - .unwrap_or(SystemTime::UNIX_EPOCH) - } else { - path.metadata() - .and_then(|metadata| metadata.modified()) - .unwrap_or(SystemTime::UNIX_EPOCH) +fn log_err_and_continue<T>(res: Result<T, impl Display>, path: &Path) -> Option<T> { + match res { + Ok(x) => Some(x), + Err(ref e) => { + eprintln!("error reading `{}`: {e}", path.display()); + None + }, } } + +fn mtime(path: &str) -> SystemTime { + log_err_and_continue(fs::metadata(path), path.as_ref()) + .and_then(|metadata| log_err_and_continue(metadata.modified(), path.as_ref())) + .unwrap_or(SystemTime::UNIX_EPOCH) +} + +fn is_metadata_outdated(time: SystemTime) -> bool { + // Ignore all IO errors here. We don't want to stop them from hosting the server. + if time < mtime("util/gh-pages/index_template.html") || time < mtime("tests/compile-test.rs") { + return true; + } + let Some(dir) = log_err_and_continue(fs::read_dir("."), ".".as_ref()) else { + return false; + }; + dir.map_while(|e| log_err_and_continue(e, ".".as_ref())).any(|e| { + let name = e.file_name(); + let name_bytes = name.as_encoded_bytes(); + if (name_bytes.starts_with(b"clippy_lints") && name_bytes != b"clippy_lints_internal") + || name_bytes == b"clippy_config" + { + WalkDir::new(&name) + .into_iter() + .map_while(|e| log_err_and_continue(e, name.as_ref())) + .filter(|e| e.file_type().is_file()) + .filter_map(|e| { + log_err_and_continue(e.metadata(), e.path()) + .and_then(|m| log_err_and_continue(m.modified(), e.path())) + }) + .any(|ftime| time < ftime) + } else { + false + } + }) +} diff --git a/src/tools/clippy/clippy_dev/src/setup/git_hook.rs b/src/tools/clippy/clippy_dev/src/setup/git_hook.rs index c7c53bc69d0..c5a1e8264c7 100644 --- a/src/tools/clippy/clippy_dev/src/setup/git_hook.rs +++ b/src/tools/clippy/clippy_dev/src/setup/git_hook.rs @@ -1,8 +1,6 @@ use std::fs; use std::path::Path; -use super::verify_inside_clippy_dir; - /// Rusts setup uses `git rev-parse --git-common-dir` to get the root directory of the repo. /// I've decided against this for the sake of simplicity and to make sure that it doesn't install /// the hook if `clippy_dev` would be used in the rust tree. The hook also references this tool @@ -35,10 +33,6 @@ pub fn install_hook(force_override: bool) { } fn check_precondition(force_override: bool) -> bool { - if !verify_inside_clippy_dir() { - return false; - } - // Make sure that we can find the git repository let git_path = Path::new(REPO_GIT_DIR); if !git_path.exists() || !git_path.is_dir() { diff --git a/src/tools/clippy/clippy_dev/src/setup/mod.rs b/src/tools/clippy/clippy_dev/src/setup/mod.rs index b0d31814639..5e938fff126 100644 --- a/src/tools/clippy/clippy_dev/src/setup/mod.rs +++ b/src/tools/clippy/clippy_dev/src/setup/mod.rs @@ -2,23 +2,3 @@ pub mod git_hook; pub mod intellij; pub mod toolchain; pub mod vscode; - -use std::path::Path; - -const CLIPPY_DEV_DIR: &str = "clippy_dev"; - -/// This function verifies that the tool is being executed in the clippy directory. -/// This is useful to ensure that setups only modify Clippy's resources. The verification -/// is done by checking that `clippy_dev` is a sub directory of the current directory. -/// -/// It will print an error message and return `false` if the directory could not be -/// verified. -fn verify_inside_clippy_dir() -> bool { - let path = Path::new(CLIPPY_DEV_DIR); - if path.exists() && path.is_dir() { - true - } else { - eprintln!("error: unable to verify that the working directory is clippy's directory"); - false - } -} diff --git a/src/tools/clippy/clippy_dev/src/setup/toolchain.rs b/src/tools/clippy/clippy_dev/src/setup/toolchain.rs index ecd80215f7e..c64ae4ef3c3 100644 --- a/src/tools/clippy/clippy_dev/src/setup/toolchain.rs +++ b/src/tools/clippy/clippy_dev/src/setup/toolchain.rs @@ -1,20 +1,12 @@ +use crate::utils::{cargo_cmd, run_exit_on_err}; use std::env::consts::EXE_SUFFIX; use std::env::current_dir; use std::ffi::OsStr; use std::fs; use std::path::{Path, PathBuf}; -use std::process::Command; use walkdir::WalkDir; -use crate::utils::exit_if_err; - -use super::verify_inside_clippy_dir; - pub fn create(standalone: bool, force: bool, release: bool, name: &str) { - if !verify_inside_clippy_dir() { - return; - } - let rustup_home = std::env::var("RUSTUP_HOME").unwrap(); let toolchain = std::env::var("RUSTUP_TOOLCHAIN").unwrap(); @@ -51,11 +43,10 @@ pub fn create(standalone: bool, force: bool, release: bool, name: &str) { } } - let status = Command::new("cargo") - .arg("build") - .args(release.then_some("--release")) - .status(); - exit_if_err(status); + run_exit_on_err( + "cargo build", + cargo_cmd().arg("build").args(release.then_some("--release")), + ); install_bin("cargo-clippy", &dest, standalone, release); install_bin("clippy-driver", &dest, standalone, release); diff --git a/src/tools/clippy/clippy_dev/src/setup/vscode.rs b/src/tools/clippy/clippy_dev/src/setup/vscode.rs index a37c873eed4..a24aef65991 100644 --- a/src/tools/clippy/clippy_dev/src/setup/vscode.rs +++ b/src/tools/clippy/clippy_dev/src/setup/vscode.rs @@ -1,8 +1,6 @@ use std::fs; use std::path::Path; -use super::verify_inside_clippy_dir; - const VSCODE_DIR: &str = ".vscode"; const TASK_SOURCE_FILE: &str = "util/etc/vscode-tasks.json"; const TASK_TARGET_FILE: &str = ".vscode/tasks.json"; @@ -22,10 +20,6 @@ pub fn install_tasks(force_override: bool) { } fn check_install_precondition(force_override: bool) -> bool { - if !verify_inside_clippy_dir() { - return false; - } - let vs_dir_path = Path::new(VSCODE_DIR); if vs_dir_path.exists() { // verify the target will be valid diff --git a/src/tools/clippy/clippy_dev/src/utils.rs b/src/tools/clippy/clippy_dev/src/utils.rs index 89962a11034..057951d0e33 100644 --- a/src/tools/clippy/clippy_dev/src/utils.rs +++ b/src/tools/clippy/clippy_dev/src/utils.rs @@ -8,15 +8,10 @@ use std::ffi::OsStr; use std::fs::{self, OpenOptions}; use std::io::{self, Read as _, Seek as _, SeekFrom, Write}; use std::path::{Path, PathBuf}; -use std::process::{self, Command, ExitStatus, Stdio}; +use std::process::{self, Command, Stdio}; use std::{env, thread}; use walkdir::WalkDir; -#[cfg(not(windows))] -static CARGO_CLIPPY_EXE: &str = "cargo-clippy"; -#[cfg(windows)] -static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe"; - #[derive(Clone, Copy)] pub enum ErrAction { Open, @@ -118,16 +113,14 @@ impl<'a> File<'a> { } } -/// Returns the path to the `cargo-clippy` binary -/// -/// # Panics -/// -/// Panics if the path of current executable could not be retrieved. +/// Creates a `Command` for running cargo. #[must_use] -pub fn cargo_clippy_path() -> PathBuf { - let mut path = env::current_exe().expect("failed to get current executable name"); - path.set_file_name(CARGO_CLIPPY_EXE); - path +pub fn cargo_cmd() -> Command { + if let Some(path) = env::var_os("CARGO") { + Command::new(path) + } else { + Command::new("cargo") + } } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] @@ -288,19 +281,6 @@ impl ClippyInfo { } } -/// # Panics -/// Panics if given command result was failed. -pub fn exit_if_err(status: io::Result<ExitStatus>) { - match status.expect("failed to run command").code() { - Some(0) => {}, - Some(n) => process::exit(n), - None => { - eprintln!("Killed by signal"); - process::exit(1); - }, - } -} - #[derive(Clone, Copy)] pub enum UpdateStatus { Unchanged, @@ -341,6 +321,7 @@ pub struct FileUpdater { dst_buf: String, } impl FileUpdater { + #[track_caller] fn update_file_checked_inner( &mut self, tool: &str, @@ -364,6 +345,7 @@ impl FileUpdater { } } + #[track_caller] fn update_file_inner(&mut self, path: &Path, update: &mut dyn FnMut(&Path, &str, &mut String) -> UpdateStatus) { let mut file = File::open(path, OpenOptions::new().read(true).write(true)); file.read_to_cleared_string(&mut self.src_buf); @@ -373,6 +355,7 @@ impl FileUpdater { } } + #[track_caller] pub fn update_file_checked( &mut self, tool: &str, @@ -383,6 +366,7 @@ impl FileUpdater { self.update_file_checked_inner(tool, mode, path.as_ref(), update); } + #[track_caller] pub fn update_file( &mut self, path: impl AsRef<Path>, @@ -450,7 +434,6 @@ pub enum Token<'a> { OpenParen, Pound, Semi, - Slash, } pub struct RustSearcher<'txt> { @@ -528,7 +511,6 @@ impl<'txt> RustSearcher<'txt> { | (Token::OpenParen, lexer::TokenKind::OpenParen) | (Token::Pound, lexer::TokenKind::Pound) | (Token::Semi, lexer::TokenKind::Semi) - | (Token::Slash, lexer::TokenKind::Slash) | ( Token::LitStr, lexer::TokenKind::Literal { @@ -601,7 +583,7 @@ impl<'txt> RustSearcher<'txt> { } } -#[expect(clippy::must_use_candidate)] +#[track_caller] pub fn try_rename_file(old_name: &Path, new_name: &Path) -> bool { match OpenOptions::new().create_new(true).write(true).open(new_name) { Ok(file) => drop(file), @@ -623,7 +605,7 @@ pub fn try_rename_file(old_name: &Path, new_name: &Path) -> bool { } } -#[expect(clippy::must_use_candidate)] +#[track_caller] pub fn try_rename_dir(old_name: &Path, new_name: &Path) -> bool { match fs::create_dir(new_name) { Ok(()) => {}, @@ -649,10 +631,19 @@ pub fn try_rename_dir(old_name: &Path, new_name: &Path) -> bool { } } -pub fn write_file(path: &Path, contents: &str) { - expect_action(fs::write(path, contents), ErrAction::Write, path); +#[track_caller] +pub fn run_exit_on_err(path: &(impl AsRef<Path> + ?Sized), cmd: &mut Command) { + match expect_action(cmd.status(), ErrAction::Run, path.as_ref()).code() { + Some(0) => {}, + Some(n) => process::exit(n), + None => { + eprintln!("{} killed by signal", path.as_ref().display()); + process::exit(1); + }, + } } +#[track_caller] #[must_use] pub fn run_with_output(path: &(impl AsRef<Path> + ?Sized), cmd: &mut Command) -> Vec<u8> { fn f(path: &Path, cmd: &mut Command) -> Vec<u8> { @@ -738,7 +729,7 @@ pub fn split_args_for_threads( } } -#[expect(clippy::must_use_candidate)] +#[track_caller] pub fn delete_file_if_exists(path: &Path) -> bool { match fs::remove_file(path) { Ok(()) => true, @@ -747,6 +738,7 @@ pub fn delete_file_if_exists(path: &Path) -> bool { } } +#[track_caller] pub fn delete_dir_if_exists(path: &Path) { match fs::remove_dir_all(path) { Ok(()) => {}, diff --git a/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs index e3b125a8d5b..eb75d5576f5 100644 --- a/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::msrvs::Msrv; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; -use clippy_utils::{get_parent_expr, is_expr_temporary_value, is_lint_allowed, msrvs, std_or_core}; +use clippy_utils::{get_parent_expr, is_expr_temporary_value, is_from_proc_macro, is_lint_allowed, msrvs, std_or_core}; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Ty, TyKind}; use rustc_lint::LateContext; @@ -22,13 +22,12 @@ pub(super) fn check<'tcx>( && !matches!(target.ty.kind, TyKind::TraitObject(..)) && let ExprKind::AddrOf(BorrowKind::Ref, mutability, e) = cast_expr.kind && !is_lint_allowed(cx, BORROW_AS_PTR, expr.hir_id) + // Fix #9884 + && !is_expr_temporary_value(cx, e) + && !is_from_proc_macro(cx, expr) { let mut app = Applicability::MachineApplicable; let snip = snippet_with_context(cx, e.span, cast_expr.span.ctxt(), "..", &mut app).0; - // Fix #9884 - if is_expr_temporary_value(cx, e) { - return false; - } let (suggestion, span) = if msrv.meets(cx, msrvs::RAW_REF_OP) { // Make sure that the span to be replaced doesn't include parentheses, that could break the diff --git a/src/tools/clippy/clippy_lints/src/casts/char_lit_as_u8.rs b/src/tools/clippy/clippy_lints/src/casts/char_lit_as_u8.rs index a7d3868f76c..964eaf2a0a2 100644 --- a/src/tools/clippy/clippy_lints/src/casts/char_lit_as_u8.rs +++ b/src/tools/clippy/clippy_lints/src/casts/char_lit_as_u8.rs @@ -4,18 +4,17 @@ use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_middle::ty::{self, UintTy}; +use rustc_middle::ty::{self, Ty, UintTy}; use super::CHAR_LIT_AS_U8; -pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { - if let ExprKind::Cast(e, _) = &expr.kind - && let ExprKind::Lit(l) = &e.kind +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from_expr: &Expr<'_>, cast_to: Ty<'_>) { + if let ExprKind::Lit(l) = &cast_from_expr.kind && let LitKind::Char(c) = l.node - && ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(expr).kind() + && ty::Uint(UintTy::U8) == *cast_to.kind() { let mut applicability = Applicability::MachineApplicable; - let snippet = snippet_with_applicability(cx, e.span, "'x'", &mut applicability); + let snippet = snippet_with_applicability(cx, cast_from_expr.span, "'x'", &mut applicability); span_lint_and_then( cx, diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs index dcc439a272c..e25df9dd249 100644 --- a/src/tools/clippy/clippy_lints/src/casts/mod.rs +++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs @@ -871,6 +871,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts { if !expr.span.from_expansion() && unnecessary_cast::check(cx, expr, cast_from_expr, cast_from, cast_to) { return; } + char_lit_as_u8::check(cx, expr, cast_from_expr, cast_to); cast_slice_from_raw_parts::check(cx, expr, cast_from_expr, cast_to, self.msrv); ptr_cast_constness::check(cx, expr, cast_from_expr, cast_from, cast_to, self.msrv); as_ptr_cast_mut::check(cx, expr, cast_from_expr, cast_to); @@ -911,7 +912,6 @@ impl<'tcx> LateLintPass<'tcx> for Casts { borrow_as_ptr::check_implicit_cast(cx, expr); } cast_ptr_alignment::check(cx, expr); - char_lit_as_u8::check(cx, expr); ptr_as_ptr::check(cx, expr, self.msrv); cast_slice_different_sizes::check(cx, expr, self.msrv); ptr_cast_constness::check_null_ptr_cast_method(cx, expr); diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs index ee0f3fa81c6..89075409098 100644 --- a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_from_proc_macro; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; @@ -25,7 +26,7 @@ impl OmitFollowedCastReason<'_> { } } -pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Msrv) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: Msrv) { if let ExprKind::Cast(cast_expr, cast_to_hir_ty) = expr.kind && let (cast_from, cast_to) = (cx.typeck_results().expr_ty(cast_expr), cx.typeck_results().expr_ty(expr)) && let ty::RawPtr(_, from_mutbl) = cast_from.kind() @@ -36,6 +37,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Msrv) { // as explained here: https://github.com/rust-lang/rust/issues/60602. && to_pointee_ty.is_sized(cx.tcx, cx.typing_env()) && msrv.meets(cx, msrvs::POINTER_CAST) + && !is_from_proc_macro(cx, expr) { let mut app = Applicability::MachineApplicable; let turbofish = match &cast_to_hir_ty.kind { diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs index 8f1c0296524..8f95c63a854 100644 --- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs +++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs @@ -56,7 +56,7 @@ impl_lint_pass!(CognitiveComplexity => [COGNITIVE_COMPLEXITY]); impl CognitiveComplexity { fn check<'tcx>( - &mut self, + &self, cx: &LateContext<'tcx>, kind: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, diff --git a/src/tools/clippy/clippy_lints/src/collapsible_if.rs b/src/tools/clippy/clippy_lints/src/collapsible_if.rs index e3103e2d301..ad610fbd8d2 100644 --- a/src/tools/clippy/clippy_lints/src/collapsible_if.rs +++ b/src/tools/clippy/clippy_lints/src/collapsible_if.rs @@ -5,7 +5,7 @@ use clippy_utils::source::{IntoSpan as _, SpanRangeExt, snippet, snippet_block_w use clippy_utils::{span_contains_non_whitespace, tokenize_with_text}; use rustc_ast::BinOpKind; use rustc_errors::Applicability; -use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind}; +use rustc_hir::{Block, Expr, ExprKind, StmtKind}; use rustc_lexer::TokenKind; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; @@ -141,11 +141,7 @@ impl CollapsibleIf { // Prevent "elseif" // Check that the "else" is followed by whitespace - let requires_space = if let Some(c) = snippet(cx, up_to_else, "..").chars().last() { - !c.is_whitespace() - } else { - false - }; + let requires_space = snippet(cx, up_to_else, "..").ends_with(|c: char| !c.is_whitespace()); let mut applicability = Applicability::MachineApplicable; diag.span_suggestion( else_block.span, @@ -173,8 +169,7 @@ impl CollapsibleIf { && cx.tcx.hir_attrs(inner.hir_id).is_empty() && let ExprKind::If(check_inner, _, None) = &inner.kind && self.eligible_condition(cx, check_inner) - && let ctxt = expr.span.ctxt() - && inner.span.ctxt() == ctxt + && expr.span.eq_ctxt(inner.span) && !block_starts_with_significant_tokens(cx, then, inner, self.lint_commented_code) { span_lint_and_then( @@ -262,14 +257,9 @@ fn block_starts_with_significant_tokens( /// If `block` is a block with either one expression or a statement containing an expression, /// return the expression. We don't peel blocks recursively, as extra blocks might be intentional. fn expr_block<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<'tcx>> { - match block.stmts { - [] => block.expr, - [ - Stmt { - kind: StmtKind::Semi(expr), - .. - }, - ] if block.expr.is_none() => Some(expr), + match (block.stmts, block.expr) { + ([], expr) => expr, + ([stmt], None) if let StmtKind::Semi(expr) = stmt.kind => Some(expr), _ => None, } } diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index e1cb08e361c..e67e8d9070f 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -187,6 +187,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::from_raw_with_void_ptr::FROM_RAW_WITH_VOID_PTR_INFO, crate::from_str_radix_10::FROM_STR_RADIX_10_INFO, crate::functions::DOUBLE_MUST_USE_INFO, + crate::functions::DUPLICATE_UNDERSCORE_ARGUMENT_INFO, crate::functions::IMPL_TRAIT_IN_PARAMS_INFO, crate::functions::MISNAMED_GETTERS_INFO, crate::functions::MUST_USE_CANDIDATE_INFO, @@ -505,7 +506,6 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::misc::USED_UNDERSCORE_BINDING_INFO, crate::misc::USED_UNDERSCORE_ITEMS_INFO, crate::misc_early::BUILTIN_TYPE_SHADOW_INFO, - crate::misc_early::DUPLICATE_UNDERSCORE_ARGUMENT_INFO, crate::misc_early::MIXED_CASE_HEX_LITERALS_INFO, crate::misc_early::REDUNDANT_AT_REST_PATTERN_INFO, crate::misc_early::REDUNDANT_PATTERN_INFO, diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index 995a1209595..9aa2f3cf0a5 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -1,12 +1,11 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; -use clippy_utils::ty::{implements_trait, is_manually_drop}; +use clippy_utils::ty::{adjust_derefs_manually_drop, implements_trait, is_manually_drop}; use clippy_utils::{ DefinedTy, ExprUseNode, expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, peel_middle_ty_refs, }; -use core::mem; use rustc_ast::util::parser::ExprPrecedence; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::Applicability; @@ -707,14 +706,6 @@ fn try_parse_ref_op<'tcx>( )) } -// Checks if the adjustments contains a deref of `ManuallyDrop<_>` -fn adjust_derefs_manually_drop<'tcx>(adjustments: &'tcx [Adjustment<'tcx>], mut ty: Ty<'tcx>) -> bool { - adjustments.iter().any(|a| { - let ty = mem::replace(&mut ty, a.target); - matches!(a.kind, Adjust::Deref(Some(ref op)) if op.mutbl == Mutability::Mut) && is_manually_drop(ty) - }) -} - // Checks whether the type for a deref call actually changed the type, not just the mutability of // the reference. fn deref_method_same_type<'tcx>(result_ty: Ty<'tcx>, arg_ty: Ty<'tcx>) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs index d27d68d3866..eca3bc390d7 100644 --- a/src/tools/clippy/clippy_lints/src/doc/mod.rs +++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs @@ -1139,12 +1139,12 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize None, "a backtick may be missing a pair", ); + text_to_check.clear(); } else { - for (text, range, assoc_code_level) in text_to_check { + for (text, range, assoc_code_level) in text_to_check.drain(..) { markdown::check(cx, valid_idents, &text, &fragments, range, assoc_code_level, blockquote_level); } } - text_to_check = Vec::new(); }, Start(FootnoteDefinition(..)) => in_footnote_definition = true, End(TagEnd::FootnoteDefinition) => in_footnote_definition = false, diff --git a/src/tools/clippy/clippy_lints/src/duplicate_mod.rs b/src/tools/clippy/clippy_lints/src/duplicate_mod.rs index ce551a64d99..759b7b6837b 100644 --- a/src/tools/clippy/clippy_lints/src/duplicate_mod.rs +++ b/src/tools/clippy/clippy_lints/src/duplicate_mod.rs @@ -63,7 +63,7 @@ impl_lint_pass!(DuplicateMod => [DUPLICATE_MOD]); impl EarlyLintPass for DuplicateMod { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - if let ItemKind::Mod(_, _, ModKind::Loaded(_, Inline::No, mod_spans, _)) = &item.kind + if let ItemKind::Mod(_, _, ModKind::Loaded(_, Inline::No { .. }, mod_spans)) = &item.kind && let FileName::Real(real) = cx.sess().source_map().span_to_filename(mod_spans.inner_span) && let Some(local_path) = real.into_local_path() && let Ok(absolute_path) = local_path.canonicalize() diff --git a/src/tools/clippy/clippy_lints/src/empty_line_after.rs b/src/tools/clippy/clippy_lints/src/empty_line_after.rs index 3bd74856165..76e67b1154b 100644 --- a/src/tools/clippy/clippy_lints/src/empty_line_after.rs +++ b/src/tools/clippy/clippy_lints/src/empty_line_after.rs @@ -442,7 +442,7 @@ impl EmptyLineAfter { None => span.shrink_to_lo(), }, mod_items: match kind { - ItemKind::Mod(_, _, ModKind::Loaded(items, _, _, _)) => items + ItemKind::Mod(_, _, ModKind::Loaded(items, _, _)) => items .iter() .filter(|i| !matches!(i.span.ctxt().outer_expn_data().kind, ExpnKind::AstPass(_))) .map(|i| i.id) diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs index e467246741c..0eefc2f6109 100644 --- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs +++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs @@ -231,9 +231,13 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx _ => (), } } + let replace_with = match callee_ty_adjusted.kind() { + ty::FnDef(def, _) => cx.tcx.def_descr(*def), + _ => "function", + }; diag.span_suggestion( expr.span, - "replace the closure with the function itself", + format!("replace the closure with the {replace_with} itself"), snippet, Applicability::MachineApplicable, ); diff --git a/src/tools/clippy/clippy_lints/src/excessive_nesting.rs b/src/tools/clippy/clippy_lints/src/excessive_nesting.rs index 1d3ae894944..5368701c304 100644 --- a/src/tools/clippy/clippy_lints/src/excessive_nesting.rs +++ b/src/tools/clippy/clippy_lints/src/excessive_nesting.rs @@ -164,7 +164,7 @@ impl Visitor<'_> for NestingVisitor<'_, '_> { } match &item.kind { - ItemKind::Trait(_) | ItemKind::Impl(_) | ItemKind::Mod(.., ModKind::Loaded(_, Inline::Yes, _, _)) => { + ItemKind::Trait(_) | ItemKind::Impl(_) | ItemKind::Mod(.., ModKind::Loaded(_, Inline::Yes, _)) => { self.nest_level += 1; if !self.check_indent(item.span, item.id) { diff --git a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs index b816963cc82..d5873b3f85a 100644 --- a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs +++ b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::sugg::Sugg; -use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; +use clippy_utils::ty::is_type_lang_item; use clippy_utils::{is_in_const_context, is_integer_literal, sym}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, PrimTy, QPath, TyKind, def}; @@ -89,5 +89,5 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 { /// Checks if a Ty is `String` or `&str` fn is_ty_stringish(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { - is_type_lang_item(cx, ty, LangItem::String) || is_type_diagnostic_item(cx, ty, sym::str) + is_type_lang_item(cx, ty, LangItem::String) || ty.peel_refs().is_str() } diff --git a/src/tools/clippy/clippy_lints/src/functions/duplicate_underscore_argument.rs b/src/tools/clippy/clippy_lints/src/functions/duplicate_underscore_argument.rs new file mode 100644 index 00000000000..b15d1b1bb79 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/functions/duplicate_underscore_argument.rs @@ -0,0 +1,34 @@ +use clippy_utils::diagnostics::span_lint; +use rustc_ast::PatKind; +use rustc_ast::visit::FnKind; +use rustc_data_structures::fx::FxHashMap; +use rustc_lint::EarlyContext; +use rustc_span::Span; + +use super::DUPLICATE_UNDERSCORE_ARGUMENT; + +pub(super) fn check(cx: &EarlyContext<'_>, fn_kind: FnKind<'_>) { + let mut registered_names: FxHashMap<String, Span> = FxHashMap::default(); + + for arg in &fn_kind.decl().inputs { + if let PatKind::Ident(_, ident, None) = arg.pat.kind { + let arg_name = ident.to_string(); + + if let Some(arg_name) = arg_name.strip_prefix('_') { + if let Some(correspondence) = registered_names.get(arg_name) { + span_lint( + cx, + DUPLICATE_UNDERSCORE_ARGUMENT, + *correspondence, + format!( + "`{arg_name}` already exists, having another argument having almost the same \ + name makes code comprehension and documentation more difficult" + ), + ); + } + } else { + registered_names.insert(arg_name, arg.pat.span); + } + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs index 6051dc9479b..ca5ea901814 100644 --- a/src/tools/clippy/clippy_lints/src/functions/mod.rs +++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs @@ -1,3 +1,4 @@ +mod duplicate_underscore_argument; mod impl_trait_in_params; mod misnamed_getters; mod must_use; @@ -11,16 +12,40 @@ mod too_many_lines; use clippy_config::Conf; use clippy_utils::msrvs::Msrv; use clippy_utils::paths::{PathNS, lookup_path_str}; +use rustc_ast::{self as ast, visit}; use rustc_hir as hir; use rustc_hir::intravisit; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc_middle::ty::TyCtxt; -use rustc_session::impl_lint_pass; +use rustc_session::{declare_lint_pass, impl_lint_pass}; use rustc_span::Span; use rustc_span::def_id::{DefIdSet, LocalDefId}; declare_clippy_lint! { /// ### What it does + /// Checks for function arguments having the similar names + /// differing by an underscore. + /// + /// ### Why is this bad? + /// It affects code readability. + /// + /// ### Example + /// ```no_run + /// fn foo(a: i32, _a: i32) {} + /// ``` + /// + /// Use instead: + /// ```no_run + /// fn bar(a: i32, _b: i32) {} + /// ``` + #[clippy::version = "pre 1.29.0"] + pub DUPLICATE_UNDERSCORE_ARGUMENT, + style, + "function arguments having names which only differ by an underscore" +} + +declare_clippy_lint! { + /// ### What it does /// Checks for functions with too many parameters. /// /// ### Why is this bad? @@ -448,6 +473,14 @@ declare_clippy_lint! { "function signature uses `&Option<T>` instead of `Option<&T>`" } +declare_lint_pass!(EarlyFunctions => [DUPLICATE_UNDERSCORE_ARGUMENT]); + +impl EarlyLintPass for EarlyFunctions { + fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: visit::FnKind<'_>, _: Span, _: ast::NodeId) { + duplicate_underscore_argument::check(cx, fn_kind); + } +} + pub struct Functions { too_many_arguments_threshold: u64, too_many_lines_threshold: u64, @@ -503,7 +536,7 @@ impl<'tcx> LateLintPass<'tcx> for Functions { ) { let hir_id = cx.tcx.local_def_id_to_hir_id(def_id); too_many_arguments::check_fn(cx, kind, decl, span, hir_id, self.too_many_arguments_threshold); - too_many_lines::check_fn(cx, kind, span, body, self.too_many_lines_threshold); + too_many_lines::check_fn(cx, kind, body, span, def_id, self.too_many_lines_threshold); not_unsafe_ptr_arg_deref::check_fn(cx, kind, decl, body, def_id); misnamed_getters::check_fn(cx, kind, decl, body, span); impl_trait_in_params::check_fn(cx, &kind, body, hir_id); diff --git a/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs index 0a7c6e9d5f8..f8e8f5544b9 100644 --- a/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs +++ b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs @@ -6,6 +6,7 @@ use rustc_hir::{Impl, ImplItem, ImplItemKind, ItemKind, Node, TraitRef}; use rustc_lint::LateContext; use rustc_span::Span; use rustc_span::symbol::{Ident, kw}; +use std::iter; use super::RENAMED_FUNCTION_PARAMS; @@ -58,16 +59,11 @@ impl RenamedFnArgs { let mut renamed: Vec<(Span, String)> = vec![]; debug_assert!(default_idents.size_hint() == current_idents.size_hint()); - while let (Some(default_ident), Some(current_ident)) = (default_idents.next(), current_idents.next()) { + for (default_ident, current_ident) in iter::zip(default_idents, current_idents) { let has_name_to_check = |ident: Option<Ident>| { - if let Some(ident) = ident - && ident.name != kw::Underscore - && !ident.name.as_str().starts_with('_') - { - Some(ident) - } else { - None - } + ident + .filter(|ident| ident.name != kw::Underscore) + .filter(|ident| !ident.name.as_str().starts_with('_')) }; if let Some(default_ident) = has_name_to_check(default_ident) @@ -97,8 +93,7 @@ fn trait_item_def_id_of_impl(cx: &LateContext<'_>, target: OwnerId) -> Option<De } fn is_from_ignored_trait(of_trait: &TraitRef<'_>, ignored_traits: &DefIdSet) -> bool { - let Some(trait_did) = of_trait.trait_def_id() else { - return false; - }; - ignored_traits.contains(&trait_did) + of_trait + .trait_def_id() + .is_some_and(|trait_did| ignored_traits.contains(&trait_did)) } diff --git a/src/tools/clippy/clippy_lints/src/functions/result.rs b/src/tools/clippy/clippy_lints/src/functions/result.rs index bb98ae82611..1f2fce687ed 100644 --- a/src/tools/clippy/clippy_lints/src/functions/result.rs +++ b/src/tools/clippy/clippy_lints/src/functions/result.rs @@ -97,11 +97,7 @@ fn check_result_unit_err(cx: &LateContext<'_>, err_ty: Ty<'_>, fn_header_span: S fn check_result_large_err<'tcx>(cx: &LateContext<'tcx>, err_ty: Ty<'tcx>, hir_ty_span: Span, large_err_threshold: u64) { if let ty::Adt(adt, subst) = err_ty.kind() - && let Some(local_def_id) = err_ty - .ty_adt_def() - .expect("already checked this is adt") - .did() - .as_local() + && let Some(local_def_id) = adt.did().as_local() && let hir::Node::Item(item) = cx.tcx.hir_node_by_def_id(local_def_id) && let hir::ItemKind::Enum(_, _, ref def) = item.kind { diff --git a/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs b/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs index 4f90d9655b4..33eede8e65a 100644 --- a/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs +++ b/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::source::SpanRangeExt; use rustc_hir as hir; +use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::FnKind; use rustc_lint::{LateContext, LintContext}; use rustc_span::Span; @@ -10,8 +11,9 @@ use super::TOO_MANY_LINES; pub(super) fn check_fn( cx: &LateContext<'_>, kind: FnKind<'_>, - span: Span, body: &hir::Body<'_>, + span: Span, + def_id: LocalDefId, too_many_lines_threshold: u64, ) { // Closures must be contained in a parent body, which will be checked for `too_many_lines`. @@ -74,7 +76,7 @@ pub(super) fn check_fn( span_lint( cx, TOO_MANY_LINES, - span, + cx.tcx.def_span(def_id), format!("this function has too many lines ({line_count}/{too_many_lines_threshold})"), ); } diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 6beddc1be14..57deb011f2b 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -176,12 +176,11 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { if let ExprKind::Let(lt) = expr.kind && match lt.pat.kind { PatKind::Slice([], None, []) => true, - PatKind::Expr(lit) => match lit.kind { - PatExprKind::Lit { lit, .. } => match lit.node { - LitKind::Str(lit, _) => lit.as_str().is_empty(), - _ => false, - }, - _ => false, + PatKind::Expr(lit) + if let PatExprKind::Lit { lit, .. } = lit.kind + && let LitKind::Str(lit, _) = lit.node => + { + lit.as_str().is_empty() }, _ => false, } @@ -336,33 +335,23 @@ fn extract_future_output<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<& } fn is_first_generic_integral<'tcx>(segment: &'tcx PathSegment<'tcx>) -> bool { - if let Some(generic_args) = segment.args { - if generic_args.args.is_empty() { - return false; - } - let arg = &generic_args.args[0]; - if let GenericArg::Type(rustc_hir::Ty { - kind: TyKind::Path(QPath::Resolved(_, path)), - .. - }) = arg - { - let segments = &path.segments; - let segment = &segments[0]; - let res = &segment.res; - if matches!(res, Res::PrimTy(PrimTy::Uint(_))) || matches!(res, Res::PrimTy(PrimTy::Int(_))) { - return true; - } - } + if let Some(generic_args) = segment.args + && let [GenericArg::Type(ty), ..] = &generic_args.args + && let TyKind::Path(QPath::Resolved(_, path)) = ty.kind + && let [segment, ..] = &path.segments + && matches!(segment.res, Res::PrimTy(PrimTy::Uint(_) | PrimTy::Int(_))) + { + true + } else { + false } - - false } fn parse_len_output<'tcx>(cx: &LateContext<'tcx>, sig: FnSig<'tcx>) -> Option<LenOutput> { if let Some(segment) = extract_future_output(cx, sig.output()) { let res = segment.res; - if matches!(res, Res::PrimTy(PrimTy::Uint(_))) || matches!(res, Res::PrimTy(PrimTy::Int(_))) { + if matches!(res, Res::PrimTy(PrimTy::Uint(_) | PrimTy::Int(_))) { return Some(LenOutput::Integral); } diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 844bc1b0e39..d468993e744 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -556,6 +556,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co store.register_late_pass(|_| Box::new(panicking_overflow_checks::PanickingOverflowChecks)); store.register_late_pass(|_| Box::<new_without_default::NewWithoutDefault>::default()); store.register_late_pass(move |_| Box::new(disallowed_names::DisallowedNames::new(conf))); + store.register_early_pass(|| Box::new(functions::EarlyFunctions)); store.register_late_pass(move |tcx| Box::new(functions::Functions::new(tcx, conf))); store.register_late_pass(move |_| Box::new(doc::Documentation::new(conf))); store.register_early_pass(move || Box::new(doc::Documentation::new(conf))); @@ -600,7 +601,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co store.register_late_pass(move |_| Box::new(trait_bounds::TraitBounds::new(conf))); store.register_late_pass(|_| Box::new(comparison_chain::ComparisonChain)); store.register_late_pass(move |tcx| Box::new(mut_key::MutableKeyType::new(tcx, conf))); - store.register_early_pass(|| Box::new(reference::DerefAddrOf)); + store.register_late_pass(|_| Box::new(reference::DerefAddrOf)); store.register_early_pass(|| Box::new(double_parens::DoubleParens)); let format_args = format_args_storage.clone(); store.register_late_pass(move |_| Box::new(format_impl::FormatImpl::new(format_args.clone()))); diff --git a/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs b/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs index 797ff1f3986..a71e6963f8c 100644 --- a/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs @@ -1,10 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::{fn_def_id, is_from_proc_macro, is_lint_allowed}; use hir::intravisit::{Visitor, walk_expr}; -use hir::{Expr, ExprKind, FnRetTy, FnSig, Node, TyKind}; use rustc_ast::Label; use rustc_errors::Applicability; -use rustc_hir as hir; +use rustc_hir::{ + self as hir, Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, Expr, ExprKind, FnRetTy, FnSig, Node, TyKind, +}; use rustc_lint::{LateContext, LintContext}; use rustc_span::sym; @@ -29,6 +30,10 @@ pub(super) fn check<'tcx>( return; } + if is_inside_unawaited_async_block(cx, expr) { + return; + } + if expr.span.in_external_macro(cx.sess().source_map()) || is_from_proc_macro(cx, expr) { return; } @@ -60,6 +65,39 @@ pub(super) fn check<'tcx>( } } +/// Check if the given expression is inside an async block that is not being awaited. +/// This helps avoid false positives when async blocks are spawned or assigned to variables. +fn is_inside_unawaited_async_block(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + let current_hir_id = expr.hir_id; + for (_, parent_node) in cx.tcx.hir_parent_iter(current_hir_id) { + if let Node::Expr(Expr { + kind: + ExprKind::Closure(Closure { + kind: ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)), + .. + }), + .. + }) = parent_node + { + return !is_async_block_awaited(cx, expr); + } + } + false +} + +fn is_async_block_awaited(cx: &LateContext<'_>, async_expr: &Expr<'_>) -> bool { + for (_, parent_node) in cx.tcx.hir_parent_iter(async_expr.hir_id) { + if let Node::Expr(Expr { + kind: ExprKind::Match(_, _, hir::MatchSource::AwaitDesugar), + .. + }) = parent_node + { + return true; + } + } + false +} + fn get_parent_fn_ret_ty<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<FnRetTy<'tcx>> { for (_, parent_node) in cx.tcx.hir_parent_iter(expr.hir_id) { match parent_node { @@ -67,8 +105,8 @@ fn get_parent_fn_ret_ty<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option // This is because we still need to backtrack one parent node to get the `OpaqueDef` ty. Node::Expr(Expr { kind: - ExprKind::Closure(hir::Closure { - kind: hir::ClosureKind::Coroutine(_), + ExprKind::Closure(Closure { + kind: ClosureKind::Coroutine(_), .. }), .. @@ -90,7 +128,7 @@ fn get_parent_fn_ret_ty<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option .. }) | Node::Expr(Expr { - kind: ExprKind::Closure(hir::Closure { fn_decl: decl, .. }), + kind: ExprKind::Closure(Closure { fn_decl: decl, .. }), .. }) => return Some(decl.output), _ => (), diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs index 1f9a943f13d..5a7967bbf94 100644 --- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs @@ -49,7 +49,7 @@ declare_clippy_lint! { } impl<'tcx> QuestionMark { - pub(crate) fn check_manual_let_else(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) { + pub(crate) fn check_manual_let_else(&self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) { if let StmtKind::Let(local) = stmt.kind && let Some(init) = local.init && local.els.is_none() diff --git a/src/tools/clippy/clippy_lints/src/matches/match_bool.rs b/src/tools/clippy/clippy_lints/src/matches/match_bool.rs index b90cf6357c5..a2c8741f4f7 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_bool.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_bool.rs @@ -12,7 +12,11 @@ use super::MATCH_BOOL; pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) { // Type of expression is `bool`. - if *cx.typeck_results().expr_ty(scrutinee).kind() == ty::Bool { + if *cx.typeck_results().expr_ty(scrutinee).kind() == ty::Bool + && arms + .iter() + .all(|arm| arm.pat.walk_short(|p| !matches!(p.kind, PatKind::Binding(..)))) + { span_lint_and_then( cx, MATCH_BOOL, diff --git a/src/tools/clippy/clippy_lints/src/matches/match_ref_pats.rs b/src/tools/clippy/clippy_lints/src/matches/match_ref_pats.rs index 5445ee1f042..5934ec40993 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_ref_pats.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_ref_pats.rs @@ -17,6 +17,11 @@ where return; } + // `!` cannot be deref-ed + if cx.typeck_results().expr_ty(scrutinee).is_never() { + return; + } + let (first_sugg, msg, title); let ctxt = expr.span.ctxt(); let mut app = Applicability::Unspecified; diff --git a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs index 8b4c1700051..eb8b16e1561 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs @@ -54,7 +54,7 @@ impl<'tcx> Visitor<'tcx> for MatchExprVisitor<'_, 'tcx> { } impl MatchExprVisitor<'_, '_> { - fn case_altered(&mut self, segment_ident: Symbol, receiver: &Expr<'_>) -> ControlFlow<CaseMethod> { + fn case_altered(&self, segment_ident: Symbol, receiver: &Expr<'_>) -> ControlFlow<CaseMethod> { if let Some(case_method) = get_case_method(segment_ident) { let ty = self.cx.typeck_results().expr_ty(receiver).peel_refs(); diff --git a/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs b/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs index 6d841853fbe..578865c3291 100644 --- a/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs +++ b/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::{has_non_owning_mutable_access, implements_trait}; -use clippy_utils::{is_mutable, is_trait_method, path_to_local, sym}; +use clippy_utils::{is_mutable, is_trait_method, path_to_local_with_projections, sym}; use rustc_errors::Applicability; use rustc_hir::{Expr, Node, PatKind}; use rustc_lint::LateContext; @@ -37,7 +37,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, self_expr: &'_ Exp // TODO: Change this to lint only when the referred iterator is not used later. If it is used later, // changing to `next_back()` may change its behavior. if !(is_mutable(cx, self_expr) || self_type.is_ref()) { - if let Some(hir_id) = path_to_local(self_expr) + if let Some(hir_id) = path_to_local_with_projections(self_expr) && let Node::Pat(pat) = cx.tcx.hir_node(hir_id) && let PatKind::Binding(_, _, ident, _) = pat.kind { diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs index 6e5da5bda8c..818e26f8aa1 100644 --- a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs +++ b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs @@ -15,7 +15,6 @@ use std::ops::ControlFlow; use super::EXPECT_FUN_CALL; /// Checks for the `EXPECT_FUN_CALL` lint. -#[allow(clippy::too_many_lines)] pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, format_args_storage: &FormatArgsStorage, @@ -25,43 +24,6 @@ pub(super) fn check<'tcx>( receiver: &'tcx hir::Expr<'tcx>, args: &'tcx [hir::Expr<'tcx>], ) { - // Strip `{}`, `&`, `as_ref()` and `as_str()` off `arg` until we're left with either a `String` or - // `&str` - fn get_arg_root<'a>(cx: &LateContext<'_>, arg: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { - let mut arg_root = peel_blocks(arg); - loop { - arg_root = match &arg_root.kind { - hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => expr, - hir::ExprKind::MethodCall(method_name, receiver, [], ..) => { - if (method_name.ident.name == sym::as_str || method_name.ident.name == sym::as_ref) && { - let arg_type = cx.typeck_results().expr_ty(receiver); - let base_type = arg_type.peel_refs(); - base_type.is_str() || is_type_lang_item(cx, base_type, hir::LangItem::String) - } { - receiver - } else { - break; - } - }, - _ => break, - }; - } - arg_root - } - - fn contains_call<'a>(cx: &LateContext<'a>, arg: &'a hir::Expr<'a>) -> bool { - for_each_expr(cx, arg, |expr| { - if matches!(expr.kind, hir::ExprKind::MethodCall { .. } | hir::ExprKind::Call { .. }) - && !is_inside_always_const_context(cx.tcx, expr.hir_id) - { - ControlFlow::Break(()) - } else { - ControlFlow::Continue(()) - } - }) - .is_some() - } - if name == sym::expect && let [arg] = args && let arg_root = get_arg_root(cx, arg) @@ -114,3 +76,40 @@ pub(super) fn check<'tcx>( ); } } + +/// Strip `{}`, `&`, `as_ref()` and `as_str()` off `arg` until we're left with either a `String` or +/// `&str` +fn get_arg_root<'a>(cx: &LateContext<'_>, arg: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { + let mut arg_root = peel_blocks(arg); + loop { + arg_root = match &arg_root.kind { + hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => expr, + hir::ExprKind::MethodCall(method_name, receiver, [], ..) => { + if (method_name.ident.name == sym::as_str || method_name.ident.name == sym::as_ref) && { + let arg_type = cx.typeck_results().expr_ty(receiver); + let base_type = arg_type.peel_refs(); + base_type.is_str() || is_type_lang_item(cx, base_type, hir::LangItem::String) + } { + receiver + } else { + break; + } + }, + _ => break, + }; + } + arg_root +} + +fn contains_call<'a>(cx: &LateContext<'a>, arg: &'a hir::Expr<'a>) -> bool { + for_each_expr(cx, arg, |expr| { + if matches!(expr.kind, hir::ExprKind::MethodCall { .. } | hir::ExprKind::Call { .. }) + && !is_inside_always_const_context(cx.tcx, expr.hir_id) + { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } + }) + .is_some() +} diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs index 4dd54cf1974..5b8457bdd16 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs @@ -106,7 +106,7 @@ enum CheckResult<'tcx> { impl<'tcx> OffendingFilterExpr<'tcx> { pub fn check_map_call( - &mut self, + &self, cx: &LateContext<'tcx>, map_body: &'tcx Body<'tcx>, map_param_id: HirId, @@ -413,7 +413,7 @@ fn is_find_or_filter<'a>( } && let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind - && let Some(mut offending_expr) = OffendingFilterExpr::hir(cx, filter_body.value, filter_param_id) + && let Some(offending_expr) = OffendingFilterExpr::hir(cx, filter_body.value, filter_param_id) && let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind && let map_body = cx.tcx.hir_body(map_body_id) diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_next.rs b/src/tools/clippy/clippy_lints/src/methods/filter_next.rs index 6c1a14fc882..72f83b245a0 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_next.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_next.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; +use clippy_utils::path_to_local_with_projections; use clippy_utils::source::snippet; use clippy_utils::ty::implements_trait; use rustc_ast::{BindingMode, Mutability}; @@ -9,21 +10,6 @@ use rustc_span::sym; use super::FILTER_NEXT; -fn path_to_local(expr: &hir::Expr<'_>) -> Option<hir::HirId> { - match expr.kind { - hir::ExprKind::Field(f, _) => path_to_local(f), - hir::ExprKind::Index(recv, _, _) => path_to_local(recv), - hir::ExprKind::Path(hir::QPath::Resolved( - _, - hir::Path { - res: rustc_hir::def::Res::Local(local), - .. - }, - )) => Some(*local), - _ => None, - } -} - /// lint use of `filter().next()` for `Iterators` pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, @@ -44,7 +30,7 @@ pub(super) fn check<'tcx>( let iter_snippet = snippet(cx, recv.span, ".."); // add note if not multi-line span_lint_and_then(cx, FILTER_NEXT, expr.span, msg, |diag| { - let (applicability, pat) = if let Some(id) = path_to_local(recv) + let (applicability, pat) = if let Some(id) = path_to_local_with_projections(recv) && let hir::Node::Pat(pat) = cx.tcx.hir_node(id) && let hir::PatKind::Binding(BindingMode(_, Mutability::Not), _, ident, _) = pat.kind { diff --git a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs index f880f1f329f..f988323a8c1 100644 --- a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs +++ b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs @@ -7,12 +7,9 @@ mod unneeded_field_pattern; mod unneeded_wildcard_pattern; mod zero_prefixed_literal; -use clippy_utils::diagnostics::span_lint; use clippy_utils::source::snippet_opt; -use rustc_ast::ast::{Expr, ExprKind, Generics, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind}; +use rustc_ast::ast::{Expr, ExprKind, Generics, LitFloatType, LitIntType, LitKind, Pat}; use rustc_ast::token; -use rustc_ast::visit::FnKind; -use rustc_data_structures::fx::FxHashMap; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_session::declare_lint_pass; use rustc_span::Span; @@ -62,29 +59,6 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for function arguments having the similar names - /// differing by an underscore. - /// - /// ### Why is this bad? - /// It affects code readability. - /// - /// ### Example - /// ```no_run - /// fn foo(a: i32, _a: i32) {} - /// ``` - /// - /// Use instead: - /// ```no_run - /// fn bar(a: i32, _b: i32) {} - /// ``` - #[clippy::version = "pre 1.29.0"] - pub DUPLICATE_UNDERSCORE_ARGUMENT, - style, - "function arguments having names which only differ by an underscore" -} - -declare_clippy_lint! { - /// ### What it does /// Warns on hexadecimal literals with mixed-case letter /// digits. /// @@ -330,7 +304,6 @@ declare_clippy_lint! { declare_lint_pass!(MiscEarlyLints => [ UNNEEDED_FIELD_PATTERN, - DUPLICATE_UNDERSCORE_ARGUMENT, MIXED_CASE_HEX_LITERALS, UNSEPARATED_LITERAL_SUFFIX, SEPARATED_LITERAL_SUFFIX, @@ -359,32 +332,6 @@ impl EarlyLintPass for MiscEarlyLints { unneeded_wildcard_pattern::check(cx, pat); } - fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, _: Span, _: NodeId) { - let mut registered_names: FxHashMap<String, Span> = FxHashMap::default(); - - for arg in &fn_kind.decl().inputs { - if let PatKind::Ident(_, ident, None) = arg.pat.kind { - let arg_name = ident.to_string(); - - if let Some(arg_name) = arg_name.strip_prefix('_') { - if let Some(correspondence) = registered_names.get(arg_name) { - span_lint( - cx, - DUPLICATE_UNDERSCORE_ARGUMENT, - *correspondence, - format!( - "`{arg_name}` already exists, having another argument having almost the same \ - name makes code comprehension and documentation more difficult" - ), - ); - } - } else { - registered_names.insert(arg_name, arg.pat.span); - } - } - } - } - fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { if expr.span.in_external_macro(cx.sess().source_map()) { return; @@ -404,7 +351,7 @@ impl MiscEarlyLints { // See <https://github.com/rust-lang/rust-clippy/issues/4507> for a regression. // FIXME: Find a better way to detect those cases. let lit_snip = match snippet_opt(cx, span) { - Some(snip) if snip.chars().next().is_some_and(|c| c.is_ascii_digit()) => snip, + Some(snip) if snip.starts_with(|c: char| c.is_ascii_digit()) => snip, _ => return, }; diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs index a489c0a4a5a..3b44d4b60d3 100644 --- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs @@ -134,7 +134,7 @@ impl<'tcx> DivergenceVisitor<'_, 'tcx> { } } - fn report_diverging_sub_expr(&mut self, e: &Expr<'_>) { + fn report_diverging_sub_expr(&self, e: &Expr<'_>) { if let Some(macro_call) = root_macro_call_first_node(self.cx, e) && self.cx.tcx.is_diagnostic_item(sym::todo_macro, macro_call.def_id) { diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs index fa5afcc0087..6ae26156bc4 100644 --- a/src/tools/clippy/clippy_lints/src/needless_bool.rs +++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs @@ -166,7 +166,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool { applicability, ); }; - if let Some((a, b)) = fetch_bool_block(then).and_then(|a| Some((a, fetch_bool_block(else_expr)?))) { + if let Some(a) = fetch_bool_block(then) + && let Some(b) = fetch_bool_block(else_expr) + { match (a, b) { (RetBool(true), RetBool(true)) | (Bool(true), Bool(true)) => { span_lint( diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs index 120a4b98a65..c7c4976aeb7 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -59,7 +59,7 @@ declare_clippy_lint! { pub struct NeedlessBorrowsForGenericArgs<'tcx> { /// Stack of (body owner, `PossibleBorrowerMap`) pairs. Used by - /// `needless_borrow_impl_arg_position` to determine when a borrowed expression can instead + /// [`needless_borrow_count`] to determine when a borrowed expression can instead /// be moved. possible_borrowers: Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>, diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs index 72e6503e7e4..0d6666eed45 100644 --- a/src/tools/clippy/clippy_lints/src/no_effect.rs +++ b/src/tools/clippy/clippy_lints/src/no_effect.rs @@ -305,11 +305,12 @@ fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) { for e in reduced { if let Some(snip) = e.span.get_source_text(cx) { snippet.push_str(&snip); - snippet.push(';'); + snippet.push_str("; "); } else { return; } } + snippet.pop(); // remove the last space span_lint_hir_and_then( cx, UNNECESSARY_OPERATION, diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index 8a5a6f4a4dc..2fffc4244a7 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -92,7 +92,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "pre 1.29.0"] pub DECLARE_INTERIOR_MUTABLE_CONST, - style, + suspicious, "declaring `const` with interior mutability" } diff --git a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs index c5873589b26..1961ac1516d 100644 --- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs +++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs @@ -248,6 +248,11 @@ impl SimilarNamesNameVisitor<'_, '_, '_> { continue; } + // Skip similarity check if both names are exactly 3 characters + if count == 3 && existing_name.len == 3 { + continue; + } + let dissimilar = match existing_name.len.cmp(&count) { Ordering::Greater => existing_name.len - count != 1 || levenstein_not_1(interned_name, existing_str), Ordering::Less => count - existing_name.len != 1 || levenstein_not_1(existing_str, interned_name), diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs index ba8f6354d97..a42763172f5 100644 --- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs +++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs @@ -173,7 +173,7 @@ impl Params { } /// Sets the `apply_lint` flag on each parameter. - fn flag_for_linting(&mut self) { + fn flag_for_linting(&self) { // Stores the list of parameters currently being resolved. Needed to avoid cycles. let mut eval_stack = Vec::new(); for param in &self.params { diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs index 466beb04b07..ea5b81aec31 100644 --- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -325,7 +325,7 @@ impl ArithmeticSideEffects { self.issue_lint(cx, expr); } - fn should_skip_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) -> bool { + fn should_skip_expr<'tcx>(&self, cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) -> bool { is_lint_allowed(cx, ARITHMETIC_SIDE_EFFECTS, expr.hir_id) || self.expr_span.is_some() || self.const_span.is_some_and(|sp| sp.contains(expr.span)) diff --git a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs index e6be536ca0f..9b1b063c473 100644 --- a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs @@ -13,7 +13,7 @@ pub struct Context { const_span: Option<Span>, } impl Context { - fn skip_expr(&mut self, e: &hir::Expr<'_>) -> bool { + fn skip_expr(&self, e: &hir::Expr<'_>) -> bool { self.expr_id.is_some() || self.const_span.is_some_and(|span| span.contains(e.span)) } diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs index d7b4a03aa53..1b1e77bbea8 100644 --- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs +++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs @@ -120,7 +120,7 @@ impl PassByRefOrValue { } } - fn check_poly_fn(&mut self, cx: &LateContext<'_>, def_id: LocalDefId, decl: &FnDecl<'_>, span: Option<Span>) { + fn check_poly_fn(&self, cx: &LateContext<'_>, def_id: LocalDefId, decl: &FnDecl<'_>, span: Option<Span>) { if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) { return; } diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index b3058c51afd..9eed46460a6 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -237,7 +237,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { .collect(); let results = check_ptr_arg_usage(cx, body, &lint_args); - for (result, args) in results.iter().zip(lint_args.iter()).filter(|(r, _)| !r.skip) { + for (result, args) in iter::zip(&results, &lint_args).filter(|(r, _)| !r.skip) { span_lint_hir_and_then(cx, PTR_ARG, args.emission_id, args.span, args.build_msg(), |diag| { diag.multipart_suggestion( "change this to", @@ -386,7 +386,6 @@ impl<'tcx> DerefTy<'tcx> { } } -#[expect(clippy::too_many_lines)] fn check_fn_args<'cx, 'tcx: 'cx>( cx: &'cx LateContext<'tcx>, fn_sig: ty::FnSig<'tcx>, @@ -413,13 +412,13 @@ fn check_fn_args<'cx, 'tcx: 'cx>( Some(sym::Vec) => ( [(sym::clone, ".to_owned()")].as_slice(), DerefTy::Slice( - name.args.and_then(|args| args.args.first()).and_then(|arg| { - if let GenericArg::Type(ty) = arg { - Some(ty.span) - } else { - None - } - }), + if let Some(name_args) = name.args + && let [GenericArg::Type(ty), ..] = name_args.args + { + Some(ty.span) + } else { + None + }, args.type_at(0), ), ), @@ -432,33 +431,29 @@ fn check_fn_args<'cx, 'tcx: 'cx>( DerefTy::Path, ), Some(sym::Cow) if mutability == Mutability::Not => { - if let Some((lifetime, ty)) = name.args.and_then(|args| { - if let [GenericArg::Lifetime(lifetime), ty] = args.args { - return Some((lifetime, ty)); - } - None - }) { + if let Some(name_args) = name.args + && let [GenericArg::Lifetime(lifetime), ty] = name_args.args + { if let LifetimeKind::Param(param_def_id) = lifetime.kind && !lifetime.is_anonymous() && fn_sig .output() .walk() - .filter_map(|arg| { - arg.as_region().and_then(|lifetime| match lifetime.kind() { - ty::ReEarlyParam(r) => Some( - cx.tcx - .generics_of(cx.tcx.parent(param_def_id.to_def_id())) - .region_param(r, cx.tcx) - .def_id, - ), - ty::ReBound(_, r) => r.kind.get_id(), - ty::ReLateParam(r) => r.kind.get_id(), - ty::ReStatic - | ty::ReVar(_) - | ty::RePlaceholder(_) - | ty::ReErased - | ty::ReError(_) => None, - }) + .filter_map(ty::GenericArg::as_region) + .filter_map(|lifetime| match lifetime.kind() { + ty::ReEarlyParam(r) => Some( + cx.tcx + .generics_of(cx.tcx.parent(param_def_id.to_def_id())) + .region_param(r, cx.tcx) + .def_id, + ), + ty::ReBound(_, r) => r.kind.get_id(), + ty::ReLateParam(r) => r.kind.get_id(), + ty::ReStatic + | ty::ReVar(_) + | ty::RePlaceholder(_) + | ty::ReErased + | ty::ReError(_) => None, }) .any(|def_id| def_id.as_local().is_some_and(|def_id| def_id == param_def_id)) { @@ -627,12 +622,16 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &Body<'tcx>, args: &[ } } + // If the expression's type gets adjusted down to the deref type, we might as + // well have started with that deref type -- the lint should fire let deref_ty = args.deref_ty.ty(self.cx); let adjusted_ty = self.cx.typeck_results().expr_ty_adjusted(e).peel_refs(); if adjusted_ty == deref_ty { return; } + // If the expression's type is constrained by `dyn Trait`, see if the deref + // type implements the trait(s) as well, and if so, the lint should fire if let ty::Dynamic(preds, ..) = adjusted_ty.kind() && matches_preds(self.cx, deref_ty, preds) { diff --git a/src/tools/clippy/clippy_lints/src/raw_strings.rs b/src/tools/clippy/clippy_lints/src/raw_strings.rs index 6a79cae32a5..943e662479e 100644 --- a/src/tools/clippy/clippy_lints/src/raw_strings.rs +++ b/src/tools/clippy/clippy_lints/src/raw_strings.rs @@ -103,15 +103,7 @@ impl EarlyLintPass for RawStrings { } impl RawStrings { - fn check_raw_string( - &mut self, - cx: &EarlyContext<'_>, - str: &str, - lit_span: Span, - prefix: &str, - max: u8, - descr: &str, - ) { + fn check_raw_string(&self, cx: &EarlyContext<'_>, str: &str, lit_span: Span, prefix: &str, max: u8, descr: &str) { if !str.contains(['\\', '"']) { span_lint_and_then( cx, diff --git a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs index 902e8af7ec4..0c1c664f111 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs @@ -88,8 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate { // We ignore macro exports. And `ListStem` uses, which aren't interesting. fn is_ignorable_export<'tcx>(item: &'tcx Item<'tcx>) -> bool { if let ItemKind::Use(path, kind) = item.kind { - let ignore = matches!(path.res.macro_ns, Some(Res::Def(DefKind::Macro(_), _))) - || kind == UseKind::ListStem; + let ignore = matches!(path.res.macro_ns, Some(Res::Def(DefKind::Macro(_), _))) || kind == UseKind::ListStem; if ignore { return true; } diff --git a/src/tools/clippy/clippy_lints/src/reference.rs b/src/tools/clippy/clippy_lints/src/reference.rs index 4bff37216ed..3bbcad12a31 100644 --- a/src/tools/clippy/clippy_lints/src/reference.rs +++ b/src/tools/clippy/clippy_lints/src/reference.rs @@ -1,10 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{SpanRangeExt, snippet_with_applicability}; -use rustc_ast::ast::{Expr, ExprKind, Mutability, UnOp}; +use clippy_utils::source::snippet; +use clippy_utils::sugg::{Sugg, has_enclosing_paren}; +use clippy_utils::ty::adjust_derefs_manually_drop; use rustc_errors::Applicability; -use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_hir::{Expr, ExprKind, HirId, Node, UnOp}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{BytePos, Span}; declare_clippy_lint! { /// ### What it does @@ -37,17 +38,12 @@ declare_clippy_lint! { declare_lint_pass!(DerefAddrOf => [DEREF_ADDROF]); -fn without_parens(mut e: &Expr) -> &Expr { - while let ExprKind::Paren(ref child_e) = e.kind { - e = child_e; - } - e -} - -impl EarlyLintPass for DerefAddrOf { - fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) { - if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.kind - && let ExprKind::AddrOf(_, ref mutability, ref addrof_target) = without_parens(deref_target).kind +impl LateLintPass<'_> for DerefAddrOf { + fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) { + if !e.span.from_expansion() + && let ExprKind::Unary(UnOp::Deref, deref_target) = e.kind + && !deref_target.span.from_expansion() + && let ExprKind::AddrOf(_, _, addrof_target) = deref_target.kind // NOTE(tesuji): `*&` forces rustc to const-promote the array to `.rodata` section. // See #12854 for details. && !matches!(addrof_target.kind, ExprKind::Array(_)) @@ -55,57 +51,82 @@ impl EarlyLintPass for DerefAddrOf { && !addrof_target.span.from_expansion() { let mut applicability = Applicability::MachineApplicable; - let sugg = if e.span.from_expansion() { - if let Some(macro_source) = e.span.get_source_text(cx) { - // Remove leading whitespace from the given span - // e.g: ` $visitor` turns into `$visitor` - let trim_leading_whitespaces = |span: Span| { - span.get_source_text(cx) - .and_then(|snip| { - #[expect(clippy::cast_possible_truncation)] - snip.find(|c: char| !c.is_whitespace()) - .map(|pos| span.lo() + BytePos(pos as u32)) - }) - .map_or(span, |start_no_whitespace| e.span.with_lo(start_no_whitespace)) - }; + let mut sugg = || Sugg::hir_with_applicability(cx, addrof_target, "_", &mut applicability); - let mut generate_snippet = |pattern: &str| { - #[expect(clippy::cast_possible_truncation)] - macro_source.rfind(pattern).map(|pattern_pos| { - let rpos = pattern_pos + pattern.len(); - let span_after_ref = e.span.with_lo(BytePos(e.span.lo().0 + rpos as u32)); - let span = trim_leading_whitespaces(span_after_ref); - snippet_with_applicability(cx, span, "_", &mut applicability) - }) - }; + // If this expression is an explicit `DerefMut` of a `ManuallyDrop` reached through a + // union, we may remove the reference if we are at the point where the implicit + // dereference would take place. Otherwise, we should not lint. + let sugg = match is_manually_drop_through_union(cx, e.hir_id, addrof_target) { + ManuallyDropThroughUnion::Directly => sugg().deref(), + ManuallyDropThroughUnion::Indirect => return, + ManuallyDropThroughUnion::No => sugg(), + }; + + let sugg = if has_enclosing_paren(snippet(cx, e.span, "")) { + sugg.maybe_paren() + } else { + sugg + }; + + span_lint_and_sugg( + cx, + DEREF_ADDROF, + e.span, + "immediately dereferencing a reference", + "try", + sugg.to_string(), + applicability, + ); + } + } +} + +/// Is this a `ManuallyDrop` reached through a union, and when is `DerefMut` called on it? +enum ManuallyDropThroughUnion { + /// `ManuallyDrop` reached through a union and immediately explicitely dereferenced + Directly, + /// `ManuallyDrop` reached through a union, and dereferenced later on + Indirect, + /// Any other situation + No, +} - if *mutability == Mutability::Mut { - generate_snippet("mut") +/// Check if `addrof_target` is part of an access to a `ManuallyDrop` entity reached through a +/// union, and when it is dereferenced using `DerefMut` starting from `expr_id` and going up. +fn is_manually_drop_through_union( + cx: &LateContext<'_>, + expr_id: HirId, + addrof_target: &Expr<'_>, +) -> ManuallyDropThroughUnion { + if is_reached_through_union(cx, addrof_target) { + let typeck = cx.typeck_results(); + for (idx, id) in std::iter::once(expr_id) + .chain(cx.tcx.hir_parent_id_iter(expr_id)) + .enumerate() + { + if let Node::Expr(expr) = cx.tcx.hir_node(id) { + if adjust_derefs_manually_drop(typeck.expr_adjustments(expr), typeck.expr_ty(expr)) { + return if idx == 0 { + ManuallyDropThroughUnion::Directly } else { - generate_snippet("&") - } - } else { - Some(snippet_with_applicability(cx, e.span, "_", &mut applicability)) + ManuallyDropThroughUnion::Indirect + }; } } else { - Some(snippet_with_applicability( - cx, - addrof_target.span, - "_", - &mut applicability, - )) - }; - if let Some(sugg) = sugg { - span_lint_and_sugg( - cx, - DEREF_ADDROF, - e.span, - "immediately dereferencing a reference", - "try", - sugg.to_string(), - applicability, - ); + break; } } } + ManuallyDropThroughUnion::No +} + +/// Checks whether `expr` denotes an object reached through a union +fn is_reached_through_union(cx: &LateContext<'_>, mut expr: &Expr<'_>) -> bool { + while let ExprKind::Field(parent, _) | ExprKind::Index(parent, _, _) = expr.kind { + if cx.typeck_results().expr_ty_adjusted(parent).is_union() { + return true; + } + expr = parent; + } + false } diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs index 5ecbb56925e..76ab3cdae22 100644 --- a/src/tools/clippy/clippy_lints/src/swap.rs +++ b/src/tools/clippy/clippy_lints/src/swap.rs @@ -380,7 +380,7 @@ impl<'tcx> IndexBinding<'_, 'tcx> { } } - fn is_used_other_than_swapping(&mut self, idx_ident: Ident) -> bool { + fn is_used_other_than_swapping(&self, idx_ident: Ident) -> bool { if Self::is_used_slice_indexed(self.swap1_idx, idx_ident) || Self::is_used_slice_indexed(self.swap2_idx, idx_ident) { @@ -389,7 +389,7 @@ impl<'tcx> IndexBinding<'_, 'tcx> { self.is_used_after_swap(idx_ident) } - fn is_used_after_swap(&mut self, idx_ident: Ident) -> bool { + fn is_used_after_swap(&self, idx_ident: Ident) -> bool { let mut v = IndexBindingVisitor { idx: idx_ident, suggest_span: self.suggest_span, diff --git a/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs index 535c044f49e..97e68b3df94 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::{eq_expr_value, path_to_local, sym}; +use clippy_utils::{eq_expr_value, path_to_local_with_projections, sym}; use rustc_abi::WrappingRange; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Node}; @@ -63,11 +63,7 @@ fn binops_with_local(cx: &LateContext<'_>, local_expr: &Expr<'_>, expr: &Expr<'_ /// Checks if an expression is a path to a local variable (with optional projections), e.g. /// `x.field[0].field2` would return true. fn is_local_with_projections(expr: &Expr<'_>) -> bool { - match expr.kind { - ExprKind::Path(_) => path_to_local(expr).is_some(), - ExprKind::Field(expr, _) | ExprKind::Index(expr, ..) => is_local_with_projections(expr), - _ => false, - } + path_to_local_with_projections(expr).is_some() } pub(super) fn check<'tcx>( diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs index d5112e2c3f9..1c7bb4314dd 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs @@ -105,7 +105,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "pre 1.29.0"] pub CROSSPOINTER_TRANSMUTE, - complexity, + suspicious, "transmutes that have to or from types that are a pointer to the other" } diff --git a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs index ec5fb2793f9..b898920baef 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs @@ -49,17 +49,7 @@ pub(super) fn check<'tcx>( true }, (ty::Int(_) | ty::Uint(_), ty::RawPtr(_, _)) => { - span_lint_and_then( - cx, - USELESS_TRANSMUTE, - e.span, - "transmute from an integer to a pointer", - |diag| { - if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) { - diag.span_suggestion(e.span, "try", arg.as_ty(to_ty.to_string()), Applicability::Unspecified); - } - }, - ); + // Handled by the upstream rustc `integer_to_ptr_transmutes` lint true }, _ => false, diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs index 1c52de52619..ba0d4de5f3b 100644 --- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -202,79 +202,41 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks { }; let item_has_safety_comment = item_has_safety_comment(cx, item); - match (&item.kind, item_has_safety_comment) { - // lint unsafe impl without safety comment - (ItemKind::Impl(Impl { of_trait: Some(of_trait), .. }), HasSafetyComment::No) if of_trait.safety.is_unsafe() => { - if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, item.hir_id()) - && !is_unsafe_from_proc_macro(cx, item.span) - { - let source_map = cx.tcx.sess.source_map(); - let span = if source_map.is_multiline(item.span) { - source_map.span_until_char(item.span, '\n') - } else { - item.span - }; - - #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] - span_lint_and_then( - cx, - UNDOCUMENTED_UNSAFE_BLOCKS, - span, - "unsafe impl missing a safety comment", - |diag| { - diag.help("consider adding a safety comment on the preceding line"); - }, - ); - } - }, - // lint safe impl with unnecessary safety comment - (ItemKind::Impl(Impl { of_trait: Some(of_trait), .. }), HasSafetyComment::Yes(pos)) if of_trait.safety.is_safe() => { - if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) { - let (span, help_span) = mk_spans(pos); - - span_lint_and_then( - cx, - UNNECESSARY_SAFETY_COMMENT, - span, - "impl has unnecessary safety comment", - |diag| { - diag.span_help(help_span, "consider removing the safety comment"); - }, - ); - } - }, - (ItemKind::Impl(_), _) => {}, - // const and static items only need a safety comment if their body is an unsafe block, lint otherwise - (&ItemKind::Const(.., body) | &ItemKind::Static(.., body), HasSafetyComment::Yes(pos)) => { - if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, body.hir_id) { - let body = cx.tcx.hir_body(body); - if !matches!( - body.value.kind, hir::ExprKind::Block(block, _) - if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) - ) { - let (span, help_span) = mk_spans(pos); - - span_lint_and_then( - cx, - UNNECESSARY_SAFETY_COMMENT, - span, - format!( - "{} has unnecessary safety comment", - cx.tcx.def_descr(item.owner_id.to_def_id()), - ), - |diag| { - diag.span_help(help_span, "consider removing the safety comment"); - }, - ); - } - } - }, - // Aside from unsafe impls and consts/statics with an unsafe block, items in general - // do not have safety invariants that need to be documented, so lint those. - (_, HasSafetyComment::Yes(pos)) => { - if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) { - let (span, help_span) = mk_spans(pos); + match item_has_safety_comment { + HasSafetyComment::Yes(pos) => check_has_safety_comment(cx, item, mk_spans(pos)), + HasSafetyComment::No => check_has_no_safety_comment(cx, item), + HasSafetyComment::Maybe => {}, + } + } +} +fn check_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>, (span, help_span): (Span, Span)) { + match &item.kind { + ItemKind::Impl(Impl { + of_trait: Some(of_trait), + .. + }) if of_trait.safety.is_safe() => { + if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) { + span_lint_and_then( + cx, + UNNECESSARY_SAFETY_COMMENT, + span, + "impl has unnecessary safety comment", + |diag| { + diag.span_help(help_span, "consider removing the safety comment"); + }, + ); + } + }, + ItemKind::Impl(_) => {}, + // const and static items only need a safety comment if their body is an unsafe block, lint otherwise + &ItemKind::Const(.., body) | &ItemKind::Static(.., body) => { + if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, body.hir_id) { + let body = cx.tcx.hir_body(body); + if !matches!( + body.value.kind, hir::ExprKind::Block(block, _) + if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) + ) { span_lint_and_then( cx, UNNECESSARY_SAFETY_COMMENT, @@ -288,12 +250,56 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks { }, ); } - }, - _ => (), - } + } + }, + // Aside from unsafe impls and consts/statics with an unsafe block, items in general + // do not have safety invariants that need to be documented, so lint those. + _ => { + if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) { + span_lint_and_then( + cx, + UNNECESSARY_SAFETY_COMMENT, + span, + format!( + "{} has unnecessary safety comment", + cx.tcx.def_descr(item.owner_id.to_def_id()), + ), + |diag| { + diag.span_help(help_span, "consider removing the safety comment"); + }, + ); + } + }, } } +fn check_has_no_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) { + if let ItemKind::Impl(Impl { + of_trait: Some(of_trait), + .. + }) = item.kind + && of_trait.safety.is_unsafe() + && !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, item.hir_id()) + && !is_unsafe_from_proc_macro(cx, item.span) + { + let source_map = cx.tcx.sess.source_map(); + let span = if source_map.is_multiline(item.span) { + source_map.span_until_char(item.span, '\n') + } else { + item.span + }; + #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] + span_lint_and_then( + cx, + UNDOCUMENTED_UNSAFE_BLOCKS, + span, + "unsafe impl missing a safety comment", + |diag| { + diag.help("consider adding a safety comment on the preceding line"); + }, + ); + } +} fn expr_has_unnecessary_safety_comment<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, @@ -505,7 +511,8 @@ fn item_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) -> HasSaf }, Node::Stmt(stmt) => { if let Node::Block(block) = cx.tcx.parent_hir_node(stmt.hir_id) { - walk_span_to_context(block.span, SyntaxContext::root()).map(Span::lo) + walk_span_to_context(block.span, SyntaxContext::root()) + .map(|sp| CommentStartBeforeItem::Offset(sp.lo())) } else { // Problem getting the parent node. Pretend a comment was found. return HasSafetyComment::Maybe; @@ -518,10 +525,12 @@ fn item_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) -> HasSaf }; let source_map = cx.sess().source_map(); + // If the comment is in the first line of the file, there is no preceding line if let Some(comment_start) = comment_start && let Ok(unsafe_line) = source_map.lookup_line(item.span.lo()) - && let Ok(comment_start_line) = source_map.lookup_line(comment_start) - && Arc::ptr_eq(&unsafe_line.sf, &comment_start_line.sf) + && let Ok(comment_start_line) = source_map.lookup_line(comment_start.into()) + && let include_first_line_of_file = matches!(comment_start, CommentStartBeforeItem::Start) + && (include_first_line_of_file || Arc::ptr_eq(&unsafe_line.sf, &comment_start_line.sf)) && let Some(src) = unsafe_line.sf.src.as_deref() { return if comment_start_line.line >= unsafe_line.line { @@ -529,7 +538,8 @@ fn item_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) -> HasSaf } else { match text_has_safety_comment( src, - &unsafe_line.sf.lines()[comment_start_line.line + 1..=unsafe_line.line], + &unsafe_line.sf.lines() + [(comment_start_line.line + usize::from(!include_first_line_of_file))..=unsafe_line.line], unsafe_line.sf.start_pos, ) { Some(b) => HasSafetyComment::Yes(b), @@ -592,12 +602,27 @@ fn stmt_has_safety_comment( HasSafetyComment::Maybe } +#[derive(Clone, Copy, Debug)] +enum CommentStartBeforeItem { + Offset(BytePos), + Start, +} + +impl From<CommentStartBeforeItem> for BytePos { + fn from(value: CommentStartBeforeItem) -> Self { + match value { + CommentStartBeforeItem::Offset(loc) => loc, + CommentStartBeforeItem::Start => BytePos(0), + } + } +} + fn comment_start_before_item_in_mod( cx: &LateContext<'_>, parent_mod: &hir::Mod<'_>, parent_mod_span: Span, item: &hir::Item<'_>, -) -> Option<BytePos> { +) -> Option<CommentStartBeforeItem> { parent_mod.item_ids.iter().enumerate().find_map(|(idx, item_id)| { if *item_id == item.item_id() { if idx == 0 { @@ -605,15 +630,18 @@ fn comment_start_before_item_in_mod( // ^------------------------------------------^ returns the start of this span // ^---------------------^ finally checks comments in this range if let Some(sp) = walk_span_to_context(parent_mod_span, SyntaxContext::root()) { - return Some(sp.lo()); + return Some(CommentStartBeforeItem::Offset(sp.lo())); } } else { // some_item /* comment */ unsafe impl T {} // ^-------^ returns the end of this span // ^---------------^ finally checks comments in this range let prev_item = cx.tcx.hir_item(parent_mod.item_ids[idx - 1]); + if prev_item.span.is_dummy() { + return Some(CommentStartBeforeItem::Start); + } if let Some(sp) = walk_span_to_context(prev_item.span, SyntaxContext::root()) { - return Some(sp.hi()); + return Some(CommentStartBeforeItem::Offset(sp.hi())); } } } @@ -668,7 +696,7 @@ fn get_body_search_span(cx: &LateContext<'_>) -> Option<Span> { }) => { return maybe_mod_item .and_then(|item| comment_start_before_item_in_mod(cx, mod_, *span, &item)) - .map(|comment_start| mod_.spans.inner_span.with_lo(comment_start)) + .map(|comment_start| mod_.spans.inner_span.with_lo(comment_start.into())) .or(Some(*span)); }, node if let Some((span, _)) = span_and_hid_of_item_alike_node(&node) diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs index 2b7d3dc0c90..6e3e41f08ee 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs @@ -55,7 +55,7 @@ impl UnnecessaryBoxReturns { } } - fn check_fn_item(&mut self, cx: &LateContext<'_>, decl: &FnDecl<'_>, def_id: LocalDefId, name: Symbol) { + fn check_fn_item(&self, cx: &LateContext<'_>, decl: &FnDecl<'_>, def_id: LocalDefId, name: Symbol) { // we don't want to tell someone to break an exported function if they ask us not to if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) { return; diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_semicolon.rs b/src/tools/clippy/clippy_lints/src/unnecessary_semicolon.rs index f1d1a76d0c2..76e24b6bf80 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_semicolon.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_semicolon.rs @@ -86,7 +86,9 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessarySemicolon { expr.kind, ExprKind::If(..) | ExprKind::Match(_, _, MatchSource::Normal | MatchSource::Postfix) ) - && cx.typeck_results().expr_ty(expr) == cx.tcx.types.unit + && cx.typeck_results().expr_ty(expr).is_unit() + // if a stmt has attrs, then turning it into an expr will break the code, since attrs aren't allowed on exprs + && cx.tcx.hir_attrs(stmt.hir_id).is_empty() { if let Some(block_is_unit) = self.is_last_in_block(stmt) { if cx.tcx.sess.edition() <= Edition2021 && leaks_droppable_temporary_with_limited_lifetime(cx, expr) { diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs index e9ad578da2f..8b278d98a30 100644 --- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs @@ -284,14 +284,14 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<Box<Pat>>, focus_idx: |k, ps1, idx| matches!( k, TupleStruct(qself2, path2, ps2) - if eq_maybe_qself(qself1.as_ref(), qself2.as_ref()) + if eq_maybe_qself(qself1.as_deref(), qself2.as_deref()) && eq_path(path1, path2) && eq_pre_post(ps1, ps2, idx) ), |k| always_pat!(k, TupleStruct(_, _, ps) => ps), ), // Transform a record pattern `S { fp_0, ..., fp_n }`. Struct(qself1, path1, fps1, rest1) => { - extend_with_struct_pat(qself1.as_ref(), path1, fps1, *rest1, start, alternatives) + extend_with_struct_pat(qself1.as_deref(), path1, fps1, *rest1, start, alternatives) }, }; @@ -304,7 +304,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<Box<Pat>>, focus_idx: /// So when we fixate on some `ident_k: pat_k`, we try to find `ident_k` in the other pattern /// and check that all `fp_i` where `i ∈ ((0...n) \ k)` between two patterns are equal. fn extend_with_struct_pat( - qself1: Option<&Box<ast::QSelf>>, + qself1: Option<&ast::QSelf>, path1: &ast::Path, fps1: &mut [ast::PatField], rest1: ast::PatFieldsRest, @@ -319,7 +319,7 @@ fn extend_with_struct_pat( |k| { matches!(k, Struct(qself2, path2, fps2, rest2) if rest1 == *rest2 // If one struct pattern has `..` so must the other. - && eq_maybe_qself(qself1, qself2.as_ref()) + && eq_maybe_qself(qself1, qself2.as_deref()) && eq_path(path1, path2) && fps1.len() == fps2.len() && fps1.iter().enumerate().all(|(idx_1, fp1)| { diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs index c641d4e55b9..490da4f1e03 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap.rs @@ -141,43 +141,45 @@ fn collect_unwrap_info<'tcx>( is_type_diagnostic_item(cx, ty, sym::Result) && matches!(method_name, sym::is_err | sym::is_ok) } - if let ExprKind::Binary(op, left, right) = &expr.kind { - match (invert, op.node) { - (false, BinOpKind::And | BinOpKind::BitAnd) | (true, BinOpKind::Or | BinOpKind::BitOr) => { - let mut unwrap_info = collect_unwrap_info(cx, if_expr, left, branch, invert, false); - unwrap_info.append(&mut collect_unwrap_info(cx, if_expr, right, branch, invert, false)); - return unwrap_info; - }, - _ => (), - } - } else if let ExprKind::Unary(UnOp::Not, expr) = &expr.kind { - return collect_unwrap_info(cx, if_expr, expr, branch, !invert, false); - } else if let ExprKind::MethodCall(method_name, receiver, [], _) = &expr.kind - && let Some(local_id) = path_to_local(receiver) - && let ty = cx.typeck_results().expr_ty(receiver) - && let name = method_name.ident.name - && (is_relevant_option_call(cx, ty, name) || is_relevant_result_call(cx, ty, name)) - { - let unwrappable = matches!(name, sym::is_some | sym::is_ok); - let safe_to_unwrap = unwrappable != invert; - let kind = if is_type_diagnostic_item(cx, ty, sym::Option) { - UnwrappableKind::Option - } else { - UnwrappableKind::Result - }; + match expr.kind { + ExprKind::Binary(op, left, right) + if matches!( + (invert, op.node), + (false, BinOpKind::And | BinOpKind::BitAnd) | (true, BinOpKind::Or | BinOpKind::BitOr) + ) => + { + let mut unwrap_info = collect_unwrap_info(cx, if_expr, left, branch, invert, false); + unwrap_info.extend(collect_unwrap_info(cx, if_expr, right, branch, invert, false)); + unwrap_info + }, + ExprKind::Unary(UnOp::Not, expr) => collect_unwrap_info(cx, if_expr, expr, branch, !invert, false), + ExprKind::MethodCall(method_name, receiver, [], _) + if let Some(local_id) = path_to_local(receiver) + && let ty = cx.typeck_results().expr_ty(receiver) + && let name = method_name.ident.name + && (is_relevant_option_call(cx, ty, name) || is_relevant_result_call(cx, ty, name)) => + { + let unwrappable = matches!(name, sym::is_some | sym::is_ok); + let safe_to_unwrap = unwrappable != invert; + let kind = if is_type_diagnostic_item(cx, ty, sym::Option) { + UnwrappableKind::Option + } else { + UnwrappableKind::Result + }; - return vec![UnwrapInfo { - local_id, - if_expr, - check: expr, - check_name: name, - branch, - safe_to_unwrap, - kind, - is_entire_condition, - }]; + vec![UnwrapInfo { + local_id, + if_expr, + check: expr, + check_name: name, + branch, + safe_to_unwrap, + kind, + is_entire_condition, + }] + }, + _ => vec![], } - Vec::new() } /// A HIR visitor delegate that checks if a local variable of type `Option` or `Result` is mutated, diff --git a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs index 1550872bca2..f1572fd65bb 100644 --- a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs +++ b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs @@ -56,6 +56,9 @@ impl LateLintPass<'_> for ZeroSizedMapValues { // cannot check if it is `Sized` or not, such as an incomplete associated type in a // type alias. See an example in `issue14822()` of `tests/ui/zero_sized_hashmap_values.rs`. && !ty.has_non_region_param() + // Ensure that no region escapes to avoid an assertion error when computing the layout. + // See an example in `issue15429()` of `tests/ui/zero_sized_hashmap_values.rs`. + && !ty.has_escaping_bound_vars() && let Ok(layout) = cx.layout_of(ty) && layout.is_zst() { diff --git a/src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs b/src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs index 5e6a40ac2eb..0fd1e11b033 100644 --- a/src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs +++ b/src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs @@ -6,7 +6,8 @@ use rustc_hir::attrs::AttributeKind; use rustc_hir::def::Res; use rustc_hir::def_id::LocalDefId; use rustc_hir::{ - AttrArgs, AttrItem, AttrPath, Attribute, HirId, Impl, Item, ItemKind, Path, QPath, TraitRef, Ty, TyKind, find_attr, + AttrArgs, AttrItem, AttrPath, Attribute, HirId, Impl, Item, ItemKind, Path, QPath, TraitImplHeader, TraitRef, Ty, + TyKind, find_attr, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_lint_defs::declare_tool_lint; @@ -56,10 +57,14 @@ impl<'tcx> LateLintPass<'tcx> for DeriveDeserializeAllowingUnknown { // Is this an `impl` (of a certain form)? let ItemKind::Impl(Impl { of_trait: - Some(TraitRef { - path: - Path { - res: Res::Def(_, trait_def_id), + Some(TraitImplHeader { + trait_ref: + TraitRef { + path: + Path { + res: Res::Def(_, trait_def_id), + .. + }, .. }, .. diff --git a/src/tools/clippy/clippy_test_deps/Cargo.lock b/src/tools/clippy/clippy_test_deps/Cargo.lock index 2f987c0137c..b22cf9d107d 100644 --- a/src/tools/clippy/clippy_test_deps/Cargo.lock +++ b/src/tools/clippy/clippy_test_deps/Cargo.lock @@ -377,9 +377,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "smallvec" diff --git a/src/tools/clippy/clippy_utils/README.md b/src/tools/clippy/clippy_utils/README.md index 6d8dd92d55d..2dfe28953d0 100644 --- a/src/tools/clippy/clippy_utils/README.md +++ b/src/tools/clippy/clippy_utils/README.md @@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain: <!-- begin autogenerated nightly --> ``` -nightly-2025-08-07 +nightly-2025-08-22 ``` <!-- end autogenerated nightly --> diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 24e017f7cf7..40c00568a3b 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -41,21 +41,23 @@ pub fn eq_pat(l: &Pat, r: &Pat) -> bool { b1 == b2 && eq_id(*i1, *i2) && both(s1.as_deref(), s2.as_deref(), eq_pat) }, (Range(lf, lt, le), Range(rf, rt, re)) => { - eq_expr_opt(lf.as_ref(), rf.as_ref()) - && eq_expr_opt(lt.as_ref(), rt.as_ref()) + eq_expr_opt(lf.as_deref(), rf.as_deref()) + && eq_expr_opt(lt.as_deref(), rt.as_deref()) && eq_range_end(&le.node, &re.node) }, (Box(l), Box(r)) | (Ref(l, Mutability::Not), Ref(r, Mutability::Not)) | (Ref(l, Mutability::Mut), Ref(r, Mutability::Mut)) => eq_pat(l, r), (Tuple(l), Tuple(r)) | (Slice(l), Slice(r)) => over(l, r, |l, r| eq_pat(l, r)), - (Path(lq, lp), Path(rq, rp)) => both(lq.as_ref(), rq.as_ref(), eq_qself) && eq_path(lp, rp), + (Path(lq, lp), Path(rq, rp)) => both(lq.as_deref(), rq.as_deref(), eq_qself) && eq_path(lp, rp), (TupleStruct(lqself, lp, lfs), TupleStruct(rqself, rp, rfs)) => { - eq_maybe_qself(lqself.as_ref(), rqself.as_ref()) && eq_path(lp, rp) && over(lfs, rfs, |l, r| eq_pat(l, r)) + eq_maybe_qself(lqself.as_deref(), rqself.as_deref()) + && eq_path(lp, rp) + && over(lfs, rfs, |l, r| eq_pat(l, r)) }, (Struct(lqself, lp, lfs, lr), Struct(rqself, rp, rfs, rr)) => { lr == rr - && eq_maybe_qself(lqself.as_ref(), rqself.as_ref()) + && eq_maybe_qself(lqself.as_deref(), rqself.as_deref()) && eq_path(lp, rp) && unordered_over(lfs, rfs, eq_field_pat) }, @@ -82,11 +84,11 @@ pub fn eq_field_pat(l: &PatField, r: &PatField) -> bool { && over(&l.attrs, &r.attrs, eq_attr) } -pub fn eq_qself(l: &Box<QSelf>, r: &Box<QSelf>) -> bool { +pub fn eq_qself(l: &QSelf, r: &QSelf) -> bool { l.position == r.position && eq_ty(&l.ty, &r.ty) } -pub fn eq_maybe_qself(l: Option<&Box<QSelf>>, r: Option<&Box<QSelf>>) -> bool { +pub fn eq_maybe_qself(l: Option<&QSelf>, r: Option<&QSelf>) -> bool { match (l, r) { (Some(l), Some(r)) => eq_qself(l, r), (None, None) => true, @@ -129,8 +131,8 @@ pub fn eq_generic_arg(l: &GenericArg, r: &GenericArg) -> bool { } } -pub fn eq_expr_opt(l: Option<&Box<Expr>>, r: Option<&Box<Expr>>) -> bool { - both(l, r, |l, r| eq_expr(l, r)) +pub fn eq_expr_opt(l: Option<&Expr>, r: Option<&Expr>) -> bool { + both(l, r, eq_expr) } pub fn eq_struct_rest(l: &StructRest, r: &StructRest) -> bool { @@ -177,7 +179,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { (Cast(l, lt), Cast(r, rt)) | (Type(l, lt), Type(r, rt)) => eq_expr(l, r) && eq_ty(lt, rt), (Let(lp, le, _, _), Let(rp, re, _, _)) => eq_pat(lp, rp) && eq_expr(le, re), (If(lc, lt, le), If(rc, rt, re)) => { - eq_expr(lc, rc) && eq_block(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()) + eq_expr(lc, rc) && eq_block(lt, rt) && eq_expr_opt(le.as_deref(), re.as_deref()) }, (While(lc, lt, ll), While(rc, rt, rl)) => { eq_label(ll.as_ref(), rl.as_ref()) && eq_expr(lc, rc) && eq_block(lt, rt) @@ -201,9 +203,11 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { (Loop(lt, ll, _), Loop(rt, rl, _)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_block(lt, rt), (Block(lb, ll), Block(rb, rl)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_block(lb, rb), (TryBlock(l), TryBlock(r)) => eq_block(l, r), - (Yield(l), Yield(r)) => eq_expr_opt(l.expr(), r.expr()) && l.same_kind(r), - (Ret(l), Ret(r)) => eq_expr_opt(l.as_ref(), r.as_ref()), - (Break(ll, le), Break(rl, re)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_expr_opt(le.as_ref(), re.as_ref()), + (Yield(l), Yield(r)) => eq_expr_opt(l.expr().map(Box::as_ref), r.expr().map(Box::as_ref)) && l.same_kind(r), + (Ret(l), Ret(r)) => eq_expr_opt(l.as_deref(), r.as_deref()), + (Break(ll, le), Break(rl, re)) => { + eq_label(ll.as_ref(), rl.as_ref()) && eq_expr_opt(le.as_deref(), re.as_deref()) + }, (Continue(ll), Continue(rl)) => eq_label(ll.as_ref(), rl.as_ref()), (Assign(l1, l2, _), Assign(r1, r2, _)) | (Index(l1, l2, _), Index(r1, r2, _)) => { eq_expr(l1, r1) && eq_expr(l2, r2) @@ -240,13 +244,13 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { }, (Gen(lc, lb, lk, _), Gen(rc, rb, rk, _)) => lc == rc && eq_block(lb, rb) && lk == rk, (Range(lf, lt, ll), Range(rf, rt, rl)) => { - ll == rl && eq_expr_opt(lf.as_ref(), rf.as_ref()) && eq_expr_opt(lt.as_ref(), rt.as_ref()) + ll == rl && eq_expr_opt(lf.as_deref(), rf.as_deref()) && eq_expr_opt(lt.as_deref(), rt.as_deref()) }, (AddrOf(lbk, lm, le), AddrOf(rbk, rm, re)) => lbk == rbk && lm == rm && eq_expr(le, re), - (Path(lq, lp), Path(rq, rp)) => both(lq.as_ref(), rq.as_ref(), eq_qself) && eq_path(lp, rp), + (Path(lq, lp), Path(rq, rp)) => both(lq.as_deref(), rq.as_deref(), eq_qself) && eq_path(lp, rp), (MacCall(l), MacCall(r)) => eq_mac_call(l, r), (Struct(lse), Struct(rse)) => { - eq_maybe_qself(lse.qself.as_ref(), rse.qself.as_ref()) + eq_maybe_qself(lse.qself.as_deref(), rse.qself.as_deref()) && eq_path(&lse.path, &rse.path) && eq_struct_rest(&lse.rest, &rse.rest) && unordered_over(&lse.fields, &rse.fields, eq_field) @@ -278,8 +282,8 @@ pub fn eq_field(l: &ExprField, r: &ExprField) -> bool { pub fn eq_arm(l: &Arm, r: &Arm) -> bool { l.is_placeholder == r.is_placeholder && eq_pat(&l.pat, &r.pat) - && eq_expr_opt(l.body.as_ref(), r.body.as_ref()) - && eq_expr_opt(l.guard.as_ref(), r.guard.as_ref()) + && eq_expr_opt(l.body.as_deref(), r.body.as_deref()) + && eq_expr_opt(l.guard.as_deref(), r.guard.as_deref()) && over(&l.attrs, &r.attrs, eq_attr) } @@ -324,7 +328,7 @@ pub fn eq_item<K>(l: &Item<K>, r: &Item<K>, mut eq_kind: impl FnMut(&K, &K) -> b over(&l.attrs, &r.attrs, eq_attr) && eq_vis(&l.vis, &r.vis) && eq_kind(&l.kind, &r.kind) } -#[expect(clippy::similar_names, clippy::too_many_lines)] // Just a big match statement +#[expect(clippy::too_many_lines)] // Just a big match statement pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { use ItemKind::*; match (l, r) { @@ -347,7 +351,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { safety: rs, define_opaque: _, }), - ) => eq_id(*li, *ri) && lm == rm && ls == rs && eq_ty(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()), + ) => eq_id(*li, *ri) && lm == rm && ls == rs && eq_ty(lt, rt) && eq_expr_opt(le.as_deref(), re.as_deref()), ( Const(box ConstItem { defaultness: ld, @@ -370,7 +374,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { && eq_id(*li, *ri) && eq_generics(lg, rg) && eq_ty(lt, rt) - && eq_expr_opt(le.as_ref(), re.as_ref()) + && eq_expr_opt(le.as_deref(), re.as_deref()) }, ( Fn(box ast::Fn { @@ -403,7 +407,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { ls == rs && eq_id(*li, *ri) && match (lmk, rmk) { - (ModKind::Loaded(litems, linline, _, _), ModKind::Loaded(ritems, rinline, _, _)) => { + (ModKind::Loaded(litems, linline, _), ModKind::Loaded(ritems, rinline, _)) => { linline == rinline && over(litems, ritems, |l, r| eq_item(l, r, eq_item_kind)) }, (ModKind::Unloaded, ModKind::Unloaded) => true, @@ -525,7 +529,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { safety: rs, define_opaque: _, }), - ) => eq_id(*li, *ri) && eq_ty(lt, rt) && lm == rm && eq_expr_opt(le.as_ref(), re.as_ref()) && ls == rs, + ) => eq_id(*li, *ri) && eq_ty(lt, rt) && lm == rm && eq_expr_opt(le.as_deref(), re.as_deref()) && ls == rs, ( Fn(box ast::Fn { defaultness: ld, @@ -607,7 +611,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { && eq_id(*li, *ri) && eq_generics(lg, rg) && eq_ty(lt, rt) - && eq_expr_opt(le.as_ref(), re.as_ref()) + && eq_expr_opt(le.as_deref(), re.as_deref()) }, ( Fn(box ast::Fn { @@ -723,7 +727,8 @@ pub fn eq_fn_header(l: &FnHeader, r: &FnHeader) -> bool { pub fn eq_opt_fn_contract(l: &Option<Box<FnContract>>, r: &Option<Box<FnContract>>) -> bool { match (l, r) { (Some(l), Some(r)) => { - eq_expr_opt(l.requires.as_ref(), r.requires.as_ref()) && eq_expr_opt(l.ensures.as_ref(), r.ensures.as_ref()) + eq_expr_opt(l.requires.as_deref(), r.requires.as_deref()) + && eq_expr_opt(l.ensures.as_deref(), r.ensures.as_deref()) }, (None, None) => true, (Some(_), None) | (None, Some(_)) => false, @@ -841,7 +846,7 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool { && eq_fn_decl(&l.decl, &r.decl) }, (Tup(l), Tup(r)) => over(l, r, |l, r| eq_ty(l, r)), - (Path(lq, lp), Path(rq, rp)) => both(lq.as_ref(), rq.as_ref(), eq_qself) && eq_path(lp, rp), + (Path(lq, lp), Path(rq, rp)) => both(lq.as_deref(), rq.as_deref(), eq_qself) && eq_path(lp, rp), (TraitObject(lg, ls), TraitObject(rg, rs)) => ls == rs && over(lg, rg, eq_generic_bound), (ImplTrait(_, lg), ImplTrait(_, rg)) => over(lg, rg, eq_generic_bound), (Typeof(l), Typeof(r)) => eq_expr(&l.value, &r.value), diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index e0c1b9d445a..c4a759e919b 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -19,8 +19,8 @@ use rustc_ast::token::CommentKind; use rustc_hir::intravisit::FnKind; use rustc_hir::{ Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, FnRetTy, HirId, Impl, - ImplItem, ImplItemKind, TraitImplHeader, IsAuto, Item, ItemKind, Lit, LoopSource, MatchSource, MutTy, Node, Path, - QPath, Safety, TraitItem, TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData, YieldSource, + ImplItem, ImplItemKind, IsAuto, Item, ItemKind, Lit, LoopSource, MatchSource, MutTy, Node, Path, QPath, Safety, + TraitImplHeader, TraitItem, TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData, YieldSource, }; use rustc_lint::{EarlyContext, LateContext, LintContext}; use rustc_middle::ty::TyCtxt; @@ -254,7 +254,10 @@ fn item_search_pat(item: &Item<'_>) -> (Pat, Pat) { ItemKind::Union(..) => (Pat::Str("union"), Pat::Str("}")), ItemKind::Trait(_, _, Safety::Unsafe, ..) | ItemKind::Impl(Impl { - of_trait: Some(TraitImplHeader { safety: Safety::Unsafe, .. }), .. + of_trait: Some(TraitImplHeader { + safety: Safety::Unsafe, .. + }), + .. }) => (Pat::Str("unsafe"), Pat::Str("}")), ItemKind::Trait(_, IsAuto::Yes, ..) => (Pat::Str("auto"), Pat::Str("}")), ItemKind::Trait(..) => (Pat::Str("trait"), Pat::Str("}")), diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs index 625e1eead21..8a19039a7fe 100644 --- a/src/tools/clippy/clippy_utils/src/diagnostics.rs +++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs @@ -22,13 +22,14 @@ fn docs_link(diag: &mut Diag<'_, ()>, lint: &'static Lint) { { diag.help(format!( "for further information visit https://rust-lang.github.io/rust-clippy/{}/index.html#{lint}", - &option_env!("RUST_RELEASE_NUM").map_or_else( - || "master".to_string(), - |n| { - // extract just major + minor version and ignore patch versions - format!("rust-{}", n.rsplit_once('.').unwrap().1) - } - ) + match option_env!("CFG_RELEASE_CHANNEL") { + // Clippy version is 0.1.xx + // + // Always use .0 because we do not generate separate lint doc pages for rust patch releases + Some("stable") => concat!("rust-1.", env!("CARGO_PKG_VERSION_PATCH"), ".0"), + Some("beta") => "beta", + _ => "master", + } )); } } diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index f0d7fb89c44..8160443f413 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -258,7 +258,7 @@ impl HirEqInterExpr<'_, '_, '_> { }) } - fn should_ignore(&mut self, expr: &Expr<'_>) -> bool { + fn should_ignore(&self, expr: &Expr<'_>) -> bool { macro_backtrace(expr.span).last().is_some_and(|macro_call| { matches!( self.inner.cx.tcx.get_diagnostic_name(macro_call.def_id), diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index fcc120656e3..8533fa85541 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -460,6 +460,23 @@ pub fn path_to_local_id(expr: &Expr<'_>, id: HirId) -> bool { path_to_local(expr) == Some(id) } +/// If the expression is a path to a local (with optional projections), +/// returns the canonical `HirId` of the local. +/// +/// For example, `x.field[0].field2` would return the `HirId` of `x`. +pub fn path_to_local_with_projections(expr: &Expr<'_>) -> Option<HirId> { + match expr.kind { + ExprKind::Field(recv, _) | ExprKind::Index(recv, _, _) => path_to_local_with_projections(recv), + ExprKind::Path(QPath::Resolved( + _, + Path { + res: Res::Local(local), .. + }, + )) => Some(*local), + _ => None, + } +} + pub trait MaybePath<'hir> { fn hir_id(&self) -> HirId; fn qpath_opt(&self) -> Option<&QPath<'hir>>; diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs index 89a83e2c48f..896d607fbcd 100644 --- a/src/tools/clippy/clippy_utils/src/msrvs.rs +++ b/src/tools/clippy/clippy_utils/src/msrvs.rs @@ -189,25 +189,25 @@ impl MsrvStack { fn parse_attrs(sess: &Session, attrs: &[impl AttributeExt]) -> Option<RustcVersion> { let mut msrv_attrs = attrs.iter().filter(|attr| attr.path_matches(&[sym::clippy, sym::msrv])); - if let Some(msrv_attr) = msrv_attrs.next() { - if let Some(duplicate) = msrv_attrs.next_back() { - sess.dcx() - .struct_span_err(duplicate.span(), "`clippy::msrv` is defined multiple times") - .with_span_note(msrv_attr.span(), "first definition found here") - .emit(); - } - - if let Some(msrv) = msrv_attr.value_str() { - if let Some(version) = parse_version(msrv) { - return Some(version); - } + let msrv_attr = msrv_attrs.next()?; - sess.dcx() - .span_err(msrv_attr.span(), format!("`{msrv}` is not a valid Rust version")); - } else { - sess.dcx().span_err(msrv_attr.span(), "bad clippy attribute"); - } + if let Some(duplicate) = msrv_attrs.next_back() { + sess.dcx() + .struct_span_err(duplicate.span(), "`clippy::msrv` is defined multiple times") + .with_span_note(msrv_attr.span(), "first definition found here") + .emit(); } - None + let Some(msrv) = msrv_attr.value_str() else { + sess.dcx().span_err(msrv_attr.span(), "bad clippy attribute"); + return None; + }; + + let Some(version) = parse_version(msrv) else { + sess.dcx() + .span_err(msrv_attr.span(), format!("`{msrv}` is not a valid Rust version")); + return None; + }; + + Some(version) } diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs index d79773f8321..fafc1d07e51 100644 --- a/src/tools/clippy/clippy_utils/src/ty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs @@ -18,6 +18,7 @@ use rustc_lint::LateContext; use rustc_middle::mir::ConstValue; use rustc_middle::mir::interpret::Scalar; use rustc_middle::traits::EvaluationResult; +use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::{ self, AdtDef, AliasTy, AssocItem, AssocTag, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef, @@ -31,7 +32,7 @@ use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; use rustc_trait_selection::traits::{Obligation, ObligationCause}; use std::assert_matches::debug_assert_matches; use std::collections::hash_map::Entry; -use std::iter; +use std::{iter, mem}; use crate::path_res; use crate::paths::{PathNS, lookup_path_str}; @@ -1382,7 +1383,6 @@ pub fn is_slice_like<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { || matches!(ty.kind(), ty::Adt(adt_def, _) if cx.tcx.is_diagnostic_item(sym::Vec, adt_def.did())) } -/// Gets the index of a field by name. pub fn get_field_idx_by_name(ty: Ty<'_>, name: Symbol) -> Option<usize> { match *ty.kind() { ty::Adt(def, _) if def.is_union() || def.is_struct() => { @@ -1392,3 +1392,11 @@ pub fn get_field_idx_by_name(ty: Ty<'_>, name: Symbol) -> Option<usize> { _ => None, } } + +/// Checks if the adjustments contain a mutable dereference of a `ManuallyDrop<_>`. +pub fn adjust_derefs_manually_drop<'tcx>(adjustments: &'tcx [Adjustment<'tcx>], mut ty: Ty<'tcx>) -> bool { + adjustments.iter().any(|a| { + let ty = mem::replace(&mut ty, a.target); + matches!(a.kind, Adjust::Deref(Some(op)) if op.mutbl == Mutability::Mut) && is_manually_drop(ty) + }) +} diff --git a/src/tools/clippy/rust-toolchain.toml b/src/tools/clippy/rust-toolchain.toml index ac51ec2d61b..5497e77e8ad 100644 --- a/src/tools/clippy/rust-toolchain.toml +++ b/src/tools/clippy/rust-toolchain.toml @@ -1,6 +1,6 @@ [toolchain] # begin autogenerated nightly -channel = "nightly-2025-08-07" +channel = "nightly-2025-08-22" # end autogenerated nightly components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" diff --git a/src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/Cargo.stderr b/src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/Cargo.stderr new file mode 100644 index 00000000000..59a7146ac90 --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/Cargo.stderr @@ -0,0 +1,26 @@ +error: module has unnecessary safety comment + --> src/main.rs:2:1 + | +2 | mod x {} + | ^^^^^^^^ + | +help: consider removing the safety comment + --> src/main.rs:1:1 + | +1 | // SAFETY: ... + | ^^^^^^^^^^^^^^ + = note: requested on the command line with `-D clippy::unnecessary-safety-comment` + +error: module has unnecessary safety comment + --> src/main.rs:5:1 + | +5 | mod y {} + | ^^^^^^^^ + | +help: consider removing the safety comment + --> src/main.rs:4:1 + | +4 | // SAFETY: ... + | ^^^^^^^^^^^^^^ + +error: could not compile `undocumented_unsafe_blocks` (bin "undocumented_unsafe_blocks") due to 2 previous errors diff --git a/src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/Cargo.toml b/src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/Cargo.toml new file mode 100644 index 00000000000..36bb3472df0 --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/Cargo.toml @@ -0,0 +1,12 @@ +# Reproducing #14553 requires the `# Safety` comment to be in the first line of +# the file. Since `unnecessary_safety_comment` is not enabled by default, we +# will set it up here. + +[package] +name = "undocumented_unsafe_blocks" +edition = "2024" +publish = false +version = "0.1.0" + +[lints.clippy] +unnecessary_safety_comment = "deny" diff --git a/src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/src/main.rs b/src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/src/main.rs new file mode 100644 index 00000000000..5cafcff99dd --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/src/main.rs @@ -0,0 +1,7 @@ +// SAFETY: ... +mod x {} + +// SAFETY: ... +mod y {} + +fn main() {} 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 14a49cb76c1..e856963c87d 100644 --- a/src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr +++ b/src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr @@ -1,12 +1,8 @@ error: this function has too many lines (2/1) --> tests/ui-toml/functions_maxlines/test.rs:19:1 | -LL | / fn too_many_lines() { -LL | | -LL | | println!("This is bad."); -LL | | println!("This is bad."); -LL | | } - | |_^ +LL | fn too_many_lines() { + | ^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::too-many-lines` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::too_many_lines)]` @@ -14,35 +10,20 @@ LL | | } error: this function has too many lines (4/1) --> tests/ui-toml/functions_maxlines/test.rs:26:1 | -LL | / async fn async_too_many_lines() { -LL | | -LL | | println!("This is bad."); -LL | | println!("This is bad."); -LL | | } - | |_^ +LL | async fn async_too_many_lines() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this function has too many lines (4/1) --> tests/ui-toml/functions_maxlines/test.rs:33:1 | -LL | / fn closure_too_many_lines() { -LL | | -LL | | let _ = { -LL | | println!("This is bad."); -LL | | println!("This is bad."); -LL | | }; -LL | | } - | |_^ +LL | fn closure_too_many_lines() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this function has too many lines (2/1) --> tests/ui-toml/functions_maxlines/test.rs:56:1 | -LL | / fn comment_before_code() { -LL | | -LL | | let _ = "test"; -LL | | /* This comment extends to the front of -LL | | the code but this line should still count. */ let _ = 5; -LL | | } - | |_^ +LL | fn comment_before_code() { + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/as_ptr_cast_mut.fixed b/src/tools/clippy/tests/ui/as_ptr_cast_mut.fixed new file mode 100644 index 00000000000..fe9c5dca5ba --- /dev/null +++ b/src/tools/clippy/tests/ui/as_ptr_cast_mut.fixed @@ -0,0 +1,38 @@ +#![allow(unused)] +#![warn(clippy::as_ptr_cast_mut)] +#![allow(clippy::wrong_self_convention, clippy::unnecessary_cast)] + +struct MutPtrWrapper(Vec<u8>); +impl MutPtrWrapper { + fn as_ptr(&mut self) -> *const u8 { + self.0.as_mut_ptr() as *const u8 + } +} + +struct Covariant<T>(*const T); +impl<T> Covariant<T> { + fn as_ptr(self) -> *const T { + self.0 + } +} + +fn main() { + let mut string = String::new(); + let _ = string.as_mut_ptr(); + //~^ as_ptr_cast_mut + + let _ = string.as_ptr() as *const i8; + let _ = string.as_mut_ptr(); + let _ = string.as_mut_ptr() as *mut u8; + let _ = string.as_mut_ptr() as *const u8; + + let nn = std::ptr::NonNull::new(4 as *mut u8).unwrap(); + let _ = nn.as_ptr() as *mut u8; + + let mut wrap = MutPtrWrapper(Vec::new()); + let _ = wrap.as_ptr() as *mut u8; + + let mut local = 4; + let ref_with_write_perm = Covariant(std::ptr::addr_of_mut!(local) as *const _); + let _ = ref_with_write_perm.as_ptr() as *mut u8; +} diff --git a/src/tools/clippy/tests/ui/as_ptr_cast_mut.rs b/src/tools/clippy/tests/ui/as_ptr_cast_mut.rs index baf7279adc4..3f22c2058d0 100644 --- a/src/tools/clippy/tests/ui/as_ptr_cast_mut.rs +++ b/src/tools/clippy/tests/ui/as_ptr_cast_mut.rs @@ -1,7 +1,6 @@ #![allow(unused)] #![warn(clippy::as_ptr_cast_mut)] #![allow(clippy::wrong_self_convention, clippy::unnecessary_cast)] -//@no-rustfix: incorrect suggestion struct MutPtrWrapper(Vec<u8>); impl MutPtrWrapper { @@ -22,9 +21,6 @@ fn main() { let _ = string.as_ptr() as *mut u8; //~^ as_ptr_cast_mut - let _: *mut i8 = string.as_ptr() as *mut _; - //~^ as_ptr_cast_mut - let _ = string.as_ptr() as *const i8; let _ = string.as_mut_ptr(); let _ = string.as_mut_ptr() as *mut u8; diff --git a/src/tools/clippy/tests/ui/as_ptr_cast_mut.stderr b/src/tools/clippy/tests/ui/as_ptr_cast_mut.stderr index b3fc223ccdb..fa9fb23e2d0 100644 --- a/src/tools/clippy/tests/ui/as_ptr_cast_mut.stderr +++ b/src/tools/clippy/tests/ui/as_ptr_cast_mut.stderr @@ -1,5 +1,5 @@ error: casting the result of `as_ptr` to *mut u8 - --> tests/ui/as_ptr_cast_mut.rs:22:13 + --> tests/ui/as_ptr_cast_mut.rs:21:13 | LL | let _ = string.as_ptr() as *mut u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `string.as_mut_ptr()` @@ -7,11 +7,5 @@ LL | let _ = string.as_ptr() as *mut u8; = note: `-D clippy::as-ptr-cast-mut` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::as_ptr_cast_mut)]` -error: casting the result of `as_ptr` to *mut i8 - --> tests/ui/as_ptr_cast_mut.rs:25:22 - | -LL | let _: *mut i8 = string.as_ptr() as *mut _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `string.as_mut_ptr()` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/src/tools/clippy/tests/ui/as_ptr_cast_mut_unfixable.rs b/src/tools/clippy/tests/ui/as_ptr_cast_mut_unfixable.rs new file mode 100644 index 00000000000..a8f6b06bd4f --- /dev/null +++ b/src/tools/clippy/tests/ui/as_ptr_cast_mut_unfixable.rs @@ -0,0 +1,16 @@ +//@no-rustfix +#![allow(unused)] +#![warn(clippy::as_ptr_cast_mut)] + +fn main() { + let mut string = String::new(); + + // the `*mut _` is actually necessary since it does two things at once: + // - changes the mutability (caught by the lint) + // - changes the type + // + // and so replacing this with `as_mut_ptr` removes the second thing, + // resulting in a type mismatch + let _: *mut i8 = string.as_ptr() as *mut _; + //~^ as_ptr_cast_mut +} diff --git a/src/tools/clippy/tests/ui/as_ptr_cast_mut_unfixable.stderr b/src/tools/clippy/tests/ui/as_ptr_cast_mut_unfixable.stderr new file mode 100644 index 00000000000..c5bcad6f4df --- /dev/null +++ b/src/tools/clippy/tests/ui/as_ptr_cast_mut_unfixable.stderr @@ -0,0 +1,11 @@ +error: casting the result of `as_ptr` to *mut i8 + --> tests/ui/as_ptr_cast_mut_unfixable.rs:14:22 + | +LL | let _: *mut i8 = string.as_ptr() as *mut _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `string.as_mut_ptr()` + | + = note: `-D clippy::as-ptr-cast-mut` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::as_ptr_cast_mut)]` + +error: aborting due to 1 previous error + diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.fixed b/src/tools/clippy/tests/ui/borrow_as_ptr.fixed index 3f6e5245b87..bfe826508f3 100644 --- a/src/tools/clippy/tests/ui/borrow_as_ptr.fixed +++ b/src/tools/clippy/tests/ui/borrow_as_ptr.fixed @@ -1,6 +1,9 @@ +//@aux-build:proc_macros.rs #![warn(clippy::borrow_as_ptr)] #![allow(clippy::useless_vec)] +extern crate proc_macros; + fn a() -> i32 { 0 } @@ -53,3 +56,12 @@ fn issue_15141() { // Don't lint cast to dyn trait pointers let b = &a as *const dyn std::any::Any; } + +fn issue15389() { + proc_macros::with_span! { + span + let var = 0u32; + // Don't lint in proc-macros + let _ = &var as *const u32; + }; +} diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.rs b/src/tools/clippy/tests/ui/borrow_as_ptr.rs index 20f4f40e001..ce248f157c6 100644 --- a/src/tools/clippy/tests/ui/borrow_as_ptr.rs +++ b/src/tools/clippy/tests/ui/borrow_as_ptr.rs @@ -1,6 +1,9 @@ +//@aux-build:proc_macros.rs #![warn(clippy::borrow_as_ptr)] #![allow(clippy::useless_vec)] +extern crate proc_macros; + fn a() -> i32 { 0 } @@ -53,3 +56,12 @@ fn issue_15141() { // Don't lint cast to dyn trait pointers let b = &a as *const dyn std::any::Any; } + +fn issue15389() { + proc_macros::with_span! { + span + let var = 0u32; + // Don't lint in proc-macros + let _ = &var as *const u32; + }; +} diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.stderr b/src/tools/clippy/tests/ui/borrow_as_ptr.stderr index b1fcce49403..b371b477a50 100644 --- a/src/tools/clippy/tests/ui/borrow_as_ptr.stderr +++ b/src/tools/clippy/tests/ui/borrow_as_ptr.stderr @@ -1,5 +1,5 @@ error: borrow as raw pointer - --> tests/ui/borrow_as_ptr.rs:11:14 + --> tests/ui/borrow_as_ptr.rs:14:14 | LL | let _p = &val as *const i32; | ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::addr_of!(val)` @@ -8,25 +8,25 @@ LL | let _p = &val as *const i32; = help: to override `-D warnings` add `#[allow(clippy::borrow_as_ptr)]` error: borrow as raw pointer - --> tests/ui/borrow_as_ptr.rs:19:18 + --> tests/ui/borrow_as_ptr.rs:22:18 | LL | let _p_mut = &mut val_mut as *mut i32; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::addr_of_mut!(val_mut)` error: borrow as raw pointer - --> tests/ui/borrow_as_ptr.rs:23:16 + --> tests/ui/borrow_as_ptr.rs:26:16 | LL | let _raw = (&mut x[1] as *mut i32).wrapping_offset(-1); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::addr_of_mut!(x[1])` error: borrow as raw pointer - --> tests/ui/borrow_as_ptr.rs:29:17 + --> tests/ui/borrow_as_ptr.rs:32:17 | LL | let _raw = (&mut x[1] as *mut i32).wrapping_offset(-1); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `&raw mut x[1]` error: implicit borrow as raw pointer - --> tests/ui/borrow_as_ptr.rs:35:25 + --> tests/ui/borrow_as_ptr.rs:38:25 | LL | let p: *const i32 = &val; | ^^^^ @@ -37,7 +37,7 @@ LL | let p: *const i32 = &raw const val; | +++++++++ error: implicit borrow as raw pointer - --> tests/ui/borrow_as_ptr.rs:39:23 + --> tests/ui/borrow_as_ptr.rs:42:23 | LL | let p: *mut i32 = &mut val; | ^^^^^^^^ @@ -48,7 +48,7 @@ LL | let p: *mut i32 = &raw mut val; | +++ error: implicit borrow as raw pointer - --> tests/ui/borrow_as_ptr.rs:44:19 + --> tests/ui/borrow_as_ptr.rs:47:19 | LL | core::ptr::eq(&val, &1); | ^^^^ diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.fixed b/src/tools/clippy/tests/ui/char_lit_as_u8.fixed index 64aacedfd36..64aacedfd36 100644 --- a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.fixed +++ b/src/tools/clippy/tests/ui/char_lit_as_u8.fixed diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8.rs b/src/tools/clippy/tests/ui/char_lit_as_u8.rs index c8774c7f309..a8f39e27605 100644 --- a/src/tools/clippy/tests/ui/char_lit_as_u8.rs +++ b/src/tools/clippy/tests/ui/char_lit_as_u8.rs @@ -1,7 +1,12 @@ #![warn(clippy::char_lit_as_u8)] fn main() { - // no suggestion, since a byte literal won't work. - let _ = '❤' as u8; + let _ = 'a' as u8; + //~^ char_lit_as_u8 + let _ = '\n' as u8; + //~^ char_lit_as_u8 + let _ = '\0' as u8; + //~^ char_lit_as_u8 + let _ = '\x01' as u8; //~^ char_lit_as_u8 } diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8.stderr b/src/tools/clippy/tests/ui/char_lit_as_u8.stderr index ec02f1341c0..9bcded7b0ff 100644 --- a/src/tools/clippy/tests/ui/char_lit_as_u8.stderr +++ b/src/tools/clippy/tests/ui/char_lit_as_u8.stderr @@ -1,12 +1,36 @@ error: casting a character literal to `u8` truncates - --> tests/ui/char_lit_as_u8.rs:5:13 + --> tests/ui/char_lit_as_u8.rs:4:13 | -LL | let _ = '❤' as u8; - | ^^^^^^^^^ +LL | let _ = 'a' as u8; + | ^^^^^^^^^ help: use a byte literal instead: `b'a'` | = note: `char` is four bytes wide, but `u8` is a single byte = note: `-D clippy::char-lit-as-u8` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::char_lit_as_u8)]` -error: aborting due to 1 previous error +error: casting a character literal to `u8` truncates + --> tests/ui/char_lit_as_u8.rs:6:13 + | +LL | let _ = '\n' as u8; + | ^^^^^^^^^^ help: use a byte literal instead: `b'\n'` + | + = note: `char` is four bytes wide, but `u8` is a single byte + +error: casting a character literal to `u8` truncates + --> tests/ui/char_lit_as_u8.rs:8:13 + | +LL | let _ = '\0' as u8; + | ^^^^^^^^^^ help: use a byte literal instead: `b'\0'` + | + = note: `char` is four bytes wide, but `u8` is a single byte + +error: casting a character literal to `u8` truncates + --> tests/ui/char_lit_as_u8.rs:10:13 + | +LL | let _ = '\x01' as u8; + | ^^^^^^^^^^^^ help: use a byte literal instead: `b'\x01'` + | + = note: `char` is four bytes wide, but `u8` is a single byte + +error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.rs b/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.rs deleted file mode 100644 index a8f39e27605..00000000000 --- a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.rs +++ /dev/null @@ -1,12 +0,0 @@ -#![warn(clippy::char_lit_as_u8)] - -fn main() { - let _ = 'a' as u8; - //~^ char_lit_as_u8 - let _ = '\n' as u8; - //~^ char_lit_as_u8 - let _ = '\0' as u8; - //~^ char_lit_as_u8 - let _ = '\x01' as u8; - //~^ char_lit_as_u8 -} diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.stderr b/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.stderr deleted file mode 100644 index 158dfd6bed2..00000000000 --- a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.stderr +++ /dev/null @@ -1,36 +0,0 @@ -error: casting a character literal to `u8` truncates - --> tests/ui/char_lit_as_u8_suggestions.rs:4:13 - | -LL | let _ = 'a' as u8; - | ^^^^^^^^^ help: use a byte literal instead: `b'a'` - | - = note: `char` is four bytes wide, but `u8` is a single byte - = note: `-D clippy::char-lit-as-u8` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::char_lit_as_u8)]` - -error: casting a character literal to `u8` truncates - --> tests/ui/char_lit_as_u8_suggestions.rs:6:13 - | -LL | let _ = '\n' as u8; - | ^^^^^^^^^^ help: use a byte literal instead: `b'\n'` - | - = note: `char` is four bytes wide, but `u8` is a single byte - -error: casting a character literal to `u8` truncates - --> tests/ui/char_lit_as_u8_suggestions.rs:8:13 - | -LL | let _ = '\0' as u8; - | ^^^^^^^^^^ help: use a byte literal instead: `b'\0'` - | - = note: `char` is four bytes wide, but `u8` is a single byte - -error: casting a character literal to `u8` truncates - --> tests/ui/char_lit_as_u8_suggestions.rs:10:13 - | -LL | let _ = '\x01' as u8; - | ^^^^^^^^^^^^ help: use a byte literal instead: `b'\x01'` - | - = note: `char` is four bytes wide, but `u8` is a single byte - -error: aborting due to 4 previous errors - diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8_unfixable.rs b/src/tools/clippy/tests/ui/char_lit_as_u8_unfixable.rs new file mode 100644 index 00000000000..e5c094f158e --- /dev/null +++ b/src/tools/clippy/tests/ui/char_lit_as_u8_unfixable.rs @@ -0,0 +1,8 @@ +//@no-rustfix +#![warn(clippy::char_lit_as_u8)] + +fn main() { + // no suggestion, since a byte literal won't work. + let _ = '❤' as u8; + //~^ char_lit_as_u8 +} diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8_unfixable.stderr b/src/tools/clippy/tests/ui/char_lit_as_u8_unfixable.stderr new file mode 100644 index 00000000000..49e555ae638 --- /dev/null +++ b/src/tools/clippy/tests/ui/char_lit_as_u8_unfixable.stderr @@ -0,0 +1,12 @@ +error: casting a character literal to `u8` truncates + --> tests/ui/char_lit_as_u8_unfixable.rs:6:13 + | +LL | let _ = '❤' as u8; + | ^^^^^^^^^ + | + = note: `char` is four bytes wide, but `u8` is a single byte + = note: `-D clippy::char-lit-as-u8` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::char_lit_as_u8)]` + +error: aborting due to 1 previous error + diff --git a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr index 26e360112b6..939b509d85c 100644 --- a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr +++ b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr @@ -330,7 +330,7 @@ LL | if X.is_some() { | = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/static-mut-references.html> = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives - = note: `#[deny(static_mut_refs)]` on by default + = note: `#[deny(static_mut_refs)]` (part of `#[deny(rust_2024_compatibility)]`) on by default error: aborting due to 36 previous errors diff --git a/src/tools/clippy/tests/ui/deref_addrof.fixed b/src/tools/clippy/tests/ui/deref_addrof.fixed index 35dbd790e89..ffe7f7d1440 100644 --- a/src/tools/clippy/tests/ui/deref_addrof.fixed +++ b/src/tools/clippy/tests/ui/deref_addrof.fixed @@ -1,11 +1,11 @@ -//@aux-build:proc_macros.rs - -#![allow(clippy::return_self_not_must_use, clippy::useless_vec)] +#![allow( + dangerous_implicit_autorefs, + clippy::explicit_auto_deref, + clippy::return_self_not_must_use, + clippy::useless_vec +)] #![warn(clippy::deref_addrof)] -extern crate proc_macros; -use proc_macros::inline_macros; - fn get_number() -> usize { 10 } @@ -56,19 +56,75 @@ fn main() { //~^ deref_addrof // do NOT lint for array as semantic differences with/out `*&`. let _arr = *&[0, 1, 2, 3, 4]; + + // Do not lint when text comes from macro + macro_rules! mac { + (dr) => { + *&0 + }; + (dr $e:expr) => { + *&$e + }; + (r $e:expr) => { + &$e + }; + } + let b = mac!(dr); + let b = mac!(dr a); + let b = *mac!(r a); } -#[derive(Copy, Clone)] -pub struct S; -#[inline_macros] -impl S { - pub fn f(&self) -> &Self { - inline!($(@expr self)) - //~^ deref_addrof +fn issue14386() { + use std::mem::ManuallyDrop; + + #[derive(Copy, Clone)] + struct Data { + num: u64, } - #[allow(unused_mut)] // mut will be unused, once the macro is fixed - pub fn f_mut(mut self) -> Self { - inline!($(@expr self)) + + #[derive(Clone, Copy)] + struct M { + md: ManuallyDrop<[u8; 4]>, + } + + union DataWithPadding<'lt> { + data: ManuallyDrop<Data>, + prim: ManuallyDrop<u64>, + padding: [u8; size_of::<Data>()], + tup: (ManuallyDrop<Data>, ()), + indirect: M, + indirect_arr: [M; 2], + indirect_ref: &'lt mut M, + } + + let mut a = DataWithPadding { + padding: [0; size_of::<DataWithPadding>()], + }; + unsafe { + a.padding = [1; size_of::<DataWithPadding>()]; //~^ deref_addrof + a.tup.1 = (); + //~^ deref_addrof + *a.prim = 0; + //~^ deref_addrof + + (*a.data).num = 42; + //~^ deref_addrof + (*a.indirect.md)[3] = 1; + //~^ deref_addrof + (*a.indirect_arr[1].md)[3] = 1; + //~^ deref_addrof + (*a.indirect_ref.md)[3] = 1; + //~^ deref_addrof + + // Check that raw pointers are properly considered as well + *a.prim = 0; + //~^ deref_addrof + (*a.data).num = 42; + //~^ deref_addrof + + // Do not lint, as the dereference happens later, we cannot + // just remove `&mut` + (*&mut a.tup).0.num = 42; } } diff --git a/src/tools/clippy/tests/ui/deref_addrof.rs b/src/tools/clippy/tests/ui/deref_addrof.rs index 96d1b92ef7b..bc253716aff 100644 --- a/src/tools/clippy/tests/ui/deref_addrof.rs +++ b/src/tools/clippy/tests/ui/deref_addrof.rs @@ -1,11 +1,11 @@ -//@aux-build:proc_macros.rs - -#![allow(clippy::return_self_not_must_use, clippy::useless_vec)] +#![allow( + dangerous_implicit_autorefs, + clippy::explicit_auto_deref, + clippy::return_self_not_must_use, + clippy::useless_vec +)] #![warn(clippy::deref_addrof)] -extern crate proc_macros; -use proc_macros::inline_macros; - fn get_number() -> usize { 10 } @@ -56,19 +56,75 @@ fn main() { //~^ deref_addrof // do NOT lint for array as semantic differences with/out `*&`. let _arr = *&[0, 1, 2, 3, 4]; + + // Do not lint when text comes from macro + macro_rules! mac { + (dr) => { + *&0 + }; + (dr $e:expr) => { + *&$e + }; + (r $e:expr) => { + &$e + }; + } + let b = mac!(dr); + let b = mac!(dr a); + let b = *mac!(r a); } -#[derive(Copy, Clone)] -pub struct S; -#[inline_macros] -impl S { - pub fn f(&self) -> &Self { - inline!(*& $(@expr self)) - //~^ deref_addrof +fn issue14386() { + use std::mem::ManuallyDrop; + + #[derive(Copy, Clone)] + struct Data { + num: u64, } - #[allow(unused_mut)] // mut will be unused, once the macro is fixed - pub fn f_mut(mut self) -> Self { - inline!(*&mut $(@expr self)) + + #[derive(Clone, Copy)] + struct M { + md: ManuallyDrop<[u8; 4]>, + } + + union DataWithPadding<'lt> { + data: ManuallyDrop<Data>, + prim: ManuallyDrop<u64>, + padding: [u8; size_of::<Data>()], + tup: (ManuallyDrop<Data>, ()), + indirect: M, + indirect_arr: [M; 2], + indirect_ref: &'lt mut M, + } + + let mut a = DataWithPadding { + padding: [0; size_of::<DataWithPadding>()], + }; + unsafe { + (*&mut a.padding) = [1; size_of::<DataWithPadding>()]; //~^ deref_addrof + (*&mut a.tup).1 = (); + //~^ deref_addrof + **&mut a.prim = 0; + //~^ deref_addrof + + (*&mut a.data).num = 42; + //~^ deref_addrof + (*&mut a.indirect.md)[3] = 1; + //~^ deref_addrof + (*&mut a.indirect_arr[1].md)[3] = 1; + //~^ deref_addrof + (*&mut a.indirect_ref.md)[3] = 1; + //~^ deref_addrof + + // Check that raw pointers are properly considered as well + **&raw mut a.prim = 0; + //~^ deref_addrof + (*&raw mut a.data).num = 42; + //~^ deref_addrof + + // Do not lint, as the dereference happens later, we cannot + // just remove `&mut` + (*&mut a.tup).0.num = 42; } } diff --git a/src/tools/clippy/tests/ui/deref_addrof.stderr b/src/tools/clippy/tests/ui/deref_addrof.stderr index 81414b625b2..65dd904a8f7 100644 --- a/src/tools/clippy/tests/ui/deref_addrof.stderr +++ b/src/tools/clippy/tests/ui/deref_addrof.stderr @@ -56,20 +56,58 @@ LL | let _repeat = *&[0; 64]; | ^^^^^^^^^ help: try: `[0; 64]` error: immediately dereferencing a reference - --> tests/ui/deref_addrof.rs:66:17 + --> tests/ui/deref_addrof.rs:104:9 | -LL | inline!(*& $(@expr self)) - | ^^^^^^^^^^^^^^^^ help: try: `$(@expr self)` +LL | (*&mut a.padding) = [1; size_of::<DataWithPadding>()]; + | ^^^^^^^^^^^^^^^^^ help: try: `a.padding` + +error: immediately dereferencing a reference + --> tests/ui/deref_addrof.rs:106:9 + | +LL | (*&mut a.tup).1 = (); + | ^^^^^^^^^^^^^ help: try: `a.tup` + +error: immediately dereferencing a reference + --> tests/ui/deref_addrof.rs:108:10 | - = note: this error originates in the macro `__inline_mac_impl` (in Nightly builds, run with -Z macro-backtrace for more info) +LL | **&mut a.prim = 0; + | ^^^^^^^^^^^^ help: try: `a.prim` error: immediately dereferencing a reference - --> tests/ui/deref_addrof.rs:71:17 + --> tests/ui/deref_addrof.rs:111:9 | -LL | inline!(*&mut $(@expr self)) - | ^^^^^^^^^^^^^^^^^^^ help: try: `$(@expr self)` +LL | (*&mut a.data).num = 42; + | ^^^^^^^^^^^^^^ help: try: `(*a.data)` + +error: immediately dereferencing a reference + --> tests/ui/deref_addrof.rs:113:9 + | +LL | (*&mut a.indirect.md)[3] = 1; + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `(*a.indirect.md)` + +error: immediately dereferencing a reference + --> tests/ui/deref_addrof.rs:115:9 + | +LL | (*&mut a.indirect_arr[1].md)[3] = 1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*a.indirect_arr[1].md)` + +error: immediately dereferencing a reference + --> tests/ui/deref_addrof.rs:117:9 + | +LL | (*&mut a.indirect_ref.md)[3] = 1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*a.indirect_ref.md)` + +error: immediately dereferencing a reference + --> tests/ui/deref_addrof.rs:121:10 + | +LL | **&raw mut a.prim = 0; + | ^^^^^^^^^^^^^^^^ help: try: `a.prim` + +error: immediately dereferencing a reference + --> tests/ui/deref_addrof.rs:123:9 | - = note: this error originates in the macro `__inline_mac_impl` (in Nightly builds, run with -Z macro-backtrace for more info) +LL | (*&raw mut a.data).num = 42; + | ^^^^^^^^^^^^^^^^^^ help: try: `(*a.data)` -error: aborting due to 11 previous errors +error: aborting due to 18 previous errors diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed index bbbd5973036..423a73734da 100644 --- a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed +++ b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed @@ -74,7 +74,7 @@ fn test_units() { /// GitHub GitLab /// IPv4 IPv6 /// ClojureScript CoffeeScript JavaScript PostScript PureScript TypeScript -/// WebAssembly +/// PowerPC WebAssembly /// NaN NaNs /// OAuth GraphQL /// OCaml diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.rs b/src/tools/clippy/tests/ui/doc/doc-fixable.rs index 1077d3580d3..8deffb4210e 100644 --- a/src/tools/clippy/tests/ui/doc/doc-fixable.rs +++ b/src/tools/clippy/tests/ui/doc/doc-fixable.rs @@ -74,7 +74,7 @@ fn test_units() { /// GitHub GitLab /// IPv4 IPv6 /// ClojureScript CoffeeScript JavaScript PostScript PureScript TypeScript -/// WebAssembly +/// PowerPC WebAssembly /// NaN NaNs /// OAuth GraphQL /// OCaml diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed b/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed index be31ee5fb48..180a513d0f8 100644 --- a/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed +++ b/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed @@ -81,6 +81,11 @@ fn issue_14139() { let (subindex, _) = (index.by_ref().take(3), 42); let _ = subindex.last(); let _ = index.next(); + + let mut index = [true, true, false, false, false, true].iter(); + let subindex = (index.by_ref().take(3), 42); + let _ = subindex.0.last(); + let _ = index.next(); } fn drop_order() { @@ -108,6 +113,12 @@ fn drop_order() { let mut v = DropDeIterator(v.into_iter()); println!("Last element is {}", v.next_back().unwrap().0); //~^ ERROR: called `Iterator::last` on a `DoubleEndedIterator` + + let v = vec![S("four"), S("five"), S("six")]; + let mut v = (DropDeIterator(v.into_iter()), 42); + println!("Last element is {}", v.0.next_back().unwrap().0); + //~^ ERROR: called `Iterator::last` on a `DoubleEndedIterator` + println!("Done"); } diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last.rs b/src/tools/clippy/tests/ui/double_ended_iterator_last.rs index 30864e15bce..3dd72cfeaac 100644 --- a/src/tools/clippy/tests/ui/double_ended_iterator_last.rs +++ b/src/tools/clippy/tests/ui/double_ended_iterator_last.rs @@ -81,6 +81,11 @@ fn issue_14139() { let (subindex, _) = (index.by_ref().take(3), 42); let _ = subindex.last(); let _ = index.next(); + + let mut index = [true, true, false, false, false, true].iter(); + let subindex = (index.by_ref().take(3), 42); + let _ = subindex.0.last(); + let _ = index.next(); } fn drop_order() { @@ -108,6 +113,12 @@ fn drop_order() { let v = DropDeIterator(v.into_iter()); println!("Last element is {}", v.last().unwrap().0); //~^ ERROR: called `Iterator::last` on a `DoubleEndedIterator` + + let v = vec![S("four"), S("five"), S("six")]; + let v = (DropDeIterator(v.into_iter()), 42); + println!("Last element is {}", v.0.last().unwrap().0); + //~^ ERROR: called `Iterator::last` on a `DoubleEndedIterator` + println!("Done"); } diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr b/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr index 72a6ead47a9..0f0056be376 100644 --- a/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr +++ b/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr @@ -18,7 +18,7 @@ LL | let _ = DeIterator.last(); | help: try: `next_back()` error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator - --> tests/ui/double_ended_iterator_last.rs:109:36 + --> tests/ui/double_ended_iterator_last.rs:114:36 | LL | println!("Last element is {}", v.last().unwrap().0); | ^^^^^^^^ @@ -30,5 +30,18 @@ LL ~ let mut v = DropDeIterator(v.into_iter()); LL ~ println!("Last element is {}", v.next_back().unwrap().0); | -error: aborting due to 3 previous errors +error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator + --> tests/ui/double_ended_iterator_last.rs:119:36 + | +LL | println!("Last element is {}", v.0.last().unwrap().0); + | ^^^^^^^^^^ + | + = note: this change will alter drop order which may be undesirable +help: try + | +LL ~ let mut v = (DropDeIterator(v.into_iter()), 42); +LL ~ println!("Last element is {}", v.0.next_back().unwrap().0); + | + +error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs b/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs deleted file mode 100644 index 73f62ac1246..00000000000 --- a/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs +++ /dev/null @@ -1,39 +0,0 @@ -//@no-rustfix: requires manual changes -#![warn(clippy::double_ended_iterator_last)] - -// Should not be linted because applying the lint would move the original iterator. This can only be -// linted if the iterator is used thereafter. -fn main() { - let mut index = [true, true, false, false, false, true].iter(); - let subindex = (index.by_ref().take(3), 42); - let _ = subindex.0.last(); - let _ = index.next(); -} - -fn drop_order() { - struct DropDeIterator(std::vec::IntoIter<S>); - impl Iterator for DropDeIterator { - type Item = S; - fn next(&mut self) -> Option<Self::Item> { - self.0.next() - } - } - impl DoubleEndedIterator for DropDeIterator { - fn next_back(&mut self) -> Option<Self::Item> { - self.0.next_back() - } - } - - struct S(&'static str); - impl std::ops::Drop for S { - fn drop(&mut self) { - println!("Dropping {}", self.0); - } - } - - let v = vec![S("one"), S("two"), S("three")]; - let v = (DropDeIterator(v.into_iter()), 42); - println!("Last element is {}", v.0.last().unwrap().0); - //~^ ERROR: called `Iterator::last` on a `DoubleEndedIterator` - println!("Done"); -} diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.stderr b/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.stderr deleted file mode 100644 index e330a22a354..00000000000 --- a/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator - --> tests/ui/double_ended_iterator_last_unfixable.rs:36:36 - | -LL | println!("Last element is {}", v.0.last().unwrap().0); - | ^^^^------ - | | - | help: try: `next_back()` - | - = note: this change will alter drop order which may be undesirable -note: this must be made mutable to use `.next_back()` - --> tests/ui/double_ended_iterator_last_unfixable.rs:36:36 - | -LL | println!("Last element is {}", v.0.last().unwrap().0); - | ^^^ - = note: `-D clippy::double-ended-iterator-last` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::double_ended_iterator_last)]` - -error: aborting due to 1 previous error - diff --git a/src/tools/clippy/tests/ui/eta.fixed b/src/tools/clippy/tests/ui/eta.fixed index c93b83f53ec..3d2b41b8fb8 100644 --- a/src/tools/clippy/tests/ui/eta.fixed +++ b/src/tools/clippy/tests/ui/eta.fixed @@ -1,3 +1,6 @@ +// we have some HELP annotations -- don't complain about them not being present everywhere +//@require-annotations-for-level: ERROR + #![warn(clippy::redundant_closure, clippy::redundant_closure_for_method_calls)] #![allow(unused)] #![allow( @@ -561,3 +564,29 @@ fn issue_14789() { std::convert::identity, ); } + +fn issue8817() { + fn f(_: u32) -> u32 { + todo!() + } + let g = |_: u32| -> u32 { todo!() }; + struct S(u32); + enum MyError { + A(S), + } + + Some(5) + .map(f) + //~^ redundant_closure + //~| HELP: replace the closure with the function itself + .map(g) + //~^ redundant_closure + //~| HELP: replace the closure with the function itself + .map(S) + //~^ redundant_closure + //~| HELP: replace the closure with the tuple struct itself + .map(MyError::A) + //~^ redundant_closure + //~| HELP: replace the closure with the tuple variant itself + .unwrap(); // just for nicer formatting +} diff --git a/src/tools/clippy/tests/ui/eta.rs b/src/tools/clippy/tests/ui/eta.rs index 273c8b21f4a..79d1103410d 100644 --- a/src/tools/clippy/tests/ui/eta.rs +++ b/src/tools/clippy/tests/ui/eta.rs @@ -1,3 +1,6 @@ +// we have some HELP annotations -- don't complain about them not being present everywhere +//@require-annotations-for-level: ERROR + #![warn(clippy::redundant_closure, clippy::redundant_closure_for_method_calls)] #![allow(unused)] #![allow( @@ -561,3 +564,29 @@ fn issue_14789() { std::convert::identity, ); } + +fn issue8817() { + fn f(_: u32) -> u32 { + todo!() + } + let g = |_: u32| -> u32 { todo!() }; + struct S(u32); + enum MyError { + A(S), + } + + Some(5) + .map(|n| f(n)) + //~^ redundant_closure + //~| HELP: replace the closure with the function itself + .map(|n| g(n)) + //~^ redundant_closure + //~| HELP: replace the closure with the function itself + .map(|n| S(n)) + //~^ redundant_closure + //~| HELP: replace the closure with the tuple struct itself + .map(|n| MyError::A(n)) + //~^ redundant_closure + //~| HELP: replace the closure with the tuple variant itself + .unwrap(); // just for nicer formatting +} diff --git a/src/tools/clippy/tests/ui/eta.stderr b/src/tools/clippy/tests/ui/eta.stderr index 8bc08add2fa..aa32ed1a38e 100644 --- a/src/tools/clippy/tests/ui/eta.stderr +++ b/src/tools/clippy/tests/ui/eta.stderr @@ -1,5 +1,5 @@ error: redundant closure - --> tests/ui/eta.rs:31:27 + --> tests/ui/eta.rs:34:27 | LL | let a = Some(1u8).map(|a| foo(a)); | ^^^^^^^^^^ help: replace the closure with the function itself: `foo` @@ -8,31 +8,31 @@ LL | let a = Some(1u8).map(|a| foo(a)); = help: to override `-D warnings` add `#[allow(clippy::redundant_closure)]` error: redundant closure - --> tests/ui/eta.rs:36:40 + --> tests/ui/eta.rs:39:40 | LL | let _: Option<Vec<u8>> = true.then(|| vec![]); // special case vec! | ^^^^^^^^^ help: replace the closure with `Vec::new`: `std::vec::Vec::new` error: redundant closure - --> tests/ui/eta.rs:39:35 + --> tests/ui/eta.rs:42:35 | LL | let d = Some(1u8).map(|a| foo((|b| foo2(b))(a))); //is adjusted? | ^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo2` error: redundant closure - --> tests/ui/eta.rs:42:26 + --> tests/ui/eta.rs:45:26 | LL | all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted | ^^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `below` error: redundant closure - --> tests/ui/eta.rs:51:27 + --> tests/ui/eta.rs:54:27 | LL | let e = Some(1u8).map(|a| generic(a)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `generic` error: redundant closure - --> tests/ui/eta.rs:104:51 + --> tests/ui/eta.rs:107:51 | LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo()); | ^^^^^^^^^^^ help: replace the closure with the method itself: `TestStruct::foo` @@ -41,178 +41,202 @@ LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo()); = help: to override `-D warnings` add `#[allow(clippy::redundant_closure_for_method_calls)]` error: redundant closure - --> tests/ui/eta.rs:106:51 + --> tests/ui/eta.rs:109:51 | LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo()); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `TestTrait::trait_foo` error: redundant closure - --> tests/ui/eta.rs:109:42 + --> tests/ui/eta.rs:112:42 | LL | let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear()); | ^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::vec::Vec::clear` error: redundant closure - --> tests/ui/eta.rs:114:29 + --> tests/ui/eta.rs:117:29 | LL | let e = Some("str").map(|s| s.to_string()); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::string::ToString::to_string` error: redundant closure - --> tests/ui/eta.rs:116:27 + --> tests/ui/eta.rs:119:27 | LL | let e = Some('a').map(|s| s.to_uppercase()); | ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_uppercase` error: redundant closure - --> tests/ui/eta.rs:119:65 + --> tests/ui/eta.rs:122:65 | LL | let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_ascii_uppercase` error: redundant closure - --> tests/ui/eta.rs:136:23 + --> tests/ui/eta.rs:139:23 | LL | let _ = x.map(|x| x.parse::<i16>()); | ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `str::parse::<i16>` error: redundant closure - --> tests/ui/eta.rs:189:22 + --> tests/ui/eta.rs:192:22 | LL | requires_fn_once(|| x()); | ^^^^^^ help: replace the closure with the function itself: `x` error: redundant closure - --> tests/ui/eta.rs:197:27 + --> tests/ui/eta.rs:200:27 | LL | let a = Some(1u8).map(|a| foo_ptr(a)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo_ptr` error: redundant closure - --> tests/ui/eta.rs:203:27 + --> tests/ui/eta.rs:206:27 | LL | let a = Some(1u8).map(|a| closure(a)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `closure` error: redundant closure - --> tests/ui/eta.rs:236:28 + --> tests/ui/eta.rs:239:28 | LL | x.into_iter().for_each(|x| add_to_res(x)); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res` error: redundant closure - --> tests/ui/eta.rs:238:28 + --> tests/ui/eta.rs:241:28 | LL | y.into_iter().for_each(|x| add_to_res(x)); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res` error: redundant closure - --> tests/ui/eta.rs:240:28 + --> tests/ui/eta.rs:243:28 | LL | z.into_iter().for_each(|x| add_to_res(x)); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `add_to_res` error: redundant closure - --> tests/ui/eta.rs:248:21 + --> tests/ui/eta.rs:251:21 | LL | Some(1).map(|n| closure(n)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut closure` error: redundant closure - --> tests/ui/eta.rs:253:21 + --> tests/ui/eta.rs:256:21 | LL | Some(1).map(|n| in_loop(n)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `in_loop` error: redundant closure - --> tests/ui/eta.rs:347:18 + --> tests/ui/eta.rs:350:18 | LL | takes_fn_mut(|| f()); | ^^^^^^ help: replace the closure with the function itself: `&mut f` error: redundant closure - --> tests/ui/eta.rs:351:19 + --> tests/ui/eta.rs:354:19 | LL | takes_fn_once(|| f()); | ^^^^^^ help: replace the closure with the function itself: `&mut f` error: redundant closure - --> tests/ui/eta.rs:356:26 + --> tests/ui/eta.rs:359:26 | LL | move || takes_fn_mut(|| f_used_once()) | ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut f_used_once` error: redundant closure - --> tests/ui/eta.rs:369:19 + --> tests/ui/eta.rs:372:19 | LL | array_opt.map(|a| a.as_slice()); | ^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8; 3]>::as_slice` error: redundant closure - --> tests/ui/eta.rs:373:19 + --> tests/ui/eta.rs:376:19 | LL | slice_opt.map(|s| s.len()); | ^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8]>::len` error: redundant closure - --> tests/ui/eta.rs:377:17 + --> tests/ui/eta.rs:380:17 | LL | ptr_opt.map(|p| p.is_null()); | ^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<*const usize>::is_null` error: redundant closure - --> tests/ui/eta.rs:382:17 + --> tests/ui/eta.rs:385:17 | LL | dyn_opt.map(|d| d.method_on_dyn()); | ^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<dyn TestTrait>::method_on_dyn` error: redundant closure - --> tests/ui/eta.rs:443:19 + --> tests/ui/eta.rs:446:19 | LL | let _ = f(&0, |x, y| f2(x, y)); | ^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `f2` error: redundant closure - --> tests/ui/eta.rs:472:22 + --> tests/ui/eta.rs:475:22 | LL | test.map(|t| t.method()) | ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `Test::method` error: redundant closure - --> tests/ui/eta.rs:477:22 + --> tests/ui/eta.rs:480:22 | LL | test.map(|t| t.method()) | ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `super::Outer::method` error: redundant closure - --> tests/ui/eta.rs:491:18 + --> tests/ui/eta.rs:494:18 | LL | test.map(|t| t.method()) | ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `test_mod::Test::method` error: redundant closure - --> tests/ui/eta.rs:499:30 + --> tests/ui/eta.rs:502:30 | LL | test.map(|t| t.method()) | ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `crate::issue_10854::d::Test::method` error: redundant closure - --> tests/ui/eta.rs:519:38 + --> tests/ui/eta.rs:522:38 | LL | let x = Box::new(|| None.map(|x| f(x))); | ^^^^^^^^ help: replace the closure with the function itself: `&f` error: redundant closure - --> tests/ui/eta.rs:524:38 + --> tests/ui/eta.rs:527:38 | LL | let x = Box::new(|| None.map(|x| f(x))); | ^^^^^^^^ help: replace the closure with the function itself: `f` error: redundant closure - --> tests/ui/eta.rs:542:35 + --> tests/ui/eta.rs:545:35 | LL | let _field = bind.or_else(|| get_default()).unwrap(); | ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `get_default` -error: aborting due to 35 previous errors +error: redundant closure + --> tests/ui/eta.rs:588:14 + | +LL | .map(|n| MyError::A(n)) + | ^^^^^^^^^^^^^^^^^ help: replace the closure with the tuple variant itself: `MyError::A` + +error: redundant closure + --> tests/ui/eta.rs:585:14 + | +LL | .map(|n| S(n)) + | ^^^^^^^^ help: replace the closure with the tuple struct itself: `S` + +error: redundant closure + --> tests/ui/eta.rs:582:14 + | +LL | .map(|n| g(n)) + | ^^^^^^^^ help: replace the closure with the function itself: `g` + +error: redundant closure + --> tests/ui/eta.rs:579:14 + | +LL | .map(|n| f(n)) + | ^^^^^^^^ help: replace the closure with the function itself: `f` + +error: aborting due to 39 previous errors diff --git a/src/tools/clippy/tests/ui/from_str_radix_10.fixed b/src/tools/clippy/tests/ui/from_str_radix_10.fixed index 4b8fd778685..47d24167e56 100644 --- a/src/tools/clippy/tests/ui/from_str_radix_10.fixed +++ b/src/tools/clippy/tests/ui/from_str_radix_10.fixed @@ -74,3 +74,13 @@ fn issue_12731() { let _ = u32::from_str_radix("123", 10); } } + +fn fix_str_ref_check() { + #![allow(clippy::needless_borrow)] + let s = "1"; + let _ = s.parse::<u32>().unwrap(); + //~^ from_str_radix_10 + let s_ref = &s; + let _ = s_ref.parse::<u32>().unwrap(); + //~^ from_str_radix_10 +} diff --git a/src/tools/clippy/tests/ui/from_str_radix_10.rs b/src/tools/clippy/tests/ui/from_str_radix_10.rs index 89002b11a99..952e19b57a0 100644 --- a/src/tools/clippy/tests/ui/from_str_radix_10.rs +++ b/src/tools/clippy/tests/ui/from_str_radix_10.rs @@ -74,3 +74,13 @@ fn issue_12731() { let _ = u32::from_str_radix("123", 10); } } + +fn fix_str_ref_check() { + #![allow(clippy::needless_borrow)] + let s = "1"; + let _ = u32::from_str_radix(&s, 10).unwrap(); + //~^ from_str_radix_10 + let s_ref = &s; + let _ = u32::from_str_radix(&s_ref, 10).unwrap(); + //~^ from_str_radix_10 +} diff --git a/src/tools/clippy/tests/ui/from_str_radix_10.stderr b/src/tools/clippy/tests/ui/from_str_radix_10.stderr index c693e8f50ff..d4e6c3657f2 100644 --- a/src/tools/clippy/tests/ui/from_str_radix_10.stderr +++ b/src/tools/clippy/tests/ui/from_str_radix_10.stderr @@ -49,5 +49,17 @@ error: this call to `from_str_radix` can be replaced with a call to `str::parse` LL | i32::from_str_radix(&stringier, 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `stringier.parse::<i32>()` -error: aborting due to 8 previous errors +error: this call to `from_str_radix` can be replaced with a call to `str::parse` + --> tests/ui/from_str_radix_10.rs:81:13 + | +LL | let _ = u32::from_str_radix(&s, 10).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.parse::<u32>()` + +error: this call to `from_str_radix` can be replaced with a call to `str::parse` + --> tests/ui/from_str_radix_10.rs:84:13 + | +LL | let _ = u32::from_str_radix(&s_ref, 10).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s_ref.parse::<u32>()` + +error: aborting due to 10 previous errors diff --git a/src/tools/clippy/tests/ui/functions_maxlines.rs b/src/tools/clippy/tests/ui/functions_maxlines.rs index e0990dadaaa..b0714552461 100644 --- a/src/tools/clippy/tests/ui/functions_maxlines.rs +++ b/src/tools/clippy/tests/ui/functions_maxlines.rs @@ -1,3 +1,4 @@ +#![allow(clippy::unused_unit, clippy::missing_safety_doc)] #![warn(clippy::too_many_lines)] fn good_lines() { @@ -55,7 +56,8 @@ fn good_lines() { println!("This is good."); } -fn bad_lines() { +#[allow(unused)] // the attr shouldn't get included in the highlight +pub async unsafe extern "Rust" fn bad_lines() -> () { //~^ too_many_lines println!("Dont get confused by braces: {{}}"); @@ -162,4 +164,115 @@ fn bad_lines() { println!("This is bad."); } +struct Foo; +impl Foo { + #[allow(unused)] // the attr shouldn't get included in the highlight + pub async unsafe extern "Rust" fn bad_lines() -> () { + //~^ too_many_lines + + println!("Dont get confused by braces: {{}}"); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/functions_maxlines.stderr b/src/tools/clippy/tests/ui/functions_maxlines.stderr index f42a2b2a22a..4c3faf45c47 100644 --- a/src/tools/clippy/tests/ui/functions_maxlines.stderr +++ b/src/tools/clippy/tests/ui/functions_maxlines.stderr @@ -1,17 +1,17 @@ -error: this function has too many lines (102/100) - --> tests/ui/functions_maxlines.rs:58:1 +error: this function has too many lines (104/100) + --> tests/ui/functions_maxlines.rs:60:1 | -LL | / fn bad_lines() { -LL | | -LL | | -LL | | println!("Dont get confused by braces: {{}}"); -... | -LL | | println!("This is bad."); -LL | | } - | |_^ +LL | pub async unsafe extern "Rust" fn bad_lines() -> () { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::too-many-lines` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::too_many_lines)]` -error: aborting due to 1 previous error +error: this function has too many lines (104/100) + --> tests/ui/functions_maxlines.rs:170:5 + | +LL | pub async unsafe extern "Rust" fn bad_lines() -> () { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors diff --git a/src/tools/clippy/tests/ui/infinite_loops.rs b/src/tools/clippy/tests/ui/infinite_loops.rs index fcd1f795fff..9b8c3933197 100644 --- a/src/tools/clippy/tests/ui/infinite_loops.rs +++ b/src/tools/clippy/tests/ui/infinite_loops.rs @@ -450,4 +450,75 @@ mod issue_12338 { } } +#[allow(clippy::let_underscore_future, clippy::empty_loop)] +mod issue_14000 { + use super::do_something; + + async fn foo() { + let _ = async move { + loop { + //~^ infinite_loop + do_something(); + } + } + .await; + let _ = async move { + loop { + //~^ infinite_loop + continue; + } + } + .await; + } + + fn bar() { + let _ = async move { + loop { + do_something(); + } + }; + + let _ = async move { + loop { + continue; + } + }; + } +} + +#[allow(clippy::let_underscore_future)] +mod tokio_spawn_test { + use super::do_something; + + fn install_ticker() { + // This should NOT trigger the lint because the async block is spawned, not awaited + std::thread::spawn(move || { + async move { + loop { + // This loop should not trigger infinite_loop lint + do_something(); + } + } + }); + } + + fn spawn_async_block() { + // This should NOT trigger the lint because the async block is not awaited + let _handle = async move { + loop { + do_something(); + } + }; + } + + fn await_async_block() { + // This SHOULD trigger the lint because the async block is awaited + let _ = async move { + loop { + do_something(); + } + }; + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/infinite_loops.stderr b/src/tools/clippy/tests/ui/infinite_loops.stderr index 4d02636ef4a..4c6b6f725f1 100644 --- a/src/tools/clippy/tests/ui/infinite_loops.stderr +++ b/src/tools/clippy/tests/ui/infinite_loops.stderr @@ -311,5 +311,27 @@ help: if this is intentional, consider specifying `!` as function return LL | fn continue_outer() -> ! { | ++++ -error: aborting due to 21 previous errors +error: infinite loop detected + --> tests/ui/infinite_loops.rs:459:13 + | +LL | / loop { +LL | | +LL | | do_something(); +LL | | } + | |_____________^ + | + = help: if this is not intended, try adding a `break` or `return` condition in the loop + +error: infinite loop detected + --> tests/ui/infinite_loops.rs:466:13 + | +LL | / loop { +LL | | +LL | | continue; +LL | | } + | |_____________^ + | + = help: if this is not intended, try adding a `break` or `return` condition in the loop + +error: aborting due to 23 previous errors diff --git a/src/tools/clippy/tests/ui/match_bool.fixed b/src/tools/clippy/tests/ui/match_bool.fixed index 1dfb82db120..876ae935afd 100644 --- a/src/tools/clippy/tests/ui/match_bool.fixed +++ b/src/tools/clippy/tests/ui/match_bool.fixed @@ -61,4 +61,17 @@ fn issue14099() { } } } +fn issue15351() { + let mut d = false; + match d { + false => println!("foo"), + ref mut d => *d = false, + } + + match d { + false => println!("foo"), + e => println!("{e}"), + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/match_bool.rs b/src/tools/clippy/tests/ui/match_bool.rs index 719b4e51eb6..a134ad8346e 100644 --- a/src/tools/clippy/tests/ui/match_bool.rs +++ b/src/tools/clippy/tests/ui/match_bool.rs @@ -113,4 +113,17 @@ fn issue14099() { } } +fn issue15351() { + let mut d = false; + match d { + false => println!("foo"), + ref mut d => *d = false, + } + + match d { + false => println!("foo"), + e => println!("{e}"), + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/match_ref_pats.fixed b/src/tools/clippy/tests/ui/match_ref_pats.fixed index 8add3da0c99..f727546838b 100644 --- a/src/tools/clippy/tests/ui/match_ref_pats.fixed +++ b/src/tools/clippy/tests/ui/match_ref_pats.fixed @@ -1,6 +1,12 @@ #![warn(clippy::match_ref_pats)] #![allow(dead_code, unused_variables)] -#![allow(clippy::enum_variant_names, clippy::equatable_if_let, clippy::uninlined_format_args)] +#![allow( + clippy::enum_variant_names, + clippy::equatable_if_let, + clippy::uninlined_format_args, + clippy::empty_loop, + clippy::diverging_sub_expression +)] fn ref_pats() { { @@ -120,4 +126,32 @@ mod issue_7740 { } } +mod issue15378 { + fn never_in_match() { + match unimplemented!() { + &_ => {}, + &&&42 => { + todo!() + }, + _ => {}, + } + + match panic!() { + &_ => {}, + &&&42 => { + todo!() + }, + _ => {}, + } + + match loop {} { + &_ => {}, + &&&42 => { + todo!() + }, + _ => {}, + } + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/match_ref_pats.rs b/src/tools/clippy/tests/ui/match_ref_pats.rs index 07889b0dfc2..eca4d584acd 100644 --- a/src/tools/clippy/tests/ui/match_ref_pats.rs +++ b/src/tools/clippy/tests/ui/match_ref_pats.rs @@ -1,6 +1,12 @@ #![warn(clippy::match_ref_pats)] #![allow(dead_code, unused_variables)] -#![allow(clippy::enum_variant_names, clippy::equatable_if_let, clippy::uninlined_format_args)] +#![allow( + clippy::enum_variant_names, + clippy::equatable_if_let, + clippy::uninlined_format_args, + clippy::empty_loop, + clippy::diverging_sub_expression +)] fn ref_pats() { { @@ -120,4 +126,32 @@ mod issue_7740 { } } +mod issue15378 { + fn never_in_match() { + match unimplemented!() { + &_ => {}, + &&&42 => { + todo!() + }, + _ => {}, + } + + match panic!() { + &_ => {}, + &&&42 => { + todo!() + }, + _ => {}, + } + + match loop {} { + &_ => {}, + &&&42 => { + todo!() + }, + _ => {}, + } + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/match_ref_pats.stderr b/src/tools/clippy/tests/ui/match_ref_pats.stderr index f81b290b32c..ecb08e6972d 100644 --- a/src/tools/clippy/tests/ui/match_ref_pats.stderr +++ b/src/tools/clippy/tests/ui/match_ref_pats.stderr @@ -1,5 +1,5 @@ error: you don't need to add `&` to all patterns - --> tests/ui/match_ref_pats.rs:8:9 + --> tests/ui/match_ref_pats.rs:14:9 | LL | / match v { LL | | @@ -19,7 +19,7 @@ LL ~ None => println!("none"), | error: you don't need to add `&` to both the expression and the patterns - --> tests/ui/match_ref_pats.rs:26:5 + --> tests/ui/match_ref_pats.rs:32:5 | LL | / match &w { LL | | @@ -37,7 +37,7 @@ LL ~ None => println!("none"), | error: redundant pattern matching, consider using `is_none()` - --> tests/ui/match_ref_pats.rs:39:12 + --> tests/ui/match_ref_pats.rs:45:12 | LL | if let &None = a { | -------^^^^^---- help: try: `if a.is_none()` @@ -46,13 +46,13 @@ LL | if let &None = a { = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/match_ref_pats.rs:45:12 + --> tests/ui/match_ref_pats.rs:51:12 | LL | if let &None = &b { | -------^^^^^----- help: try: `if b.is_none()` error: you don't need to add `&` to all patterns - --> tests/ui/match_ref_pats.rs:106:9 + --> tests/ui/match_ref_pats.rs:112:9 | LL | / match foobar_variant!(0) { LL | | diff --git a/src/tools/clippy/tests/ui/ptr_arg.stderr b/src/tools/clippy/tests/ui/ptr_arg.stderr index 87235057349..f32e83d8b81 100644 --- a/src/tools/clippy/tests/ui/ptr_arg.stderr +++ b/src/tools/clippy/tests/ui/ptr_arg.stderr @@ -268,10 +268,10 @@ LL | fn barbar(_x: &mut Vec<u32>, y: &mut String) { | ^^^^^^^^^^^ help: change this to: `&mut str` error: eliding a lifetime that's named elsewhere is confusing - --> tests/ui/ptr_arg.rs:314:36 + --> tests/ui/ptr_arg.rs:314:56 | LL | fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str { - | ^^ ^^ ---- the same lifetime is elided here + | -- -- ^^^^ the same lifetime is elided here | | | | | the lifetime is named here | the lifetime is named here diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.fixed b/src/tools/clippy/tests/ui/ptr_as_ptr.fixed index 71fea6144e7..78e1ceb480a 100644 --- a/src/tools/clippy/tests/ui/ptr_as_ptr.fixed +++ b/src/tools/clippy/tests/ui/ptr_as_ptr.fixed @@ -2,8 +2,8 @@ #![warn(clippy::ptr_as_ptr)] -#[macro_use] extern crate proc_macros; +use proc_macros::{external, inline_macros, with_span}; mod issue_11278_a { #[derive(Debug)] @@ -53,11 +53,13 @@ fn main() { //~^ ptr_as_ptr // Make sure the lint is triggered inside a macro - let _ = inline!($ptr.cast::<i32>()); - //~^ ptr_as_ptr + // FIXME: `is_from_proc_macro` incorrectly stops the lint from firing here + let _ = inline!($ptr as *const i32); // Do not lint inside macros from external crates let _ = external!($ptr as *const i32); + + let _ = with_span!(expr $ptr as *const i32); } #[clippy::msrv = "1.37"] diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.rs b/src/tools/clippy/tests/ui/ptr_as_ptr.rs index 4d507592a1e..70732cf0a6c 100644 --- a/src/tools/clippy/tests/ui/ptr_as_ptr.rs +++ b/src/tools/clippy/tests/ui/ptr_as_ptr.rs @@ -2,8 +2,8 @@ #![warn(clippy::ptr_as_ptr)] -#[macro_use] extern crate proc_macros; +use proc_macros::{external, inline_macros, with_span}; mod issue_11278_a { #[derive(Debug)] @@ -53,11 +53,13 @@ fn main() { //~^ ptr_as_ptr // Make sure the lint is triggered inside a macro + // FIXME: `is_from_proc_macro` incorrectly stops the lint from firing here let _ = inline!($ptr as *const i32); - //~^ ptr_as_ptr // Do not lint inside macros from external crates let _ = external!($ptr as *const i32); + + let _ = with_span!(expr $ptr as *const i32); } #[clippy::msrv = "1.37"] diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.stderr b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr index adad159bb0f..c0a2a4b6d20 100644 --- a/src/tools/clippy/tests/ui/ptr_as_ptr.stderr +++ b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr @@ -38,174 +38,166 @@ LL | let _: *mut i32 = mut_ptr as _; | ^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:56:21 - | -LL | let _ = inline!($ptr as *const i32); - | ^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `$ptr.cast::<i32>()` - | - = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:78:13 + --> tests/ui/ptr_as_ptr.rs:80:13 | LL | let _ = ptr as *const i32; | ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::<i32>()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:80:13 + --> tests/ui/ptr_as_ptr.rs:82:13 | LL | let _ = mut_ptr as *mut i32; | ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::<i32>()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:88:9 + --> tests/ui/ptr_as_ptr.rs:90:9 | LL | ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::<u32>()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:93:9 + --> tests/ui/ptr_as_ptr.rs:95:9 | LL | std::ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut::<u32>()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:99:9 + --> tests/ui/ptr_as_ptr.rs:101:9 | LL | ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::<u32>()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:104:9 + --> tests/ui/ptr_as_ptr.rs:106:9 | LL | core::ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut::<u32>()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:110:9 + --> tests/ui/ptr_as_ptr.rs:112:9 | LL | ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::<u32>()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:115:9 + --> tests/ui/ptr_as_ptr.rs:117:9 | LL | std::ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null::<u32>()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:121:9 + --> tests/ui/ptr_as_ptr.rs:123:9 | LL | ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::<u32>()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:126:9 + --> tests/ui/ptr_as_ptr.rs:128:9 | LL | core::ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null::<u32>()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:134:9 + --> tests/ui/ptr_as_ptr.rs:136:9 | LL | ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:139:9 + --> tests/ui/ptr_as_ptr.rs:141:9 | LL | std::ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:145:9 + --> tests/ui/ptr_as_ptr.rs:147:9 | LL | ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:150:9 + --> tests/ui/ptr_as_ptr.rs:152:9 | LL | core::ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:156:9 + --> tests/ui/ptr_as_ptr.rs:158:9 | LL | ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:161:9 + --> tests/ui/ptr_as_ptr.rs:163:9 | LL | std::ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:167:9 + --> tests/ui/ptr_as_ptr.rs:169:9 | LL | ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:172:9 + --> tests/ui/ptr_as_ptr.rs:174:9 | LL | core::ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:180:9 + --> tests/ui/ptr_as_ptr.rs:182:9 | LL | ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:185:9 + --> tests/ui/ptr_as_ptr.rs:187:9 | LL | std::ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:191:9 + --> tests/ui/ptr_as_ptr.rs:193:9 | LL | ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:196:9 + --> tests/ui/ptr_as_ptr.rs:198:9 | LL | core::ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:202:9 + --> tests/ui/ptr_as_ptr.rs:204:9 | LL | ptr::null() as _ | ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:207:9 + --> tests/ui/ptr_as_ptr.rs:209:9 | LL | std::ptr::null() as _ | ^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:213:9 + --> tests/ui/ptr_as_ptr.rs:215:9 | LL | ptr::null() as _ | ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:218:9 + --> tests/ui/ptr_as_ptr.rs:220:9 | LL | core::ptr::null() as _ | ^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:226:43 + --> tests/ui/ptr_as_ptr.rs:228:43 | LL | let _: fn() = std::mem::transmute(std::ptr::null::<()>() as *const u8); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null::<u8>()` -error: aborting due to 34 previous errors +error: aborting due to 33 previous errors diff --git a/src/tools/clippy/tests/ui/similar_names.rs b/src/tools/clippy/tests/ui/similar_names.rs index 69b6ab6220b..55a141209f0 100644 --- a/src/tools/clippy/tests/ui/similar_names.rs +++ b/src/tools/clippy/tests/ui/similar_names.rs @@ -89,6 +89,10 @@ fn main() { let iter: i32; let item: i32; + + // 3 letter names are allowed to be similar + let kta: i32; + let ktv: i32; } fn foo() { diff --git a/src/tools/clippy/tests/ui/similar_names.stderr b/src/tools/clippy/tests/ui/similar_names.stderr index 8d722fb8b56..c226f73d4db 100644 --- a/src/tools/clippy/tests/ui/similar_names.stderr +++ b/src/tools/clippy/tests/ui/similar_names.stderr @@ -49,13 +49,13 @@ LL | let parser: i32; | ^^^^^^ error: binding's name is too similar to existing binding - --> tests/ui/similar_names.rs:98:16 + --> tests/ui/similar_names.rs:102:16 | LL | bpple: sprang, | ^^^^^^ | note: existing binding defined here - --> tests/ui/similar_names.rs:97:16 + --> tests/ui/similar_names.rs:101:16 | LL | apple: spring, | ^^^^^^ diff --git a/src/tools/clippy/tests/ui/transmute.rs b/src/tools/clippy/tests/ui/transmute.rs index e968e7a5924..e7099104f94 100644 --- a/src/tools/clippy/tests/ui/transmute.rs +++ b/src/tools/clippy/tests/ui/transmute.rs @@ -4,6 +4,7 @@ dead_code, clippy::borrow_as_ptr, unnecessary_transmutes, + integer_to_ptr_transmutes, clippy::needless_lifetimes, clippy::missing_transmute_annotations )] @@ -60,12 +61,10 @@ fn useless() { //~^ useless_transmute let _: *const usize = std::mem::transmute(5_isize); - //~^ useless_transmute let _ = std::ptr::dangling::<usize>(); let _: *const usize = std::mem::transmute(1 + 1usize); - //~^ useless_transmute let _ = (1 + 1_usize) as *const usize; } diff --git a/src/tools/clippy/tests/ui/transmute.stderr b/src/tools/clippy/tests/ui/transmute.stderr index 79528ec06f1..9478db09481 100644 --- a/src/tools/clippy/tests/ui/transmute.stderr +++ b/src/tools/clippy/tests/ui/transmute.stderr @@ -1,5 +1,5 @@ error: transmute from a reference to a pointer - --> tests/ui/transmute.rs:33:27 + --> tests/ui/transmute.rs:34:27 | LL | let _: *const T = core::mem::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T` @@ -8,61 +8,49 @@ LL | let _: *const T = core::mem::transmute(t); = help: to override `-D warnings` add `#[allow(clippy::useless_transmute)]` error: transmute from a reference to a pointer - --> tests/ui/transmute.rs:36:25 + --> tests/ui/transmute.rs:37:25 | LL | let _: *mut T = core::mem::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *mut T` error: transmute from a reference to a pointer - --> tests/ui/transmute.rs:39:27 + --> tests/ui/transmute.rs:40:27 | LL | let _: *const U = core::mem::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *const U` error: transmute from a type (`std::vec::Vec<i32>`) to itself - --> tests/ui/transmute.rs:47:27 + --> tests/ui/transmute.rs:48:27 | LL | let _: Vec<i32> = core::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec<i32>`) to itself - --> tests/ui/transmute.rs:50:27 + --> tests/ui/transmute.rs:51:27 | LL | let _: Vec<i32> = core::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec<i32>`) to itself - --> tests/ui/transmute.rs:53:27 + --> tests/ui/transmute.rs:54:27 | LL | let _: Vec<i32> = std::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec<i32>`) to itself - --> tests/ui/transmute.rs:56:27 + --> tests/ui/transmute.rs:57:27 | LL | let _: Vec<i32> = std::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec<i32>`) to itself - --> tests/ui/transmute.rs:59:27 + --> tests/ui/transmute.rs:60:27 | LL | let _: Vec<i32> = my_transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^ -error: transmute from an integer to a pointer - --> tests/ui/transmute.rs:62:31 - | -LL | let _: *const usize = std::mem::transmute(5_isize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `5_isize as *const usize` - -error: transmute from an integer to a pointer - --> tests/ui/transmute.rs:67:31 - | -LL | let _: *const usize = std::mem::transmute(1 + 1usize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(1 + 1usize) as *const usize` - error: transmute from a type (`*const Usize`) to the type that it points to (`Usize`) - --> tests/ui/transmute.rs:99:24 + --> tests/ui/transmute.rs:98:24 | LL | let _: Usize = core::mem::transmute(int_const_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,25 +59,25 @@ LL | let _: Usize = core::mem::transmute(int_const_ptr); = help: to override `-D warnings` add `#[allow(clippy::crosspointer_transmute)]` error: transmute from a type (`*mut Usize`) to the type that it points to (`Usize`) - --> tests/ui/transmute.rs:102:24 + --> tests/ui/transmute.rs:101:24 | LL | let _: Usize = core::mem::transmute(int_mut_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`Usize`) to a pointer to that type (`*const Usize`) - --> tests/ui/transmute.rs:105:31 + --> tests/ui/transmute.rs:104:31 | LL | let _: *const Usize = core::mem::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`) - --> tests/ui/transmute.rs:108:29 + --> tests/ui/transmute.rs:107:29 | LL | let _: *mut Usize = core::mem::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a `u8` to a `bool` - --> tests/ui/transmute.rs:115:28 + --> tests/ui/transmute.rs:114:28 | LL | let _: bool = unsafe { std::mem::transmute(0_u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `0_u8 != 0` @@ -98,7 +86,7 @@ LL | let _: bool = unsafe { std::mem::transmute(0_u8) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_bool)]` error: transmute from a `&[u8]` to a `&str` - --> tests/ui/transmute.rs:122:28 + --> tests/ui/transmute.rs:121:28 | LL | let _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(B).unwrap()` @@ -107,16 +95,16 @@ LL | let _: &str = unsafe { std::mem::transmute(B) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_bytes_to_str)]` error: transmute from a `&mut [u8]` to a `&mut str` - --> tests/ui/transmute.rs:125:32 + --> tests/ui/transmute.rs:124:32 | LL | let _: &mut str = unsafe { std::mem::transmute(mb) }; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()` error: transmute from a `&[u8]` to a `&str` - --> tests/ui/transmute.rs:128:30 + --> tests/ui/transmute.rs:127:30 | LL | const _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_unchecked(B)` -error: aborting due to 18 previous errors +error: aborting due to 16 previous errors diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed index e7ad2a1cbbc..02f67f79e2b 100644 --- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed +++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed @@ -13,9 +13,6 @@ fn main() { // We should see an error message for each transmute, and no error messages for // the casts, since the casts are the recommended fixes. - // e is an integer and U is *U_0, while U_0: Sized; addr-ptr-cast - let _ptr_i32_transmute = unsafe { usize::MAX as *const i32 }; - //~^ useless_transmute let ptr_i32 = usize::MAX as *const i32; // e has type *T, U is *U_0, and either U_0: Sized ... diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs index 42a81777a82..c5e156405eb 100644 --- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs +++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs @@ -13,9 +13,6 @@ fn main() { // We should see an error message for each transmute, and no error messages for // the casts, since the casts are the recommended fixes. - // e is an integer and U is *U_0, while U_0: Sized; addr-ptr-cast - let _ptr_i32_transmute = unsafe { transmute::<usize, *const i32>(usize::MAX) }; - //~^ useless_transmute let ptr_i32 = usize::MAX as *const i32; // e has type *T, U is *U_0, and either U_0: Sized ... diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr index 7746f087cc7..f39a64d57eb 100644 --- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr +++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr @@ -1,14 +1,5 @@ -error: transmute from an integer to a pointer - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:17:39 - | -LL | let _ptr_i32_transmute = unsafe { transmute::<usize, *const i32>(usize::MAX) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `usize::MAX as *const i32` - | - = note: `-D clippy::useless-transmute` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::useless_transmute)]` - error: transmute from a pointer to a pointer - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:22:38 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:19:38 | LL | let _ptr_i8_transmute = unsafe { transmute::<*const i32, *const i8>(ptr_i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -22,7 +13,7 @@ LL + let _ptr_i8_transmute = unsafe { ptr_i32.cast::<i8>() }; | error: transmute from a pointer to a pointer - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:29:46 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:26:46 | LL | let _ptr_to_unsized_transmute = unsafe { transmute::<*const [i32], *const [u32]>(slice_ptr) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -34,7 +25,7 @@ LL + let _ptr_to_unsized_transmute = unsafe { slice_ptr as *const [u32] }; | error: transmute from `*const i32` to `usize` which could be expressed as a pointer cast instead - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:36:50 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:33:50 | LL | let _usize_from_int_ptr_transmute = unsafe { transmute::<*const i32, usize>(ptr_i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr_i32 as usize` @@ -43,40 +34,43 @@ LL | let _usize_from_int_ptr_transmute = unsafe { transmute::<*const i32, us = help: to override `-D warnings` add `#[allow(clippy::transmutes_expressible_as_ptr_casts)]` error: transmute from a reference to a pointer - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:43:41 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:40:41 | LL | let _array_ptr_transmute = unsafe { transmute::<&[i32; 4], *const [i32; 4]>(array_ref) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `array_ref as *const [i32; 4]` + | + = note: `-D clippy::useless-transmute` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::useless_transmute)]` error: transmute from `fn(usize) -> u8` to `*const usize` which could be expressed as a pointer cast instead - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:52:41 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:49:41 | LL | let _usize_ptr_transmute = unsafe { transmute::<fn(usize) -> u8, *const usize>(foo) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `foo as *const usize` error: transmute from `fn(usize) -> u8` to `usize` which could be expressed as a pointer cast instead - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:57:49 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:54:49 | LL | let _usize_from_fn_ptr_transmute = unsafe { transmute::<fn(usize) -> u8, usize>(foo) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `foo as usize` error: transmute from `*const u32` to `usize` which could be expressed as a pointer cast instead - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:61:36 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:58:36 | LL | let _usize_from_ref = unsafe { transmute::<*const u32, usize>(&1u32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&1u32 as *const u32 as usize` error: transmute from a reference to a pointer - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:73:14 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:70:14 | LL | unsafe { transmute::<&[i32; 1], *const u8>(in_param) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `in_param as *const [i32; 1] as *const u8` error: transmute from `fn()` to `*const u8` which could be expressed as a pointer cast instead - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:92:28 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:89:28 | LL | let _x: u8 = unsafe { *std::mem::transmute::<fn(), *const u8>(f) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(f as *const u8)` -error: aborting due to 10 previous errors +error: aborting due to 9 previous errors diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.fixed b/src/tools/clippy/tests/ui/unnecessary_operation.fixed index ac9fa4de20a..db5409bc491 100644 --- a/src/tools/clippy/tests/ui/unnecessary_operation.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_operation.fixed @@ -78,25 +78,25 @@ fn main() { //~^ unnecessary_operation get_number(); //~^ unnecessary_operation - 5;get_number(); + 5; get_number(); //~^ unnecessary_operation get_number(); //~^ unnecessary_operation get_number(); //~^ unnecessary_operation - 5;6;get_number(); + 5; 6; get_number(); //~^ unnecessary_operation get_number(); //~^ unnecessary_operation get_number(); //~^ unnecessary_operation - 5;get_number(); + 5; get_number(); //~^ unnecessary_operation - 42;get_number(); + 42; get_number(); //~^ unnecessary_operation assert!([42, 55].len() > get_usize()); //~^ unnecessary_operation - 42;get_number(); + 42; get_number(); //~^ unnecessary_operation get_number(); //~^ unnecessary_operation diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.stderr b/src/tools/clippy/tests/ui/unnecessary_operation.stderr index 0fda1dfde19..3439ba2e33e 100644 --- a/src/tools/clippy/tests/ui/unnecessary_operation.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_operation.stderr @@ -35,7 +35,7 @@ error: unnecessary operation --> tests/ui/unnecessary_operation.rs:81:5 | LL | 5 + get_number(); - | ^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();` + | ^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5; get_number();` error: unnecessary operation --> tests/ui/unnecessary_operation.rs:83:5 @@ -53,7 +53,7 @@ error: unnecessary operation --> tests/ui/unnecessary_operation.rs:87:5 | LL | (5, 6, get_number()); - | ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;6;get_number();` + | ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5; 6; get_number();` error: unnecessary operation --> tests/ui/unnecessary_operation.rs:89:5 @@ -71,13 +71,13 @@ error: unnecessary operation --> tests/ui/unnecessary_operation.rs:93:5 | LL | 5..get_number(); - | ^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();` + | ^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5; get_number();` error: unnecessary operation --> tests/ui/unnecessary_operation.rs:95:5 | LL | [42, get_number()]; - | ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();` + | ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42; get_number();` error: unnecessary operation --> tests/ui/unnecessary_operation.rs:97:5 @@ -89,7 +89,7 @@ error: unnecessary operation --> tests/ui/unnecessary_operation.rs:99:5 | LL | (42, get_number()).1; - | ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();` + | ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42; get_number();` error: unnecessary operation --> tests/ui/unnecessary_operation.rs:101:5 diff --git a/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2021.fixed b/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2021.fixed index f10d804c8cc..797f1505f49 100644 --- a/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2021.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2021.fixed @@ -63,3 +63,12 @@ fn issue14100() -> bool { // cast into the `bool` function return type. if return true {}; } + +fn issue15426(x: u32) { + // removing the `;` would turn the stmt into an expr, but attrs aren't allowed on exprs + #[rustfmt::skip] + match x { + 0b00 => {} 0b01 => {} + 0b11 => {} _ => {} + }; +} diff --git a/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2024.fixed b/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2024.fixed index 32a3bb9b408..d2609cea000 100644 --- a/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2024.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2024.fixed @@ -63,3 +63,12 @@ fn issue14100() -> bool { // cast into the `bool` function return type. if return true {}; } + +fn issue15426(x: u32) { + // removing the `;` would turn the stmt into an expr, but attrs aren't allowed on exprs + #[rustfmt::skip] + match x { + 0b00 => {} 0b01 => {} + 0b11 => {} _ => {} + }; +} diff --git a/src/tools/clippy/tests/ui/unnecessary_semicolon.rs b/src/tools/clippy/tests/ui/unnecessary_semicolon.rs index 91b28218022..55f1ec84cb0 100644 --- a/src/tools/clippy/tests/ui/unnecessary_semicolon.rs +++ b/src/tools/clippy/tests/ui/unnecessary_semicolon.rs @@ -63,3 +63,12 @@ fn issue14100() -> bool { // cast into the `bool` function return type. if return true {}; } + +fn issue15426(x: u32) { + // removing the `;` would turn the stmt into an expr, but attrs aren't allowed on exprs + #[rustfmt::skip] + match x { + 0b00 => {} 0b01 => {} + 0b11 => {} _ => {} + }; +} diff --git a/src/tools/clippy/tests/ui/zero_sized_hashmap_values.rs b/src/tools/clippy/tests/ui/zero_sized_hashmap_values.rs index dcbfd16843d..ee2fd19b5ee 100644 --- a/src/tools/clippy/tests/ui/zero_sized_hashmap_values.rs +++ b/src/tools/clippy/tests/ui/zero_sized_hashmap_values.rs @@ -92,6 +92,14 @@ fn issue14822() { //~^ zero_sized_map_values } +fn issue15429() { + struct E<'a>(&'a [E<'a>]); + + // The assertion error happens when the type being evaluated has escaping bound vars + // as it cannot be wrapped in a dummy binder during size computation. + type F = dyn for<'a> FnOnce(HashMap<u32, E<'a>>) -> u32; +} + fn main() { let _: HashMap<String, ()> = HashMap::new(); //~^ zero_sized_map_values diff --git a/src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr b/src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr index d29491fa05c..52ffef280c1 100644 --- a/src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr +++ b/src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr @@ -89,7 +89,7 @@ LL | type D = HashMap<u32, S<E>>; = help: consider using a set instead error: map with zero-sized value type - --> tests/ui/zero_sized_hashmap_values.rs:96:34 + --> tests/ui/zero_sized_hashmap_values.rs:104:34 | LL | let _: HashMap<String, ()> = HashMap::new(); | ^^^^^^^ @@ -97,7 +97,7 @@ LL | let _: HashMap<String, ()> = HashMap::new(); = help: consider using a set instead error: map with zero-sized value type - --> tests/ui/zero_sized_hashmap_values.rs:96:12 + --> tests/ui/zero_sized_hashmap_values.rs:104:12 | LL | let _: HashMap<String, ()> = HashMap::new(); | ^^^^^^^^^^^^^^^^^^^ @@ -105,7 +105,7 @@ LL | let _: HashMap<String, ()> = HashMap::new(); = help: consider using a set instead error: map with zero-sized value type - --> tests/ui/zero_sized_hashmap_values.rs:102:12 + --> tests/ui/zero_sized_hashmap_values.rs:110:12 | LL | let _: HashMap<_, _> = std::iter::empty::<(String, ())>().collect(); | ^^^^^^^^^^^^^ diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 2d49b1a7097..7fc80c1edb1 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -692,7 +692,9 @@ pub struct Config { pub minicore_path: Utf8PathBuf, /// Current codegen backend used. - pub codegen_backend: CodegenBackend, + pub default_codegen_backend: CodegenBackend, + /// Name/path of the backend to use instead of `default_codegen_backend`. + pub override_codegen_backend: Option<String>, } impl Config { @@ -796,7 +798,8 @@ impl Config { profiler_runtime: Default::default(), diff_command: Default::default(), minicore_path: Default::default(), - codegen_backend: CodegenBackend::Llvm, + default_codegen_backend: CodegenBackend::Llvm, + override_codegen_backend: None, } } diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index 13e694b7f03..f2ad049d526 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -205,6 +205,8 @@ pub struct TestProps { pub dont_require_annotations: HashSet<ErrorKind>, /// Whether pretty printers should be disabled in gdb. pub disable_gdb_pretty_printers: bool, + /// Compare the output by lines, rather than as a single string. + pub compare_output_by_lines: bool, } mod directives { @@ -254,6 +256,7 @@ mod directives { // This isn't a real directive, just one that is probably mistyped often pub const INCORRECT_COMPILER_FLAGS: &'static str = "compiler-flags"; pub const DISABLE_GDB_PRETTY_PRINTERS: &'static str = "disable-gdb-pretty-printers"; + pub const COMPARE_OUTPUT_BY_LINES: &'static str = "compare-output-by-lines"; } impl TestProps { @@ -310,6 +313,7 @@ impl TestProps { add_core_stubs: false, dont_require_annotations: Default::default(), disable_gdb_pretty_printers: false, + compare_output_by_lines: false, } } @@ -664,6 +668,11 @@ impl TestProps { DISABLE_GDB_PRETTY_PRINTERS, &mut self.disable_gdb_pretty_printers, ); + config.set_name_directive( + ln, + COMPARE_OUTPUT_BY_LINES, + &mut self.compare_output_by_lines, + ); }, ); @@ -1624,7 +1633,7 @@ fn ignore_backends( } } }) { - if config.codegen_backend == backend { + if config.default_codegen_backend == backend { return IgnoreDecision::Ignore { reason: format!("{} backend is marked as ignore", backend.as_str()), }; @@ -1651,12 +1660,12 @@ fn needs_backends( panic!("Invalid needs-backends value `{backend}` in `{path}`: {error}") } }) - .any(|backend| config.codegen_backend == backend) + .any(|backend| config.default_codegen_backend == backend) { return IgnoreDecision::Ignore { reason: format!( "{} backend is not part of required backends", - config.codegen_backend.as_str() + config.default_codegen_backend.as_str() ), }; } diff --git a/src/tools/compiletest/src/directives/directive_names.rs b/src/tools/compiletest/src/directives/directive_names.rs index f7955429d83..0ef84fb4594 100644 --- a/src/tools/compiletest/src/directives/directive_names.rs +++ b/src/tools/compiletest/src/directives/directive_names.rs @@ -17,6 +17,7 @@ pub(crate) const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "check-run-results", "check-stdout", "check-test-line-numbers-match", + "compare-output-by-lines", "compile-flags", "disable-gdb-pretty-printers", "doc-flags", @@ -194,6 +195,7 @@ pub(crate) const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "only-bpf", "only-cdb", "only-dist", + "only-eabihf", "only-elf", "only-emscripten", "only-gnu", diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index f5409e78341..469dd68207e 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -212,9 +212,15 @@ pub fn parse_config(args: Vec<String>) -> Config { ) .optopt( "", - "codegen-backend", + "default-codegen-backend", "the codegen backend currently used", "CODEGEN BACKEND NAME", + ) + .optopt( + "", + "override-codegen-backend", + "the codegen backend to use instead of the default one", + "CODEGEN BACKEND [NAME | PATH]", ); let (argv0, args_) = args.split_first().unwrap(); @@ -276,14 +282,17 @@ pub fn parse_config(args: Vec<String>) -> Config { || directives::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?), ); - let codegen_backend = match matches.opt_str("codegen-backend").as_deref() { + let default_codegen_backend = match matches.opt_str("default-codegen-backend").as_deref() { Some(backend) => match CodegenBackend::try_from(backend) { Ok(backend) => backend, - Err(error) => panic!("invalid value `{backend}` for `--codegen-backend`: {error}"), + Err(error) => { + panic!("invalid value `{backend}` for `--defalt-codegen-backend`: {error}") + } }, // By default, it's always llvm. None => CodegenBackend::Llvm, }; + let override_codegen_backend = matches.opt_str("override-codegen-backend"); let run_ignored = matches.opt_present("ignored"); let with_rustc_debug_assertions = matches.opt_present("with-rustc-debug-assertions"); @@ -472,7 +481,8 @@ pub fn parse_config(args: Vec<String>) -> Config { minicore_path: opt_path(matches, "minicore-path"), - codegen_backend, + default_codegen_backend, + override_codegen_backend, } } @@ -812,13 +822,13 @@ fn collect_tests_from_dir( && let Some(Utf8Component::Normal(parent)) = components.next() && parent == "tests" && let Ok(backend) = CodegenBackend::try_from(backend) - && backend != cx.config.codegen_backend + && backend != cx.config.default_codegen_backend { // We ignore asm tests which don't match the current codegen backend. warning!( "Ignoring tests in `{dir}` because they don't match the configured codegen \ backend (`{}`)", - cx.config.codegen_backend.as_str(), + cx.config.default_codegen_backend.as_str(), ); return Ok(TestCollector::new()); } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 821cb128647..739db8fa095 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1558,6 +1558,11 @@ impl<'test> TestCx<'test> { rustc.arg("--sysroot").arg(&self.config.sysroot_base); } + // If the provided codegen backend is not LLVM, we need to pass it. + if let Some(ref backend) = self.config.override_codegen_backend { + rustc.arg(format!("-Zcodegen-backend={}", backend)); + } + // Optionally prevent default --target if specified in test compile-flags. let custom_target = self.props.compile_flags.iter().any(|x| x.starts_with("--target")); @@ -2749,7 +2754,11 @@ impl<'test> TestCx<'test> { // Wrapper tools set by `runner` might provide extra output on failure, // for example a WebAssembly runtime might print the stack trace of an // `unreachable` instruction by default. - let compare_output_by_lines = self.config.runner.is_some(); + // + // Also, some tests like `ui/parallel-rustc` have non-deterministic + // orders of output, so we need to compare by lines. + let compare_output_by_lines = + self.props.compare_output_by_lines || self.config.runner.is_some(); let tmp; let (expected, actual): (&str, &str) = if compare_output_by_lines { diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml index c47f9695624..7d79c384f85 100644 --- a/src/tools/miri/.github/workflows/ci.yml +++ b/src/tools/miri/.github/workflows/ci.yml @@ -69,12 +69,6 @@ jobs: sudo apt update # Install needed packages sudo apt install $(echo "libatomic1: zlib1g-dev:" | sed 's/:/:${{ matrix.multiarch }}/g') - - name: Install rustup on Windows ARM - if: ${{ matrix.os == 'windows-11-arm' }} - run: | - curl -LOs https://static.rust-lang.org/rustup/dist/aarch64-pc-windows-msvc/rustup-init.exe - ./rustup-init.exe -y --no-modify-path - echo "$USERPROFILE/.cargo/bin" >> "$GITHUB_PATH" - uses: ./.github/workflows/setup with: toolchain_flags: "--host ${{ matrix.host_target }}" @@ -169,7 +163,13 @@ jobs: run: rustup toolchain install nightly --profile minimal - name: Install rustup-toolchain-install-master run: cargo install -f rustup-toolchain-install-master - - name: Push changes to a branch and create PR + # Create a token for the next step so it can create a PR that actually runs CI. + - uses: actions/create-github-app-token@v2 + id: app-token + with: + app-id: ${{ vars.APP_CLIENT_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + - name: pull changes from rustc and create PR run: | # Make it easier to see what happens. set -x @@ -198,9 +198,9 @@ jobs: BRANCH="rustup-$(date -u +%Y-%m-%d)" git switch -c $BRANCH git push -u origin $BRANCH - gh pr create -B master --title 'Automatic Rustup' --body 'Please close and re-open this PR to trigger CI, then enable auto-merge.' + gh pr create -B master --title 'Automatic Rustup' --body "Update \`rustc\` to https://github.com/rust-lang/rust/commit/$(cat rust-version)." env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} cron-fail-notify: name: cronjob failure notification diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml index 91dadf78a2f..99111092d39 100644 --- a/src/tools/miri/Cargo.toml +++ b/src/tools/miri/Cargo.toml @@ -78,6 +78,7 @@ native-lib = ["dep:libffi", "dep:libloading", "dep:capstone", "dep:ipc-channel", [lints.rust.unexpected_cfgs] level = "warn" +check-cfg = ['cfg(bootstrap)'] # Be aware that this file is inside a workspace when used via the # submodule in the rustc repo. That means there are many cargo features diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 2178caf6396..59adc572eaa 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -733dab558992d902d6d17576de1da768094e2cf3 +f605b57042ffeb320d7ae44490113a827139b766 diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 9ecbd31c5b9..b5ca9601547 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -282,7 +282,8 @@ pub fn report_error<'tcx>( }, TreeBorrowsUb { title: _, details, history } => { let mut helps = vec![ - note!("this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental") + note!("this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental"), + note!("see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information"), ]; for m in details { helps.push(note!("{m}")); diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 49021b1c4a2..0b2ce900414 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -12,10 +12,11 @@ use rand::rngs::StdRng; use rand::{Rng, SeedableRng}; use rustc_abi::{Align, ExternAbi, Size}; use rustc_apfloat::{Float, FloatConvert}; -use rustc_hir::attrs::InlineAttr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; #[allow(unused)] use rustc_data_structures::static_assert_size; +use rustc_hir::attrs::InlineAttr; +use rustc_middle::middle::codegen_fn_attrs::TargetFeatureKind; use rustc_middle::mir; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::{ @@ -1076,7 +1077,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { .target_features .iter() .filter(|&feature| { - !feature.implied && !ecx.tcx.sess.target_features.contains(&feature.name) + feature.kind != TargetFeatureKind::Implied && !ecx.tcx.sess.target_features.contains(&feature.name) }) .fold(String::new(), |mut s, feature| { if !s.is_empty() { @@ -1111,6 +1112,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { ) -> InterpResult<'tcx, Option<(&'tcx mir::Body<'tcx>, ty::Instance<'tcx>)>> { // For foreign items, try to see if we can emulate them. if ecx.tcx.is_foreign_item(instance.def_id()) { + let _trace = enter_trace_span!("emulate_foreign_item"); // An external function call that does not have a MIR body. We either find MIR elsewhere // or emulate its effect. // This will be Ok(None) if we're emulating the intrinsic entirely within Miri (no need @@ -1123,6 +1125,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { } // Otherwise, load the MIR. + let _trace = enter_trace_span!("load_mir"); interp_ok(Some((ecx.load_mir(instance.def, None)?, instance))) } @@ -1394,6 +1397,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { GlobalDataRaceHandler::Genmc(genmc_ctx) => genmc_ctx.memory_load(machine, ptr.addr(), range.size)?, GlobalDataRaceHandler::Vclocks(_data_race) => { + let _trace = enter_trace_span!(data_race::before_memory_read); let AllocDataRaceHandler::Vclocks(data_race, weak_memory) = &alloc_extra.data_race else { unreachable!(); @@ -1429,6 +1433,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { genmc_ctx.memory_store(machine, ptr.addr(), range.size)?; } GlobalDataRaceHandler::Vclocks(_global_state) => { + let _trace = enter_trace_span!(data_race::before_memory_write); let AllocDataRaceHandler::Vclocks(data_race, weak_memory) = &mut alloc_extra.data_race else { @@ -1465,6 +1470,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { GlobalDataRaceHandler::Genmc(genmc_ctx) => genmc_ctx.handle_dealloc(machine, ptr.addr(), size, align, kind)?, GlobalDataRaceHandler::Vclocks(_global_state) => { + let _trace = enter_trace_span!(data_race::before_memory_deallocation); let data_race = alloc_extra.data_race.as_vclocks_mut().unwrap(); data_race.write( alloc_id, @@ -1675,6 +1681,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { local: mir::Local, ) -> InterpResult<'tcx> { if let Some(data_race) = &frame.extra.data_race { + let _trace = enter_trace_span!(data_race::after_local_read); data_race.local_read(local, &ecx.machine); } interp_ok(()) @@ -1686,6 +1693,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { storage_live: bool, ) -> InterpResult<'tcx> { if let Some(data_race) = &ecx.frame().extra.data_race { + let _trace = enter_trace_span!(data_race::after_local_write); data_race.local_write(local, storage_live, &ecx.machine); } interp_ok(()) @@ -1708,6 +1716,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { if let Some(data_race) = &machine.threads.active_thread_stack().last().unwrap().extra.data_race { + let _trace = enter_trace_span!(data_race::after_local_moved_to_memory); data_race.local_moved_to_memory( local, alloc_info.data_race.as_vclocks_mut().unwrap(), diff --git a/src/tools/miri/src/operator.rs b/src/tools/miri/src/operator.rs index 3c3f2c28535..116f45f18dd 100644 --- a/src/tools/miri/src/operator.rs +++ b/src/tools/miri/src/operator.rs @@ -57,7 +57,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let ptr = left.to_scalar().to_pointer(this)?; // We do the actual operation with usize-typed scalars. let left = ImmTy::from_uint(ptr.addr().bytes(), this.machine.layouts.usize); - let result = this.binary_op(bin_op, &left, &right)?; + let result = this.binary_op(bin_op, &left, right)?; // Construct a new pointer with the provenance of `ptr` (the LHS). let result_ptr = Pointer::new( ptr.provenance, diff --git a/src/tools/miri/src/shims/extern_static.rs b/src/tools/miri/src/shims/extern_static.rs index 49c0c380a08..c2527bf8e25 100644 --- a/src/tools/miri/src/shims/extern_static.rs +++ b/src/tools/miri/src/shims/extern_static.rs @@ -62,7 +62,7 @@ impl<'tcx> MiriMachine<'tcx> { } "android" => { Self::null_ptr_extern_statics(ecx, &["bsd_signal"])?; - Self::weak_symbol_extern_statics(ecx, &["signal", "getrandom"])?; + Self::weak_symbol_extern_statics(ecx, &["signal", "getrandom", "gettid"])?; } "windows" => { // "_tls_used" diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 21545b68029..a700644b95d 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -5,6 +5,7 @@ use std::path::Path; use rustc_abi::{Align, AlignFromBytesError, CanonAbi, Size}; use rustc_apfloat::Float; use rustc_ast::expand::allocator::alloc_error_handler_name; +use rustc_hir::attrs::Linkage; use rustc_hir::def::DefKind; use rustc_hir::def_id::CrateNum; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; @@ -138,7 +139,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Entry::Occupied(e) => e.into_mut(), Entry::Vacant(e) => { // Find it if it was not cached. - let mut instance_and_crate: Option<(ty::Instance<'_>, CrateNum)> = None; + + struct SymbolTarget<'tcx> { + instance: ty::Instance<'tcx>, + cnum: CrateNum, + is_weak: bool, + } + let mut symbol_target: Option<SymbolTarget<'tcx>> = None; helpers::iter_exported_symbols(tcx, |cnum, def_id| { let attrs = tcx.codegen_fn_attrs(def_id); // Skip over imports of items. @@ -146,7 +153,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return interp_ok(()); } // Skip over items without an explicitly defined symbol name. - if !(attrs.export_name.is_some() + if !(attrs.symbol_name.is_some() || attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) || attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)) { @@ -155,40 +162,80 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let instance = Instance::mono(tcx, def_id); let symbol_name = tcx.symbol_name(instance).name; + let is_weak = attrs.linkage == Some(Linkage::WeakAny); if symbol_name == link_name.as_str() { - if let Some((original_instance, original_cnum)) = instance_and_crate { - // Make sure we are consistent wrt what is 'first' and 'second'. - let original_span = tcx.def_span(original_instance.def_id()).data(); - let span = tcx.def_span(def_id).data(); - if original_span < span { - throw_machine_stop!(TerminationInfo::MultipleSymbolDefinitions { - link_name, - first: original_span, - first_crate: tcx.crate_name(original_cnum), - second: span, - second_crate: tcx.crate_name(cnum), - }); - } else { - throw_machine_stop!(TerminationInfo::MultipleSymbolDefinitions { - link_name, - first: span, - first_crate: tcx.crate_name(cnum), - second: original_span, - second_crate: tcx.crate_name(original_cnum), - }); + if let Some(original) = &symbol_target { + // There is more than one definition with this name. What we do now + // depends on whether one or both definitions are weak. + match (is_weak, original.is_weak) { + (false, true) => { + // Original definition is a weak definition. Override it. + + symbol_target = Some(SymbolTarget { + instance: ty::Instance::mono(tcx, def_id), + cnum, + is_weak, + }); + } + (true, false) => { + // Current definition is a weak definition. Keep the original one. + } + (true, true) | (false, false) => { + // Either both definitions are non-weak or both are weak. In + // either case return an error. For weak definitions we error + // because it is unspecified which definition would have been + // picked by the linker. + + // Make sure we are consistent wrt what is 'first' and 'second'. + let original_span = + tcx.def_span(original.instance.def_id()).data(); + let span = tcx.def_span(def_id).data(); + if original_span < span { + throw_machine_stop!( + TerminationInfo::MultipleSymbolDefinitions { + link_name, + first: original_span, + first_crate: tcx.crate_name(original.cnum), + second: span, + second_crate: tcx.crate_name(cnum), + } + ); + } else { + throw_machine_stop!( + TerminationInfo::MultipleSymbolDefinitions { + link_name, + first: span, + first_crate: tcx.crate_name(cnum), + second: original_span, + second_crate: tcx.crate_name(original.cnum), + } + ); + } + } } + } else { + symbol_target = Some(SymbolTarget { + instance: ty::Instance::mono(tcx, def_id), + cnum, + is_weak, + }); } - if !matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) { - throw_ub_format!( - "attempt to call an exported symbol that is not defined as a function" - ); - } - instance_and_crate = Some((ty::Instance::mono(tcx, def_id), cnum)); } interp_ok(()) })?; - e.insert(instance_and_crate.map(|ic| ic.0)) + // Once we identified the instance corresponding to the symbol, ensure + // it is a function. It is okay to encounter non-functions in the search above + // as long as the final instance we arrive at is a function. + if let Some(SymbolTarget { instance, .. }) = symbol_target { + if !matches!(tcx.def_kind(instance.def_id()), DefKind::Fn | DefKind::AssocFn) { + throw_ub_format!( + "attempt to call an exported symbol that is not defined as a function" + ); + } + } + + e.insert(symbol_target.map(|SymbolTarget { instance, .. }| instance)) } }; match instance { diff --git a/src/tools/miri/src/shims/native_lib/mod.rs b/src/tools/miri/src/shims/native_lib/mod.rs index 36c18379cb8..74b9b704fea 100644 --- a/src/tools/miri/src/shims/native_lib/mod.rs +++ b/src/tools/miri/src/shims/native_lib/mod.rs @@ -242,13 +242,9 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { match evt { AccessEvent::Read(_) => { - // FIXME: ProvenanceMap should have something like get_range(). - let p_map = alloc.provenance(); - for idx in overlap { - // If a provenance was read by the foreign code, expose it. - if let Some((prov, _idx)) = p_map.get_byte(Size::from_bytes(idx), this) { - this.expose_provenance(prov)?; - } + // If a provenance was read by the foreign code, expose it. + for prov in alloc.provenance().get_range(this, overlap.into()) { + this.expose_provenance(prov)?; } } AccessEvent::Write(_, certain) => { diff --git a/src/tools/miri/src/shims/unix/android/foreign_items.rs b/src/tools/miri/src/shims/unix/android/foreign_items.rs index 04c5d28838b..6cb0d221fc0 100644 --- a/src/tools/miri/src/shims/unix/android/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/android/foreign_items.rs @@ -4,13 +4,14 @@ use rustc_span::Symbol; use rustc_target::callconv::FnAbi; use crate::shims::unix::android::thread::prctl; +use crate::shims::unix::env::EvalContextExt as _; use crate::shims::unix::linux_like::epoll::EvalContextExt as _; use crate::shims::unix::linux_like::eventfd::EvalContextExt as _; use crate::shims::unix::linux_like::syscall::syscall; use crate::*; -pub fn is_dyn_sym(_name: &str) -> bool { - false +pub fn is_dyn_sym(name: &str) -> bool { + matches!(name, "gettid") } impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} @@ -54,6 +55,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?; } + "gettid" => { + let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let result = this.unix_gettid(link_name.as_str())?; + this.write_scalar(result, dest)?; + } + // Dynamically invoked syscalls "syscall" => syscall(this, link_name, abi, args, dest)?, diff --git a/src/tools/miri/test-cargo-miri/run-test.py b/src/tools/miri/test-cargo-miri/run-test.py index 40bfe7f845f..6b3b6343b82 100755 --- a/src/tools/miri/test-cargo-miri/run-test.py +++ b/src/tools/miri/test-cargo-miri/run-test.py @@ -37,7 +37,7 @@ def cargo_miri(cmd, quiet = True, targets = None): def normalize_stdout(str): str = str.replace("src\\", "src/") # normalize paths across platforms - str = re.sub("finished in \\d+\\.\\d\\ds", "finished in $TIME", str) # the time keeps changing, obviously + str = re.sub("\\b\\d+\\.\\d+s\\b", "$TIME", str) # the time keeps changing, obviously return str def check_output(actual, path, name): diff --git a/src/tools/miri/test-cargo-miri/test.default.stdout.ref b/src/tools/miri/test-cargo-miri/test.default.stdout.ref index 2d74d82f769..ef092ef703b 100644 --- a/src/tools/miri/test-cargo-miri/test.default.stdout.ref +++ b/src/tools/miri/test-cargo-miri/test.default.stdout.ref @@ -14,3 +14,4 @@ running 5 tests ..... test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME +all doctests ran in $TIME; merged doctests compilation took $TIME diff --git a/src/tools/miri/test-cargo-miri/test.filter.stdout.ref b/src/tools/miri/test-cargo-miri/test.filter.stdout.ref index b68bc983276..071aa5691c1 100644 --- a/src/tools/miri/test-cargo-miri/test.filter.stdout.ref +++ b/src/tools/miri/test-cargo-miri/test.filter.stdout.ref @@ -15,3 +15,4 @@ running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 5 filtered out; finished in $TIME +all doctests ran in $TIME; merged doctests compilation took $TIME diff --git a/src/tools/miri/test-cargo-miri/test.multiple_targets.stdout.ref b/src/tools/miri/test-cargo-miri/test.multiple_targets.stdout.ref index a376530a8cf..20139e9ffe6 100644 --- a/src/tools/miri/test-cargo-miri/test.multiple_targets.stdout.ref +++ b/src/tools/miri/test-cargo-miri/test.multiple_targets.stdout.ref @@ -25,8 +25,10 @@ running 5 tests ..... test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME +all doctests ran in $TIME; merged doctests compilation took $TIME running 5 tests ..... test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME +all doctests ran in $TIME; merged doctests compilation took $TIME diff --git a/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr b/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr index 17efb10ceb0..449a29088a0 100644 --- a/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr +++ b/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr @@ -5,6 +5,7 @@ LL | *x = 1; | ^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> has state Frozen which forbids this child write access help: the accessed tag <TAG> was created here, in the initial state Reserved --> tests/fail/async-shared-mutable.rs:LL:CC diff --git a/src/tools/miri/tests/fail/both_borrows/alias_through_mutation.tree.stderr b/src/tools/miri/tests/fail/both_borrows/alias_through_mutation.tree.stderr index 9e992f88f0c..95b7e99dedc 100644 --- a/src/tools/miri/tests/fail/both_borrows/alias_through_mutation.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/alias_through_mutation.tree.stderr @@ -5,6 +5,7 @@ LL | let _val = *target_alias; | ^^^^^^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> has state Disabled which forbids this child read access help: the accessed tag <TAG> was created here, in the initial state Frozen --> tests/fail/both_borrows/alias_through_mutation.rs:LL:CC diff --git a/src/tools/miri/tests/fail/both_borrows/aliasing_mut1.tree.stderr b/src/tools/miri/tests/fail/both_borrows/aliasing_mut1.tree.stderr index e331ff2406d..207ed3131af 100644 --- a/src/tools/miri/tests/fail/both_borrows/aliasing_mut1.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/aliasing_mut1.tree.stderr @@ -5,6 +5,7 @@ LL | *x = 1; | ^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> has state Reserved (conflicted) which forbids this child write access help: the accessed tag <TAG> was created here, in the initial state Reserved --> tests/fail/both_borrows/aliasing_mut1.rs:LL:CC diff --git a/src/tools/miri/tests/fail/both_borrows/aliasing_mut2.tree.stderr b/src/tools/miri/tests/fail/both_borrows/aliasing_mut2.tree.stderr index a2191da0b4f..90b1b1294c7 100644 --- a/src/tools/miri/tests/fail/both_borrows/aliasing_mut2.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/aliasing_mut2.tree.stderr @@ -5,6 +5,7 @@ LL | *y = 2; | ^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> has state Reserved (conflicted) which forbids this child write access help: the accessed tag <TAG> was created here, in the initial state Reserved --> tests/fail/both_borrows/aliasing_mut2.rs:LL:CC diff --git a/src/tools/miri/tests/fail/both_borrows/aliasing_mut3.tree.stderr b/src/tools/miri/tests/fail/both_borrows/aliasing_mut3.tree.stderr index e92cad1777b..73a50276463 100644 --- a/src/tools/miri/tests/fail/both_borrows/aliasing_mut3.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/aliasing_mut3.tree.stderr @@ -5,6 +5,7 @@ LL | *x = 1; | ^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> has state Reserved (conflicted) which forbids this child write access help: the accessed tag <TAG> was created here, in the initial state Reserved --> tests/fail/both_borrows/aliasing_mut3.rs:LL:CC diff --git a/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.tree.stderr b/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.tree.stderr index e195b0a7e87..a6a6da3fa2a 100644 --- a/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/aliasing_mut4.tree.stderr @@ -5,6 +5,7 @@ LL | crate::intrinsics::write_via_move(dest, src); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> is foreign to the protected tag <TAG> (i.e., it is not a child) = help: this foreign write access would cause the protected tag <TAG> (currently Frozen) to become Disabled = help: protected tags must never be Disabled diff --git a/src/tools/miri/tests/fail/both_borrows/box_exclusive_violation1.tree.stderr b/src/tools/miri/tests/fail/both_borrows/box_exclusive_violation1.tree.stderr index 30832ae60ac..d4cfab024ba 100644 --- a/src/tools/miri/tests/fail/both_borrows/box_exclusive_violation1.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/box_exclusive_violation1.tree.stderr @@ -5,6 +5,7 @@ LL | *LEAK = 7; | ^^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> has state Disabled which forbids this child write access help: the accessed tag <TAG> was created here, in the initial state Frozen --> tests/fail/both_borrows/box_exclusive_violation1.rs:LL:CC diff --git a/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr b/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr index d7b865d57a8..3c8ec7f7d3e 100644 --- a/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr @@ -5,6 +5,7 @@ LL | *y | ^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> is foreign to the protected tag <TAG> (i.e., it is not a child) = help: this foreign read access would cause the protected tag <TAG> (currently Active) to become Disabled = help: protected tags must never be Disabled diff --git a/src/tools/miri/tests/fail/both_borrows/buggy_as_mut_slice.tree.stderr b/src/tools/miri/tests/fail/both_borrows/buggy_as_mut_slice.tree.stderr index ad5df3399c8..6588bc25df1 100644 --- a/src/tools/miri/tests/fail/both_borrows/buggy_as_mut_slice.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/buggy_as_mut_slice.tree.stderr @@ -5,6 +5,7 @@ LL | v2[1] = 7; | ^^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> has state Disabled which forbids this child write access help: the accessed tag <TAG> was created here, in the initial state Reserved --> tests/fail/both_borrows/buggy_as_mut_slice.rs:LL:CC diff --git a/src/tools/miri/tests/fail/both_borrows/buggy_split_at_mut.tree.stderr b/src/tools/miri/tests/fail/both_borrows/buggy_split_at_mut.tree.stderr index 4ab49e75adb..6ef27515fcd 100644 --- a/src/tools/miri/tests/fail/both_borrows/buggy_split_at_mut.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/buggy_split_at_mut.tree.stderr @@ -5,6 +5,7 @@ LL | b[1] = 6; | ^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> has state Disabled which forbids this child write access help: the accessed tag <TAG> was created here, in the initial state Reserved --> tests/fail/both_borrows/buggy_split_at_mut.rs:LL:CC diff --git a/src/tools/miri/tests/fail/both_borrows/illegal_write1.tree.stderr b/src/tools/miri/tests/fail/both_borrows/illegal_write1.tree.stderr index b718e19ff5a..4ffc7a75e66 100644 --- a/src/tools/miri/tests/fail/both_borrows/illegal_write1.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/illegal_write1.tree.stderr @@ -5,6 +5,7 @@ LL | unsafe { *x = 42 }; | ^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> has state Frozen which forbids this child write access help: the accessed tag <TAG> was created here, in the initial state Frozen --> tests/fail/both_borrows/illegal_write1.rs:LL:CC diff --git a/src/tools/miri/tests/fail/both_borrows/illegal_write5.tree.stderr b/src/tools/miri/tests/fail/both_borrows/illegal_write5.tree.stderr index d4c78c4bd33..fc5b12da70e 100644 --- a/src/tools/miri/tests/fail/both_borrows/illegal_write5.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/illegal_write5.tree.stderr @@ -5,6 +5,7 @@ LL | let _val = *xref; | ^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> has state Disabled which forbids this child read access help: the accessed tag <TAG> was created here, in the initial state Reserved --> tests/fail/both_borrows/illegal_write5.rs:LL:CC diff --git a/src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr b/src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr index e537bc18c05..6780e52c3ba 100644 --- a/src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr @@ -5,6 +5,7 @@ LL | unsafe { *y = 2 }; | ^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> is foreign to the protected tag <TAG> (i.e., it is not a child) = help: this foreign write access would cause the protected tag <TAG> (currently Active) to become Disabled = help: protected tags must never be Disabled diff --git a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector2.tree.stderr b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector2.tree.stderr index af90e75d384..90a89e48e61 100644 --- a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector2.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector2.tree.stderr @@ -5,6 +5,7 @@ LL | unsafe { *x = 0 }; | ^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> is foreign to the protected tag <TAG> (i.e., it is not a child) = help: this foreign write access would cause the protected tag <TAG> (currently Frozen) to become Disabled = help: protected tags must never be Disabled diff --git a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.tree.stderr b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.tree.stderr index 5d5f5e59ead..8bac71dcd46 100644 --- a/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/invalidate_against_protector3.tree.stderr @@ -5,6 +5,7 @@ LL | unsafe { *x = 0 }; | ^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child) = help: this foreign write access would cause the protected tag <TAG> (currently Frozen) to become Disabled = help: protected tags must never be Disabled diff --git a/src/tools/miri/tests/fail/both_borrows/load_invalid_shr.tree.stderr b/src/tools/miri/tests/fail/both_borrows/load_invalid_shr.tree.stderr index 86c12603c07..e4bde2f7aea 100644 --- a/src/tools/miri/tests/fail/both_borrows/load_invalid_shr.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/load_invalid_shr.tree.stderr @@ -5,6 +5,7 @@ LL | let _val = *xref_in_mem; | ^^^^^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> has state Disabled which forbids this reborrow (acting as a child read access) help: the accessed tag <TAG> was created here, in the initial state Frozen --> tests/fail/both_borrows/load_invalid_shr.rs:LL:CC diff --git a/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation1.tree.stderr b/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation1.tree.stderr index 5f14f23e8d6..f5c1dea69f0 100644 --- a/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation1.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation1.tree.stderr @@ -5,6 +5,7 @@ LL | *LEAK = 7; | ^^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> has state Disabled which forbids this child write access help: the accessed tag <TAG> was created here, in the initial state Frozen --> tests/fail/both_borrows/mut_exclusive_violation1.rs:LL:CC diff --git a/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation2.tree.stderr b/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation2.tree.stderr index edc72b0abbf..c1b0821a9fe 100644 --- a/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation2.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/mut_exclusive_violation2.tree.stderr @@ -5,6 +5,7 @@ LL | *raw1 = 3; | ^^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> has state Disabled which forbids this child write access help: the accessed tag <TAG> was created here, in the initial state Reserved --> tests/fail/both_borrows/mut_exclusive_violation2.rs:LL:CC diff --git a/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.tree.stderr b/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.tree.stderr index 1984a6a0746..aa07ef53b31 100644 --- a/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/newtype_pair_retagging.tree.stderr @@ -5,6 +5,7 @@ LL | self.1.deallocate(From::from(ptr.cast()), layout); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> is foreign to the protected tag <TAG> (i.e., it is not a child) = help: this deallocation (acting as a foreign write access) would cause the protected tag <TAG> (currently Reserved (conflicted)) to become Disabled = help: protected tags must never be Disabled diff --git a/src/tools/miri/tests/fail/both_borrows/newtype_retagging.tree.stderr b/src/tools/miri/tests/fail/both_borrows/newtype_retagging.tree.stderr index 7bd0cd14d79..c8a72c59176 100644 --- a/src/tools/miri/tests/fail/both_borrows/newtype_retagging.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/newtype_retagging.tree.stderr @@ -5,6 +5,7 @@ LL | self.1.deallocate(From::from(ptr.cast()), layout); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> is foreign to the protected tag <TAG> (i.e., it is not a child) = help: this deallocation (acting as a foreign write access) would cause the protected tag <TAG> (currently Reserved (conflicted)) to become Disabled = help: protected tags must never be Disabled diff --git a/src/tools/miri/tests/fail/both_borrows/outdated_local.tree.stderr b/src/tools/miri/tests/fail/both_borrows/outdated_local.tree.stderr index 8cb44d2635f..5310f8b9d09 100644 --- a/src/tools/miri/tests/fail/both_borrows/outdated_local.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/outdated_local.tree.stderr @@ -5,6 +5,7 @@ LL | assert_eq!(unsafe { *y }, 1); | ^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> has state Disabled which forbids this child read access help: the accessed tag <TAG> was created here, in the initial state Frozen --> tests/fail/both_borrows/outdated_local.rs:LL:CC diff --git a/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr.tree.stderr b/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr.tree.stderr index 1bd760426da..3c813d35031 100644 --- a/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr.tree.stderr @@ -5,6 +5,7 @@ LL | foo(xref); | ^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> has state Disabled which forbids this reborrow (acting as a child read access) help: the accessed tag <TAG> was created here, in the initial state Frozen --> tests/fail/both_borrows/pass_invalid_shr.rs:LL:CC diff --git a/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr_option.tree.stderr b/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr_option.tree.stderr index 2f999a8aae0..4747c65ba83 100644 --- a/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr_option.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr_option.tree.stderr @@ -5,6 +5,7 @@ LL | foo(some_xref); | ^^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> has state Disabled which forbids this reborrow (acting as a child read access) help: the accessed tag <TAG> was created here, in the initial state Frozen --> tests/fail/both_borrows/pass_invalid_shr_option.rs:LL:CC diff --git a/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr_tuple.tree.stderr b/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr_tuple.tree.stderr index b30bda598d2..da011cfd3f7 100644 --- a/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr_tuple.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/pass_invalid_shr_tuple.tree.stderr @@ -5,6 +5,7 @@ LL | foo(pair_xref); | ^^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> has state Disabled which forbids this reborrow (acting as a child read access) help: the accessed tag <TAG> was created here, in the initial state Frozen --> tests/fail/both_borrows/pass_invalid_shr_tuple.rs:LL:CC diff --git a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.tree.stderr b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.tree.stderr index 2b2650a254d..ee0f313d980 100644 --- a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.tree.stderr @@ -5,6 +5,7 @@ LL | ret | ^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> has state Disabled which forbids this reborrow (acting as a child read access) help: the accessed tag <TAG> was created here, in the initial state Frozen --> tests/fail/both_borrows/return_invalid_shr.rs:LL:CC diff --git a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.tree.stderr b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.tree.stderr index b8e963f87d9..16110e5b062 100644 --- a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.tree.stderr @@ -5,6 +5,7 @@ LL | ret | ^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> has state Disabled which forbids this reborrow (acting as a child read access) help: the accessed tag <TAG> was created here, in the initial state Frozen --> tests/fail/both_borrows/return_invalid_shr_option.rs:LL:CC diff --git a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.tree.stderr b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.tree.stderr index 8e499369f08..f93698f570e 100644 --- a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.tree.stderr @@ -5,6 +5,7 @@ LL | ret | ^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> has state Disabled which forbids this reborrow (acting as a child read access) help: the accessed tag <TAG> was created here, in the initial state Frozen --> tests/fail/both_borrows/return_invalid_shr_tuple.rs:LL:CC diff --git a/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation1.tree.stderr b/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation1.tree.stderr index a28754f5412..d9b75f65f75 100644 --- a/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation1.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation1.tree.stderr @@ -5,6 +5,7 @@ LL | *(x as *const i32 as *mut i32) = 7; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> has state Frozen which forbids this child write access help: the accessed tag <TAG> was created here, in the initial state Frozen --> tests/fail/both_borrows/shr_frozen_violation1.rs:LL:CC diff --git a/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation2.tree.stderr b/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation2.tree.stderr index 0eb2dc3df77..c680c04137b 100644 --- a/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation2.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation2.tree.stderr @@ -5,6 +5,7 @@ LL | let _val = *frozen; | ^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> has state Disabled which forbids this child read access help: the accessed tag <TAG> was created here, in the initial state Frozen --> tests/fail/both_borrows/shr_frozen_violation2.rs:LL:CC diff --git a/src/tools/miri/tests/fail/both_borrows/zero-sized-protected.tree.stderr b/src/tools/miri/tests/fail/both_borrows/zero-sized-protected.tree.stderr index 2a9a9afb0f0..66a7d7794e9 100644 --- a/src/tools/miri/tests/fail/both_borrows/zero-sized-protected.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/zero-sized-protected.tree.stderr @@ -5,6 +5,7 @@ LL | unsafe { dealloc(ptr, l) }; | ^^^^^^^^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the allocation of the accessed tag <TAG> (root of the allocation) also contains the strongly protected tag <TAG> = help: the strongly protected tag <TAG> disallows deallocations help: the accessed tag <TAG> was created here diff --git a/src/tools/miri/tests/fail/branchless-select-i128-pointer.rs b/src/tools/miri/tests/fail/branchless-select-i128-pointer.rs index 2b861e5447b..7147813c4b6 100644 --- a/src/tools/miri/tests/fail/branchless-select-i128-pointer.rs +++ b/src/tools/miri/tests/fail/branchless-select-i128-pointer.rs @@ -1,3 +1,5 @@ +#![allow(integer_to_ptr_transmutes)] + use std::mem::transmute; #[cfg(target_pointer_width = "32")] diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.rs b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.rs new file mode 100644 index 00000000000..744d64b9b1e --- /dev/null +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.rs @@ -0,0 +1,36 @@ +//! Ensure we detect aliasing of two in-place arguments for the tricky case where they do not +//! live in memory. +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows +// Validation forces more things into memory, which we can't have here. +//@compile-flags: -Zmiri-disable-validation +#![feature(custom_mir, core_intrinsics)] +use std::intrinsics::mir::*; + +pub struct S(i32); + +#[custom_mir(dialect = "runtime", phase = "optimized")] +fn main() { + mir! { + let _unit: (); + { + let staging = S(42); // This forces `staging` into memory... + let non_copy = staging; // ... so we move it to a non-inmemory local here. + // This specifically uses a type with scalar representation to tempt Miri to use the + // efficient way of storing local variables (outside adressable memory). + Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(after_call), UnwindContinue()) + //~[stack]^ ERROR: not granting access + //~[tree]| ERROR: /read access .* forbidden/ + } + after_call = { + Return() + } + } +} + +pub fn callee(x: S, mut y: S) { + // With the setup above, if `x` and `y` are both moved, + // then writing to `y` will change the value stored in `x`! + y.0 = 0; + assert_eq!(x.0, 42); +} diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.stack.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.stack.stderr new file mode 100644 index 00000000000..0c1100cae63 --- /dev/null +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.stack.stderr @@ -0,0 +1,25 @@ +error: Undefined Behavior: not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected + --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC + | +LL | Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(after_call), UnwindContinue()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: <TAG> was created here, as the root tag for ALLOC + --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC + | +LL | Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(after_call), UnwindContinue()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: <TAG> is this argument + --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC + | +LL | y.0 = 0; + | ^^^^^^^ + = note: BACKTRACE (of the first span): + = note: inside `main` at tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.tree.stderr new file mode 100644 index 00000000000..2266a9c39f9 --- /dev/null +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.tree.stderr @@ -0,0 +1,34 @@ +error: Undefined Behavior: read access through <TAG> (root of the allocation) at ALLOC[0x0] is forbidden + --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC + | +LL | Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(after_call), UnwindContinue()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information + = help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child) + = help: this foreign read access would cause the protected tag <TAG> (currently Active) to become Disabled + = help: protected tags must never be Disabled +help: the accessed tag <TAG> was created here + --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC + | +LL | Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(after_call), UnwindContinue()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: the protected tag <TAG> was created here, in the initial state Reserved + --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC + | +LL | y.0 = 0; + | ^^^^^^^ +help: the protected tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x4] + --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC + | +LL | y.0 = 0; + | ^^^^^^^ + = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference + = note: BACKTRACE (of the first span): + = note: inside `main` at tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.rs b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.rs new file mode 100644 index 00000000000..dff724f8d96 --- /dev/null +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.rs @@ -0,0 +1,34 @@ +//! Ensure we detect aliasing of a in-place argument with the return place for the tricky case where +//! they do not live in memory. +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows +// Validation forces more things into memory, which we can't have here. +//@compile-flags: -Zmiri-disable-validation +#![feature(custom_mir, core_intrinsics)] +use std::intrinsics::mir::*; + +#[allow(unused)] +pub struct S(i32); + +#[custom_mir(dialect = "runtime", phase = "optimized")] +fn main() { + mir! { + let _unit: (); + { + let staging = S(42); // This forces `staging` into memory... + let _non_copy = staging; // ... so we move it to a non-inmemory local here. + // This specifically uses a type with scalar representation to tempt Miri to use the + // efficient way of storing local variables (outside adressable memory). + Call(_non_copy = callee(Move(_non_copy)), ReturnTo(after_call), UnwindContinue()) + //~[stack]^ ERROR: not granting access + //~[tree]| ERROR: /reborrow .* forbidden/ + } + after_call = { + Return() + } + } +} + +pub fn callee(x: S) -> S { + x +} diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.stack.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.stack.stderr new file mode 100644 index 00000000000..fcd5b8752e7 --- /dev/null +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.stack.stderr @@ -0,0 +1,25 @@ +error: Undefined Behavior: not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected + --> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC + | +LL | Call(_non_copy = callee(Move(_non_copy)), ReturnTo(after_call), UnwindContinue()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: <TAG> was created here, as the root tag for ALLOC + --> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC + | +LL | Call(_non_copy = callee(Move(_non_copy)), ReturnTo(after_call), UnwindContinue()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: <TAG> is this argument + --> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC + | +LL | x + | ^ + = note: BACKTRACE (of the first span): + = note: inside `main` at tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.tree.stderr new file mode 100644 index 00000000000..b7f514de0af --- /dev/null +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.tree.stderr @@ -0,0 +1,34 @@ +error: Undefined Behavior: reborrow through <TAG> (root of the allocation) at ALLOC[0x0] is forbidden + --> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC + | +LL | Call(_non_copy = callee(Move(_non_copy)), ReturnTo(after_call), UnwindContinue()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information + = help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child) + = help: this reborrow (acting as a foreign read access) would cause the protected tag <TAG> (currently Active) to become Disabled + = help: protected tags must never be Disabled +help: the accessed tag <TAG> was created here + --> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC + | +LL | Call(_non_copy = callee(Move(_non_copy)), ReturnTo(after_call), UnwindContinue()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: the protected tag <TAG> was created here, in the initial state Reserved + --> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC + | +LL | x + | ^ +help: the protected tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x4] + --> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC + | +LL | x + | ^ + = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference + = note: BACKTRACE (of the first span): + = note: inside `main` at tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr index 2f1dc1988f5..1995528e9f9 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr @@ -5,6 +5,7 @@ LL | unsafe { ptr.write(S(0)) }; | ^^^^^^^^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child) = help: this foreign write access would cause the protected tag <TAG> (currently Active) to become Disabled = help: protected tags must never be Disabled diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr index 5db5a6cac4d..e506a61c6bb 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr @@ -5,6 +5,7 @@ LL | unsafe { ptr.read() }; | ^^^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child) = help: this foreign read access would cause the protected tag <TAG> (currently Active) to become Disabled = help: protected tags must never be Disabled diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr index 24091547258..d478568ceae 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr @@ -11,8 +11,8 @@ LL | unsafe { ptr.read() }; note: inside `main` --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | -LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation: ALLOC (stack variable, size: 4, align: 4) { diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.rs b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.rs index a6e0134bd17..dc22e129e18 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.rs +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.rs @@ -10,11 +10,11 @@ use std::intrinsics::mir::*; pub fn main() { mir! { { - let x = 0; - let ptr = &raw mut x; + let _x = 0; + let ptr = &raw mut _x; // We arrange for `myfun` to have a pointer that aliases // its return place. Even just reading from that pointer is UB. - Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue()) + Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) } after_call = { @@ -25,7 +25,7 @@ pub fn main() { fn myfun(ptr: *mut i32) -> i32 { unsafe { ptr.read() }; - //~[stack]^ ERROR: not granting access + //~[stack]^ ERROR: does not exist in the borrow stack //~[tree]| ERROR: /read access .* forbidden/ //~[none]| ERROR: uninitialized // Without an aliasing model, reads are "fine" but at least they return uninit data. diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.stack.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.stack.stderr index 77cc0332a1c..86adbab353b 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.stack.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected +error: Undefined Behavior: attempting a read access using <TAG> at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | LL | unsafe { ptr.read() }; - | ^^^^^^^^^^ Undefined Behavior occurred here + | ^^^^^^^^^^ this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information @@ -11,12 +11,12 @@ help: <TAG> was created by a SharedReadWrite retag at offsets [0x0..0x4] | LL | / mir! { LL | | { -LL | | let x = 0; -LL | | let ptr = &raw mut x; +LL | | let _x = 0; +LL | | let ptr = &raw mut _x; ... | LL | | } | |_____^ -help: <TAG> is this argument +help: <TAG> was later invalidated at offsets [0x0..0x4] by a Unique in-place function argument/return passing protection --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | LL | unsafe { ptr.read() }; @@ -26,8 +26,8 @@ LL | unsafe { ptr.read() }; note: inside `main` --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | -LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr index bae3819c979..b1aa2ba2886 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr @@ -5,6 +5,7 @@ LL | unsafe { ptr.read() }; | ^^^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child) = help: this foreign read access would cause the protected tag <TAG> (currently Active) to become Disabled = help: protected tags must never be Disabled @@ -13,8 +14,8 @@ help: the accessed tag <TAG> was created here | LL | / mir! { LL | | { -LL | | let x = 0; -LL | | let ptr = &raw mut x; +LL | | let _x = 0; +LL | | let ptr = &raw mut _x; ... | LL | | } | |_____^ @@ -34,8 +35,8 @@ LL | unsafe { ptr.read() }; note: inside `main` --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | -LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.rs b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.rs index 6155e925c4b..2fddaf37235 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.rs +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.rs @@ -14,7 +14,7 @@ pub fn main() { let ptr = &raw mut _x; // We arrange for `myfun` to have a pointer that aliases // its return place. Writing to that pointer is UB. - Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue()) + Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) } after_call = { @@ -26,7 +26,7 @@ pub fn main() { fn myfun(ptr: *mut i32) -> i32 { // This overwrites the return place, which shouldn't be possible through another pointer. unsafe { ptr.write(0) }; - //~[stack]^ ERROR: strongly protected + //~[stack]^ ERROR: does not exist in the borrow stack //~[tree]| ERROR: /write access .* forbidden/ 13 } diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.stack.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.stack.stderr index 828b2339f8c..faae6172d75 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.stack.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected +error: Undefined Behavior: attempting a write access using <TAG> at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC | LL | unsafe { ptr.write(0) }; - | ^^^^^^^^^^^^ Undefined Behavior occurred here + | ^^^^^^^^^^^^ this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information @@ -16,7 +16,7 @@ LL | | let ptr = &raw mut _x; ... | LL | | } | |_____^ -help: <TAG> is this argument +help: <TAG> was later invalidated at offsets [0x0..0x4] by a Unique in-place function argument/return passing protection --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC | LL | unsafe { ptr.write(0) }; @@ -26,8 +26,8 @@ LL | unsafe { ptr.write(0) }; note: inside `main` --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC | -LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr index e0df9370fee..0cf449ea3ec 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr @@ -5,6 +5,7 @@ LL | unsafe { ptr.write(0) }; | ^^^^^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child) = help: this foreign write access would cause the protected tag <TAG> (currently Active) to become Disabled = help: protected tags must never be Disabled @@ -34,8 +35,8 @@ LL | unsafe { ptr.write(0) }; note: inside `main` --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC | -LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs index 37ee7ae1b0d..5f3ecb65022 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs @@ -16,7 +16,7 @@ pub fn main() { let ptr = &raw mut _x; // We arrange for `myfun` to have a pointer that aliases // its return place. Writing to that pointer is UB. - Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue()) + Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) } after_call = { @@ -32,7 +32,7 @@ fn myfun(ptr: *mut i32) -> i32 { fn myfun2(ptr: *mut i32) -> i32 { // This overwrites the return place, which shouldn't be possible through another pointer. unsafe { ptr.write(0) }; - //~[stack]^ ERROR: strongly protected + //~[stack]^ ERROR: does not exist in the borrow stack //~[tree]| ERROR: /write access .* forbidden/ 13 } diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.stack.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.stack.stderr index f5183cfaf5b..1a18857bb17 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.stack.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected +error: Undefined Behavior: attempting a write access using <TAG> at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC | LL | unsafe { ptr.write(0) }; - | ^^^^^^^^^^^^ Undefined Behavior occurred here + | ^^^^^^^^^^^^ this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information @@ -16,18 +16,18 @@ LL | | let ptr = &raw mut _x; ... | LL | | } | |_____^ -help: <TAG> is this argument +help: <TAG> was later invalidated at offsets [0x0..0x4] by a Unique in-place function argument/return passing protection --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC | -LL | unsafe { ptr.write(0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | become myfun2(ptr) + | ^^^^^^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): = note: inside `myfun2` at tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC note: inside `main` --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC | -LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr index fa03ed6869b..a006c6feae4 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr @@ -5,6 +5,7 @@ LL | unsafe { ptr.write(0) }; | ^^^^^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child) = help: this foreign write access would cause the protected tag <TAG> (currently Active) to become Disabled = help: protected tags must never be Disabled @@ -34,8 +35,8 @@ LL | unsafe { ptr.write(0) }; note: inside `main` --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC | -LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/provenance/provenance_transmute.rs b/src/tools/miri/tests/fail/provenance/provenance_transmute.rs index d72f10530d7..60cb9a7f6bf 100644 --- a/src/tools/miri/tests/fail/provenance/provenance_transmute.rs +++ b/src/tools/miri/tests/fail/provenance/provenance_transmute.rs @@ -1,5 +1,7 @@ //@compile-flags: -Zmiri-permissive-provenance +#![allow(integer_to_ptr_transmutes)] + use std::mem; // This is the example from diff --git a/src/tools/miri/tests/fail/tree_borrows/alternate-read-write.stderr b/src/tools/miri/tests/fail/tree_borrows/alternate-read-write.stderr index 63c6287f20d..9e955a6d5b1 100644 --- a/src/tools/miri/tests/fail/tree_borrows/alternate-read-write.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/alternate-read-write.stderr @@ -5,6 +5,7 @@ LL | *y += 1; // Failure | ^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> has state Frozen which forbids this child write access help: the accessed tag <TAG> was created here, in the initial state Reserved --> tests/fail/tree_borrows/alternate-read-write.rs:LL:CC diff --git a/src/tools/miri/tests/fail/tree_borrows/cell-inside-struct.stderr b/src/tools/miri/tests/fail/tree_borrows/cell-inside-struct.stderr index 81d5aba6b2e..5e43d174ed9 100644 --- a/src/tools/miri/tests/fail/tree_borrows/cell-inside-struct.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/cell-inside-struct.stderr @@ -11,6 +11,7 @@ LL | (*a).field1 = 88; | ^^^^^^^^^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> (a) has state Frozen which forbids this child write access help: the accessed tag <TAG> was created here, in the initial state Cell --> tests/fail/tree_borrows/cell-inside-struct.rs:LL:CC diff --git a/src/tools/miri/tests/fail/tree_borrows/error-range.stderr b/src/tools/miri/tests/fail/tree_borrows/error-range.stderr index 9a52f68d9b6..3dc120a20d2 100644 --- a/src/tools/miri/tests/fail/tree_borrows/error-range.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/error-range.stderr @@ -5,6 +5,7 @@ LL | rmut[5] += 1; | ^^^^^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> has state Disabled which forbids this child read access help: the accessed tag <TAG> was created here, in the initial state Reserved --> tests/fail/tree_borrows/error-range.rs:LL:CC diff --git a/src/tools/miri/tests/fail/tree_borrows/fnentry_invalidation.stderr b/src/tools/miri/tests/fail/tree_borrows/fnentry_invalidation.stderr index ed345aae38f..7886029dccf 100644 --- a/src/tools/miri/tests/fail/tree_borrows/fnentry_invalidation.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/fnentry_invalidation.stderr @@ -5,6 +5,7 @@ LL | *z = 2; | ^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> has state Frozen which forbids this child write access help: the accessed tag <TAG> was created here, in the initial state Reserved --> tests/fail/tree_borrows/fnentry_invalidation.rs:LL:CC diff --git a/src/tools/miri/tests/fail/tree_borrows/outside-range.stderr b/src/tools/miri/tests/fail/tree_borrows/outside-range.stderr index bbd33dc3560..7960f42faa5 100644 --- a/src/tools/miri/tests/fail/tree_borrows/outside-range.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/outside-range.stderr @@ -5,6 +5,7 @@ LL | *y.add(3) = 42; | ^^^^^^^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> is foreign to the protected tag <TAG> (i.e., it is not a child) = help: this foreign write access would cause the protected tag <TAG> (currently Reserved) to become Disabled = help: protected tags must never be Disabled diff --git a/src/tools/miri/tests/fail/tree_borrows/parent_read_freezes_raw_mut.stderr b/src/tools/miri/tests/fail/tree_borrows/parent_read_freezes_raw_mut.stderr index a4119bc0178..2edbbd80569 100644 --- a/src/tools/miri/tests/fail/tree_borrows/parent_read_freezes_raw_mut.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/parent_read_freezes_raw_mut.stderr @@ -5,6 +5,7 @@ LL | *ptr = 0; | ^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> has state Frozen which forbids this child write access help: the accessed tag <TAG> was created here, in the initial state Reserved --> tests/fail/tree_borrows/parent_read_freezes_raw_mut.rs:LL:CC diff --git a/src/tools/miri/tests/fail/tree_borrows/pass_invalid_mut.stderr b/src/tools/miri/tests/fail/tree_borrows/pass_invalid_mut.stderr index de01a9f0e80..c00c67173b7 100644 --- a/src/tools/miri/tests/fail/tree_borrows/pass_invalid_mut.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/pass_invalid_mut.stderr @@ -5,6 +5,7 @@ LL | *nope = 31; | ^^^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> is a child of the conflicting tag <TAG> = help: the conflicting tag <TAG> has state Frozen which forbids this child write access help: the accessed tag <TAG> was created here diff --git a/src/tools/miri/tests/fail/tree_borrows/protector-write-lazy.stderr b/src/tools/miri/tests/fail/tree_borrows/protector-write-lazy.stderr index af226b9e3be..7cebd7f32a0 100644 --- a/src/tools/miri/tests/fail/tree_borrows/protector-write-lazy.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/protector-write-lazy.stderr @@ -5,6 +5,7 @@ LL | unsafe { println!("Value of funky: {}", *funky_ptr_lazy_on_fst_elem) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> has state Disabled which forbids this reborrow (acting as a child read access) help: the accessed tag <TAG> was created here, in the initial state Reserved --> tests/fail/tree_borrows/protector-write-lazy.rs:LL:CC diff --git a/src/tools/miri/tests/fail/tree_borrows/repeated_foreign_read_lazy_conflicted.stderr b/src/tools/miri/tests/fail/tree_borrows/repeated_foreign_read_lazy_conflicted.stderr index 8421df5ab79..012d7caef50 100644 --- a/src/tools/miri/tests/fail/tree_borrows/repeated_foreign_read_lazy_conflicted.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/repeated_foreign_read_lazy_conflicted.stderr @@ -5,6 +5,7 @@ LL | *(x as *mut u8).byte_sub(1) = 42; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> has state Reserved (conflicted) which forbids this child write access help: the accessed tag <TAG> was created here, in the initial state Reserved --> tests/fail/tree_borrows/repeated_foreign_read_lazy_conflicted.rs:LL:CC diff --git a/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr b/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr index 00d5c3e6b67..b1c3ffe86ef 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr @@ -15,6 +15,7 @@ LL | *y = 1; | ^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> (y, callee:y, caller:y) is foreign to the protected tag <TAG> (callee:x) (i.e., it is not a child) = help: this foreign write access would cause the protected tag <TAG> (callee:x) (currently Reserved) to become Disabled = help: protected tags must never be Disabled diff --git a/src/tools/miri/tests/fail/tree_borrows/reserved/int-protected-write.stderr b/src/tools/miri/tests/fail/tree_borrows/reserved/int-protected-write.stderr index c003938db33..5f3129b9dc0 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reserved/int-protected-write.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/reserved/int-protected-write.stderr @@ -15,6 +15,7 @@ LL | *y = 0; | ^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> (y, callee:y, caller:y) is foreign to the protected tag <TAG> (callee:x) (i.e., it is not a child) = help: this foreign write access would cause the protected tag <TAG> (callee:x) (currently Reserved) to become Disabled = help: protected tags must never be Disabled diff --git a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.with.stderr b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.with.stderr index a8db7070333..7565fa6203f 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.with.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.with.stderr @@ -19,6 +19,7 @@ LL | unsafe { *y = 13 } | ^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> has state Disabled which forbids this child write access help: the accessed tag <TAG> was created here, in the initial state Reserved --> tests/fail/tree_borrows/reservedim_spurious_write.rs:LL:CC diff --git a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.without.stderr b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.without.stderr index 5eeefd450c6..7f791c88dde 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.without.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.without.stderr @@ -19,6 +19,7 @@ LL | unsafe { *y = 13 } | ^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> has state Disabled which forbids this child write access help: the accessed tag <TAG> was created here, in the initial state Reserved --> tests/fail/tree_borrows/reservedim_spurious_write.rs:LL:CC diff --git a/src/tools/miri/tests/fail/tree_borrows/return_invalid_mut.stderr b/src/tools/miri/tests/fail/tree_borrows/return_invalid_mut.stderr index a0ebf0ecbd2..ba8ab472872 100644 --- a/src/tools/miri/tests/fail/tree_borrows/return_invalid_mut.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/return_invalid_mut.stderr @@ -5,6 +5,7 @@ LL | *ret = 3; | ^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> is a child of the conflicting tag <TAG> = help: the conflicting tag <TAG> has state Frozen which forbids this child write access help: the accessed tag <TAG> was created here diff --git a/src/tools/miri/tests/fail/tree_borrows/spurious_read.stderr b/src/tools/miri/tests/fail/tree_borrows/spurious_read.stderr index a3b0d5f13ad..8f2534d6b6e 100644 --- a/src/tools/miri/tests/fail/tree_borrows/spurious_read.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/spurious_read.stderr @@ -18,6 +18,7 @@ LL | *y = 2; | ^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> has state Reserved (conflicted) which forbids this child write access help: the accessed tag <TAG> was created here, in the initial state Reserved --> tests/fail/tree_borrows/spurious_read.rs:LL:CC diff --git a/src/tools/miri/tests/fail/tree_borrows/strongly-protected.stderr b/src/tools/miri/tests/fail/tree_borrows/strongly-protected.stderr index 56617f6d6a6..685abee3292 100644 --- a/src/tools/miri/tests/fail/tree_borrows/strongly-protected.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/strongly-protected.stderr @@ -5,6 +5,7 @@ LL | self.1.deallocate(From::from(ptr.cast()), layout); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the allocation of the accessed tag <TAG> also contains the strongly protected tag <TAG> = help: the strongly protected tag <TAG> disallows deallocations help: the accessed tag <TAG> was created here diff --git a/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.stderr b/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.stderr index 8669a14ecc7..b98d2fafcf4 100644 --- a/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.stderr @@ -5,6 +5,7 @@ LL | *m = 42; | ^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> is a child of the conflicting tag <TAG> = help: the conflicting tag <TAG> has state Frozen which forbids this child write access help: the accessed tag <TAG> was created here diff --git a/src/tools/miri/tests/fail/tree_borrows/write-during-2phase.stderr b/src/tools/miri/tests/fail/tree_borrows/write-during-2phase.stderr index 693d1853550..7f55e06a6bb 100644 --- a/src/tools/miri/tests/fail/tree_borrows/write-during-2phase.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/write-during-2phase.stderr @@ -5,6 +5,7 @@ LL | fn add(&mut self, n: u64) -> u64 { | ^^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> has state Disabled which forbids this reborrow (acting as a child read access) help: the accessed tag <TAG> was created here, in the initial state Reserved --> tests/fail/tree_borrows/write-during-2phase.rs:LL:CC diff --git a/src/tools/miri/tests/fail/validity/dangling_ref1.rs b/src/tools/miri/tests/fail/validity/dangling_ref1.rs index fc3a9f34463..57ba1117e76 100644 --- a/src/tools/miri/tests/fail/validity/dangling_ref1.rs +++ b/src/tools/miri/tests/fail/validity/dangling_ref1.rs @@ -1,5 +1,8 @@ // Make sure we catch this even without Stacked Borrows //@compile-flags: -Zmiri-disable-stacked-borrows + +#![allow(integer_to_ptr_transmutes)] + use std::mem; fn main() { diff --git a/src/tools/miri/tests/panic/oob_subslice.stderr b/src/tools/miri/tests/panic/oob_subslice.stderr index f8270f4ad4d..e1e5bd33d31 100644 --- a/src/tools/miri/tests/panic/oob_subslice.stderr +++ b/src/tools/miri/tests/panic/oob_subslice.stderr @@ -1,5 +1,5 @@ thread 'main' ($TID) panicked at tests/panic/oob_subslice.rs:LL:CC: -range end index 5 out of range for slice of length 4 +range end index 4 out of range for slice of length 4 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect diff --git a/src/tools/miri/tests/panic/transmute_fat2.rs b/src/tools/miri/tests/panic/transmute_fat2.rs index e695ff2d57b..7441f25d03e 100644 --- a/src/tools/miri/tests/panic/transmute_fat2.rs +++ b/src/tools/miri/tests/panic/transmute_fat2.rs @@ -1,3 +1,5 @@ +#![allow(integer_to_ptr_transmutes)] + fn main() { #[cfg(all(target_endian = "little", target_pointer_width = "64"))] let bad = unsafe { std::mem::transmute::<u128, &[u8]>(42) }; diff --git a/src/tools/miri/tests/pass/binops.rs b/src/tools/miri/tests/pass/binops.rs index 0aff7acb29d..fcbe6c85b7b 100644 --- a/src/tools/miri/tests/pass/binops.rs +++ b/src/tools/miri/tests/pass/binops.rs @@ -32,6 +32,7 @@ fn test_bool() { assert_eq!(true ^ true, false); } +#[allow(integer_to_ptr_transmutes)] fn test_ptr() { unsafe { let p1: *const u8 = ::std::mem::transmute(0_usize); diff --git a/src/tools/miri/tests/pass/function_calls/exported_symbol_weak.rs b/src/tools/miri/tests/pass/function_calls/exported_symbol_weak.rs new file mode 100644 index 00000000000..abf4b6718ab --- /dev/null +++ b/src/tools/miri/tests/pass/function_calls/exported_symbol_weak.rs @@ -0,0 +1,39 @@ +#![feature(linkage)] + +// FIXME move this module to a separate crate once aux-build is allowed +// This currently depends on the fact that miri skips the codegen check +// that denies multiple symbols with the same name. +mod first { + #[no_mangle] + #[linkage = "weak"] + extern "C" fn foo() -> i32 { + 1 + } + + #[no_mangle] + #[linkage = "weak"] + extern "C" fn bar() -> i32 { + 2 + } +} + +mod second { + #[no_mangle] + extern "C" fn bar() -> i32 { + 3 + } +} + +extern "C" { + fn foo() -> i32; + fn bar() -> i32; +} + +fn main() { + unsafe { + // If there is no non-weak definition, the weak definition will be used. + assert_eq!(foo(), 1); + // Non-weak definition takes presedence. + assert_eq!(bar(), 3); + } +} diff --git a/src/tools/miri/tests/pass/prefetch.rs b/src/tools/miri/tests/pass/prefetch.rs new file mode 100644 index 00000000000..99c75c38bde --- /dev/null +++ b/src/tools/miri/tests/pass/prefetch.rs @@ -0,0 +1,23 @@ +#![feature(core_intrinsics)] + +// Test that these intrinsics work. Their behavior should be a no-op. + +fn main() { + static X: [u8; 8] = [0; 8]; + + ::std::intrinsics::prefetch_read_data::<_, 1>(::std::ptr::null::<u8>()); + ::std::intrinsics::prefetch_read_data::<_, 2>(::std::ptr::dangling::<u8>()); + ::std::intrinsics::prefetch_read_data::<_, 3>(X.as_ptr()); + + ::std::intrinsics::prefetch_write_data::<_, 1>(::std::ptr::null::<u8>()); + ::std::intrinsics::prefetch_write_data::<_, 2>(::std::ptr::dangling::<u8>()); + ::std::intrinsics::prefetch_write_data::<_, 3>(X.as_ptr()); + + ::std::intrinsics::prefetch_read_instruction::<_, 1>(::std::ptr::null::<u8>()); + ::std::intrinsics::prefetch_read_instruction::<_, 2>(::std::ptr::dangling::<u8>()); + ::std::intrinsics::prefetch_read_instruction::<_, 3>(X.as_ptr()); + + ::std::intrinsics::prefetch_write_instruction::<_, 1>(::std::ptr::null::<u8>()); + ::std::intrinsics::prefetch_write_instruction::<_, 2>(::std::ptr::dangling::<u8>()); + ::std::intrinsics::prefetch_write_instruction::<_, 3>(X.as_ptr()); +} diff --git a/src/tools/miri/tests/pass/too-large-primval-write-problem.rs b/src/tools/miri/tests/pass/too-large-primval-write-problem.rs index f4c418bd78a..00882b7ecca 100644 --- a/src/tools/miri/tests/pass/too-large-primval-write-problem.rs +++ b/src/tools/miri/tests/pass/too-large-primval-write-problem.rs @@ -7,6 +7,8 @@ // // This is just intended as a regression test to make sure we don't reintroduce this problem. +#![allow(integer_to_ptr_transmutes)] + #[cfg(target_pointer_width = "32")] fn main() { use std::mem::transmute; diff --git a/src/tools/miri/triagebot.toml b/src/tools/miri/triagebot.toml index a0ce9f80024..c747cbb0a52 100644 --- a/src/tools/miri/triagebot.toml +++ b/src/tools/miri/triagebot.toml @@ -50,11 +50,14 @@ new_pr = true [autolabel."S-waiting-on-author"] new_draft = true -# Automatically close and reopen PRs made by bots to run CI on them -[bot-pull-requests] - -# Canonicalize issue numbers to avoid closing the wrong issue when upstreaming this subtree +# Canonicalize issue numbers to avoid closing the wrong issue when upstreaming this subtree. [canonicalize-issue-links] -# Prevents mentions in commits to avoid users being spammed +# Prevents mentions in commits to avoid users being spammed. [no-mentions] + +# Show range-diff links on force pushes. +[range-diff] + +# Add link to the review body to review changes since posting it. +[review-changes-since] diff --git a/src/tools/opt-dist/src/exec.rs b/src/tools/opt-dist/src/exec.rs index a8d4c93d160..a3935f98359 100644 --- a/src/tools/opt-dist/src/exec.rs +++ b/src/tools/opt-dist/src/exec.rs @@ -189,6 +189,12 @@ impl Bootstrap { self } + /// Rebuild rustc in case of statically linked LLVM + pub fn rustc_rebuild(mut self) -> Self { + self.cmd = self.cmd.arg("--keep-stage").arg("0"); + self + } + pub fn run(self, timer: &mut TimerSection) -> anyhow::Result<()> { self.cmd.run()?; let metrics = load_metrics(&self.metrics_path)?; diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs index 19706b4a4f0..339c25552ad 100644 --- a/src/tools/opt-dist/src/main.rs +++ b/src/tools/opt-dist/src/main.rs @@ -375,8 +375,14 @@ fn execute_pipeline( let mut dist = Bootstrap::dist(env, &dist_args) .llvm_pgo_optimize(llvm_pgo_profile.as_ref()) - .rustc_pgo_optimize(&rustc_pgo_profile) - .avoid_rustc_rebuild(); + .rustc_pgo_optimize(&rustc_pgo_profile); + + // if LLVM is not built we'll have PGO optimized rustc + dist = if env.supports_shared_llvm() || !env.build_llvm() { + dist.avoid_rustc_rebuild() + } else { + dist.rustc_rebuild() + }; for bolt_profile in bolt_profiles { dist = dist.with_bolt_profile(bolt_profile); diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index e42f266391e..cd7ee6fb4fe 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -97,9 +97,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.98" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" [[package]] name = "autocfg" @@ -124,9 +124,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.1" +version = "2.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +checksum = "6a65b545ab31d687cff52899d4890855fec459eb6afe0da6417b8a18da87aa29" [[package]] name = "block-buffer" @@ -156,9 +156,9 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "cc" -version = "1.2.32" +version = "1.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2352e5597e9c544d5e6d9c95190d5d27738ade584fa8db0a16e130e5c2b5296e" +checksum = "3ee0f8803222ba5a7e2777dd72ca451868909b1ac410621b676adf07280e9b5f" dependencies = [ "shlex", ] @@ -185,9 +185,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.43" +version = "4.5.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50fd97c9dc2399518aa331917ac6f274280ec5eb34e555dd291899745c48ec6f" +checksum = "1fc0e74a703892159f5ae7d3aac52c8e6c392f5ae5f359c70b5881d60aaac318" dependencies = [ "clap_builder", "clap_derive", @@ -195,9 +195,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.43" +version = "4.5.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c35b5830294e1fa0462034af85cc95225a4cb07092c088c55bda3147cfcd8f65" +checksum = "b3e7f4214277f3c7aa526a59dd3fbe306a370daee1f8b7b8c987069cd8e888a8" dependencies = [ "anstream", "anstyle", @@ -208,18 +208,18 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.56" +version = "4.5.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67e4efcbb5da11a92e8a609233aa1e8a7d91e38de0be865f016d14700d45a7fd" +checksum = "4d9501bd3f5f09f7bbee01da9a511073ed30a80cd7a509f1214bb74eadea71ad" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.5.41" +version = "4.5.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef4f52386a59ca4c860f7393bcf8abd8dfd91ecccc0f774635ff68e92eeef491" +checksum = "14cb31bb0a7d536caef2639baa7fad459e15c3144efefa6dbd1c84562c4739f6" dependencies = [ "heck", "proc-macro2", @@ -559,7 +559,7 @@ dependencies = [ "pest_derive", "serde", "serde_json", - "thiserror 2.0.12", + "thiserror 2.0.15", ] [[package]] @@ -1035,7 +1035,7 @@ version = "6.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "336b9c63443aceef14bea841b899035ae3abe89b7c486aaf4c5bd8aafedac3f0" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "libc", "once_cell", "onig_sys", @@ -1104,7 +1104,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323" dependencies = [ "memchr", - "thiserror 2.0.12", + "thiserror 2.0.15", "ucd-trie", ] @@ -1240,9 +1240,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] @@ -1253,7 +1253,7 @@ version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "memchr", "pulldown-cmark-escape 0.10.1", "unicase", @@ -1265,7 +1265,7 @@ version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f86ba2052aebccc42cbbb3ed234b8b13ce76f75c3551a303cb2bcffcff12bb14" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "getopts", "memchr", "pulldown-cmark-escape 0.11.0", @@ -1347,7 +1347,7 @@ version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", ] [[package]] @@ -1385,6 +1385,7 @@ version = "0.1.0" dependencies = [ "clap", "env_logger", + "libc", "mdbook", "mdbook-i18n-helpers", "mdbook-spec", @@ -1397,7 +1398,7 @@ version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "errno", "libc", "linux-raw-sys", @@ -1546,9 +1547,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.104" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", @@ -1612,12 +1613,12 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45c6481c4829e4cc63825e62c49186a34538b7b2750b73b266581ffb612fb5ed" +checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0" dependencies = [ "rustix", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -1637,11 +1638,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.12" +version = "2.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "80d76d3f064b981389ecb4b6b7f45a0bf9fdac1d5b9204c7bd6714fecc302850" dependencies = [ - "thiserror-impl 2.0.12", + "thiserror-impl 2.0.15", ] [[package]] @@ -1657,9 +1658,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "44d29feb33e986b6ea906bd9c3559a856983f92371b3eaa5e83782a351623de0" dependencies = [ "proc-macro2", "quote", @@ -2116,7 +2117,7 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", ] [[package]] diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index c7c6e39f157..b34c39c225d 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -10,6 +10,9 @@ edition = "2021" [dependencies] clap = "4.0.32" env_logger = "0.11" +# FIXME: Remove this pin once this rustix issue is resolved +# https://github.com/bytecodealliance/rustix/issues/1496 +libc = "=0.2.174" mdbook-trpl = { path = "../../doc/book/packages/mdbook-trpl" } mdbook-i18n-helpers = "0.3.3" mdbook-spec = { path = "../../doc/reference/mdbook-spec" } diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index a1e632ce743..ff809d58e90 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -405,6 +405,24 @@ async function runChecks(testFile, doSearch, parseQuery) { return res; } +function mostRecentMatch(staticFiles, regex) { + const matchingEntries = fs.readdirSync(staticFiles) + .filter(f => f.match(regex)) + .map(f => { + const stats = fs.statSync(path.join(staticFiles, f)); + return { + path: f, + time: stats.mtimeMs, + }; + }); + if (matchingEntries.length === 0) { + throw "No static file matching regex"; + } + // We sort entries in descending order. + matchingEntries.sort((a, b) => b.time - a.time); + return matchingEntries[0].path; +} + /** * Load searchNNN.js and search-indexNNN.js. * @@ -417,9 +435,9 @@ async function runChecks(testFile, doSearch, parseQuery) { */ async function loadSearchJS(doc_folder, resource_suffix) { const staticFiles = path.join(doc_folder, "static.files"); - const stringdexJs = fs.readdirSync(staticFiles).find(f => f.match(/stringdex.*\.js$/)); + const stringdexJs = mostRecentMatch(staticFiles, /stringdex.*\.js$/); const stringdexModule = require(path.join(staticFiles, stringdexJs)); - const searchJs = fs.readdirSync(staticFiles).find(f => f.match(/search.*\.js$/)); + const searchJs = mostRecentMatch(staticFiles, /search-[0-9a-f]{8}.*\.js$/); const searchModule = require(path.join(staticFiles, searchJs)); globalThis.nonnull = (x, msg) => { if (x === null) { diff --git a/src/tools/rustfmt/Cargo.toml b/src/tools/rustfmt/Cargo.toml index e497b792342..6392ffbe409 100644 --- a/src/tools/rustfmt/Cargo.toml +++ b/src/tools/rustfmt/Cargo.toml @@ -40,7 +40,7 @@ cargo_metadata = "0.18" clap = { version = "4.4.2", features = ["derive"] } clap-cargo = "0.12.0" diff = "0.1" -dirs = "5.0" +dirs = "6.0" getopts = "0.2" ignore = "0.4" itertools = "0.12" diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index 10df6f96702..6555679c394 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -3600,7 +3600,7 @@ pub(crate) fn rewrite_extern_crate( pub(crate) fn is_mod_decl(item: &ast::Item) -> bool { !matches!( item.kind, - ast::ItemKind::Mod(_, _, ast::ModKind::Loaded(_, ast::Inline::Yes, _, _)) + ast::ItemKind::Mod(_, _, ast::ModKind::Loaded(_, ast::Inline::Yes, _)) ) } diff --git a/src/tools/rustfmt/src/modules.rs b/src/tools/rustfmt/src/modules.rs index 3bc656b64b3..af9feccb32e 100644 --- a/src/tools/rustfmt/src/modules.rs +++ b/src/tools/rustfmt/src/modules.rs @@ -316,11 +316,12 @@ impl<'ast, 'psess, 'c> ModResolver<'ast, 'psess> { self.directory = directory; } match (sub_mod.ast_mod_kind, sub_mod.items) { - (Some(Cow::Borrowed(ast::ModKind::Loaded(items, _, _, _))), _) => { + (Some(Cow::Borrowed(ast::ModKind::Loaded(items, _, _))), _) => { self.visit_mod_from_ast(items) } - (Some(Cow::Owned(ast::ModKind::Loaded(items, _, _, _))), _) - | (_, Cow::Owned(items)) => self.visit_mod_outside_ast(items), + (Some(Cow::Owned(ast::ModKind::Loaded(items, _, _))), _) | (_, Cow::Owned(items)) => { + self.visit_mod_outside_ast(items) + } (_, _) => Ok(()), } } diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs index 23d07c930d9..a3acbb218ff 100644 --- a/src/tools/rustfmt/src/visitor.rs +++ b/src/tools/rustfmt/src/visitor.rs @@ -942,7 +942,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { let ident_str = rewrite_ident(&self.get_context(), ident).to_owned(); self.push_str(&ident_str); - if let ast::ModKind::Loaded(ref items, ast::Inline::Yes, ref spans, _) = mod_kind { + if let ast::ModKind::Loaded(ref items, ast::Inline::Yes, ref spans) = mod_kind { let ast::ModSpans { inner_span, inject_use_span: _, diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 858b058cb7d..80b6d54ce1c 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -592,6 +592,8 @@ pub fn check(root: &Path, cargo: &Path, bless: bool, bad: &mut bool) { if workspace == "library" { check_runtime_license_exceptions(&metadata, bad); + check_runtime_no_duplicate_dependencies(&metadata, bad); + check_runtime_no_proc_macros(&metadata, bad); checked_runtime_licenses = true; } } @@ -790,6 +792,37 @@ fn check_license_exceptions( } } +fn check_runtime_no_duplicate_dependencies(metadata: &Metadata, bad: &mut bool) { + let mut seen_pkgs = HashSet::new(); + for pkg in &metadata.packages { + if pkg.source.is_none() { + continue; + } + + if !seen_pkgs.insert(&*pkg.name) { + tidy_error!( + bad, + "duplicate package `{}` is not allowed for the standard library", + pkg.name + ); + } + } +} + +fn check_runtime_no_proc_macros(metadata: &Metadata, bad: &mut bool) { + for pkg in &metadata.packages { + if pkg.targets.iter().any(|target| target.is_proc_macro()) { + tidy_error!( + bad, + "proc macro `{}` is not allowed as standard library dependency.\n\ + Using proc macros in the standard library would break cross-compilation \ + as proc-macros don't get shipped for the host tuple.", + pkg.name + ); + } + } +} + /// Checks the dependency of `restricted_dependency_crates` at the given path. Changes `bad` to /// `true` if a check failed. /// diff --git a/src/tools/tidy/src/extra_checks/mod.rs b/src/tools/tidy/src/extra_checks/mod.rs index f90f716cd95..31169ec5967 100644 --- a/src/tools/tidy/src/extra_checks/mod.rs +++ b/src/tools/tidy/src/extra_checks/mod.rs @@ -41,7 +41,6 @@ const RUFF_CONFIG_PATH: &[&str] = &["src", "tools", "tidy", "config", "ruff.toml const RUFF_CACHE_PATH: &[&str] = &["cache", "ruff_cache"]; const PIP_REQ_PATH: &[&str] = &["src", "tools", "tidy", "config", "requirements.txt"]; -// this must be kept in sync with with .github/workflows/spellcheck.yml const SPELLCHECK_DIRS: &[&str] = &["compiler", "library", "src/bootstrap", "src/librustdoc"]; pub fn check( @@ -51,6 +50,7 @@ pub fn check( librustdoc_path: &Path, tools_path: &Path, npm: &Path, + cargo: &Path, bless: bool, extra_checks: Option<&str>, pos_args: &[String], @@ -63,6 +63,7 @@ pub fn check( librustdoc_path, tools_path, npm, + cargo, bless, extra_checks, pos_args, @@ -78,6 +79,7 @@ fn check_impl( librustdoc_path: &Path, tools_path: &Path, npm: &Path, + cargo: &Path, bless: bool, extra_checks: Option<&str>, pos_args: &[String], @@ -293,7 +295,7 @@ fn check_impl( } else { eprintln!("spellcheck files"); } - spellcheck_runner(&args)?; + spellcheck_runner(root_path, &outdir, &cargo, &args)?; } if js_lint || js_typecheck { @@ -576,34 +578,25 @@ fn shellcheck_runner(args: &[&OsStr]) -> Result<(), Error> { if status.success() { Ok(()) } else { Err(Error::FailedCheck("shellcheck")) } } -/// Check that spellchecker is installed then run it at the given path -fn spellcheck_runner(args: &[&str]) -> Result<(), Error> { - // sync version with .github/workflows/spellcheck.yml - let expected_version = "typos-cli 1.34.0"; - match Command::new("typos").arg("--version").output() { - Ok(o) => { - let stdout = String::from_utf8_lossy(&o.stdout); - if stdout.trim() != expected_version { - return Err(Error::Version { - program: "typos", - required: expected_version, - installed: stdout.trim().to_string(), - }); +/// Ensure that spellchecker is installed then run it at the given path +fn spellcheck_runner( + src_root: &Path, + outdir: &Path, + cargo: &Path, + args: &[&str], +) -> Result<(), Error> { + let bin_path = + crate::ensure_version_or_cargo_install(outdir, cargo, "typos-cli", "typos", "1.34.0")?; + match Command::new(bin_path).current_dir(src_root).args(args).status() { + Ok(status) => { + if status.success() { + Ok(()) + } else { + Err(Error::FailedCheck("typos")) } } - Err(e) if e.kind() == io::ErrorKind::NotFound => { - return Err(Error::MissingReq( - "typos", - "spellcheck file checks", - // sync version with .github/workflows/spellcheck.yml - Some("install tool via `cargo install typos-cli@1.34.0`".to_owned()), - )); - } - Err(e) => return Err(e.into()), + Err(err) => Err(Error::Generic(format!("failed to run typos tool: {err:?}"))), } - - let status = Command::new("typos").args(args).status()?; - if status.success() { Ok(()) } else { Err(Error::FailedCheck("typos")) } } /// Check git for tracked files matching an extension diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 4ea9d051ddb..37713cbf75e 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -4,7 +4,9 @@ //! to be used by tools. use std::ffi::OsStr; +use std::path::{Path, PathBuf}; use std::process::Command; +use std::{env, io}; use build_helper::ci::CiEnv; use build_helper::git::{GitConfig, get_closest_upstream_commit}; @@ -180,6 +182,70 @@ pub fn files_modified(ci_info: &CiInfo, pred: impl Fn(&str) -> bool) -> bool { !v.is_empty() } +/// If the given executable is installed with the given version, use that, +/// otherwise install via cargo. +pub fn ensure_version_or_cargo_install( + build_dir: &Path, + cargo: &Path, + pkg_name: &str, + bin_name: &str, + version: &str, +) -> io::Result<PathBuf> { + // ignore the process exit code here and instead just let the version number check fail. + // we also importantly don't return if the program wasn't installed, + // instead we want to continue to the fallback. + 'ck: { + // FIXME: rewrite as if-let chain once this crate is 2024 edition. + let Ok(output) = Command::new(bin_name).arg("--version").output() else { + break 'ck; + }; + let Ok(s) = str::from_utf8(&output.stdout) else { + break 'ck; + }; + let Some(v) = s.trim().split_whitespace().last() else { + break 'ck; + }; + if v == version { + return Ok(PathBuf::from(bin_name)); + } + } + + let tool_root_dir = build_dir.join("misc-tools"); + let tool_bin_dir = tool_root_dir.join("bin"); + eprintln!("building external tool {bin_name} from package {pkg_name}@{version}"); + // use --force to ensure that if the required version is bumped, we update it. + // use --target-dir to ensure we have a build cache so repeated invocations aren't slow. + // modify PATH so that cargo doesn't print a warning telling the user to modify the path. + let cargo_exit_code = Command::new(cargo) + .args(["install", "--locked", "--force", "--quiet"]) + .arg("--root") + .arg(&tool_root_dir) + .arg("--target-dir") + .arg(tool_root_dir.join("target")) + .arg(format!("{pkg_name}@{version}")) + .env( + "PATH", + env::join_paths( + env::split_paths(&env::var("PATH").unwrap()) + .chain(std::iter::once(tool_bin_dir.clone())), + ) + .expect("build dir contains invalid char"), + ) + .env("RUSTFLAGS", "-Copt-level=0") + .spawn()? + .wait()?; + if !cargo_exit_code.success() { + return Err(io::Error::other("cargo install failed")); + } + let bin_path = tool_bin_dir.join(bin_name); + assert!( + matches!(bin_path.try_exists(), Ok(true)), + "cargo install did not produce the expected binary" + ); + eprintln!("finished building tool {bin_name}"); + Ok(bin_path) +} + pub mod alphabetical; pub mod bins; pub mod debug_artifacts; diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index cd2567ddb64..bfe30258915 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -184,6 +184,7 @@ fn main() { &librustdoc_path, &tools_path, &npm, + &cargo, bless, extra_checks, pos_args  | 
