diff --git a/Cargo.lock b/Cargo.lock index d5c9a5e4d0d0..bf31bf72d4c1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -593,7 +593,6 @@ dependencies = [ "syn 2.0.55", "tempfile", "termize", - "tester", "tokio", "toml 0.7.8", "ui_test 0.22.2", @@ -5508,19 +5507,6 @@ dependencies = [ "std", ] -[[package]] -name = "tester" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e8bf7e0eb2dd7b4228cc1b6821fc5114cd6841ae59f652a85488c016091e5f" -dependencies = [ - "cfg-if", - "getopts", - "libc", - "num_cpus", - "term", -] - [[package]] name = "thin-vec" version = "0.2.13" diff --git a/README.md b/README.md index 6d6383351caf..3690a9c93c52 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,36 @@ -# The Rust Programming Language +
+ + + + The Rust Programming Language: A language empowering everyone to build reliable and efficient software + -[![Rust Community](https://img.shields.io/badge/Rust_Community%20-Join_us-brightgreen?style=plastic&logo=rust)](https://www.rust-lang.org/community) +[Website][Rust] | [Getting started] | [Learn] | [Documentation] | [Contributing] +
This is the main source code repository for [Rust]. It contains the compiler, standard library, and documentation. [Rust]: https://www.rust-lang.org/ +[Getting Started]: https://www.rust-lang.org/learn/get-started +[Learn]: https://www.rust-lang.org/learn +[Documentation]: https://www.rust-lang.org/learn#learn-use +[Contributing]: CONTRIBUTING.md -**Note: this README is for _users_ rather than _contributors_.** -If you wish to _contribute_ to the compiler, you should read -[CONTRIBUTING.md](CONTRIBUTING.md) instead. +## Why Rust? -
-Table of Contents +- **Performance:** Fast and memory-efficient, suitable for critical services, embedded devices, and easily integrate with other languages. -- [Quick Start](#quick-start) -- [Installing from Source](#installing-from-source) -- [Getting Help](#getting-help) -- [Contributing](#contributing) -- [License](#license) -- [Trademark](#trademark) +- **Reliability:** Our rich type system and ownership model ensure memory and thread safety, reducing bugs at compile-time. -
+- **Productivity:** Comprehensive documentation, a compiler committed to providing great diagnostics, and advanced tooling including package manager and build tool ([Cargo]), auto-formatter ([rustfmt]), linter ([Clippy]) and editor support ([rust-analyzer]). + +[Cargo]: https://github.com/rust-lang/cargo +[rustfmt]: https://github.com/rust-lang/rustfmt +[Clippy]: https://github.com/rust-lang/rust-clippy +[rust-analyzer]: https://github.com/rust-lang/rust-analyzer ## Quick Start diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index c10a6258d397..e29ef591bcb5 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2484,6 +2484,14 @@ pub enum CoroutineKind { } impl CoroutineKind { + pub fn span(self) -> Span { + match self { + CoroutineKind::Async { span, .. } => span, + CoroutineKind::Gen { span, .. } => span, + CoroutineKind::AsyncGen { span, .. } => span, + } + } + pub fn is_async(self) -> bool { matches!(self, CoroutineKind::Async { .. }) } diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 402044c7af9d..1c34fd0afbb6 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -19,7 +19,7 @@ struct NodeCollector<'a, 'hir> { parenting: LocalDefIdMap, /// The parent of this node - parent_node: hir::ItemLocalId, + parent_node: ItemLocalId, owner: OwnerId, } @@ -31,17 +31,16 @@ pub(super) fn index_hir<'hir>( bodies: &SortedMap>, num_nodes: usize, ) -> (IndexVec>, LocalDefIdMap) { - let zero_id = ItemLocalId::ZERO; - let err_node = ParentedNode { parent: zero_id, node: Node::Err(item.span()) }; + let err_node = ParentedNode { parent: ItemLocalId::ZERO, node: Node::Err(item.span()) }; let mut nodes = IndexVec::from_elem_n(err_node, num_nodes); // This node's parent should never be accessed: the owner's parent is computed by the // hir_owner_parent query. Make it invalid (= ItemLocalId::MAX) to force an ICE whenever it is // used. - nodes[zero_id] = ParentedNode { parent: ItemLocalId::INVALID, node: item.into() }; + nodes[ItemLocalId::ZERO] = ParentedNode { parent: ItemLocalId::INVALID, node: item.into() }; let mut collector = NodeCollector { tcx, owner: item.def_id(), - parent_node: zero_id, + parent_node: ItemLocalId::ZERO, nodes, bodies, parenting: Default::default(), @@ -112,7 +111,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { } fn insert_nested(&mut self, item: LocalDefId) { - if self.parent_node.as_u32() != 0 { + if self.parent_node != ItemLocalId::ZERO { self.parenting.insert(item, self.parent_node); } } diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 28a13d275a55..ac3799e7a056 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -68,7 +68,7 @@ ast_passes_extern_block_suggestion = if you meant to declare an externally defin ast_passes_extern_fn_qualifiers = functions in `extern` blocks cannot have qualifiers .label = in this `extern` block - .suggestion = remove the qualifiers + .suggestion = remove this qualifier ast_passes_extern_item_ascii = items in `extern` blocks cannot use non-ascii identifiers .label = in this `extern` block diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 80c62d3fecf4..093a985495c9 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -514,13 +514,32 @@ impl<'a> AstValidator<'a> { } /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`. - fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) { - if header.has_qualifiers() { + fn check_foreign_fn_headerless( + &self, + // Deconstruct to ensure exhaustiveness + FnHeader { unsafety, coroutine_kind, constness, ext }: FnHeader, + ) { + let report_err = |span| { self.dcx().emit_err(errors::FnQualifierInExtern { - span: ident.span, + span: span, block: self.current_extern_span(), - sugg_span: span.until(ident.span.shrink_to_lo()), }); + }; + match unsafety { + Unsafe::Yes(span) => report_err(span), + Unsafe::No => (), + } + match coroutine_kind { + Some(knd) => report_err(knd.span()), + None => (), + } + match constness { + Const::Yes(span) => report_err(span), + Const::No => (), + } + match ext { + Extern::None => (), + Extern::Implicit(span) | Extern::Explicit(_, span) => report_err(span), } } @@ -1145,7 +1164,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => { self.check_defaultness(fi.span, *defaultness); self.check_foreign_fn_bodyless(fi.ident, body.as_deref()); - self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header); + self.check_foreign_fn_headerless(sig.header); self.check_foreign_item_ascii_only(fi.ident); } ForeignItemKind::TyAlias(box TyAlias { diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 9e8c1d7f5fd1..8ae9f7d3966f 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -270,11 +270,10 @@ pub struct FnBodyInExtern { #[diag(ast_passes_extern_fn_qualifiers)] pub struct FnQualifierInExtern { #[primary_span] + #[suggestion(code = "", applicability = "maybe-incorrect")] pub span: Span, #[label] pub block: Span, - #[suggestion(code = "fn ", applicability = "maybe-incorrect", style = "verbose")] - pub sugg_span: Span, } #[derive(Diagnostic)] diff --git a/compiler/rustc_codegen_cranelift/.cirrus.yml b/compiler/rustc_codegen_cranelift/.cirrus.yml index aa1a2bad2cf2..97c2f45d31e2 100644 --- a/compiler/rustc_codegen_cranelift/.cirrus.yml +++ b/compiler/rustc_codegen_cranelift/.cirrus.yml @@ -13,4 +13,7 @@ task: - ./y.sh prepare test_script: - . $HOME/.cargo/env + # Disabling incr comp reduces cache size and incr comp doesn't save as much + # on CI anyway. + - export CARGO_BUILD_INCREMENTAL=false - ./y.sh test diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml b/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml index e6bf944f5527..a745f2801cc4 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml @@ -3,6 +3,8 @@ name: Abi-cafe on: - push +permissions: {} + jobs: abi_cafe: runs-on: ${{ matrix.os }} diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml index 526871d0c05f..913a5c5a8500 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml @@ -4,6 +4,20 @@ on: - push - pull_request +defaults: + run: + shell: bash + +permissions: {} + +env: + # Disabling incr comp reduces cache size and incr comp doesn't save as much + # on CI anyway. + CARGO_BUILD_INCREMENTAL: false + # Rust's CI denies warnings. Deny them here too to ensure subtree syncs don't + # fail because of warnings. + RUSTFLAGS: "-Dwarnings" + jobs: rustfmt: runs-on: ubuntu-latest @@ -23,15 +37,15 @@ jobs: cargo fmt --check rustfmt --check build_system/main.rs rustfmt --check example/* + rustfmt --check scripts/*.rs test: runs-on: ${{ matrix.os }} timeout-minutes: 60 - defaults: - run: - shell: bash + env: + CG_CLIF_EXPENSIVE_CHECKS: 1 strategy: fail-fast: false @@ -47,15 +61,19 @@ jobs: - os: ubuntu-latest env: TARGET_TRIPLE: x86_64-pc-windows-gnu + apt_deps: gcc-mingw-w64-x86-64 wine-stable - os: ubuntu-latest env: TARGET_TRIPLE: aarch64-unknown-linux-gnu + apt_deps: gcc-aarch64-linux-gnu qemu-user - os: ubuntu-latest env: TARGET_TRIPLE: s390x-unknown-linux-gnu + apt_deps: gcc-s390x-linux-gnu qemu-user - os: ubuntu-latest env: TARGET_TRIPLE: riscv64gc-unknown-linux-gnu + apt_deps: gcc-riscv64-linux-gnu qemu-user - os: windows-latest env: TARGET_TRIPLE: x86_64-pc-windows-msvc @@ -80,29 +98,11 @@ jobs: if: matrix.os == 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu' run: rustup set default-host x86_64-pc-windows-gnu - - name: Install MinGW toolchain and wine - if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu' + - name: Install toolchain and emulator + if: matrix.apt_deps != null run: | sudo apt-get update - sudo apt-get install -y gcc-mingw-w64-x86-64 wine-stable - - - name: Install AArch64 toolchain and qemu - if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'aarch64-unknown-linux-gnu' - run: | - sudo apt-get update - sudo apt-get install -y gcc-aarch64-linux-gnu qemu-user - - - name: Install s390x toolchain and qemu - if: matrix.env.TARGET_TRIPLE == 's390x-unknown-linux-gnu' - run: | - sudo apt-get update - sudo apt-get install -y gcc-s390x-linux-gnu qemu-user - - - name: Install riscv64gc toolchain and qemu - if: matrix.env.TARGET_TRIPLE == 'riscv64gc-unknown-linux-gnu' - run: | - sudo apt-get update - sudo apt-get install -y gcc-riscv64-linux-gnu qemu-user + sudo apt-get install -y ${{ matrix.apt_deps }} - name: Prepare dependencies run: ./y.sh prepare @@ -142,10 +142,6 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 60 - defaults: - run: - shell: bash - steps: - uses: actions/checkout@v4 @@ -168,10 +164,6 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 60 - defaults: - run: - shell: bash - steps: - uses: actions/checkout@v4 @@ -193,20 +185,16 @@ jobs: run: ./y.sh prepare - name: Build - run: CI_OPT=1 ./y.sh build --sysroot none + run: ./y.sh build --sysroot none - name: Benchmark - run: CI_OPT=1 ./y.sh bench + run: ./y.sh bench dist: runs-on: ${{ matrix.os }} timeout-minutes: 60 - defaults: - run: - shell: bash - strategy: fail-fast: false matrix: @@ -252,10 +240,10 @@ jobs: run: ./y.sh prepare - name: Build backend - run: CI_OPT=1 ./y.sh build --sysroot none + run: ./y.sh build --sysroot none - name: Build sysroot - run: CI_OPT=1 ./y.sh build + run: ./y.sh build - name: Package prebuilt cg_clif run: tar cvfJ cg_clif.tar.xz dist diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml b/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml index 930d025b73ed..75ea94ee7979 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml @@ -3,6 +3,8 @@ name: Various rustc tests on: - push +permissions: {} + jobs: bootstrap_rustc: runs-on: ubuntu-latest diff --git a/compiler/rustc_codegen_cranelift/Readme.md b/compiler/rustc_codegen_cranelift/Readme.md index a297b22326f3..00ea15cb38cc 100644 --- a/compiler/rustc_codegen_cranelift/Readme.md +++ b/compiler/rustc_codegen_cranelift/Readme.md @@ -101,27 +101,7 @@ For additional ways to use rustc_codegen_cranelift like the JIT mode see [usage. ## Building and testing with changes in rustc code -This is useful when changing code in `rustc_codegen_cranelift` as part of changing [main Rust repository](https://github.com/rust-lang/rust/). -This can happen, for example, when you are implementing a new compiler intrinsic. - -Instruction below uses `$RustCheckoutDir` as substitute for any folder where you cloned Rust repository. - -You need to do this steps to successfully compile and use the cranelift backend with your changes in rustc code: - -1. `cd $RustCheckoutDir` -2. Run `python x.py setup` and choose option for compiler (`b`). -3. Build compiler and necessary tools: `python x.py build --stage=2 compiler library/std src/tools/rustdoc src/tools/rustfmt` - * (Optional) You can also build cargo by adding `src/tools/cargo` to previous command. -4. Copy cargo from a nightly toolchain: `cp $(rustup +nightly which cargo) ./build/host/stage2/bin/cargo`. Note that you would need to do this every time you rebuilt `rust` repository. -5. Link your new `rustc` to toolchain: `rustup toolchain link stage2 ./build/host/stage2/`. -6. (Windows only) compile the build system: `rustc +stage2 -O build_system/main.rs -o y.exe`. -7. You need to prefix every `./y.sh` (or `y` if you built `build_system/main.rs` as `y`) command by `rustup run stage2` to make cg_clif use your local changes in rustc. - * `rustup run stage2 ./y.sh prepare` - * `rustup run stage2 ./y.sh build` - * (Optional) run tests: `rustup run stage2 ./y.sh test` -8. Now you can use your cg_clif build to compile other Rust programs, e.g. you can open any Rust crate and run commands like `$RustCheckoutDir/compiler/rustc_codegen_cranelift/dist/cargo-clif build --release`. - -You can also set `rust-analyzer.rustc.source` to your rust workspace to get rust-analyzer to understand your changes. +See [rustc_testing.md](docs/rustc_testing.md). ## Not yet supported diff --git a/compiler/rustc_codegen_cranelift/build_system/build_backend.rs b/compiler/rustc_codegen_cranelift/build_system/build_backend.rs index d90111adf776..129713e574ad 100644 --- a/compiler/rustc_codegen_cranelift/build_system/build_backend.rs +++ b/compiler/rustc_codegen_cranelift/build_system/build_backend.rs @@ -1,9 +1,10 @@ +use std::env; use std::path::PathBuf; use crate::path::{Dirs, RelPath}; use crate::rustc_info::get_file_name; use crate::shared_utils::{rustflags_from_env, rustflags_to_cmd_env}; -use crate::utils::{is_ci, is_ci_opt, maybe_incremental, CargoProject, Compiler, LogGroup}; +use crate::utils::{CargoProject, Compiler, LogGroup}; pub(crate) static CG_CLIF: CargoProject = CargoProject::new(&RelPath::SOURCE, "cg_clif"); @@ -16,20 +17,15 @@ pub(crate) fn build_backend( let _group = LogGroup::guard("Build backend"); let mut cmd = CG_CLIF.build(&bootstrap_host_compiler, dirs); - maybe_incremental(&mut cmd); let mut rustflags = rustflags_from_env("RUSTFLAGS"); rustflags.push("-Zallow-features=rustc_private".to_owned()); - if is_ci() { - // Deny warnings on CI - rustflags.push("-Dwarnings".to_owned()); - - if !is_ci_opt() { - cmd.env("CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS", "true"); - cmd.env("CARGO_PROFILE_RELEASE_OVERFLOW_CHECKS", "true"); - } + if env::var("CG_CLIF_EXPENSIVE_CHECKS").is_ok() { + // Enabling debug assertions implicitly enables the clif ir verifier + cmd.env("CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS", "true"); + cmd.env("CARGO_PROFILE_RELEASE_OVERFLOW_CHECKS", "true"); } if use_unstable_features { diff --git a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs index 1ed896c6bf0e..10c3f9cfa2ce 100644 --- a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs +++ b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs @@ -6,8 +6,7 @@ use std::process::Command; use crate::path::{Dirs, RelPath}; use crate::rustc_info::get_file_name; use crate::utils::{ - maybe_incremental, remove_dir_if_exists, spawn_and_wait, try_hard_link, CargoProject, Compiler, - LogGroup, + remove_dir_if_exists, spawn_and_wait, try_hard_link, CargoProject, Compiler, LogGroup, }; use crate::{config, CodegenBackend, SysrootKind}; @@ -270,7 +269,6 @@ fn build_clif_sysroot_for_triple( } compiler.rustflags.extend(rustflags); let mut build_cmd = STANDARD_LIBRARY.build(&compiler, dirs); - maybe_incremental(&mut build_cmd); if channel == "release" { build_cmd.arg("--release"); } diff --git a/compiler/rustc_codegen_cranelift/build_system/main.rs b/compiler/rustc_codegen_cranelift/build_system/main.rs index e8cf486e966e..cdd2bae03f8f 100644 --- a/compiler/rustc_codegen_cranelift/build_system/main.rs +++ b/compiler/rustc_codegen_cranelift/build_system/main.rs @@ -6,7 +6,7 @@ use std::env; use std::path::PathBuf; use std::process; -use self::utils::{is_ci, is_ci_opt, Compiler}; +use self::utils::Compiler; mod abi_cafe; mod bench; @@ -60,14 +60,9 @@ fn main() { } env::set_var("CG_CLIF_DISABLE_INCR_CACHE", "1"); - if is_ci() { - // Disabling incr comp reduces cache size and incr comp doesn't save as much on CI anyway - env::set_var("CARGO_BUILD_INCREMENTAL", "false"); - - if !is_ci_opt() { - // Enable the Cranelift verifier - env::set_var("CG_CLIF_ENABLE_VERIFIER", "1"); - } + // Force incr comp even in release mode unless in CI or incremental builds are explicitly disabled + if env::var_os("CARGO_BUILD_INCREMENTAL").is_none() { + env::set_var("CARGO_BUILD_INCREMENTAL", "true"); } let mut args = env::args().skip(1); diff --git a/compiler/rustc_codegen_cranelift/build_system/prepare.rs b/compiler/rustc_codegen_cranelift/build_system/prepare.rs index 3677d0a7d360..5525a5f63e93 100644 --- a/compiler/rustc_codegen_cranelift/build_system/prepare.rs +++ b/compiler/rustc_codegen_cranelift/build_system/prepare.rs @@ -15,7 +15,6 @@ pub(crate) fn prepare(dirs: &Dirs) { RelPath::DOWNLOAD.ensure_exists(dirs); crate::tests::RAND_REPO.fetch(dirs); crate::tests::REGEX_REPO.fetch(dirs); - crate::tests::PORTABLE_SIMD_REPO.fetch(dirs); } pub(crate) fn prepare_stdlib(dirs: &Dirs, rustc: &Path) { diff --git a/compiler/rustc_codegen_cranelift/build_system/tests.rs b/compiler/rustc_codegen_cranelift/build_system/tests.rs index 1c3e615c7aba..9efb6ed715ca 100644 --- a/compiler/rustc_codegen_cranelift/build_system/tests.rs +++ b/compiler/rustc_codegen_cranelift/build_system/tests.rs @@ -130,16 +130,10 @@ pub(crate) static REGEX_REPO: GitRepo = GitRepo::github( pub(crate) static REGEX: CargoProject = CargoProject::new(®EX_REPO.source_dir(), "regex_target"); -pub(crate) static PORTABLE_SIMD_REPO: GitRepo = GitRepo::github( - "rust-lang", - "portable-simd", - "5794c837bc605c4cd9dbb884285976dfdb293cce", - "a64d8fdd0ed0d9c4", - "portable-simd", -); +pub(crate) static PORTABLE_SIMD_SRC: RelPath = RelPath::BUILD.join("coretests"); pub(crate) static PORTABLE_SIMD: CargoProject = - CargoProject::new(&PORTABLE_SIMD_REPO.source_dir(), "portable-simd_target"); + CargoProject::new(&PORTABLE_SIMD_SRC, "portable-simd_target"); static LIBCORE_TESTS_SRC: RelPath = RelPath::BUILD.join("coretests"); @@ -221,7 +215,12 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[ } }), TestCase::custom("test.portable-simd", &|runner| { - PORTABLE_SIMD_REPO.patch(&runner.dirs); + apply_patches( + &runner.dirs, + "portable-simd", + &runner.stdlib_source.join("library/portable-simd"), + &PORTABLE_SIMD_SRC.to_path(&runner.dirs), + ); PORTABLE_SIMD.clean(&runner.dirs); diff --git a/compiler/rustc_codegen_cranelift/build_system/utils.rs b/compiler/rustc_codegen_cranelift/build_system/utils.rs index 149f1618f5c0..9f95122b341c 100644 --- a/compiler/rustc_codegen_cranelift/build_system/utils.rs +++ b/compiler/rustc_codegen_cranelift/build_system/utils.rs @@ -254,14 +254,6 @@ pub(crate) fn copy_dir_recursively(from: &Path, to: &Path) { } } -pub(crate) fn is_ci() -> bool { - env::var("CI").is_ok() -} - -pub(crate) fn is_ci_opt() -> bool { - env::var("CI_OPT").is_ok() -} - static IN_GROUP: AtomicBool = AtomicBool::new(false); pub(crate) struct LogGroup { is_gha: bool, @@ -288,13 +280,3 @@ impl Drop for LogGroup { IN_GROUP.store(false, Ordering::SeqCst); } } - -pub(crate) fn maybe_incremental(cmd: &mut Command) { - if is_ci() || std::env::var("CARGO_BUILD_INCREMENTAL").map_or(false, |val| val == "false") { - // Disabling incr comp reduces cache size and incr comp doesn't save as much on CI anyway - cmd.env("CARGO_BUILD_INCREMENTAL", "false"); - } else { - // Force incr comp even in release mode unless in CI or incremental builds are explicitly disabled - cmd.env("CARGO_BUILD_INCREMENTAL", "true"); - } -} diff --git a/compiler/rustc_codegen_cranelift/docs/rustc_testing.md b/compiler/rustc_codegen_cranelift/docs/rustc_testing.md new file mode 100644 index 000000000000..88c555572318 --- /dev/null +++ b/compiler/rustc_codegen_cranelift/docs/rustc_testing.md @@ -0,0 +1,23 @@ +# Building and testing with changes in rustc code + +This is useful when changing code in `rustc_codegen_cranelift` as part of changing [main Rust repository](https://github.com/rust-lang/rust/). +This can happen, for example, when you are implementing a new compiler intrinsic. + +Instruction below uses `$RustCheckoutDir` as substitute for any folder where you cloned Rust repository. + +You need to do this steps to successfully compile and use the cranelift backend with your changes in rustc code: + +1. `cd $RustCheckoutDir` +2. Run `python x.py setup` and choose option for compiler (`b`). +3. Build compiler and necessary tools: `python x.py build --stage=2 compiler library/std src/tools/rustdoc src/tools/rustfmt` + * (Optional) You can also build cargo by adding `src/tools/cargo` to previous command. +4. Copy cargo from a nightly toolchain: `cp $(rustup +nightly which cargo) ./build/host/stage2/bin/cargo`. Note that you would need to do this every time you rebuilt `rust` repository. +5. Link your new `rustc` to toolchain: `rustup toolchain link stage2 ./build/host/stage2/`. +6. (Windows only) compile the build system: `rustc +stage2 -O build_system/main.rs -o y.exe`. +7. You need to prefix every `./y.sh` (or `y` if you built `build_system/main.rs` as `y`) command by `rustup run stage2` to make cg_clif use your local changes in rustc. + * `rustup run stage2 ./y.sh prepare` + * `rustup run stage2 ./y.sh build` + * (Optional) run tests: `rustup run stage2 ./y.sh test` +8. Now you can use your cg_clif build to compile other Rust programs, e.g. you can open any Rust crate and run commands like `$RustCheckoutDir/compiler/rustc_codegen_cranelift/dist/cargo-clif build --release`. + +You can also set `rust-analyzer.rustc.source` to your rust workspace to get rust-analyzer to understand your changes. diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs index 1cee51319078..e45c16ee280a 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs @@ -90,8 +90,9 @@ unsafe impl Sync for i16 {} unsafe impl Sync for i32 {} unsafe impl Sync for isize {} unsafe impl Sync for char {} +unsafe impl Sync for f32 {} unsafe impl<'a, T: ?Sized> Sync for &'a T {} -unsafe impl Sync for [u8; 16] {} +unsafe impl Sync for [T; N] {} #[lang = "freeze"] unsafe auto trait Freeze {} @@ -467,7 +468,6 @@ pub fn panic(_msg: &'static str) -> ! { macro_rules! panic_const { ($($lang:ident = $message:expr,)+) => { - #[cfg(not(bootstrap))] pub mod panic_const { use super::*; diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain index 612fc61ec27d..09e436b3eed0 100644 --- a/compiler/rustc_codegen_cranelift/rust-toolchain +++ b/compiler/rustc_codegen_cranelift/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-03-28" +channel = "nightly-2024-04-05" components = ["rust-src", "rustc-dev", "llvm-tools"] diff --git a/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs b/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs index 03912b18ea5f..0252d5b33403 100755 --- a/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs +++ b/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs @@ -1,5 +1,5 @@ #!/usr/bin/env bash -#![forbid(unsafe_code)]/* This line is ignored by bash +#![rustfmt::skip]/* This line is ignored by bash # This block is ignored by rustc pushd $(dirname "$0")/../ RUSTC="$(pwd)/dist/rustc-clif" @@ -26,11 +26,8 @@ fn main() -> Result<(), Box> { } let profile = std::fs::read_to_string(profile_name) .map_err(|err| format!("Failed to read profile {}", err))?; - let mut output = std::fs::OpenOptions::new() - .create(true) - .write(true) - .truncate(true) - .open(output_name)?; + let mut output = + std::fs::OpenOptions::new().create(true).write(true).truncate(true).open(output_name)?; for line in profile.lines() { let mut stack = &line[..line.rfind(" ").unwrap()]; diff --git a/compiler/rustc_codegen_cranelift/src/num.rs b/compiler/rustc_codegen_cranelift/src/num.rs index 796182418ad6..714858084ec9 100644 --- a/compiler/rustc_codegen_cranelift/src/num.rs +++ b/compiler/rustc_codegen_cranelift/src/num.rs @@ -130,7 +130,7 @@ pub(crate) fn codegen_int_binop<'tcx>( in_lhs: CValue<'tcx>, in_rhs: CValue<'tcx>, ) -> CValue<'tcx> { - if bin_op != BinOp::Shl && bin_op != BinOp::Shr { + if !matches!(bin_op, BinOp::Shl | BinOp::ShlUnchecked | BinOp::Shr | BinOp::ShrUnchecked) { assert_eq!( in_lhs.layout().ty, in_rhs.layout().ty, diff --git a/compiler/rustc_codegen_gcc/Cargo.lock b/compiler/rustc_codegen_gcc/Cargo.lock index ab2c7ca8a47c..3ecb0ef6b4d2 100644 --- a/compiler/rustc_codegen_gcc/Cargo.lock +++ b/compiler/rustc_codegen_gcc/Cargo.lock @@ -79,16 +79,18 @@ dependencies = [ [[package]] name = "gccjit" -version = "1.0.0" -source = "git+https://github.com/antoyo/gccjit.rs#9f8f67edc006d543b17529a001803ffece48349e" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecaa4c3da2d74c1a991b4faff75d49ab1d0522d9a99d8e2614b3b04d226417ce" dependencies = [ "gccjit_sys", ] [[package]] name = "gccjit_sys" -version = "0.0.1" -source = "git+https://github.com/antoyo/gccjit.rs#9f8f67edc006d543b17529a001803ffece48349e" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "406a66fba005f1a02661f2f9443e5693dd3a667b7c58e70aa4ccc4c8b50b4758" dependencies = [ "libc", ] diff --git a/compiler/rustc_codegen_gcc/Cargo.toml b/compiler/rustc_codegen_gcc/Cargo.toml index 100c10ef1d7a..c5aa2eed1e00 100644 --- a/compiler/rustc_codegen_gcc/Cargo.toml +++ b/compiler/rustc_codegen_gcc/Cargo.toml @@ -22,7 +22,7 @@ master = ["gccjit/master"] default = ["master"] [dependencies] -gccjit = { git = "https://github.com/antoyo/gccjit.rs" } +gccjit = "2.0" # Local copy. #gccjit = { path = "../gccjit.rs" } diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 4efea66a7f1e..68ba8cbf7b77 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -912,6 +912,7 @@ fn target_is_apple(cgcx: &CodegenContext) -> bool { || cgcx.opts.target_triple.triple().contains("-darwin") || cgcx.opts.target_triple.triple().contains("-tvos") || cgcx.opts.target_triple.triple().contains("-watchos") + || cgcx.opts.target_triple.triple().contains("-visionos") } fn target_is_aix(cgcx: &CodegenContext) -> bool { diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 278db21b0a1f..3f3969bbca35 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -17,11 +17,11 @@ use rustc_span::Symbol; /// Generates and exports the Coverage Map. /// -/// Rust Coverage Map generation supports LLVM Coverage Mapping Format version -/// 6 (zero-based encoded as 5), as defined at -/// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format). +/// Rust Coverage Map generation supports LLVM Coverage Mapping Format versions +/// 6 and 7 (encoded as 5 and 6 respectively), as described at +/// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/18.0-2024-02-13/llvm/docs/CoverageMappingFormat.rst). /// These versions are supported by the LLVM coverage tools (`llvm-profdata` and `llvm-cov`) -/// bundled with Rust's fork of LLVM. +/// distributed in the `llvm-tools-preview` rustup component. /// /// Consequently, Rust's bundled version of Clang also generates Coverage Maps compliant with /// the same version. Clang's implementation of Coverage Map generation was referenced when @@ -31,10 +31,21 @@ use rustc_span::Symbol; pub fn finalize(cx: &CodegenCx<'_, '_>) { let tcx = cx.tcx; - // Ensure the installed version of LLVM supports Coverage Map Version 6 - // (encoded as a zero-based value: 5), which was introduced with LLVM 13. - let version = coverageinfo::mapping_version(); - assert_eq!(version, 5, "The `CoverageMappingVersion` exposed by `llvm-wrapper` is out of sync"); + // Ensure that LLVM is using a version of the coverage mapping format that + // agrees with our Rust-side code. Expected versions (encoded as n-1) are: + // - `CovMapVersion::Version6` (5) used by LLVM 13-17 + // - `CovMapVersion::Version7` (6) used by LLVM 18 + let covmap_version = { + let llvm_covmap_version = coverageinfo::mapping_version(); + let expected_versions = 5..=6; + assert!( + expected_versions.contains(&llvm_covmap_version), + "Coverage mapping version exposed by `llvm-wrapper` is out of sync; \ + expected {expected_versions:?} but was {llvm_covmap_version}" + ); + // This is the version number that we will embed in the covmap section: + llvm_covmap_version + }; debug!("Generating coverage map for CodegenUnit: `{}`", cx.codegen_unit.name()); @@ -74,7 +85,7 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) { // Generate the coverage map header, which contains the filenames used by // this CGU's coverage mappings, and store it in a well-known global. - let cov_data_val = generate_coverage_map(cx, version, filenames_size, filenames_val); + let cov_data_val = generate_coverage_map(cx, covmap_version, filenames_size, filenames_val); coverageinfo::save_cov_data_to_mod(cx, cov_data_val); let mut unused_function_names = Vec::new(); diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs index 68c1770c1d4a..140566e8da9b 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs @@ -24,8 +24,6 @@ pub(crate) mod ffi; pub(crate) mod map_data; pub mod mapgen; -const VAR_ALIGN: Align = Align::EIGHT; - /// A context object for maintaining all state needed by the coverageinfo module. pub struct CrateCoverageContext<'ll, 'tcx> { /// Coverage data for each instrumented function identified by DefId. @@ -226,7 +224,8 @@ pub(crate) fn save_cov_data_to_mod<'ll, 'tcx>( llvm::set_global_constant(llglobal, true); llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); llvm::set_section(llglobal, &covmap_section_name); - llvm::set_alignment(llglobal, VAR_ALIGN); + // LLVM's coverage mapping format specifies 8-byte alignment for items in this section. + llvm::set_alignment(llglobal, Align::EIGHT); cx.add_used_global(llglobal); } @@ -256,7 +255,8 @@ pub(crate) fn save_func_record_to_mod<'ll, 'tcx>( llvm::set_linkage(llglobal, llvm::Linkage::LinkOnceODRLinkage); llvm::set_visibility(llglobal, llvm::Visibility::Hidden); llvm::set_section(llglobal, covfun_section_name); - llvm::set_alignment(llglobal, VAR_ALIGN); + // LLVM's coverage mapping format specifies 8-byte alignment for items in this section. + llvm::set_alignment(llglobal, Align::EIGHT); llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name); cx.add_used_global(llglobal); } diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index 3ef8538ced3a..f86cdcaa6f79 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -147,7 +147,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { for options in [ TypeIdOptions::GENERALIZE_POINTERS, TypeIdOptions::NORMALIZE_INTEGERS, - TypeIdOptions::NO_SELF_TYPE_ERASURE, + TypeIdOptions::USE_CONCRETE_SELF, ] .into_iter() .powerset() diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 7c7f702b2c39..ac278de02af2 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2946,7 +2946,7 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { let os = &sess.target.os; let llvm_target = &sess.target.llvm_target; if sess.target.vendor != "apple" - || !matches!(os.as_ref(), "ios" | "tvos" | "watchos" | "macos") + || !matches!(os.as_ref(), "ios" | "tvos" | "watchos" | "visionos" | "macos") || !matches!(flavor, LinkerFlavor::Darwin(..)) { return; @@ -2971,6 +2971,8 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { ("arm64_32", "watchos") => "watchos", ("aarch64", "watchos") if llvm_target.ends_with("-simulator") => "watchsimulator", ("aarch64", "watchos") => "watchos", + ("aarch64", "visionos") if llvm_target.ends_with("-simulator") => "xrsimulator", + ("aarch64", "visionos") => "xros", ("arm", "watchos") => "watchos", (_, "macos") => "macosx", _ => { @@ -3027,6 +3029,10 @@ fn get_apple_sdk_root(sdk_name: &str) -> Result {} "watchsimulator" if sdkroot.contains("WatchOS.platform") || sdkroot.contains("MacOSX.platform") => {} + "visionos" + if sdkroot.contains("XROS.platform") || sdkroot.contains("MacOSX.platform") => {} + "visionossimulator" + if sdkroot.contains("XROS.platform") || sdkroot.contains("MacOSX.platform") => {} // Ignore `SDKROOT` if it's not a valid path. _ if !p.is_absolute() || p == Path::new("/") || !p.exists() => {} _ => return Ok(sdkroot), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 4c975c7b9e05..36db377f7e0a 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -567,6 +567,8 @@ declare_features! ( (unstable, proc_macro_hygiene, "1.30.0", Some(54727)), /// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions. (unstable, raw_ref_op, "1.41.0", Some(64490)), + /// Allows `&` and `&mut` patterns to consume match-ergonomics-inserted references. + (incomplete, ref_pat_everywhere, "CURRENT_RUSTC_VERSION", Some(123076)), /// Allows using the `#[register_tool]` attribute. (unstable, register_tool, "1.41.0", Some(66079)), /// Allows the `#[repr(i128)]` attribute for enums. diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index f538d6bcb981..cd5da279a262 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -380,14 +380,19 @@ impl Definitions { pub fn local_def_path_hash_to_def_id( &self, hash: DefPathHash, - err: &mut dyn FnMut() -> !, + err_msg: &dyn std::fmt::Debug, ) -> LocalDefId { debug_assert!(hash.stable_crate_id() == self.table.stable_crate_id); + #[cold] + #[inline(never)] + fn err(err_msg: &dyn std::fmt::Debug) -> ! { + panic!("{err_msg:?}") + } self.table .def_path_hash_to_index .get(&hash.local_hash()) .map(|local_def_index| LocalDefId { local_def_index }) - .unwrap_or_else(|| err()) + .unwrap_or_else(|| err(err_msg)) } pub fn def_path_hash_to_def_index_map(&self) -> &DefPathHashMap { diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 0e75a47683dc..aa94632b2b07 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -918,7 +918,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let param = callee_args.const_at(host_effect_index); let cause = self.misc(span); - match self.at(&cause, self.param_env).eq(infer::DefineOpaqueTypes::No, effect, param) { + // We know the type of `effect` to be `bool`, there will be no opaque type inference. + match self.at(&cause, self.param_env).eq(infer::DefineOpaqueTypes::Yes, effect, param) { Ok(infer::InferOk { obligations, value: () }) => { self.register_predicates(obligations); } diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 36af53940156..dbae8bfb5424 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -227,11 +227,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { kind: TypeVariableOriginKind::ClosureSynthetic, span: expr_span, }); - let closure_kind_ty = self.next_ty_var(TypeVariableOrigin { - // FIXME(eddyb) distinguish closure kind inference variables from the rest. - kind: TypeVariableOriginKind::ClosureSynthetic, - span: expr_span, - }); + + let closure_kind_ty = match expected_kind { + Some(kind) => Ty::from_closure_kind(tcx, kind), + + // Create a type variable (for now) to represent the closure kind. + // It will be unified during the upvar inference phase (`upvar.rs`) + None => self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::ClosureSynthetic, + span: expr_span, + }), + }; + let coroutine_captures_by_ref_ty = self.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::ClosureSynthetic, span: expr_span, @@ -262,10 +269,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, ); - let coroutine_kind_ty = self.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::ClosureSynthetic, - span: expr_span, - }); + let coroutine_kind_ty = match expected_kind { + Some(kind) => Ty::from_coroutine_closure_kind(tcx, kind), + + // Create a type variable (for now) to represent the closure kind. + // It will be unified during the upvar inference phase (`upvar.rs`) + None => self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::ClosureSynthetic, + span: expr_span, + }), + }; + let coroutine_upvars_ty = self.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::ClosureSynthetic, span: expr_span, diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 564de4ab9e74..75a68f16cf18 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -400,7 +400,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // what our ideal rcvr ty would look like. let _ = self .at(&ObligationCause::dummy(), self.param_env) - .eq(DefineOpaqueTypes::No, method.sig.inputs()[idx + 1], arg_ty) + .eq(DefineOpaqueTypes::Yes, method.sig.inputs()[idx + 1], arg_ty) .ok()?; self.select_obligations_where_possible(|errs| { // Yeet the errors, we're already reporting errors. @@ -479,7 +479,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .and_then(|method| { let _ = self .at(&ObligationCause::dummy(), self.param_env) - .eq(DefineOpaqueTypes::No, ideal_rcvr_ty, expected_ty) + .eq(DefineOpaqueTypes::Yes, ideal_rcvr_ty, expected_ty) .ok()?; Some(method) }); diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index d3e6eb124f72..d8f62f7a2b64 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -44,10 +44,7 @@ use rustc_infer::infer::InferOk; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::ObligationCause; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase}; -use rustc_middle::ty::error::{ - ExpectedFound, - TypeError::{FieldMisMatch, Sorts}, -}; +use rustc_middle::ty::error::{ExpectedFound, TypeError::Sorts}; use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, AdtKind, Ty, TypeVisitableExt}; use rustc_session::errors::ExprParenthesesNeeded; @@ -1811,7 +1808,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let target_ty = self.field_ty(base_expr.span, f, args); let cause = self.misc(base_expr.span); match self.at(&cause, self.param_env).sup( - DefineOpaqueTypes::No, + // We're already using inference variables for any params, and don't allow converting + // between different structs, so there is no way this ever actually defines an opaque type. + // Thus choosing `Yes` is fine. + DefineOpaqueTypes::Yes, target_ty, fru_ty, ) { @@ -1819,16 +1819,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.register_predicates(obligations) } Err(_) => { - // This should never happen, since we're just subtyping the - // remaining_fields, but it's fine to emit this, I guess. - self.err_ctxt() - .report_mismatched_types( - &cause, - target_ty, - fru_ty, - FieldMisMatch(variant.name, ident.name), - ) - .emit(); + span_bug!( + cause.span(), + "subtyping remaining fields of type changing FRU failed: {target_ty} != {fru_ty}: {}::{}", + variant.name, + ident.name, + ); } } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 8d4d0833eef6..85d04f7d1c41 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -461,7 +461,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { where T: TypeVisitable>, { - t.has_free_regions() || t.has_projections() || t.has_infer_types() + t.has_free_regions() || t.has_aliases() || t.has_infer_types() } pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index f1feffcc82cc..64b816553dff 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -687,7 +687,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Using probe here, since we don't want this subtyping to affect inference. let subtyping_error = self.probe(|_| { self.at(&self.misc(arg_span), self.param_env) - .sup(DefineOpaqueTypes::No, formal_input_ty, coerced_ty) + .sup(DefineOpaqueTypes::Yes, formal_input_ty, coerced_ty) .err() }); diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 9d247c46bab4..bb47f8dfba46 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -130,7 +130,14 @@ enum AdjustMode { /// Peel off all immediate reference types. Peel, /// Reset binding mode to the initial mode. + /// Used for destructuring assignment, where we don't want any match ergonomics. Reset, + /// Produced by ref patterns. + /// Reset the binding mode to the initial mode, + /// and if the old biding mode was by-reference + /// with mutability matching the pattern, + /// mark the pattern as having consumed this reference. + ResetAndConsumeRef(Mutability), /// Pass on the input binding mode and expected type. Pass, } @@ -174,7 +181,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => None, }; let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res)); - let (expected, def_bm) = self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode); + let (expected, def_bm, ref_pattern_already_consumed) = + self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode); let pat_info = PatInfo { binding_mode: def_bm, top_info: ti, @@ -211,7 +219,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info), PatKind::Deref(inner) => self.check_pat_deref(pat.span, inner, expected, pat_info), - PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info), + PatKind::Ref(inner, mutbl) => self.check_pat_ref( + pat, + inner, + mutbl, + expected, + pat_info, + ref_pattern_already_consumed, + ), PatKind::Slice(before, slice, after) => { self.check_pat_slice(pat.span, before, slice, after, expected, pat_info) } @@ -264,17 +279,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Compute the new expected type and default binding mode from the old ones /// as well as the pattern form we are currently checking. + /// + /// Last entry is only relevant for ref patterns (`&` and `&mut`); + /// if `true`, then the ref pattern consumed a match ergonomics inserted reference + /// and so does no need to match against a reference in the scrutinee type. fn calc_default_binding_mode( &self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, def_bm: BindingAnnotation, adjust_mode: AdjustMode, - ) -> (Ty<'tcx>, BindingAnnotation) { + ) -> (Ty<'tcx>, BindingAnnotation, bool) { match adjust_mode { - AdjustMode::Pass => (expected, def_bm), - AdjustMode::Reset => (expected, INITIAL_BM), - AdjustMode::Peel => self.peel_off_references(pat, expected, def_bm), + AdjustMode::Pass => (expected, def_bm, false), + AdjustMode::Reset => (expected, INITIAL_BM, false), + AdjustMode::ResetAndConsumeRef(mutbl) => { + (expected, INITIAL_BM, def_bm.0 == ByRef::Yes(mutbl)) + } + AdjustMode::Peel => { + let peeled = self.peel_off_references(pat, expected, def_bm); + (peeled.0, peeled.1, false) + } } } @@ -329,7 +354,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // ``` // // See issue #46688. - PatKind::Ref(..) => AdjustMode::Reset, + PatKind::Ref(_, mutbl) => AdjustMode::ResetAndConsumeRef(*mutbl), // A `_` pattern works with any expected type, so there's no need to do anything. PatKind::Wild // A malformed pattern doesn't have an expected type, so let's just accept any type. @@ -840,8 +865,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let Some(mt) = self.shallow_resolve(expected).builtin_deref(true) && let ty::Dynamic(..) = mt.ty.kind() { - // This is "x = SomeTrait" being reduced from - // "let &x = &SomeTrait" or "let box x = Box", an error. + // This is "x = dyn SomeTrait" being reduced from + // "let &x = &dyn SomeTrait" or "let box x = Box", an error. let type_str = self.ty_to_string(expected); let mut err = struct_span_code_err!( self.dcx(), @@ -2036,6 +2061,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { mutbl: Mutability, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_>, + consumed_inherited_ref: bool, ) -> Ty<'tcx> { let tcx = self.tcx; let expected = self.shallow_resolve(expected); @@ -2051,26 +2077,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match *expected.kind() { ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty), _ => { - let inner_ty = self.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeInference, - span: inner.span, - }); - let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty); - debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty); - let err = self.demand_eqtype_pat_diag( - pat.span, - expected, - ref_ty, - pat_info.top_info, - ); + if consumed_inherited_ref && self.tcx.features().ref_pat_everywhere { + // We already matched against a match-ergonmics inserted reference, + // so we don't need to match against a reference from the original type. + // Save this infor for use in lowering later + self.typeck_results + .borrow_mut() + .skipped_ref_pats_mut() + .insert(pat.hir_id); + (expected, expected) + } else { + let inner_ty = self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span: inner.span, + }); + let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty); + debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty); + let err = self.demand_eqtype_pat_diag( + pat.span, + expected, + ref_ty, + pat_info.top_info, + ); - // Look for a case like `fn foo(&foo: u32)` and suggest - // `fn foo(foo: &u32)` - if let Some(mut err) = err { - self.borrow_pat_suggestion(&mut err, pat); - err.emit(); + // Look for a case like `fn foo(&foo: u32)` and suggest + // `fn foo(foo: &u32)` + if let Some(mut err) = err { + self.borrow_pat_suggestion(&mut err, pat); + err.emit(); + } + (ref_ty, inner_ty) } - (ref_ty, inner_ty) } } } diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 72e5b1ed95bf..c987bfb9a0e8 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -166,7 +166,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, body_id: hir::BodyId, body: &'tcx hir::Body<'tcx>, - capture_clause: hir::CaptureBy, + mut capture_clause: hir::CaptureBy, ) { // Extract the type of the closure. let ty = self.node_ty(closure_hir_id); @@ -259,6 +259,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) .consume_body(body); + // If a coroutine is comes from a coroutine-closure that is `move`, but + // the coroutine-closure was inferred to be `FnOnce` during signature + // inference, then it's still possible that we try to borrow upvars from + // the coroutine-closure because they are not used by the coroutine body + // in a way that forces a move. + // + // This would lead to an impossible to satisfy situation, since `AsyncFnOnce` + // coroutine bodies can't borrow from their parent closure. To fix this, + // we force the inner coroutine to also be `move`. This only matters for + // coroutine-closures that are `move` since otherwise they themselves will + // be borrowing from the outer environment, so there's no self-borrows occuring. + if let UpvarArgs::Coroutine(..) = args + && let hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Closure) = + self.tcx.coroutine_kind(closure_def_id).expect("coroutine should have kind") + && let parent_hir_id = + self.tcx.local_def_id_to_hir_id(self.tcx.local_parent(closure_def_id)) + && let parent_ty = self.node_ty(parent_hir_id) + && let Some(ty::ClosureKind::FnOnce) = self.closure_kind(parent_ty) + { + capture_clause = self.tcx.hir_node(parent_hir_id).expect_closure().capture_clause; + } + debug!( "For closure={:?}, capture_information={:#?}", closure_def_id, delegate.capture_information @@ -399,16 +421,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); // Additionally, we can now constrain the coroutine's kind type. - let ty::Coroutine(_, coroutine_args) = - *self.typeck_results.borrow().expr_ty(body.value).kind() - else { - bug!(); - }; - self.demand_eqtype( - span, - coroutine_args.as_coroutine().kind_ty(), - Ty::from_coroutine_closure_kind(self.tcx, closure_kind), - ); + // + // We only do this if `infer_kind`, because if we have constrained + // the kind from closure signature inference, the kind inferred + // for the inner coroutine may actually be more restrictive. + if infer_kind { + let ty::Coroutine(_, coroutine_args) = + *self.typeck_results.borrow().expr_ty(body.value).kind() + else { + bug!(); + }; + self.demand_eqtype( + span, + coroutine_args.as_coroutine().kind_ty(), + Ty::from_coroutine_closure_kind(self.tcx, closure_kind), + ); + } } self.log_closure_min_capture_info(closure_def_id, span); diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index f4516b684c38..6604bf094c14 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -345,6 +345,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { _ => {} }; + self.visit_skipped_ref_pats(p.hir_id); self.visit_pat_adjustments(p.span, p.hir_id); self.visit_node_id(p.span, p.hir_id); @@ -674,6 +675,14 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } + #[instrument(skip(self), level = "debug")] + fn visit_skipped_ref_pats(&mut self, hir_id: hir::HirId) { + if self.fcx.typeck_results.borrow_mut().skipped_ref_pats_mut().remove(hir_id) { + debug!("node is a skipped ref pat"); + self.typeck_results.skipped_ref_pats_mut().insert(hir_id); + } + } + fn visit_liberated_fn_sigs(&mut self) { let fcx_typeck_results = self.fcx.typeck_results.borrow(); assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index 357f2ae92d4c..26aaa24771fe 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -11,6 +11,7 @@ use rustc_session::config::IncrementalStateAssertion; use rustc_session::Session; use rustc_span::ErrorGuaranteed; use std::path::{Path, PathBuf}; +use std::sync::Arc; use super::data::*; use super::file_format; @@ -88,7 +89,7 @@ fn delete_dirty_work_product(sess: &Session, swp: SerializedWorkProduct) { work_product::delete_workproduct_files(sess, &swp.work_product); } -fn load_dep_graph(sess: &Session) -> LoadResult<(SerializedDepGraph, WorkProductMap)> { +fn load_dep_graph(sess: &Session) -> LoadResult<(Arc, WorkProductMap)> { let prof = sess.prof.clone(); if sess.opts.incremental.is_none() { diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs index 32759f5284af..9777f7692809 100644 --- a/compiler/rustc_incremental/src/persist/save.rs +++ b/compiler/rustc_incremental/src/persist/save.rs @@ -10,6 +10,7 @@ use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_serialize::Encodable as RustcEncodable; use rustc_session::Session; use std::fs; +use std::sync::Arc; use super::data::*; use super::dirty_clean; @@ -147,7 +148,7 @@ fn encode_query_cache(tcx: TyCtxt<'_>, encoder: FileEncoder) -> FileEncodeResult /// and moves it to the permanent dep-graph path pub(crate) fn build_dep_graph( sess: &Session, - prev_graph: SerializedDepGraph, + prev_graph: Arc, prev_work_products: WorkProductMap, ) -> Option { if sess.opts.incremental.is_none() { diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 3e89327d20fd..6e5ed0a31cb1 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -843,7 +843,9 @@ impl<'tcx> InferCtxt<'tcx> { { let origin = &ObligationCause::dummy(); self.probe(|_| { - self.at(origin, param_env).sub(DefineOpaqueTypes::No, expected, actual).is_ok() + // We're only answering whether there could be a subtyping relation, and with + // opaque types, "there could be one", via registering a hidden type. + self.at(origin, param_env).sub(DefineOpaqueTypes::Yes, expected, actual).is_ok() }) } @@ -852,7 +854,9 @@ impl<'tcx> InferCtxt<'tcx> { T: at::ToTrace<'tcx>, { let origin = &ObligationCause::dummy(); - self.probe(|_| self.at(origin, param_env).eq(DefineOpaqueTypes::No, a, b).is_ok()) + // We're only answering whether the types could be the same, and with + // opaque types, "they can be the same", via registering a hidden type. + self.probe(|_| self.at(origin, param_env).eq(DefineOpaqueTypes::Yes, a, b).is_ok()) } #[instrument(skip(self), level = "debug")] diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index d938a0ccb398..797c0df4d73b 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -443,7 +443,7 @@ lint_non_local_definitions_impl = non-local `impl` definition, they should be av [one] `{$body_name}` *[other] `{$body_name}` and up {$depth} bodies } - .non_local = an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + .non_local = an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` .exception = one exception to the rule are anon-const (`const _: () = {"{"} ... {"}"}`) at top-level module and anon-const at the same nesting as the trait or type .const_anon = use a const-anon item to suppress this lint diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs index 7c4d92d3ce03..1e9c60a540d4 100644 --- a/compiler/rustc_lint/src/non_local_def.rs +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -1,6 +1,18 @@ -use rustc_hir::{def::DefKind, Body, Item, ItemKind, Node, Path, QPath, TyKind}; +use rustc_hir::{def::DefKind, Body, Item, ItemKind, Node, TyKind}; +use rustc_hir::{Path, QPath}; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::infer::InferCtxt; +use rustc_infer::traits::{Obligation, ObligationCause}; +use rustc_middle::query::Key; +use rustc_middle::ty::{self, Binder, Ty, TyCtxt, TypeFoldable, TypeFolder}; +use rustc_middle::ty::{EarlyBinder, TraitRef, TypeSuperFoldable}; use rustc_span::def_id::{DefId, LOCAL_CRATE}; +use rustc_span::Span; use rustc_span::{sym, symbol::kw, ExpnKind, MacroKind}; +use rustc_trait_selection::infer::TyCtxtInferExt; +use rustc_trait_selection::traits::error_reporting::ambiguity::{ + compute_applicable_impls_for_diagnostics, CandidateSource, +}; use crate::lints::{NonLocalDefinitionsCargoUpdateNote, NonLocalDefinitionsDiag}; use crate::{LateContext, LateLintPass, LintContext}; @@ -35,7 +47,7 @@ declare_lint! { /// All nested bodies (functions, enum discriminant, array length, consts) (expect for /// `const _: Ty = { ... }` in top-level module, which is still undecided) are checked. pub NON_LOCAL_DEFINITIONS, - Allow, + Warn, "checks for non-local definitions", report_in_external_macro } @@ -66,7 +78,8 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { return; } - let parent = cx.tcx.parent(item.owner_id.def_id.into()); + let def_id = item.owner_id.def_id.into(); + let parent = cx.tcx.parent(def_id); let parent_def_kind = cx.tcx.def_kind(parent); let parent_opt_item_name = cx.tcx.opt_item_name(parent); @@ -121,6 +134,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { None }; + // Part 1: Is the Self type local? let self_ty_has_local_parent = match impl_.self_ty.kind { TyKind::Path(QPath::Resolved(_, ty_path)) => { path_has_local_parent(ty_path, cx, parent, parent_parent) @@ -150,41 +164,70 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { | TyKind::Err(_) => false, }; + if self_ty_has_local_parent { + return; + } + + // Part 2: Is the Trait local? let of_trait_has_local_parent = impl_ .of_trait .map(|of_trait| path_has_local_parent(of_trait.path, cx, parent, parent_parent)) .unwrap_or(false); - // If none of them have a local parent (LOGICAL NOR) this means that - // this impl definition is a non-local definition and so we lint on it. - if !(self_ty_has_local_parent || of_trait_has_local_parent) { - let const_anon = if self.body_depth == 1 - && parent_def_kind == DefKind::Const - && parent_opt_item_name != Some(kw::Underscore) - && let Some(parent) = parent.as_local() - && let Node::Item(item) = cx.tcx.hir_node_by_def_id(parent) - && let ItemKind::Const(ty, _, _) = item.kind - && let TyKind::Tup(&[]) = ty.kind - { - Some(item.ident.span) - } else { - None - }; - - cx.emit_span_lint( - NON_LOCAL_DEFINITIONS, - item.span, - NonLocalDefinitionsDiag::Impl { - depth: self.body_depth, - body_kind_descr: cx.tcx.def_kind_descr(parent_def_kind, parent), - body_name: parent_opt_item_name - .map(|s| s.to_ident_string()) - .unwrap_or_else(|| "".to_string()), - cargo_update: cargo_update(), - const_anon, - }, - ) + if of_trait_has_local_parent { + return; } + + // Part 3: Is the impl definition leaking outside it's defining scope? + // + // We always consider inherent impls to be leaking. + let impl_has_enough_non_local_candidates = cx + .tcx + .impl_trait_ref(def_id) + .map(|binder| { + impl_trait_ref_has_enough_non_local_candidates( + cx.tcx, + item.span, + def_id, + binder, + |did| did_has_local_parent(did, cx.tcx, parent, parent_parent), + ) + }) + .unwrap_or(false); + + if impl_has_enough_non_local_candidates { + return; + } + + // Get the span of the parent const item ident (if it's a not a const anon). + // + // Used to suggest changing the const item to a const anon. + let span_for_const_anon_suggestion = if self.body_depth == 1 + && parent_def_kind == DefKind::Const + && parent_opt_item_name != Some(kw::Underscore) + && let Some(parent) = parent.as_local() + && let Node::Item(item) = cx.tcx.hir_node_by_def_id(parent) + && let ItemKind::Const(ty, _, _) = item.kind + && let TyKind::Tup(&[]) = ty.kind + { + Some(item.ident.span) + } else { + None + }; + + cx.emit_span_lint( + NON_LOCAL_DEFINITIONS, + item.span, + NonLocalDefinitionsDiag::Impl { + depth: self.body_depth, + body_kind_descr: cx.tcx.def_kind_descr(parent_def_kind, parent), + body_name: parent_opt_item_name + .map(|s| s.to_ident_string()) + .unwrap_or_else(|| "".to_string()), + cargo_update: cargo_update(), + const_anon: span_for_const_anon_suggestion, + }, + ) } ItemKind::Macro(_macro, MacroKind::Bang) if cx.tcx.has_attr(item.owner_id.def_id, sym::macro_export) => @@ -207,6 +250,81 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { } } +// Detecting if the impl definition is leaking outside of it's defining scope. +// +// Rule: for each impl, instantiate all local types with inference vars and +// then assemble candidates for that goal, if there are more than 1 (non-private +// impls), it does not leak. +// +// https://github.com/rust-lang/rust/issues/121621#issuecomment-1976826895 +fn impl_trait_ref_has_enough_non_local_candidates<'tcx>( + tcx: TyCtxt<'tcx>, + infer_span: Span, + trait_def_id: DefId, + binder: EarlyBinder>, + mut did_has_local_parent: impl FnMut(DefId) -> bool, +) -> bool { + let infcx = tcx.infer_ctxt().build(); + let trait_ref = binder.instantiate(tcx, infcx.fresh_args_for_item(infer_span, trait_def_id)); + + let trait_ref = trait_ref.fold_with(&mut ReplaceLocalTypesWithInfer { + infcx: &infcx, + infer_span, + did_has_local_parent: &mut did_has_local_parent, + }); + + let poly_trait_obligation = Obligation::new( + tcx, + ObligationCause::dummy(), + ty::ParamEnv::empty(), + Binder::dummy(trait_ref), + ); + + let ambiguities = compute_applicable_impls_for_diagnostics(&infcx, &poly_trait_obligation); + + let mut it = ambiguities.iter().filter(|ambi| match ambi { + CandidateSource::DefId(did) => !did_has_local_parent(*did), + CandidateSource::ParamEnv(_) => unreachable!(), + }); + + let _ = it.next(); + it.next().is_some() +} + +/// Replace every local type by inference variable. +/// +/// ```text +/// as std::cmp::PartialEq>> +/// to +/// as std::cmp::PartialEq>> +/// ``` +struct ReplaceLocalTypesWithInfer<'a, 'tcx, F: FnMut(DefId) -> bool> { + infcx: &'a InferCtxt<'tcx>, + did_has_local_parent: F, + infer_span: Span, +} + +impl<'a, 'tcx, F: FnMut(DefId) -> bool> TypeFolder> + for ReplaceLocalTypesWithInfer<'a, 'tcx, F> +{ + fn interner(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + if let Some(ty_did) = t.ty_def_id() + && (self.did_has_local_parent)(ty_did) + { + self.infcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span: self.infer_span, + }) + } else { + t.super_fold_with(self) + } + } +} + /// Given a path and a parent impl def id, this checks if the if parent resolution /// def id correspond to the def id of the parent impl definition. /// @@ -216,16 +334,29 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { /// std::convert::PartialEq> /// ^^^^^^^^^^^^^^^^^^^^^^^ /// ``` +#[inline] fn path_has_local_parent( path: &Path<'_>, cx: &LateContext<'_>, impl_parent: DefId, impl_parent_parent: Option, ) -> bool { - path.res.opt_def_id().is_some_and(|did| { - did.is_local() && { - let res_parent = cx.tcx.parent(did); - res_parent == impl_parent || Some(res_parent) == impl_parent_parent - } - }) + path.res + .opt_def_id() + .is_some_and(|did| did_has_local_parent(did, cx.tcx, impl_parent, impl_parent_parent)) +} + +/// Given a def id and a parent impl def id, this checks if the parent +/// def id correspond to the def id of the parent impl definition. +#[inline] +fn did_has_local_parent( + did: DefId, + tcx: TyCtxt<'_>, + impl_parent: DefId, + impl_parent_parent: Option, +) -> bool { + did.is_local() && { + let res_parent = tcx.parent(did); + res_parent == impl_parent || Some(res_parent) == impl_parent_parent + } } diff --git a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp index 60789b07e54e..0998b463a886 100644 --- a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp @@ -1,8 +1,8 @@ #include "LLVMWrapper.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ProfileData/Coverage/CoverageMapping.h" #include "llvm/ProfileData/Coverage/CoverageMappingWriter.h" #include "llvm/ProfileData/InstrProf.h" -#include "llvm/ADT/ArrayRef.h" #include @@ -103,35 +103,30 @@ fromRust(LLVMRustCounterExprKind Kind) { } extern "C" void LLVMRustCoverageWriteFilenamesSectionToBuffer( - const char *const Filenames[], - size_t FilenamesLen, - const size_t *const Lengths, - size_t LengthsLen, + const char *const Filenames[], size_t FilenamesLen, // String start pointers + const size_t *const Lengths, size_t LengthsLen, // Corresponding lengths RustStringRef BufferOut) { if (FilenamesLen != LengthsLen) { report_fatal_error( "Mismatched lengths in LLVMRustCoverageWriteFilenamesSectionToBuffer"); } - SmallVector FilenameRefs; + SmallVector FilenameRefs; FilenameRefs.reserve(FilenamesLen); for (size_t i = 0; i < FilenamesLen; i++) { FilenameRefs.emplace_back(Filenames[i], Lengths[i]); } - auto FilenamesWriter = - coverage::CoverageFilenamesSectionWriter(ArrayRef(FilenameRefs)); + auto FilenamesWriter = coverage::CoverageFilenamesSectionWriter( + ArrayRef(FilenameRefs)); auto OS = RawRustStringOstream(BufferOut); FilenamesWriter.write(OS); } extern "C" void LLVMRustCoverageWriteMappingToBuffer( - const unsigned *VirtualFileMappingIDs, - unsigned NumVirtualFileMappingIDs, - const LLVMRustCounterExpression *RustExpressions, - unsigned NumExpressions, + const unsigned *VirtualFileMappingIDs, unsigned NumVirtualFileMappingIDs, + const LLVMRustCounterExpression *RustExpressions, unsigned NumExpressions, const LLVMRustCounterMappingRegion *RustMappingRegions, - unsigned NumMappingRegions, - RustStringRef BufferOut) { + unsigned NumMappingRegions, RustStringRef BufferOut) { // Convert from FFI representation to LLVM representation. SmallVector MappingRegions; MappingRegions.reserve(NumMappingRegions); @@ -142,7 +137,7 @@ extern "C" void LLVMRustCoverageWriteMappingToBuffer( #if LLVM_VERSION_GE(18, 0) && LLVM_VERSION_LT(19, 0) coverage::CounterMappingRegion::MCDCParameters{}, #endif - Region.FileID, Region.ExpandedFileID, + Region.FileID, Region.ExpandedFileID, // File IDs, then region info. Region.LineStart, Region.ColumnStart, Region.LineEnd, Region.ColumnEnd, fromRust(Region.Kind)); } @@ -158,29 +153,25 @@ extern "C" void LLVMRustCoverageWriteMappingToBuffer( auto CoverageMappingWriter = coverage::CoverageMappingWriter( ArrayRef(VirtualFileMappingIDs, NumVirtualFileMappingIDs), - Expressions, - MappingRegions); + Expressions, MappingRegions); auto OS = RawRustStringOstream(BufferOut); CoverageMappingWriter.write(OS); } -extern "C" LLVMValueRef LLVMRustCoverageCreatePGOFuncNameVar( - LLVMValueRef F, - const char *FuncName, - size_t FuncNameLen) { +extern "C" LLVMValueRef +LLVMRustCoverageCreatePGOFuncNameVar(LLVMValueRef F, const char *FuncName, + size_t FuncNameLen) { auto FuncNameRef = StringRef(FuncName, FuncNameLen); return wrap(createPGOFuncNameVar(*cast(unwrap(F)), FuncNameRef)); } -extern "C" uint64_t LLVMRustCoverageHashByteArray( - const char *Bytes, - size_t NumBytes) { +extern "C" uint64_t LLVMRustCoverageHashByteArray(const char *Bytes, + size_t NumBytes) { auto StrRef = StringRef(Bytes, NumBytes); return IndexedInstrProf::ComputeHash(StrRef); } -static void WriteSectionNameToString(LLVMModuleRef M, - InstrProfSectKind SK, +static void WriteSectionNameToString(LLVMModuleRef M, InstrProfSectKind SK, RustStringRef Str) { auto TargetTriple = Triple(unwrap(M)->getTargetTriple()); auto name = getInstrProfSectionName(SK, TargetTriple.getObjectFormat()); @@ -193,8 +184,9 @@ extern "C" void LLVMRustCoverageWriteMapSectionNameToString(LLVMModuleRef M, WriteSectionNameToString(M, IPSK_covmap, Str); } -extern "C" void LLVMRustCoverageWriteFuncSectionNameToString(LLVMModuleRef M, - RustStringRef Str) { +extern "C" void +LLVMRustCoverageWriteFuncSectionNameToString(LLVMModuleRef M, + RustStringRef Str) { WriteSectionNameToString(M, IPSK_covfun, Str); } @@ -205,5 +197,8 @@ extern "C" void LLVMRustCoverageWriteMappingVarNameToString(RustStringRef Str) { } extern "C" uint32_t LLVMRustCoverageMappingVersion() { - return coverage::CovMapVersion::Version6; + // This should always be `CurrentVersion`, because that's the version LLVM + // will use when encoding the data we give it. If for some reason we ever + // want to override the version number we _emit_, do it on the Rust side. + return coverage::CovMapVersion::CurrentVersion; } diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index 39d82c489d53..3c5bf6eb8246 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -194,9 +194,10 @@ impl DepNodeExt for DepNode { /// has been removed. fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option { if tcx.fingerprint_style(self.kind) == FingerprintStyle::DefPathHash { - Some(tcx.def_path_hash_to_def_id(DefPathHash(self.hash.into()), &mut || { - panic!("Failed to extract DefId: {:?} {}", self.kind, self.hash) - })) + Some(tcx.def_path_hash_to_def_id( + DefPathHash(self.hash.into()), + &("Failed to extract DefId", self.kind, self.hash), + )) } else { None } @@ -390,9 +391,10 @@ impl<'tcx> DepNodeParams> for HirId { let (local_hash, local_id) = Fingerprint::from(dep_node.hash).split(); let def_path_hash = DefPathHash::new(tcx.stable_crate_id(LOCAL_CRATE), local_hash); let def_id = tcx - .def_path_hash_to_def_id(def_path_hash, &mut || { - panic!("Failed to extract HirId: {:?} {}", dep_node.kind, dep_node.hash) - }) + .def_path_hash_to_def_id( + def_path_hash, + &("Failed to extract HirId", dep_node.kind, dep_node.hash), + ) .expect_local(); let local_id = local_id .as_u64() diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 42a06c968c75..94d1039c763f 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -179,7 +179,7 @@ pub fn provide(providers: &mut Providers) { .parenting .get(&owner_id.def_id) .copied() - .unwrap_or(ItemLocalId::from_u32(0)), + .unwrap_or(ItemLocalId::ZERO), } }) }; diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index 0c91dc6d3c68..582a18066881 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -33,10 +33,6 @@ rustc_index::newtype_index! { pub struct CounterId {} } -impl CounterId { - pub const START: Self = Self::ZERO; -} - rustc_index::newtype_index! { /// ID of a coverage-counter expression. Values ascend from 0. /// @@ -55,10 +51,6 @@ rustc_index::newtype_index! { pub struct ExpressionId {} } -impl ExpressionId { - pub const START: Self = Self::ZERO; -} - /// Enum that can hold a constant zero value, the ID of an physical coverage /// counter, or the ID of a coverage-counter expression. /// diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 3835bd371d99..4f7b2f7cbe48 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -341,7 +341,7 @@ macro_rules! make_mir_visitor { ty::InstanceDef::Intrinsic(_def_id) | ty::InstanceDef::VTableShim(_def_id) | - ty::InstanceDef::ReifyShim(_def_id) | + ty::InstanceDef::ReifyShim(_def_id, _) | ty::InstanceDef::Virtual(_def_id, _) | ty::InstanceDef::ThreadLocalShim(_def_id) | ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } | diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index 9c7c46f2ad24..8f02b3121acd 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -737,9 +737,10 @@ impl<'a, 'tcx> SpanDecoder for CacheDecoder<'a, 'tcx> { // If we get to this point, then all of the query inputs were green, // which means that the definition with this hash is guaranteed to // still exist in the current compilation session. - self.tcx.def_path_hash_to_def_id(def_path_hash, &mut || { - panic!("Failed to convert DefPathHash {def_path_hash:?}") - }) + self.tcx.def_path_hash_to_def_id( + def_path_hash, + &("Failed to convert DefPathHash", def_path_hash), + ) } fn decode_attr_id(&mut self) -> rustc_span::AttrId { diff --git a/compiler/rustc_middle/src/traits/solve/inspect.rs b/compiler/rustc_middle/src/traits/solve/inspect.rs index 16842c8208f8..52cdbae1e564 100644 --- a/compiler/rustc_middle/src/traits/solve/inspect.rs +++ b/compiler/rustc_middle/src/traits/solve/inspect.rs @@ -121,8 +121,6 @@ pub enum ProbeStep<'tcx> { /// used whenever there are multiple candidates to prove the /// current goalby . NestedProbe(Probe<'tcx>), - CommitIfOkStart, - CommitIfOkSuccess, } /// What kind of probe we're in. In case the probe represents a candidate, or @@ -132,6 +130,8 @@ pub enum ProbeStep<'tcx> { pub enum ProbeKind<'tcx> { /// The root inference context while proving a goal. Root { result: QueryResult<'tcx> }, + /// Trying to normalize an alias by at least one step in `NormalizesTo`. + TryNormalizeNonRigid { result: QueryResult<'tcx> }, /// Probe entered when normalizing the self ty during candidate assembly NormalizedSelfTyAssembly, /// Some candidate to prove the current goal. @@ -143,9 +143,6 @@ pub enum ProbeKind<'tcx> { /// Used in the probe that wraps normalizing the non-self type for the unsize /// trait, which is also structurally matched on. UnsizeAssembly, - /// A call to `EvalCtxt::commit_if_ok` which failed, causing the work - /// to be discarded. - CommitIfOk, /// During upcasting from some source object to target object type, used to /// do a probe to find out what projection type(s) may be used to prove that /// the source type upholds all of the target type's object bounds. diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_middle/src/traits/solve/inspect/format.rs index 439312050172..98f01fe87724 100644 --- a/compiler/rustc_middle/src/traits/solve/inspect/format.rs +++ b/compiler/rustc_middle/src/traits/solve/inspect/format.rs @@ -100,6 +100,9 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> { ProbeKind::Root { result } => { write!(self.f, "ROOT RESULT: {result:?}") } + ProbeKind::TryNormalizeNonRigid { result } => { + write!(self.f, "TRY NORMALIZE NON-RIGID: {result:?}") + } ProbeKind::NormalizedSelfTyAssembly => { write!(self.f, "NORMALIZING SELF TY FOR ASSEMBLY:") } @@ -109,9 +112,6 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> { ProbeKind::UpcastProjectionCompatibility => { write!(self.f, "PROBING FOR PROJECTION COMPATIBILITY FOR UPCASTING:") } - ProbeKind::CommitIfOk => { - write!(self.f, "COMMIT_IF_OK:") - } ProbeKind::MiscCandidate { name, result } => { write!(self.f, "CANDIDATE {name}: {result:?}") } @@ -132,8 +132,6 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> { } ProbeStep::EvaluateGoals(eval) => this.format_added_goals_evaluation(eval)?, ProbeStep::NestedProbe(probe) => this.format_probe(probe)?, - ProbeStep::CommitIfOkStart => writeln!(this.f, "COMMIT_IF_OK START")?, - ProbeStep::CommitIfOkSuccess => writeln!(this.f, "COMMIT_IF_OK SUCCESS")?, } } Ok(()) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index b8d68c1b8be4..75deffe69576 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1121,7 +1121,11 @@ impl<'tcx> TyCtxt<'tcx> { /// Converts a `DefPathHash` to its corresponding `DefId` in the current compilation /// session, if it still exists. This is used during incremental compilation to /// turn a deserialized `DefPathHash` into its current `DefId`. - pub fn def_path_hash_to_def_id(self, hash: DefPathHash, err: &mut dyn FnMut() -> !) -> DefId { + pub fn def_path_hash_to_def_id( + self, + hash: DefPathHash, + err_msg: &dyn std::fmt::Debug, + ) -> DefId { debug!("def_path_hash_to_def_id({:?})", hash); let stable_crate_id = hash.stable_crate_id(); @@ -1129,7 +1133,11 @@ impl<'tcx> TyCtxt<'tcx> { // If this is a DefPathHash from the local crate, we can look up the // DefId in the tcx's `Definitions`. if stable_crate_id == self.stable_crate_id(LOCAL_CRATE) { - self.untracked.definitions.read().local_def_path_hash_to_def_id(hash, err).to_def_id() + self.untracked + .definitions + .read() + .local_def_path_hash_to_def_id(hash, err_msg) + .to_def_id() } else { // If this is a DefPathHash from an upstream crate, let the CrateStore map // it to a DefId. diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 4fec5653a798..4a7720b38f85 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -31,6 +31,28 @@ pub struct Instance<'tcx> { pub args: GenericArgsRef<'tcx>, } +/// Describes why a `ReifyShim` was created. This is needed to distingish a ReifyShim created to +/// adjust for things like `#[track_caller]` in a vtable from a `ReifyShim` created to produce a +/// function pointer from a vtable entry. +/// Currently, this is only used when KCFI is enabled, as only KCFI needs to treat those two +/// `ReifyShim`s differently. +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[derive(TyEncodable, TyDecodable, HashStable)] +pub enum ReifyReason { + /// The `ReifyShim` was created to produce a function pointer. This happens when: + /// * A vtable entry is directly converted to a function call (e.g. creating a fn ptr from a + /// method on a `dyn` object). + /// * A function with `#[track_caller]` is converted to a function pointer + /// * If KCFI is enabled, creating a function pointer from a method on an object-safe trait. + /// This includes the case of converting `::call`-like methods on closure-likes to function + /// pointers. + FnPtr, + /// This `ReifyShim` was created to populate a vtable. Currently, this happens when a + /// `#[track_caller]` mismatch occurs between the implementation of a method and the method. + /// This includes the case of `::call`-like methods in closure-likes' vtables. + Vtable, +} + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)] pub enum InstanceDef<'tcx> { @@ -67,7 +89,13 @@ pub enum InstanceDef<'tcx> { /// Because this is a required part of the function's ABI but can't be tracked /// as a property of the function pointer, we use a single "caller location" /// (the definition of the function itself). - ReifyShim(DefId), + /// + /// The second field encodes *why* this shim was created. This allows distinguishing between + /// a `ReifyShim` that appears in a vtable vs one that appears as a function pointer. + /// + /// This field will only be populated if we are compiling in a mode that needs these shims + /// to be separable, currently only when KCFI is enabled. + ReifyShim(DefId, Option), /// `::call_*` (generated `FnTrait` implementation for `fn()` pointers). /// @@ -194,7 +222,7 @@ impl<'tcx> InstanceDef<'tcx> { match self { InstanceDef::Item(def_id) | InstanceDef::VTableShim(def_id) - | InstanceDef::ReifyShim(def_id) + | InstanceDef::ReifyShim(def_id, _) | InstanceDef::FnPtrShim(def_id, _) | InstanceDef::Virtual(def_id, _) | InstanceDef::Intrinsic(def_id) @@ -354,7 +382,9 @@ fn fmt_instance( match instance.def { InstanceDef::Item(_) => Ok(()), InstanceDef::VTableShim(_) => write!(f, " - shim(vtable)"), - InstanceDef::ReifyShim(_) => write!(f, " - shim(reify)"), + InstanceDef::ReifyShim(_, None) => write!(f, " - shim(reify)"), + InstanceDef::ReifyShim(_, Some(ReifyReason::FnPtr)) => write!(f, " - shim(reify-fnptr)"), + InstanceDef::ReifyShim(_, Some(ReifyReason::Vtable)) => write!(f, " - shim(reify-vtable)"), InstanceDef::ThreadLocalShim(_) => write!(f, " - shim(tls)"), InstanceDef::Intrinsic(_) => write!(f, " - intrinsic"), InstanceDef::Virtual(_, num) => write!(f, " - virtual#{num}"), @@ -476,15 +506,34 @@ impl<'tcx> Instance<'tcx> { debug!("resolve(def_id={:?}, args={:?})", def_id, args); // Use either `resolve_closure` or `resolve_for_vtable` assert!(!tcx.is_closure_like(def_id), "Called `resolve_for_fn_ptr` on closure: {def_id:?}"); + let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::FnPtr); Instance::resolve(tcx, param_env, def_id, args).ok().flatten().map(|mut resolved| { match resolved.def { InstanceDef::Item(def) if resolved.def.requires_caller_location(tcx) => { debug!(" => fn pointer created for function with #[track_caller]"); - resolved.def = InstanceDef::ReifyShim(def); + resolved.def = InstanceDef::ReifyShim(def, reason); } InstanceDef::Virtual(def_id, _) => { debug!(" => fn pointer created for virtual call"); - resolved.def = InstanceDef::ReifyShim(def_id); + resolved.def = InstanceDef::ReifyShim(def_id, reason); + } + // Reify `Trait::method` implementations if KCFI is enabled + // FIXME(maurer) only reify it if it is a vtable-safe function + _ if tcx.sess.is_sanitizer_kcfi_enabled() + && tcx.associated_item(def_id).trait_item_def_id.is_some() => + { + // If this function could also go in a vtable, we need to `ReifyShim` it with + // KCFI because it can only attach one type per function. + resolved.def = InstanceDef::ReifyShim(resolved.def_id(), reason) + } + // Reify `::call`-like method implementations if KCFI is enabled + _ if tcx.sess.is_sanitizer_kcfi_enabled() + && tcx.is_closure_like(resolved.def_id()) => + { + // Reroute through a reify via the *unresolved* instance. The resolved one can't + // be directly reified because it's closure-like. The reify can handle the + // unresolved instance. + resolved = Instance { def: InstanceDef::ReifyShim(def_id, reason), args } } _ => {} } @@ -508,6 +557,7 @@ impl<'tcx> Instance<'tcx> { debug!(" => associated item with unsizeable self: Self"); Some(Instance { def: InstanceDef::VTableShim(def_id), args }) } else { + let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::Vtable); Instance::resolve(tcx, param_env, def_id, args).ok().flatten().map(|mut resolved| { match resolved.def { InstanceDef::Item(def) => { @@ -544,18 +594,18 @@ impl<'tcx> Instance<'tcx> { // Create a shim for the `FnOnce/FnMut/Fn` method we are calling // - unlike functions, invoking a closure always goes through a // trait. - resolved = Instance { def: InstanceDef::ReifyShim(def_id), args }; + resolved = Instance { def: InstanceDef::ReifyShim(def_id, reason), args }; } else { debug!( " => vtable fn pointer created for function with #[track_caller]: {:?}", def ); - resolved.def = InstanceDef::ReifyShim(def); + resolved.def = InstanceDef::ReifyShim(def, reason); } } } InstanceDef::Virtual(def_id, _) => { debug!(" => vtable fn pointer created for virtual call"); - resolved.def = InstanceDef::ReifyShim(def_id); + resolved.def = InstanceDef::ReifyShim(def_id, reason) } _ => {} } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 62bfa0ff9288..fb56c71c517b 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -88,7 +88,7 @@ pub use self::context::{ tls, CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, TyCtxtFeed, }; -pub use self::instance::{Instance, InstanceDef, ShortInstance, UnusedGenericParams}; +pub use self::instance::{Instance, InstanceDef, ReifyReason, ShortInstance, UnusedGenericParams}; pub use self::list::List; pub use self::parameterized::ParameterizedOverTcx; pub use self::predicate::{ diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index d4c8f5900f9e..585436744602 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -49,7 +49,7 @@ impl<'tcx> TyCtxt<'tcx> { let value = self.erase_regions(value); debug!(?value); - if !value.has_projections() { + if !value.has_aliases() { value } else { value.fold_with(&mut NormalizeAfterErasingRegionsFolder { tcx: self, param_env }) @@ -81,7 +81,7 @@ impl<'tcx> TyCtxt<'tcx> { let value = self.erase_regions(value); debug!(?value); - if !value.has_projections() { + if !value.has_aliases() { Ok(value) } else { let mut folder = TryNormalizeAfterErasingRegionsFolder::new(self, param_env); diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index a62379def534..0e7010e67d7d 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -449,6 +449,7 @@ TrivialTypeTraversalAndLiftImpls! { crate::ty::ClosureKind, crate::ty::ParamConst, crate::ty::ParamTy, + crate::ty::instance::ReifyReason, interpret::AllocId, interpret::CtfeProvenance, interpret::Scalar, diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 0d74524276fa..995feeaa1487 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -96,6 +96,10 @@ pub struct TypeckResults<'tcx> { /// pat_adjustments: ItemLocalMap>>, + /// Set of reference patterns that match against a match-ergonomics inserted reference + /// (as opposed to against a reference in the scrutinee type). + skipped_ref_pats: ItemLocalSet, + /// Records the reasons that we picked the kind of each closure; /// not all closures are present in the map. closure_kind_origins: ItemLocalMap<(Span, HirPlace<'tcx>)>, @@ -228,6 +232,7 @@ impl<'tcx> TypeckResults<'tcx> { adjustments: Default::default(), pat_binding_modes: Default::default(), pat_adjustments: Default::default(), + skipped_ref_pats: Default::default(), closure_kind_origins: Default::default(), liberated_fn_sigs: Default::default(), fru_field_types: Default::default(), @@ -435,6 +440,14 @@ impl<'tcx> TypeckResults<'tcx> { LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments } } + pub fn skipped_ref_pats(&self) -> LocalSetInContext<'_> { + LocalSetInContext { hir_owner: self.hir_owner, data: &self.skipped_ref_pats } + } + + pub fn skipped_ref_pats_mut(&mut self) -> LocalSetInContextMut<'_> { + LocalSetInContextMut { hir_owner: self.hir_owner, data: &mut self.skipped_ref_pats } + } + /// Does the pattern recursively contain a `ref mut` binding in it? /// /// This is used to determined whether a `deref` pattern should emit a `Deref` @@ -629,6 +642,49 @@ impl<'a, V> LocalTableInContextMut<'a, V> { } } +#[derive(Clone, Copy, Debug)] +pub struct LocalSetInContext<'a> { + hir_owner: OwnerId, + data: &'a ItemLocalSet, +} + +impl<'a> LocalSetInContext<'a> { + pub fn is_empty(&self) -> bool { + self.data.is_empty() + } + + pub fn contains(&self, id: hir::HirId) -> bool { + validate_hir_id_for_typeck_results(self.hir_owner, id); + self.data.contains(&id.local_id) + } +} + +#[derive(Debug)] +pub struct LocalSetInContextMut<'a> { + hir_owner: OwnerId, + data: &'a mut ItemLocalSet, +} + +impl<'a> LocalSetInContextMut<'a> { + pub fn is_empty(&self) -> bool { + self.data.is_empty() + } + + pub fn contains(&self, id: hir::HirId) -> bool { + validate_hir_id_for_typeck_results(self.hir_owner, id); + self.data.contains(&id.local_id) + } + pub fn insert(&mut self, id: hir::HirId) -> bool { + validate_hir_id_for_typeck_results(self.hir_owner, id); + self.data.insert(id.local_id) + } + + pub fn remove(&mut self, id: hir::HirId) -> bool { + validate_hir_id_for_typeck_results(self.hir_owner, id); + self.data.remove(&id.local_id) + } +} + rustc_index::newtype_index! { #[derive(HashStable)] #[encodable] diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 1ea671a4f791..367c391b45a4 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -214,12 +214,77 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// /// ## False edges /// - /// We don't want to have the exact structure of the decision tree be - /// visible through borrow checking. False edges ensure that the CFG as - /// seen by borrow checking doesn't encode this. False edges are added: + /// We don't want to have the exact structure of the decision tree be visible through borrow + /// checking. Specifically we want borrowck to think that: + /// - at any point, any or none of the patterns and guards seen so far may have been tested; + /// - after the match, any of the patterns may have matched. /// - /// * From each pre-binding block to the next pre-binding block. - /// * From each otherwise block to the next pre-binding block. + /// For example, all of these would fail to error if borrowck could see the real CFG (examples + /// taken from `tests/ui/nll/match-cfg-fake-edges.rs`): + /// ```ignore (too many errors, this is already in the test suite) + /// let x = String::new(); + /// let _ = match true { + /// _ => {}, + /// _ => drop(x), + /// }; + /// // Borrowck must not know the second arm is never run. + /// drop(x); //~ ERROR use of moved value + /// + /// let x; + /// # let y = true; + /// match y { + /// _ if { x = 2; true } => {}, + /// // Borrowck must not know the guard is always run. + /// _ => drop(x), //~ ERROR used binding `x` is possibly-uninitialized + /// }; + /// + /// let x = String::new(); + /// # let y = true; + /// match y { + /// false if { drop(x); true } => {}, + /// // Borrowck must not know the guard is not run in the `true` case. + /// true => drop(x), //~ ERROR use of moved value: `x` + /// false => {}, + /// }; + /// + /// # let mut y = (true, true); + /// let r = &mut y.1; + /// match y { + /// //~^ ERROR cannot use `y.1` because it was mutably borrowed + /// (false, true) => {} + /// // Borrowck must not know we don't test `y.1` when `y.0` is `true`. + /// (true, _) => drop(r), + /// (false, _) => {} + /// }; + /// ``` + /// + /// We add false edges to act as if we were naively matching each arm in order. What we need is + /// a (fake) path from each candidate to the next, specifically from candidate C's pre-binding + /// block to next candidate D's pre-binding block. For maximum precision (needed for deref + /// patterns), we choose the earliest node on D's success path that doesn't also lead to C (to + /// avoid loops). + /// + /// This turns out to be easy to compute: that block is the `start_block` of the first call to + /// `match_candidates` where D is the first candidate in the list. + /// + /// For example: + /// ```rust + /// # let (x, y) = (true, true); + /// match (x, y) { + /// (true, true) => 1, + /// (false, true) => 2, + /// (true, false) => 3, + /// _ => 4, + /// } + /// # ; + /// ``` + /// In this example, the pre-binding block of arm 1 has a false edge to the block for result + /// `false` of the first test on `x`. The other arms have false edges to the pre-binding blocks + /// of the next arm. + /// + /// On top of this, we also add a false edge from the otherwise_block of each guard to the + /// aforementioned start block of the next candidate, to ensure borrock doesn't rely on which + /// guards may have run. #[instrument(level = "debug", skip(self, arms))] pub(crate) fn match_expr( &mut self, @@ -365,7 +430,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { for candidate in candidates { candidate.visit_leaves(|leaf_candidate| { if let Some(ref mut prev) = previous_candidate { - prev.next_candidate_pre_binding_block = leaf_candidate.pre_binding_block; + assert!(leaf_candidate.false_edge_start_block.is_some()); + prev.next_candidate_start_block = leaf_candidate.false_edge_start_block; } previous_candidate = Some(leaf_candidate); }); @@ -1010,8 +1076,12 @@ struct Candidate<'pat, 'tcx> { /// The block before the `bindings` have been established. pre_binding_block: Option, - /// The pre-binding block of the next candidate. - next_candidate_pre_binding_block: Option, + + /// The earliest block that has only candidates >= this one as descendents. Used for false + /// edges, see the doc for [`Builder::match_expr`]. + false_edge_start_block: Option, + /// The `false_edge_start_block` of the next candidate. + next_candidate_start_block: Option, } impl<'tcx, 'pat> Candidate<'pat, 'tcx> { @@ -1033,7 +1103,8 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> { or_span: None, otherwise_block: None, pre_binding_block: None, - next_candidate_pre_binding_block: None, + false_edge_start_block: None, + next_candidate_start_block: None, } } @@ -1325,6 +1396,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { otherwise_block: BasicBlock, candidates: &mut [&mut Candidate<'_, 'tcx>], ) { + if let [first, ..] = candidates { + if first.false_edge_start_block.is_none() { + first.false_edge_start_block = Some(start_block); + } + } + match candidates { [] => { // If there are no candidates that still need testing, we're done. Since all matches are @@ -1545,6 +1622,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .into_iter() .map(|flat_pat| Candidate::from_flat_pat(flat_pat, candidate.has_guard)) .collect(); + candidate.subcandidates[0].false_edge_start_block = candidate.false_edge_start_block; } /// Try to merge all of the subcandidates of the given candidate into one. This avoids @@ -1564,6 +1642,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let any_matches = self.cfg.start_new_block(); let or_span = candidate.or_span.take().unwrap(); let source_info = self.source_info(or_span); + if candidate.false_edge_start_block.is_none() { + candidate.false_edge_start_block = + candidate.subcandidates[0].false_edge_start_block; + } for subcandidate in mem::take(&mut candidate.subcandidates) { let or_block = subcandidate.pre_binding_block.unwrap(); self.cfg.goto(or_block, source_info, any_matches); @@ -1979,12 +2061,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut block = candidate.pre_binding_block.unwrap(); - if candidate.next_candidate_pre_binding_block.is_some() { + if candidate.next_candidate_start_block.is_some() { let fresh_block = self.cfg.start_new_block(); self.false_edges( block, fresh_block, - candidate.next_candidate_pre_binding_block, + candidate.next_candidate_start_block, candidate_source_info, ); block = fresh_block; @@ -2132,7 +2214,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.false_edges( otherwise_post_guard_block, otherwise_block, - candidate.next_candidate_pre_binding_block, + candidate.next_candidate_start_block, source_info, ); diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index a4992da679e8..133cf8e33492 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -65,7 +65,14 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // we wrap the unadjusted pattern in `PatKind::Deref` repeatedly, consuming the // adjustments in *reverse order* (last-in-first-out, so that the last `Deref` inserted // gets the least-dereferenced type). - let unadjusted_pat = self.lower_pattern_unadjusted(pat); + let unadjusted_pat = match pat.kind { + hir::PatKind::Ref(inner, _) + if self.typeck_results.skipped_ref_pats().contains(pat.hir_id) => + { + self.lower_pattern_unadjusted(inner) + } + _ => self.lower_pattern_unadjusted(pat), + }; self.typeck_results.pat_adjustments().get(pat.hir_id).unwrap_or(&vec![]).iter().rev().fold( unadjusted_pat, |pat: Box<_>, ref_ty| { diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs index 0866205dfd0d..de43f9faff90 100644 --- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs +++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs @@ -91,15 +91,17 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody { return; } - let ty::Coroutine(_, coroutine_args) = *coroutine_ty.kind() else { bug!("{body:#?}") }; - // We don't need to generate a by-move coroutine if the kind of the coroutine is - // already `FnOnce` -- that means that any upvars that the closure consumes have - // already been taken by-value. - let coroutine_kind = coroutine_args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap(); - if coroutine_kind == ty::ClosureKind::FnOnce { + // We don't need to generate a by-move coroutine if the coroutine body was + // produced by the `CoroutineKindShim`, since it's already by-move. + if matches!(body.source.instance, ty::InstanceDef::CoroutineKindShim { .. }) { return; } + let ty::Coroutine(_, args) = *coroutine_ty.kind() else { bug!("{body:#?}") }; + let args = args.as_coroutine(); + + let coroutine_kind = args.kind_ty().to_opt_closure_kind().unwrap(); + let parent_def_id = tcx.local_parent(coroutine_def_id); let ty::CoroutineClosure(_, parent_args) = *tcx.type_of(parent_def_id).instantiate_identity().kind() @@ -128,6 +130,12 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody { // the outer closure body -- we need to change the coroutine to take the // upvar by value. if coroutine_capture.is_by_ref() && !parent_capture.is_by_ref() { + assert_ne!( + coroutine_kind, + ty::ClosureKind::FnOnce, + "`FnOnce` coroutine-closures return coroutines that capture from \ + their body; it will always result in a borrowck error!" + ); by_ref_fields.insert(FieldIdx::from_usize(num_args + idx)); } diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs index b5dd9dcc7b46..65715253647a 100644 --- a/compiler/rustc_mir_transform/src/coverage/query.rs +++ b/compiler/rustc_mir_transform/src/coverage/query.rs @@ -59,7 +59,7 @@ fn coverage_ids_info<'tcx>( _ => None, }) .max() - .unwrap_or(CounterId::START); + .unwrap_or(CounterId::ZERO); CoverageIdsInfo { max_counter_id } } diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 5f74841151cd..60513a674af9 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -324,7 +324,7 @@ impl<'tcx> Inliner<'tcx> { // do not need to catch this here, we can wait until the inliner decides to continue // inlining a second time. InstanceDef::VTableShim(_) - | InstanceDef::ReifyShim(_) + | InstanceDef::ReifyShim(..) | InstanceDef::FnPtrShim(..) | InstanceDef::ClosureOnceShim { .. } | InstanceDef::ConstructCoroutineInClosureShim { .. } @@ -1077,7 +1077,7 @@ fn try_instance_mir<'tcx>( let fields = def.all_fields(); for field in fields { let field_ty = field.ty(tcx, args); - if field_ty.has_param() && field_ty.has_projections() { + if field_ty.has_param() && field_ty.has_aliases() { return Err("cannot build drop shim for polymorphic type"); } } diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index 85e74a69cced..99c7b616f1b2 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -85,7 +85,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( // again, a function item can end up getting inlined. Thus we'll be able to cause // a cycle that way InstanceDef::VTableShim(_) - | InstanceDef::ReifyShim(_) + | InstanceDef::ReifyShim(..) | InstanceDef::FnPtrShim(..) | InstanceDef::ClosureOnceShim { .. } | InstanceDef::ConstructCoroutineInClosureShim { .. } diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 93bad8826255..fa6906bdd554 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -55,7 +55,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' // a virtual call, or a direct call to a function for which // indirect calls must be codegen'd differently than direct ones // (such as `#[track_caller]`). - ty::InstanceDef::ReifyShim(def_id) => { + ty::InstanceDef::ReifyShim(def_id, _) => { build_call_shim(tcx, instance, None, CallKind::Direct(def_id)) } ty::InstanceDef::ClosureOnceShim { call_once: _, track_caller: _ } => { diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index f223f64f2c5d..534937003ebf 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -13,6 +13,7 @@ use std::fmt::Debug; use std::hash::Hash; use std::marker::PhantomData; use std::sync::atomic::Ordering; +use std::sync::Arc; use super::query::DepGraphQuery; use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex}; @@ -81,7 +82,7 @@ pub(crate) struct DepGraphData { /// The dep-graph from the previous compilation session. It contains all /// nodes and edges as well as all fingerprints of nodes that have them. - previous: SerializedDepGraph, + previous: Arc, colors: DepNodeColorMap, @@ -113,7 +114,7 @@ where impl DepGraph { pub fn new( profiler: &SelfProfilerRef, - prev_graph: SerializedDepGraph, + prev_graph: Arc, prev_work_products: WorkProductMap, encoder: FileEncoder, record_graph: bool, @@ -127,6 +128,7 @@ impl DepGraph { encoder, record_graph, record_stats, + prev_graph.clone(), ); let colors = DepNodeColorMap::new(prev_graph_node_count); @@ -1084,6 +1086,7 @@ impl CurrentDepGraph { encoder: FileEncoder, record_graph: bool, record_stats: bool, + previous: Arc, ) -> Self { use std::time::{SystemTime, UNIX_EPOCH}; @@ -1116,6 +1119,7 @@ impl CurrentDepGraph { record_graph, record_stats, profiler, + previous, ), new_node_to_index: Sharded::new(|| { FxHashMap::with_capacity_and_hasher( @@ -1236,16 +1240,14 @@ impl CurrentDepGraph { match prev_index_to_index[prev_index] { Some(dep_node_index) => dep_node_index, None => { - let key = prev_graph.index_to_node(prev_index); - let edges = prev_graph - .edge_targets_from(prev_index) - .map(|i| prev_index_to_index[i].unwrap()) - .collect(); - let fingerprint = prev_graph.fingerprint_by_index(prev_index); - let dep_node_index = self.encoder.send(key, fingerprint, edges); + let dep_node_index = self.encoder.send_promoted(prev_index, &*prev_index_to_index); prev_index_to_index[prev_index] = Some(dep_node_index); #[cfg(debug_assertions)] - self.record_edge(dep_node_index, key, fingerprint); + self.record_edge( + dep_node_index, + prev_graph.index_to_node(prev_index), + prev_graph.fingerprint_by_index(prev_index), + ); dep_node_index } } diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index 0c6a63582931..2bc7cb995475 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -41,6 +41,7 @@ use crate::dep_graph::edges::EdgesVec; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fingerprint::PackedFingerprint; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::outline; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sync::Lock; use rustc_data_structures::unhash::UnhashMap; @@ -49,6 +50,7 @@ use rustc_serialize::opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixed use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use std::iter; use std::marker::PhantomData; +use std::sync::Arc; // The maximum value of `SerializedDepNodeIndex` leaves the upper two bits // unused so that we can store multiple index types in `CompressedHybridIndex`, @@ -94,7 +96,7 @@ impl SerializedDepGraph { pub fn edge_targets_from( &self, source: SerializedDepNodeIndex, - ) -> impl Iterator + '_ { + ) -> impl Iterator + Clone + '_ { let header = self.edge_list_indices[source]; let mut raw = &self.edge_list_data[header.start()..]; // Figure out where the edge list for `source` ends by getting the start index of the next @@ -176,7 +178,7 @@ fn mask(bits: usize) -> usize { impl SerializedDepGraph { #[instrument(level = "debug", skip(d))] - pub fn decode(d: &mut MemDecoder<'_>) -> SerializedDepGraph { + pub fn decode(d: &mut MemDecoder<'_>) -> Arc { // The last 16 bytes are the node count and edge count. debug!("position: {:?}", d.position()); let (node_count, edge_count, graph_size) = @@ -254,7 +256,13 @@ impl SerializedDepGraph { index[node.kind.as_usize()].insert(node.hash, idx); } - SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data, index } + Arc::new(SerializedDepGraph { + nodes, + fingerprints, + edge_list_indices, + edge_list_data, + index, + }) } } @@ -299,21 +307,24 @@ impl SerializedNodeHeader { const MAX_INLINE_LEN: usize = (u16::MAX as usize >> (Self::TOTAL_BITS - Self::LEN_BITS)) - 1; #[inline] - fn new(node_info: &NodeInfo) -> Self { + fn new( + node: DepNode, + fingerprint: Fingerprint, + edge_max_index: u32, + edge_count: usize, + ) -> Self { debug_assert_eq!(Self::TOTAL_BITS, Self::LEN_BITS + Self::WIDTH_BITS + Self::KIND_BITS); - let NodeInfo { node, fingerprint, edges } = node_info; - let mut head = node.kind.as_inner(); - let free_bytes = edges.max_index().leading_zeros() as usize / 8; + let free_bytes = edge_max_index.leading_zeros() as usize / 8; let bytes_per_index = (DEP_NODE_SIZE - free_bytes).saturating_sub(1); head |= (bytes_per_index as u16) << Self::KIND_BITS; // Encode number of edges + 1 so that we can reserve 0 to indicate that the len doesn't fit // in this bitfield. - if edges.len() <= Self::MAX_INLINE_LEN { - head |= (edges.len() as u16 + 1) << (Self::KIND_BITS + Self::WIDTH_BITS); + if edge_count <= Self::MAX_INLINE_LEN { + head |= (edge_count as u16 + 1) << (Self::KIND_BITS + Self::WIDTH_BITS); } let hash: Fingerprint = node.hash.into(); @@ -327,10 +338,10 @@ impl SerializedNodeHeader { #[cfg(debug_assertions)] { let res = Self { bytes, _marker: PhantomData }; - assert_eq!(node_info.fingerprint, res.fingerprint()); - assert_eq!(node_info.node, res.node()); + assert_eq!(fingerprint, res.fingerprint()); + assert_eq!(node, res.node()); if let Some(len) = res.len() { - assert_eq!(node_info.edges.len(), len); + assert_eq!(edge_count, len); } } Self { bytes, _marker: PhantomData } @@ -393,21 +404,61 @@ struct NodeInfo { impl NodeInfo { fn encode(&self, e: &mut FileEncoder) { - let header = SerializedNodeHeader::::new(self); + let NodeInfo { node, fingerprint, ref edges } = *self; + let header = + SerializedNodeHeader::::new(node, fingerprint, edges.max_index(), edges.len()); e.write_array(header.bytes); if header.len().is_none() { - e.emit_usize(self.edges.len()); + e.emit_usize(edges.len()); } let bytes_per_index = header.bytes_per_index(); - for node_index in self.edges.iter() { + for node_index in edges.iter() { e.write_with(|dest| { *dest = node_index.as_u32().to_le_bytes(); bytes_per_index }); } } + + /// Encode a node that was promoted from the previous graph. It reads the edges directly from + /// the previous dep graph and expects all edges to already have a new dep node index assigned. + /// This avoids the overhead of constructing `EdgesVec`, which would be needed to call `encode`. + #[inline] + fn encode_promoted( + e: &mut FileEncoder, + node: DepNode, + fingerprint: Fingerprint, + prev_index: SerializedDepNodeIndex, + prev_index_to_index: &IndexVec>, + previous: &SerializedDepGraph, + ) -> usize { + let edges = previous.edge_targets_from(prev_index); + let edge_count = edges.size_hint().0; + + // Find the highest edge in the new dep node indices + let edge_max = + edges.clone().map(|i| prev_index_to_index[i].unwrap().as_u32()).max().unwrap_or(0); + + let header = SerializedNodeHeader::::new(node, fingerprint, edge_max, edge_count); + e.write_array(header.bytes); + + if header.len().is_none() { + e.emit_usize(edge_count); + } + + let bytes_per_index = header.bytes_per_index(); + for node_index in edges { + let node_index = prev_index_to_index[node_index].unwrap(); + e.write_with(|dest| { + *dest = node_index.as_u32().to_le_bytes(); + bytes_per_index + }); + } + + edge_count + } } struct Stat { @@ -417,6 +468,7 @@ struct Stat { } struct EncoderState { + previous: Arc, encoder: FileEncoder, total_node_count: usize, total_edge_count: usize, @@ -428,8 +480,9 @@ struct EncoderState { } impl EncoderState { - fn new(encoder: FileEncoder, record_stats: bool) -> Self { + fn new(encoder: FileEncoder, record_stats: bool, previous: Arc) -> Self { Self { + previous, encoder, total_edge_count: 0, total_node_count: 0, @@ -439,36 +492,99 @@ impl EncoderState { } } + #[inline] + fn record( + &mut self, + node: DepNode, + edge_count: usize, + edges: impl FnOnce(&mut Self) -> Vec, + record_graph: &Option>, + ) -> DepNodeIndex { + let index = DepNodeIndex::new(self.total_node_count); + + self.total_node_count += 1; + self.kind_stats[node.kind.as_usize()] += 1; + self.total_edge_count += edge_count; + + if let Some(record_graph) = &record_graph { + // Call `edges` before the outlined code to allow the closure to be optimized out. + let edges = edges(self); + + // Outline the build of the full dep graph as it's typically disabled and cold. + outline(move || { + // Do not ICE when a query is called from within `with_query`. + if let Some(record_graph) = &mut record_graph.try_lock() { + record_graph.push(index, node, &edges); + } + }); + } + + if let Some(stats) = &mut self.stats { + let kind = node.kind; + + // Outline the stats code as it's typically disabled and cold. + outline(move || { + let stat = + stats.entry(kind).or_insert(Stat { kind, node_counter: 0, edge_counter: 0 }); + stat.node_counter += 1; + stat.edge_counter += edge_count as u64; + }); + } + + index + } + + /// Encodes a node to the current graph. fn encode_node( &mut self, node: &NodeInfo, record_graph: &Option>, ) -> DepNodeIndex { - let index = DepNodeIndex::new(self.total_node_count); - self.total_node_count += 1; - self.kind_stats[node.node.kind.as_usize()] += 1; + node.encode::(&mut self.encoder); + self.record( + node.node, + node.edges.len(), + |_| node.edges[..].iter().copied().collect(), + record_graph, + ) + } - let edge_count = node.edges.len(); - self.total_edge_count += edge_count; + /// Encodes a node that was promoted from the previous graph. It reads the information directly from + /// the previous dep graph for performance reasons. + /// + /// This differs from `encode_node` where you have to explictly provide the relevant `NodeInfo`. + /// + /// It expects all edges to already have a new dep node index assigned. + #[inline] + fn encode_promoted_node( + &mut self, + prev_index: SerializedDepNodeIndex, + record_graph: &Option>, + prev_index_to_index: &IndexVec>, + ) -> DepNodeIndex { + let node = self.previous.index_to_node(prev_index); - if let Some(record_graph) = &record_graph { - // Do not ICE when a query is called from within `with_query`. - if let Some(record_graph) = &mut record_graph.try_lock() { - record_graph.push(index, node.node, &node.edges); - } - } + let fingerprint = self.previous.fingerprint_by_index(prev_index); + let edge_count = NodeInfo::encode_promoted::( + &mut self.encoder, + node, + fingerprint, + prev_index, + prev_index_to_index, + &self.previous, + ); - if let Some(stats) = &mut self.stats { - let kind = node.node.kind; - - let stat = stats.entry(kind).or_insert(Stat { kind, node_counter: 0, edge_counter: 0 }); - stat.node_counter += 1; - stat.edge_counter += edge_count as u64; - } - - let encoder = &mut self.encoder; - node.encode::(encoder); - index + self.record( + node, + edge_count, + |this| { + this.previous + .edge_targets_from(prev_index) + .map(|i| prev_index_to_index[i].unwrap()) + .collect() + }, + record_graph, + ) } fn finish(self, profiler: &SelfProfilerRef) -> FileEncodeResult { @@ -479,6 +595,7 @@ impl EncoderState { stats: _, kind_stats, marker: _, + previous: _, } = self; let node_count = total_node_count.try_into().unwrap(); @@ -520,9 +637,10 @@ impl GraphEncoder { record_graph: bool, record_stats: bool, profiler: &SelfProfilerRef, + previous: Arc, ) -> Self { let record_graph = record_graph.then(|| Lock::new(DepGraphQuery::new(prev_node_count))); - let status = Lock::new(Some(EncoderState::new(encoder, record_stats))); + let status = Lock::new(Some(EncoderState::new(encoder, record_stats, previous))); GraphEncoder { status, record_graph, profiler: profiler.clone() } } @@ -596,6 +714,22 @@ impl GraphEncoder { self.status.lock().as_mut().unwrap().encode_node(&node, &self.record_graph) } + /// Encodes a node that was promoted from the previous graph. It reads the information directly from + /// the previous dep graph and expects all edges to already have a new dep node index assigned. + #[inline] + pub(crate) fn send_promoted( + &self, + prev_index: SerializedDepNodeIndex, + prev_index_to_index: &IndexVec>, + ) -> DepNodeIndex { + let _prof_timer = self.profiler.generic_activity("incr_comp_encode_dep_graph"); + self.status.lock().as_mut().unwrap().encode_promoted_node( + prev_index, + &self.record_graph, + prev_index_to_index, + ) + } + pub fn finish(&self) -> FileEncodeResult { let _prof_timer = self.profiler.generic_activity("incr_comp_encode_dep_graph_finish"); diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index b24ed573ff97..43a43e01a9ad 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -605,6 +605,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { && !this.tcx.features().f16 && !ident.span.allows_unstable(sym::f16) && finalize.is_some() + && innermost_result.is_none() { feature_err( this.tcx.sess, @@ -618,6 +619,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { && !this.tcx.features().f128 && !ident.span.allows_unstable(sym::f128) && finalize.is_some() + && innermost_result.is_none() { feature_err( this.tcx.sess, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index a13c9c9b2784..ea0f7adf6f91 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1456,6 +1456,7 @@ symbols! { receiver, recursion_limit, reexport_test_harness_main, + ref_pat_everywhere, ref_unwind_safe_trait, reference, reflect, diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 1c62ce2d214b..f68668a91e68 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -2,7 +2,7 @@ use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher}; use rustc_hir::def_id::CrateNum; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; use rustc_middle::ty::print::{PrettyPrinter, Print, PrintError, Printer}; -use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, Instance, ReifyReason, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{GenericArg, GenericArgKind}; use std::fmt::{self, Write}; @@ -71,8 +71,14 @@ pub(super) fn mangle<'tcx>( ty::InstanceDef::VTableShim(..) => { printer.write_str("{{vtable-shim}}").unwrap(); } - ty::InstanceDef::ReifyShim(..) => { - printer.write_str("{{reify-shim}}").unwrap(); + ty::InstanceDef::ReifyShim(_, reason) => { + printer.write_str("{{reify-shim").unwrap(); + match reason { + Some(ReifyReason::FnPtr) => printer.write_str("-fnptr").unwrap(), + Some(ReifyReason::Vtable) => printer.write_str("-vtable").unwrap(), + None => (), + } + printer.write_str("}}").unwrap(); } // FIXME(async_closures): This shouldn't be needed when we fix // `Instance::ty`/`Instance::def_id`. diff --git a/compiler/rustc_symbol_mangling/src/typeid.rs b/compiler/rustc_symbol_mangling/src/typeid.rs index fc1e8e46e8de..7bd998294dd5 100644 --- a/compiler/rustc_symbol_mangling/src/typeid.rs +++ b/compiler/rustc_symbol_mangling/src/typeid.rs @@ -4,7 +4,7 @@ /// For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler, /// see design document in the tracking issue #89653. use bitflags::bitflags; -use rustc_middle::ty::{Instance, Ty, TyCtxt}; +use rustc_middle::ty::{Instance, InstanceDef, ReifyReason, Ty, TyCtxt}; use rustc_target::abi::call::FnAbi; use std::hash::Hasher; use twox_hash::XxHash64; @@ -26,7 +26,12 @@ bitflags! { const NORMALIZE_INTEGERS = 4; /// Do not perform self type erasure for attaching a secondary type id to methods with their /// concrete self so they can be used as function pointers. - const NO_SELF_TYPE_ERASURE = 8; + /// + /// (This applies to typeid_for_instance only and should be used to attach a secondary type + /// id to methods during their declaration/definition so they match the type ids returned by + /// either typeid_for_instance or typeid_for_fnabi at call sites during code generation for + /// type membership tests when methods are used as function pointers.) + const USE_CONCRETE_SELF = 8; } } @@ -67,8 +72,26 @@ pub fn kcfi_typeid_for_fnabi<'tcx>( pub fn kcfi_typeid_for_instance<'tcx>( tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, - options: TypeIdOptions, + mut options: TypeIdOptions, ) -> u32 { + // KCFI support for Rust shares most of its implementation with the CFI support, with some key + // differences: + // + // 1. KCFI performs type tests differently and are implemented as different LLVM passes than CFI + // to not require LTO. + // 2. KCFI has the limitation that a function or method may have one type id assigned only. + // + // Because of the limitation listed above (2), the current KCFI implementation (not CFI) does + // reifying of types (i.e., adds shims/trampolines for indirect calls in these cases) for: + // + // * Supporting casting between function items, closures, and Fn trait objects. + // * Supporting methods being cast as function pointers. + // + // This was implemented for KCFI support in #123106 and #123052 (which introduced the + // ReifyReason). The tracking issue for KCFI support for Rust is #123479. + if matches!(instance.def, InstanceDef::ReifyShim(_, Some(ReifyReason::FnPtr))) { + options.insert(TypeIdOptions::USE_CONCRETE_SELF); + } // A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the // xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.) let mut hash: XxHash64 = Default::default(); diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs index 5f5d90f359a2..7f223f132505 100644 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs @@ -11,13 +11,14 @@ use rustc_data_structures::base_n; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; +use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::layout::IntegerExt; -use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::{ self, Const, ExistentialPredicate, FloatTy, FnSig, Instance, IntTy, List, Region, RegionKind, TermKind, Ty, TyCtxt, UintTy, }; use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgsRef}; +use rustc_middle::ty::{TypeFoldable, TypeVisitableExt}; use rustc_span::def_id::DefId; use rustc_span::sym; use rustc_target::abi::call::{Conv, FnAbi, PassMode}; @@ -182,14 +183,15 @@ fn encode_fnsig<'tcx>( // Encode the return type let transform_ty_options = TransformTyOptions::from_bits(options.bits()) .unwrap_or_else(|| bug!("encode_fnsig: invalid option(s) `{:?}`", options.bits())); - let ty = transform_ty(tcx, fn_sig.output(), &mut Vec::new(), transform_ty_options); + let mut type_folder = TransformTy::new(tcx, transform_ty_options); + let ty = fn_sig.output().fold_with(&mut type_folder); s.push_str(&encode_ty(tcx, ty, dict, encode_ty_options)); // Encode the parameter types let tys = fn_sig.inputs(); if !tys.is_empty() { for ty in tys { - let ty = transform_ty(tcx, *ty, &mut Vec::new(), transform_ty_options); + let ty = ty.fold_with(&mut type_folder); s.push_str(&encode_ty(tcx, ty, dict, encode_ty_options)); } @@ -523,15 +525,9 @@ fn encode_ty<'tcx>( ty::Array(ty0, len) => { // A + let len = len.eval_target_usize(tcx, ty::ParamEnv::reveal_all()); let mut s = String::from("A"); - let _ = write!( - s, - "{}", - &len.try_to_scalar() - .unwrap() - .to_target_usize(&tcx.data_layout) - .expect("Array lens are defined in usize") - ); + let _ = write!(s, "{}", &len); s.push_str(&encode_ty(tcx, *ty0, dict, options)); compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); typeid.push_str(&s); @@ -756,278 +752,208 @@ fn encode_ty<'tcx>( typeid } -/// Transforms predicates for being encoded and used in the substitution dictionary. -fn transform_predicates<'tcx>( +struct TransformTy<'tcx> { tcx: TyCtxt<'tcx>, - predicates: &List>, -) -> &'tcx List> { - tcx.mk_poly_existential_predicates_from_iter(predicates.iter().filter_map(|predicate| { - match predicate.skip_binder() { - ty::ExistentialPredicate::Trait(trait_ref) => { - let trait_ref = ty::TraitRef::identity(tcx, trait_ref.def_id); - Some(ty::Binder::dummy(ty::ExistentialPredicate::Trait( - ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref), - ))) - } - ty::ExistentialPredicate::Projection(..) => None, - ty::ExistentialPredicate::AutoTrait(..) => Some(predicate), - } - })) + options: TransformTyOptions, + parents: Vec>, } -/// Transforms args for being encoded and used in the substitution dictionary. -fn transform_args<'tcx>( - tcx: TyCtxt<'tcx>, - args: GenericArgsRef<'tcx>, - parents: &mut Vec>, - options: TransformTyOptions, -) -> GenericArgsRef<'tcx> { - let args = args.iter().map(|arg| match arg.unpack() { - GenericArgKind::Type(ty) if ty.is_c_void(tcx) => Ty::new_unit(tcx).into(), - GenericArgKind::Type(ty) => transform_ty(tcx, ty, parents, options).into(), - _ => arg, - }); - tcx.mk_args_from_iter(args) +impl<'tcx> TransformTy<'tcx> { + fn new(tcx: TyCtxt<'tcx>, options: TransformTyOptions) -> Self { + TransformTy { tcx, options, parents: Vec::new() } + } } -// Transforms a ty:Ty for being encoded and used in the substitution dictionary. It transforms all -// c_void types into unit types unconditionally, generalizes pointers if -// TransformTyOptions::GENERALIZE_POINTERS option is set, and normalizes integers if -// TransformTyOptions::NORMALIZE_INTEGERS option is set. -fn transform_ty<'tcx>( - tcx: TyCtxt<'tcx>, - mut ty: Ty<'tcx>, - parents: &mut Vec>, - options: TransformTyOptions, -) -> Ty<'tcx> { - match ty.kind() { - ty::Float(..) | ty::Str | ty::Never | ty::Foreign(..) | ty::CoroutineWitness(..) => {} +impl<'tcx> TypeFolder> for TransformTy<'tcx> { + // Transforms a ty:Ty for being encoded and used in the substitution dictionary. It transforms + // all c_void types into unit types unconditionally, generalizes pointers if + // TransformTyOptions::GENERALIZE_POINTERS option is set, and normalizes integers if + // TransformTyOptions::NORMALIZE_INTEGERS option is set. + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + match t.kind() { + ty::Array(..) + | ty::Closure(..) + | ty::Coroutine(..) + | ty::CoroutineClosure(..) + | ty::CoroutineWitness(..) + | ty::Float(..) + | ty::FnDef(..) + | ty::Foreign(..) + | ty::Never + | ty::Slice(..) + | ty::Str + | ty::Tuple(..) => t.super_fold_with(self), - ty::Bool => { - if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) { - // Note: on all platforms that Rust's currently supports, its size and alignment are - // 1, and its ABI class is INTEGER - see Rust Layout and ABIs. - // - // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#bool.) - // - // Clang represents bool as an 8-bit unsigned integer. - ty = tcx.types.u8; - } - } - - ty::Char => { - if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) { - // Since #118032, char is guaranteed to have the same size, alignment, and function - // call ABI as u32 on all platforms. - ty = tcx.types.u32; - } - } - - ty::Int(..) | ty::Uint(..) => { - if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) { - // Note: C99 7.18.2.4 requires uintptr_t and intptr_t to be at least 16-bit wide. - // All platforms we currently support have a C platform, and as a consequence, - // isize/usize are at least 16-bit wide for all of them. - // - // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#isize-and-usize.) - match ty.kind() { - ty::Int(IntTy::Isize) => match tcx.sess.target.pointer_width { - 16 => ty = tcx.types.i16, - 32 => ty = tcx.types.i32, - 64 => ty = tcx.types.i64, - 128 => ty = tcx.types.i128, - _ => bug!( - "transform_ty: unexpected pointer width `{}`", - tcx.sess.target.pointer_width - ), - }, - ty::Uint(UintTy::Usize) => match tcx.sess.target.pointer_width { - 16 => ty = tcx.types.u16, - 32 => ty = tcx.types.u32, - 64 => ty = tcx.types.u64, - 128 => ty = tcx.types.u128, - _ => bug!( - "transform_ty: unexpected pointer width `{}`", - tcx.sess.target.pointer_width - ), - }, - _ => (), + ty::Bool => { + if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) { + // Note: on all platforms that Rust's currently supports, its size and alignment + // are 1, and its ABI class is INTEGER - see Rust Layout and ABIs. + // + // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#bool.) + // + // Clang represents bool as an 8-bit unsigned integer. + self.tcx.types.u8 + } else { + t } } - } - _ if ty.is_unit() => {} - - ty::Tuple(tys) => { - ty = Ty::new_tup_from_iter( - tcx, - tys.iter().map(|ty| transform_ty(tcx, ty, parents, options)), - ); - } - - ty::Array(ty0, len) => { - let len = len.eval_target_usize(tcx, ty::ParamEnv::reveal_all()); - - ty = Ty::new_array(tcx, transform_ty(tcx, *ty0, parents, options), len); - } - - ty::Slice(ty0) => { - ty = Ty::new_slice(tcx, transform_ty(tcx, *ty0, parents, options)); - } - - ty::Adt(adt_def, args) => { - if ty.is_c_void(tcx) { - ty = Ty::new_unit(tcx); - } else if options.contains(TransformTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c() - { - ty = Ty::new_adt(tcx, *adt_def, ty::List::empty()); - } else if adt_def.repr().transparent() && adt_def.is_struct() && !parents.contains(&ty) - { - // Don't transform repr(transparent) types with an user-defined CFI encoding to - // preserve the user-defined CFI encoding. - if let Some(_) = tcx.get_attr(adt_def.did(), sym::cfi_encoding) { - return ty; + ty::Char => { + if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) { + // Since #118032, char is guaranteed to have the same size, alignment, and + // function call ABI as u32 on all platforms. + self.tcx.types.u32 + } else { + t } - let variant = adt_def.non_enum_variant(); - let param_env = tcx.param_env(variant.def_id); - let field = variant.fields.iter().find(|field| { - let ty = tcx.type_of(field.did).instantiate_identity(); - let is_zst = - tcx.layout_of(param_env.and(ty)).is_ok_and(|layout| layout.is_zst()); - !is_zst - }); - if let Some(field) = field { - let ty0 = tcx.type_of(field.did).instantiate(tcx, args); - // Generalize any repr(transparent) user-defined type that is either a pointer - // or reference, and either references itself or any other type that contains or - // references itself, to avoid a reference cycle. + } - // If the self reference is not through a pointer, for example, due - // to using `PhantomData`, need to skip normalizing it if we hit it again. - parents.push(ty); - if ty0.is_any_ptr() && ty0.contains(ty) { - ty = transform_ty( - tcx, - ty0, - parents, - options | TransformTyOptions::GENERALIZE_POINTERS, - ); - } else { - ty = transform_ty(tcx, ty0, parents, options); + ty::Int(..) | ty::Uint(..) => { + if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) { + // Note: C99 7.18.2.4 requires uintptr_t and intptr_t to be at least 16-bit + // wide. All platforms we currently support have a C platform, and as a + // consequence, isize/usize are at least 16-bit wide for all of them. + // + // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#isize-and-usize.) + match t.kind() { + ty::Int(IntTy::Isize) => match self.tcx.sess.target.pointer_width { + 16 => self.tcx.types.i16, + 32 => self.tcx.types.i32, + 64 => self.tcx.types.i64, + 128 => self.tcx.types.i128, + _ => bug!( + "fold_ty: unexpected pointer width `{}`", + self.tcx.sess.target.pointer_width + ), + }, + ty::Uint(UintTy::Usize) => match self.tcx.sess.target.pointer_width { + 16 => self.tcx.types.u16, + 32 => self.tcx.types.u32, + 64 => self.tcx.types.u64, + 128 => self.tcx.types.u128, + _ => bug!( + "fold_ty: unexpected pointer width `{}`", + self.tcx.sess.target.pointer_width + ), + }, + _ => t, } - parents.pop(); } else { - // Transform repr(transparent) types without non-ZST field into () - ty = Ty::new_unit(tcx); - } - } else { - ty = Ty::new_adt(tcx, *adt_def, transform_args(tcx, args, parents, options)); - } - } - - ty::FnDef(def_id, args) => { - ty = Ty::new_fn_def(tcx, *def_id, transform_args(tcx, args, parents, options)); - } - - ty::Closure(def_id, args) => { - ty = Ty::new_closure(tcx, *def_id, transform_args(tcx, args, parents, options)); - } - - ty::CoroutineClosure(def_id, args) => { - ty = Ty::new_coroutine_closure( - tcx, - *def_id, - transform_args(tcx, args, parents, options), - ); - } - - ty::Coroutine(def_id, args) => { - ty = Ty::new_coroutine(tcx, *def_id, transform_args(tcx, args, parents, options)); - } - - ty::Ref(region, ty0, ..) => { - if options.contains(TransformTyOptions::GENERALIZE_POINTERS) { - if ty.is_mutable_ptr() { - ty = Ty::new_mut_ref(tcx, tcx.lifetimes.re_static, Ty::new_unit(tcx)); - } else { - ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, Ty::new_unit(tcx)); - } - } else { - if ty.is_mutable_ptr() { - ty = Ty::new_mut_ref(tcx, *region, transform_ty(tcx, *ty0, parents, options)); - } else { - ty = Ty::new_imm_ref(tcx, *region, transform_ty(tcx, *ty0, parents, options)); + t } } - } - ty::RawPtr(ptr_ty, _) => { - if options.contains(TransformTyOptions::GENERALIZE_POINTERS) { - if ty.is_mutable_ptr() { - ty = Ty::new_mut_ptr(tcx, Ty::new_unit(tcx)); + ty::Adt(..) if t.is_c_void(self.tcx) => self.tcx.types.unit, + + ty::Adt(adt_def, args) => { + if adt_def.repr().transparent() && adt_def.is_struct() && !self.parents.contains(&t) + { + // Don't transform repr(transparent) types with an user-defined CFI encoding to + // preserve the user-defined CFI encoding. + if let Some(_) = self.tcx.get_attr(adt_def.did(), sym::cfi_encoding) { + return t; + } + let variant = adt_def.non_enum_variant(); + let param_env = self.tcx.param_env(variant.def_id); + let field = variant.fields.iter().find(|field| { + let ty = self.tcx.type_of(field.did).instantiate_identity(); + let is_zst = self + .tcx + .layout_of(param_env.and(ty)) + .is_ok_and(|layout| layout.is_zst()); + !is_zst + }); + if let Some(field) = field { + let ty0 = self.tcx.type_of(field.did).instantiate(self.tcx, args); + // Generalize any repr(transparent) user-defined type that is either a + // pointer or reference, and either references itself or any other type that + // contains or references itself, to avoid a reference cycle. + + // If the self reference is not through a pointer, for example, due + // to using `PhantomData`, need to skip normalizing it if we hit it again. + self.parents.push(t); + let ty = if ty0.is_any_ptr() && ty0.contains(t) { + let options = self.options; + self.options |= TransformTyOptions::GENERALIZE_POINTERS; + let ty = ty0.fold_with(self); + self.options = options; + ty + } else { + ty0.fold_with(self) + }; + self.parents.pop(); + ty + } else { + // Transform repr(transparent) types without non-ZST field into () + self.tcx.types.unit + } } else { - ty = Ty::new_imm_ptr(tcx, Ty::new_unit(tcx)); - } - } else { - if ty.is_mutable_ptr() { - ty = Ty::new_mut_ptr(tcx, transform_ty(tcx, *ptr_ty, parents, options)); - } else { - ty = Ty::new_imm_ptr(tcx, transform_ty(tcx, *ptr_ty, parents, options)); + t.super_fold_with(self) } } - } - ty::FnPtr(fn_sig) => { - if options.contains(TransformTyOptions::GENERALIZE_POINTERS) { - ty = Ty::new_imm_ptr(tcx, Ty::new_unit(tcx)); - } else { - let parameters: Vec> = fn_sig - .skip_binder() - .inputs() - .iter() - .map(|ty| transform_ty(tcx, *ty, parents, options)) - .collect(); - let output = transform_ty(tcx, fn_sig.skip_binder().output(), parents, options); - ty = Ty::new_fn_ptr( - tcx, - ty::Binder::bind_with_vars( - tcx.mk_fn_sig( - parameters, - output, - fn_sig.c_variadic(), - fn_sig.unsafety(), - fn_sig.abi(), - ), - fn_sig.bound_vars(), - ), + ty::Ref(..) => { + if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) { + if t.is_mutable_ptr() { + Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_static, self.tcx.types.unit) + } else { + Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, self.tcx.types.unit) + } + } else { + t.super_fold_with(self) + } + } + + ty::RawPtr(..) => { + if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) { + if t.is_mutable_ptr() { + Ty::new_mut_ptr(self.tcx, self.tcx.types.unit) + } else { + Ty::new_imm_ptr(self.tcx, self.tcx.types.unit) + } + } else { + t.super_fold_with(self) + } + } + + ty::FnPtr(..) => { + if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) { + Ty::new_imm_ptr(self.tcx, self.tcx.types.unit) + } else { + t.super_fold_with(self) + } + } + + ty::Dynamic(predicates, _region, kind) => { + let predicates = self.tcx.mk_poly_existential_predicates_from_iter( + predicates.iter().filter_map(|predicate| match predicate.skip_binder() { + ty::ExistentialPredicate::Trait(trait_ref) => { + let trait_ref = ty::TraitRef::identity(self.tcx, trait_ref.def_id); + Some(ty::Binder::dummy(ty::ExistentialPredicate::Trait( + ty::ExistentialTraitRef::erase_self_ty(self.tcx, trait_ref), + ))) + } + ty::ExistentialPredicate::Projection(..) => None, + ty::ExistentialPredicate::AutoTrait(..) => Some(predicate), + }), ); + + Ty::new_dynamic(self.tcx, predicates, self.tcx.lifetimes.re_erased, *kind) } - } - ty::Dynamic(predicates, _region, kind) => { - ty = Ty::new_dynamic( - tcx, - transform_predicates(tcx, predicates), - tcx.lifetimes.re_erased, - *kind, - ); - } + ty::Alias(..) => { + self.fold_ty(self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), t)) + } - ty::Alias(..) => { - ty = transform_ty( - tcx, - tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty), - parents, - options, - ); - } - - ty::Bound(..) | ty::Error(..) | ty::Infer(..) | ty::Param(..) | ty::Placeholder(..) => { - bug!("transform_ty: unexpected `{:?}`", ty.kind()); + ty::Bound(..) | ty::Error(..) | ty::Infer(..) | ty::Param(..) | ty::Placeholder(..) => { + bug!("fold_ty: unexpected `{:?}`", t.kind()); + } } } - ty + fn interner(&self) -> TyCtxt<'tcx> { + self.tcx + } } /// Returns a type metadata identifier for the specified FnAbi using the Itanium C++ ABI with vendor @@ -1068,7 +994,8 @@ pub fn typeid_for_fnabi<'tcx>( // Encode the return type let transform_ty_options = TransformTyOptions::from_bits(options.bits()) .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits())); - let ty = transform_ty(tcx, fn_abi.ret.layout.ty, &mut Vec::new(), transform_ty_options); + let mut type_folder = TransformTy::new(tcx, transform_ty_options); + let ty = fn_abi.ret.layout.ty.fold_with(&mut type_folder); typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); // Encode the parameter types @@ -1080,7 +1007,7 @@ pub fn typeid_for_fnabi<'tcx>( let mut pushed_arg = false; for arg in fn_abi.args.iter().filter(|arg| arg.mode != PassMode::Ignore) { pushed_arg = true; - let ty = transform_ty(tcx, arg.layout.ty, &mut Vec::new(), transform_ty_options); + let ty = arg.layout.ty.fold_with(&mut type_folder); typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); } if !pushed_arg { @@ -1093,8 +1020,7 @@ pub fn typeid_for_fnabi<'tcx>( if fn_abi.args[n].mode == PassMode::Ignore { continue; } - let ty = - transform_ty(tcx, fn_abi.args[n].layout.ty, &mut Vec::new(), transform_ty_options); + let ty = fn_abi.args[n].layout.ty.fold_with(&mut type_folder); typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); } @@ -1172,7 +1098,7 @@ pub fn typeid_for_instance<'tcx>( instance.args = tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1)); } - if !options.contains(EncodeTyOptions::NO_SELF_TYPE_ERASURE) { + if !options.contains(EncodeTyOptions::USE_CONCRETE_SELF) { if let Some(impl_id) = tcx.impl_of_method(instance.def_id()) && let Some(trait_ref) = tcx.impl_trait_ref(impl_id) { diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 4369f020d27a..8cb5370bb4a8 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -8,8 +8,8 @@ use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::print::{Print, PrintError, Printer}; use rustc_middle::ty::{ - self, EarlyBinder, FloatTy, Instance, IntTy, Ty, TyCtxt, TypeVisitable, TypeVisitableExt, - UintTy, + self, EarlyBinder, FloatTy, Instance, IntTy, ReifyReason, Ty, TyCtxt, TypeVisitable, + TypeVisitableExt, UintTy, }; use rustc_middle::ty::{GenericArg, GenericArgKind}; use rustc_span::symbol::kw; @@ -44,7 +44,9 @@ pub(super) fn mangle<'tcx>( let shim_kind = match instance.def { ty::InstanceDef::ThreadLocalShim(_) => Some("tls"), ty::InstanceDef::VTableShim(_) => Some("vtable"), - ty::InstanceDef::ReifyShim(_) => Some("reify"), + ty::InstanceDef::ReifyShim(_, None) => Some("reify"), + ty::InstanceDef::ReifyShim(_, Some(ReifyReason::FnPtr)) => Some("reify-fnptr"), + ty::InstanceDef::ReifyShim(_, Some(ReifyReason::Vtable)) => Some("reify-vtable"), ty::InstanceDef::ConstructCoroutineInClosureShim { .. } | ty::InstanceDef::CoroutineKindShim { .. } => Some("fn_once"), diff --git a/compiler/rustc_target/src/spec/base/apple/mod.rs b/compiler/rustc_target/src/spec/base/apple/mod.rs index dd75377ead2a..96da0b6fd1f5 100644 --- a/compiler/rustc_target/src/spec/base/apple/mod.rs +++ b/compiler/rustc_target/src/spec/base/apple/mod.rs @@ -102,6 +102,7 @@ fn pre_link_args(os: &'static str, arch: Arch, abi: &'static str) -> LinkArgs { "ios" => ios_deployment_target(arch, abi), "tvos" => tvos_deployment_target(), "watchos" => watchos_deployment_target(), + "visionos" => visionos_deployment_target(), "macos" => macos_deployment_target(arch), _ => unreachable!(), }; @@ -202,6 +203,8 @@ pub fn sdk_version(platform: u32) -> Option<(u32, u32)> { | object::macho::PLATFORM_TVOSSIMULATOR | object::macho::PLATFORM_MACCATALYST => Some((16, 2)), object::macho::PLATFORM_WATCHOS | object::macho::PLATFORM_WATCHOSSIMULATOR => Some((9, 1)), + // FIXME: Upgrade to `object-rs` 0.33+ implementation with visionOS platform definition + 11 | 12 => Some((1, 0)), _ => None, } } @@ -216,6 +219,9 @@ pub fn platform(target: &Target) -> Option { ("watchos", _) => object::macho::PLATFORM_WATCHOS, ("tvos", "sim") => object::macho::PLATFORM_TVOSSIMULATOR, ("tvos", _) => object::macho::PLATFORM_TVOS, + // FIXME: Upgrade to `object-rs` 0.33+ implementation with visionOS platform definition + ("visionos", "sim") => 12, + ("visionos", _) => 11, _ => return None, }) } @@ -240,6 +246,7 @@ pub fn deployment_target(target: &Target) -> Option<(u32, u32)> { } "watchos" => watchos_deployment_target(), "tvos" => tvos_deployment_target(), + "visionos" => visionos_deployment_target(), _ => return None, }; @@ -290,6 +297,7 @@ fn link_env_remove(os: &'static str) -> StaticCow<[StaticCow]> { || sdkroot.contains("AppleTVSimulator.platform") || sdkroot.contains("WatchOS.platform") || sdkroot.contains("WatchSimulator.platform") + || sdkroot.contains("XROS.platform") { env_remove.push("SDKROOT".into()) } @@ -299,6 +307,7 @@ fn link_env_remove(os: &'static str) -> StaticCow<[StaticCow]> { // although this is apparently ignored when using the linker at "/usr/bin/ld". env_remove.push("IPHONEOS_DEPLOYMENT_TARGET".into()); env_remove.push("TVOS_DEPLOYMENT_TARGET".into()); + env_remove.push("XROS_DEPLOYMENT_TARGET".into()); env_remove.into() } else { // Otherwise if cross-compiling for a different OS/SDK (including Mac Catalyst), remove any part @@ -363,3 +372,18 @@ pub fn watchos_sim_llvm_target(arch: Arch) -> String { let (major, minor) = watchos_deployment_target(); format!("{}-apple-watchos{}.{}.0-simulator", arch.target_name(), major, minor) } + +fn visionos_deployment_target() -> (u32, u32) { + // If you are looking for the default deployment target, prefer `rustc --print deployment-target`. + from_set_deployment_target("XROS_DEPLOYMENT_TARGET").unwrap_or((1, 0)) +} + +pub fn visionos_llvm_target(arch: Arch) -> String { + let (major, minor) = visionos_deployment_target(); + format!("{}-apple-visionos{}.{}.0", arch.target_name(), major, minor) +} + +pub fn visionos_sim_llvm_target(arch: Arch) -> String { + let (major, minor) = visionos_deployment_target(); + format!("{}-apple-visionos{}.{}.0-simulator", arch.target_name(), major, minor) +} diff --git a/compiler/rustc_target/src/spec/base/apple/tests.rs b/compiler/rustc_target/src/spec/base/apple/tests.rs index 097039d6c738..7a985ad4dc05 100644 --- a/compiler/rustc_target/src/spec/base/apple/tests.rs +++ b/compiler/rustc_target/src/spec/base/apple/tests.rs @@ -1,6 +1,7 @@ use crate::spec::targets::{ - aarch64_apple_darwin, aarch64_apple_ios_sim, aarch64_apple_watchos_sim, i686_apple_darwin, - x86_64_apple_darwin, x86_64_apple_ios, x86_64_apple_tvos, x86_64_apple_watchos_sim, + aarch64_apple_darwin, aarch64_apple_ios_sim, aarch64_apple_visionos_sim, + aarch64_apple_watchos_sim, i686_apple_darwin, x86_64_apple_darwin, x86_64_apple_ios, + x86_64_apple_tvos, x86_64_apple_watchos_sim, }; #[test] @@ -12,6 +13,7 @@ fn simulator_targets_set_abi() { aarch64_apple_ios_sim::target(), // Note: There is currently no ARM64 tvOS simulator target aarch64_apple_watchos_sim::target(), + aarch64_apple_visionos_sim::target(), ]; for target in &all_sim_targets { @@ -32,7 +34,11 @@ fn macos_link_environment_unmodified() { // for the host. assert_eq!( target.link_env_remove, - crate::spec::cvs!["IPHONEOS_DEPLOYMENT_TARGET", "TVOS_DEPLOYMENT_TARGET"], + crate::spec::cvs![ + "IPHONEOS_DEPLOYMENT_TARGET", + "TVOS_DEPLOYMENT_TARGET", + "XROS_DEPLOYMENT_TARGET" + ], ); } } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 966da2c5eda5..e94c7f3cc582 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1557,6 +1557,9 @@ supported_targets! { ("aarch64-apple-watchos", aarch64_apple_watchos), ("aarch64-apple-watchos-sim", aarch64_apple_watchos_sim), + ("aarch64-apple-visionos", aarch64_apple_visionos), + ("aarch64-apple-visionos-sim", aarch64_apple_visionos_sim), + ("armebv7r-none-eabi", armebv7r_none_eabi), ("armebv7r-none-eabihf", armebv7r_none_eabihf), ("armv7r-none-eabi", armv7r_none_eabi), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs new file mode 100644 index 000000000000..7afe224163bc --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs @@ -0,0 +1,27 @@ +use crate::spec::base::apple::{opts, visionos_llvm_target, Arch}; +use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions}; + +pub fn target() -> Target { + let arch = Arch::Arm64; + let mut base = opts("visionos", arch); + base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD; + + Target { + llvm_target: visionos_llvm_target(arch).into(), + metadata: crate::spec::TargetMetadata { + description: Some("ARM64 Apple visionOS".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, + pointer_width: 64, + data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".into(), + arch: arch.target_arch(), + options: TargetOptions { + features: "+neon,+fp-armv8,+apple-a16".into(), + max_atomic_width: Some(128), + frame_pointer: FramePointer::NonLeaf, + ..base + }, + } +} diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs new file mode 100644 index 000000000000..422b2d7b922f --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs @@ -0,0 +1,27 @@ +use crate::spec::base::apple::{opts, visionos_sim_llvm_target, Arch}; +use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions}; + +pub fn target() -> Target { + let arch = Arch::Arm64_sim; + let mut base = opts("visionos", arch); + base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD; + + Target { + llvm_target: visionos_sim_llvm_target(arch).into(), + metadata: crate::spec::TargetMetadata { + description: Some("ARM64 Apple visionOS simulator".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, + pointer_width: 64, + data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".into(), + arch: arch.target_arch(), + options: TargetOptions { + features: "+neon,+fp-armv8,+apple-a16".into(), + max_atomic_width: Some(128), + frame_pointer: FramePointer::NonLeaf, + ..base + }, + } +} diff --git a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs index d9ebc7fbc1ae..2f86506e2d05 100644 --- a/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armebv7r_none_eabihf.rs @@ -22,7 +22,7 @@ pub fn target() -> Target { linker: Some("rust-lld".into()), relocation_model: RelocModel::Static, panic_strategy: PanicStrategy::Abort, - features: "+vfp3,-d32,-fp16".into(), + features: "+vfp3d16".into(), max_atomic_width: Some(64), emit_debug_gdb_scripts: false, // GCC defaults to 8 for arm-none here. diff --git a/compiler/rustc_target/src/spec/targets/armv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7r_none_eabihf.rs index a8c622ccce28..7c39d2d38de8 100644 --- a/compiler/rustc_target/src/spec/targets/armv7r_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7r_none_eabihf.rs @@ -21,7 +21,7 @@ pub fn target() -> Target { linker: Some("rust-lld".into()), relocation_model: RelocModel::Static, panic_strategy: PanicStrategy::Abort, - features: "+vfp3,-d32,-fp16".into(), + features: "+vfp3d16".into(), max_atomic_width: Some(64), emit_debug_gdb_scripts: false, // GCC defaults to 8 for arm-none here. diff --git a/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs index 8c6bc6d72675..bff812a5d5c7 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7em_none_eabihf.rs @@ -25,16 +25,15 @@ pub fn target() -> Target { options: TargetOptions { abi: "eabihf".into(), - // `+vfp4` is the lowest common denominator between the Cortex-M4 (vfp4-16) and the - // Cortex-M7 (vfp5) - // `-d32` both the Cortex-M4 and the Cortex-M7 only have 16 double-precision registers - // available - // `-fp64` The Cortex-M4 only supports single precision floating point operations - // whereas in the Cortex-M7 double precision is optional + // vfp4 is the lowest common denominator between the Cortex-M4F (vfp4) and the + // Cortex-M7 (vfp5). + // Both the Cortex-M4 and the Cortex-M7 only have 16 double-precision registers + // available, and the Cortex-M4 only supports single-precision floating point operations + // whereas in the Cortex-M7 double-precision is optional. // // Reference: // ARMv7-M Architecture Reference Manual - A2.5 The optional floating-point extension - features: "+vfp4,-d32,-fp64".into(), + features: "+vfp4d16sp".into(), max_atomic_width: Some(32), ..base::thumb::opts() }, diff --git a/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs index 2fef08261e1e..88796e7a756b 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv8m_main_none_eabihf.rs @@ -22,8 +22,7 @@ pub fn target() -> Target { // processor, the Cortex-M33 Technical Reference Manual states that // the FPU uses the FPv5 architecture, single-precision instructions // and 16 D registers. - // These parameters map to the following LLVM features. - features: "+fp-armv8,-fp64,-d32".into(), + features: "+fp-armv8d16sp".into(), max_atomic_width: Some(32), ..base::thumb::opts() }, diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs index e081a9100e2f..f2c441dcbeda 100644 --- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs +++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs @@ -2,8 +2,8 @@ //! Doing this via a separate goal is called "deferred alias relation" and part //! of our more general approach to "lazy normalization". //! -//! This is done by first normalizing both sides of the goal, ending up in -//! either a concrete type, rigid alias, or an infer variable. +//! This is done by first structurally normalizing both sides of the goal, ending +//! up in either a concrete type, rigid alias, or an infer variable. //! These are related further according to the rules below: //! //! (1.) If we end up with two rigid aliases, then we relate them structurally. @@ -14,18 +14,10 @@ //! //! (3.) Otherwise, if we end with two rigid (non-projection) or infer types, //! relate them structurally. -//! -//! Subtle: when relating an opaque to another type, we emit a -//! `NormalizesTo(opaque, ?fresh_var)` goal when trying to normalize the opaque. -//! This nested goal starts out as ambiguous and does not actually define the opaque. -//! However, if `?fresh_var` ends up geteting equated to another type, we retry the -//! `NormalizesTo` goal, at which point the opaque is actually defined. use super::EvalCtxt; -use rustc_infer::traits::query::NoSolution; -use rustc_infer::traits::solve::GoalSource; use rustc_middle::traits::solve::{Certainty, Goal, QueryResult}; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty; impl<'tcx> EvalCtxt<'_, 'tcx> { #[instrument(level = "debug", skip(self), ret)] @@ -36,21 +28,34 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let tcx = self.tcx(); let Goal { param_env, predicate: (lhs, rhs, direction) } = goal; - let Some(lhs) = self.try_normalize_term(param_env, lhs)? else { - return self - .evaluate_added_goals_and_make_canonical_response(Certainty::overflow(true)); + // Structurally normalize the lhs. + let lhs = if let Some(alias) = lhs.to_alias_ty(self.tcx()) { + let term = self.next_term_infer_of_kind(lhs); + self.add_normalizes_to_goal(goal.with(tcx, ty::NormalizesTo { alias, term })); + term + } else { + lhs }; - let Some(rhs) = self.try_normalize_term(param_env, rhs)? else { - return self - .evaluate_added_goals_and_make_canonical_response(Certainty::overflow(true)); + // Structurally normalize the rhs. + let rhs = if let Some(alias) = rhs.to_alias_ty(self.tcx()) { + let term = self.next_term_infer_of_kind(rhs); + self.add_normalizes_to_goal(goal.with(tcx, ty::NormalizesTo { alias, term })); + term + } else { + rhs }; + // Apply the constraints. + self.try_evaluate_added_goals()?; + let lhs = self.resolve_vars_if_possible(lhs); + let rhs = self.resolve_vars_if_possible(rhs); + debug!(?lhs, ?rhs); + let variance = match direction { ty::AliasRelationDirection::Equate => ty::Variance::Invariant, ty::AliasRelationDirection::Subtype => ty::Variance::Covariant, }; - match (lhs.to_alias_ty(tcx), rhs.to_alias_ty(tcx)) { (None, None) => { self.relate(param_env, lhs, variance, rhs)?; @@ -58,14 +63,18 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } (Some(alias), None) => { - self.relate_rigid_alias_non_alias(param_env, alias, variance, rhs) + self.relate_rigid_alias_non_alias(param_env, alias, variance, rhs)?; + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + (None, Some(alias)) => { + self.relate_rigid_alias_non_alias( + param_env, + alias, + variance.xform(ty::Variance::Contravariant), + lhs, + )?; + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } - (None, Some(alias)) => self.relate_rigid_alias_non_alias( - param_env, - alias, - variance.xform(ty::Variance::Contravariant), - lhs, - ), (Some(alias_lhs), Some(alias_rhs)) => { self.relate(param_env, alias_lhs, variance, alias_rhs)?; @@ -73,104 +82,4 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } } - - /// Relate a rigid alias with another type. This is the same as - /// an ordinary relate except that we treat the outer most alias - /// constructor as rigid. - #[instrument(level = "debug", skip(self, param_env), ret)] - fn relate_rigid_alias_non_alias( - &mut self, - param_env: ty::ParamEnv<'tcx>, - alias: ty::AliasTy<'tcx>, - variance: ty::Variance, - term: ty::Term<'tcx>, - ) -> QueryResult<'tcx> { - // NOTE: this check is purely an optimization, the structural eq would - // always fail if the term is not an inference variable. - if term.is_infer() { - let tcx = self.tcx(); - // We need to relate `alias` to `term` treating only the outermost - // constructor as rigid, relating any contained generic arguments as - // normal. We do this by first structurally equating the `term` - // with the alias constructor instantiated with unconstrained infer vars, - // and then relate this with the whole `alias`. - // - // Alternatively we could modify `Equate` for this case by adding another - // variant to `StructurallyRelateAliases`. - let identity_args = self.fresh_args_for_item(alias.def_id); - let rigid_ctor = ty::AliasTy::new(tcx, alias.def_id, identity_args); - self.eq_structurally_relating_aliases(param_env, term, rigid_ctor.to_ty(tcx).into())?; - self.eq(param_env, alias, rigid_ctor)?; - self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - } else { - Err(NoSolution) - } - } - - // FIXME: This needs a name that reflects that it's okay to bottom-out with an inference var. - /// Normalize the `term` to equate it later. - #[instrument(level = "debug", skip(self, param_env), ret)] - fn try_normalize_term( - &mut self, - param_env: ty::ParamEnv<'tcx>, - term: ty::Term<'tcx>, - ) -> Result>, NoSolution> { - match term.unpack() { - ty::TermKind::Ty(ty) => { - Ok(self.try_normalize_ty_recur(param_env, 0, ty).map(Into::into)) - } - ty::TermKind::Const(_) => { - if let Some(alias) = term.to_alias_ty(self.tcx()) { - let term = self.next_term_infer_of_kind(term); - self.add_normalizes_to_goal(Goal::new( - self.tcx(), - param_env, - ty::NormalizesTo { alias, term }, - )); - self.try_evaluate_added_goals()?; - Ok(Some(self.resolve_vars_if_possible(term))) - } else { - Ok(Some(term)) - } - } - } - } - - #[instrument(level = "debug", skip(self, param_env), ret)] - fn try_normalize_ty_recur( - &mut self, - param_env: ty::ParamEnv<'tcx>, - depth: usize, - ty: Ty<'tcx>, - ) -> Option> { - if !self.tcx().recursion_limit().value_within_limit(depth) { - return None; - } - - let ty::Alias(kind, alias) = *ty.kind() else { - return Some(ty); - }; - - match self.commit_if_ok(|this| { - let tcx = this.tcx(); - let normalized_ty = this.next_ty_infer(); - let normalizes_to = ty::NormalizesTo { alias, term: normalized_ty.into() }; - match kind { - ty::AliasKind::Opaque => { - // HACK: Unlike for associated types, `normalizes-to` for opaques - // is currently not treated as a function. We do not erase the - // expected term. - this.add_goal(GoalSource::Misc, Goal::new(tcx, param_env, normalizes_to)); - } - ty::AliasKind::Projection | ty::AliasKind::Inherent | ty::AliasKind::Weak => { - this.add_normalizes_to_goal(Goal::new(tcx, param_env, normalizes_to)) - } - } - this.try_evaluate_added_goals()?; - Ok(this.resolve_vars_if_possible(normalized_ty)) - }) { - Ok(ty) => self.try_normalize_ty_recur(param_env, depth + 1, ty), - Err(NoSolution) => Some(ty), - } - } } diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 5e580df01cbe..35f7d1d71510 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -312,11 +312,18 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { fn forced_ambiguity(&mut self, cause: MaybeCause) -> Vec> { let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc); let certainty = Certainty::Maybe(cause); - let result = self.evaluate_added_goals_and_make_canonical_response(certainty).unwrap(); + // This may fail if `try_evaluate_added_goals` overflows because it + // fails to reach a fixpoint but ends up getting an error after + // running for some additional step. + // + // FIXME: Add a test for this. It seems to be necessary for typenum but + // is incredibly hard to minimize as it may rely on being inside of a + // trait solver cycle. + let result = self.evaluate_added_goals_and_make_canonical_response(certainty); let mut dummy_probe = self.inspect.new_probe(); - dummy_probe.probe_kind(ProbeKind::TraitCandidate { source, result: Ok(result) }); + dummy_probe.probe_kind(ProbeKind::TraitCandidate { source, result }); self.inspect.finish_probe(dummy_probe); - vec![Candidate { source, result }] + if let Ok(result) = result { vec![Candidate { source, result }] } else { vec![] } } #[instrument(level = "debug", skip_all)] diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index 619435d2e8d5..4a4efb6884fc 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -332,7 +332,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { /// whether an alias is rigid by using the trait solver. When instantiating a response /// from the solver we assume that the solver correctly handled aliases and therefore /// always relate them structurally here. - #[instrument(level = "debug", skip(infcx), ret)] + #[instrument(level = "debug", skip(infcx))] fn unify_query_var_values( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/commit_if_ok.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/commit_if_ok.rs deleted file mode 100644 index c8f9a461adf5..000000000000 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/commit_if_ok.rs +++ /dev/null @@ -1,47 +0,0 @@ -use super::{EvalCtxt, NestedGoals}; -use crate::solve::inspect; -use rustc_middle::traits::query::NoSolution; - -impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { - pub(in crate::solve) fn commit_if_ok( - &mut self, - f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> Result, - ) -> Result { - let mut nested_ecx = EvalCtxt { - infcx: self.infcx, - variables: self.variables, - var_values: self.var_values, - is_normalizes_to_goal: self.is_normalizes_to_goal, - predefined_opaques_in_body: self.predefined_opaques_in_body, - max_input_universe: self.max_input_universe, - search_graph: self.search_graph, - nested_goals: NestedGoals::new(), - tainted: self.tainted, - inspect: self.inspect.new_probe(), - }; - - let result = nested_ecx.infcx.commit_if_ok(|_| f(&mut nested_ecx)); - if result.is_ok() { - let EvalCtxt { - infcx: _, - variables: _, - var_values: _, - is_normalizes_to_goal: _, - predefined_opaques_in_body: _, - max_input_universe: _, - search_graph: _, - nested_goals, - tainted, - inspect, - } = nested_ecx; - self.nested_goals.extend(nested_goals); - self.tainted = tainted; - self.inspect.integrate_snapshot(inspect); - } else { - nested_ecx.inspect.probe_kind(inspect::ProbeKind::CommitIfOk); - self.inspect.finish_probe(nested_ecx.inspect); - } - - result - } -} diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index a0fe6eca0fc8..1739bd70e7b5 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -24,7 +24,6 @@ use rustc_middle::ty::{ use rustc_session::config::DumpSolverProofTree; use rustc_span::DUMMY_SP; use std::io::Write; -use std::iter; use std::ops::ControlFlow; use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment}; @@ -36,7 +35,6 @@ use super::{GoalSource, SolverMode}; pub use select::InferCtxtSelectExt; mod canonical; -mod commit_if_ok; mod probe; mod select; @@ -124,11 +122,6 @@ impl<'tcx> NestedGoals<'tcx> { pub(super) fn is_empty(&self) -> bool { self.normalizes_to_goals.is_empty() && self.goals.is_empty() } - - pub(super) fn extend(&mut self, other: NestedGoals<'tcx>) { - self.normalizes_to_goals.extend(other.normalizes_to_goals); - self.goals.extend(other.goals) - } } #[derive(PartialEq, Eq, Debug, Hash, HashStable, Clone, Copy)] @@ -511,12 +504,6 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { self.inspect.evaluate_added_goals_loop_start(); - fn with_misc_source<'tcx>( - it: impl IntoIterator>>, - ) -> impl Iterator>)> { - iter::zip(iter::repeat(GoalSource::Misc), it) - } - // If this loop did not result in any progress, what's our final certainty. let mut unchanged_certainty = Some(Certainty::Yes); for goal in goals.normalizes_to_goals { @@ -534,16 +521,28 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { unconstrained_goal, )?; // Add the nested goals from normalization to our own nested goals. + debug!(?nested_goals); goals.goals.extend(nested_goals); // Finally, equate the goal's RHS with the unconstrained var. - // We put the nested goals from this into goals instead of - // next_goals to avoid needing to process the loop one extra - // time if this goal returns something -- I don't think this - // matters in practice, though. - let eq_goals = - self.eq_and_get_goals(goal.param_env, goal.predicate.term, unconstrained_rhs)?; - goals.goals.extend(with_misc_source(eq_goals)); + // + // SUBTLE: + // We structurally relate aliases here. This is necessary + // as we otherwise emit a nested `AliasRelate` goal in case the + // returned term is a rigid alias, resulting in overflow. + // + // It is correct as both `goal.predicate.term` and `unconstrained_rhs` + // start out as an unconstrained inference variable so any aliases get + // fully normalized when instantiating it. + // + // FIXME: Strictly speaking this may be incomplete if the normalized-to + // type contains an ambiguous alias referencing bound regions. We should + // consider changing this to only use "shallow structural equality". + self.eq_structurally_relating_aliases( + goal.param_env, + goal.predicate.term, + unconstrained_rhs, + )?; // We only look at the `projection_ty` part here rather than // looking at the "has changed" return from evaluate_goal, @@ -720,7 +719,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ) -> Result<(), NoSolution> { self.infcx .at(&ObligationCause::dummy(), param_env) - .eq(DefineOpaqueTypes::No, lhs, rhs) + // New solver ignores DefineOpaqueTypes, so choose Yes for consistency + .eq(DefineOpaqueTypes::Yes, lhs, rhs) .map(|InferOk { value: (), obligations }| { self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into())); }) @@ -730,6 +730,46 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { }) } + /// This should be used when relating a rigid alias with another type. + /// + /// Normally we emit a nested `AliasRelate` when equating an inference + /// variable and an alias. This causes us to instead constrain the inference + /// variable to the alias without emitting a nested alias relate goals. + #[instrument(level = "debug", skip(self, param_env), ret)] + pub(super) fn relate_rigid_alias_non_alias( + &mut self, + param_env: ty::ParamEnv<'tcx>, + alias: ty::AliasTy<'tcx>, + variance: ty::Variance, + term: ty::Term<'tcx>, + ) -> Result<(), NoSolution> { + // NOTE: this check is purely an optimization, the structural eq would + // always fail if the term is not an inference variable. + if term.is_infer() { + let tcx = self.tcx(); + // We need to relate `alias` to `term` treating only the outermost + // constructor as rigid, relating any contained generic arguments as + // normal. We do this by first structurally equating the `term` + // with the alias constructor instantiated with unconstrained infer vars, + // and then relate this with the whole `alias`. + // + // Alternatively we could modify `Equate` for this case by adding another + // variant to `StructurallyRelateAliases`. + let identity_args = self.fresh_args_for_item(alias.def_id); + let rigid_ctor = ty::AliasTy::new(tcx, alias.def_id, identity_args); + let ctor_ty = rigid_ctor.to_ty(tcx); + let InferOk { value: (), obligations } = self + .infcx + .at(&ObligationCause::dummy(), param_env) + .trace(term, ctor_ty.into()) + .eq_structurally_relating_aliases(term, ctor_ty.into())?; + debug_assert!(obligations.is_empty()); + self.relate(param_env, alias, variance, rigid_ctor) + } else { + Err(NoSolution) + } + } + /// This sohuld only be used when we're either instantiating a previously /// unconstrained "return value" or when we're sure that all aliases in /// the types are rigid. @@ -759,7 +799,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ) -> Result<(), NoSolution> { self.infcx .at(&ObligationCause::dummy(), param_env) - .sub(DefineOpaqueTypes::No, sub, sup) + // New solver ignores DefineOpaqueTypes, so choose Yes for consistency + .sub(DefineOpaqueTypes::Yes, sub, sup) .map(|InferOk { value: (), obligations }| { self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into())); }) @@ -779,7 +820,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ) -> Result<(), NoSolution> { self.infcx .at(&ObligationCause::dummy(), param_env) - .relate(DefineOpaqueTypes::No, lhs, variance, rhs) + // New solver ignores DefineOpaqueTypes, so choose Yes for consistency + .relate(DefineOpaqueTypes::Yes, lhs, variance, rhs) .map(|InferOk { value: (), obligations }| { self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into())); }) @@ -803,7 +845,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ) -> Result>>, NoSolution> { self.infcx .at(&ObligationCause::dummy(), param_env) - .eq(DefineOpaqueTypes::No, lhs, rhs) + // New solver ignores DefineOpaqueTypes, so choose Yes for consistency + .eq(DefineOpaqueTypes::Yes, lhs, rhs) .map(|InferOk { value: (), obligations }| { obligations.into_iter().map(|o| o.into()).collect() }) diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs index e0c7804b6db5..6644d3c77afd 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs @@ -182,7 +182,8 @@ fn rematch_impl<'tcx>( let mut nested = infcx .at(&ObligationCause::dummy(), goal.param_env) - .eq(DefineOpaqueTypes::No, goal.predicate.trait_ref, impl_trait_ref) + // New solver ignores DefineOpaqueTypes, so choose Yes for consistency + .eq(DefineOpaqueTypes::Yes, goal.predicate.trait_ref, impl_trait_ref) .map_err(|_| SelectionError::Unimplemented)? .into_obligations(); @@ -257,7 +258,8 @@ fn rematch_unsize<'tcx>( nested.extend( infcx .at(&ObligationCause::dummy(), goal.param_env) - .eq(DefineOpaqueTypes::No, a_elem_ty, b_elem_ty) + // New solver ignores DefineOpaqueTypes, so choose Yes for consistency + .eq(DefineOpaqueTypes::Yes, a_elem_ty, b_elem_ty) .expect("expected rematch to succeed") .into_obligations(), ); @@ -300,7 +302,8 @@ fn rematch_unsize<'tcx>( nested.extend( infcx .at(&ObligationCause::dummy(), goal.param_env) - .eq(DefineOpaqueTypes::No, unsized_a_ty, b_ty) + // New solver ignores DefineOpaqueTypes, so choose Yes for consistency + .eq(DefineOpaqueTypes::Yes, unsized_a_ty, b_ty) .expect("expected rematch to succeed") .into_obligations(), ); @@ -329,7 +332,8 @@ fn rematch_unsize<'tcx>( nested.extend( infcx .at(&ObligationCause::dummy(), goal.param_env) - .eq(DefineOpaqueTypes::No, unsized_a_ty, b_ty) + // New solver ignores DefineOpaqueTypes, so choose Yes for consistency + .eq(DefineOpaqueTypes::Yes, unsized_a_ty, b_ty) .expect("expected rematch to succeed") .into_obligations(), ); diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index cfec2e9bbf35..56c32d3d5391 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -130,17 +130,14 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { self.candidates_recur(candidates, nested_goals, probe); nested_goals.truncate(num_goals); } - inspect::ProbeStep::EvaluateGoals(_) - | inspect::ProbeStep::CommitIfOkStart - | inspect::ProbeStep::CommitIfOkSuccess => (), + inspect::ProbeStep::EvaluateGoals(_) => (), } } match probe.kind { inspect::ProbeKind::NormalizedSelfTyAssembly | inspect::ProbeKind::UnsizeAssembly - | inspect::ProbeKind::UpcastProjectionCompatibility - | inspect::ProbeKind::CommitIfOk => (), + | inspect::ProbeKind::UpcastProjectionCompatibility => (), // We add a candidate for the root evaluation if there // is only one way to prove a given goal, e.g. for `WellFormed`. // @@ -157,7 +154,8 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { }); } } - inspect::ProbeKind::MiscCandidate { name: _, result } + inspect::ProbeKind::TryNormalizeNonRigid { result } + | inspect::ProbeKind::MiscCandidate { name: _, result } | inspect::ProbeKind::TraitCandidate { source: _, result } => { candidates.push(InspectCandidate { goal: self, diff --git a/compiler/rustc_trait_selection/src/solve/inspect/build.rs b/compiler/rustc_trait_selection/src/solve/inspect/build.rs index 4da999f2406b..43c76cc5f4a0 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/build.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/build.rs @@ -220,8 +220,6 @@ enum WipProbeStep<'tcx> { AddGoal(GoalSource, inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>), EvaluateGoals(WipAddedGoalsEvaluation<'tcx>), NestedProbe(WipProbe<'tcx>), - CommitIfOkStart, - CommitIfOkSuccess, } impl<'tcx> WipProbeStep<'tcx> { @@ -230,8 +228,6 @@ impl<'tcx> WipProbeStep<'tcx> { WipProbeStep::AddGoal(source, goal) => inspect::ProbeStep::AddGoal(source, goal), WipProbeStep::EvaluateGoals(eval) => inspect::ProbeStep::EvaluateGoals(eval.finalize()), WipProbeStep::NestedProbe(probe) => inspect::ProbeStep::NestedProbe(probe.finalize()), - WipProbeStep::CommitIfOkStart => inspect::ProbeStep::CommitIfOkStart, - WipProbeStep::CommitIfOkSuccess => inspect::ProbeStep::CommitIfOkSuccess, } } } @@ -467,29 +463,6 @@ impl<'tcx> ProofTreeBuilder<'tcx> { } } - /// Used by `EvalCtxt::commit_if_ok` to flatten the work done inside - /// of the probe into the parent. - pub fn integrate_snapshot(&mut self, probe: ProofTreeBuilder<'tcx>) { - if let Some(this) = self.as_mut() { - match (this, *probe.state.unwrap()) { - ( - DebugSolver::Probe(WipProbe { steps, .. }) - | DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep { - evaluation: WipProbe { steps, .. }, - .. - }), - DebugSolver::Probe(probe), - ) => { - steps.push(WipProbeStep::CommitIfOkStart); - assert_eq!(probe.kind, None); - steps.extend(probe.steps); - steps.push(WipProbeStep::CommitIfOkSuccess); - } - _ => unreachable!(), - } - } - } - pub fn new_evaluate_added_goals(&mut self) -> ProofTreeBuilder<'tcx> { self.nested(|| WipAddedGoalsEvaluation { evaluations: vec![], result: None }) } diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index b1c03e82cab9..5b45e1a34e48 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -177,7 +177,7 @@ impl<'tcx> FallibleTypeFolder> for NormalizationFolder<'_, 'tcx> { fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result, Self::Error> { let infcx = self.at.infcx; debug_assert_eq!(ty, infcx.shallow_resolve(ty)); - if !ty.has_projections() { + if !ty.has_aliases() { return Ok(ty); } @@ -204,7 +204,7 @@ impl<'tcx> FallibleTypeFolder> for NormalizationFolder<'_, 'tcx> { fn try_fold_const(&mut self, ct: ty::Const<'tcx>) -> Result, Self::Error> { let infcx = self.at.infcx; debug_assert_eq!(ct, infcx.shallow_resolve(ct)); - if !ct.has_projections() { + if !ct.has_aliases() { return Ok(ct); } diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index d8aeadd07b3d..fb296d55100d 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -7,6 +7,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::LangItem; use rustc_infer::traits::query::NoSolution; +use rustc_infer::traits::solve::inspect::ProbeKind; use rustc_infer::traits::specialization_graph::LeafDef; use rustc_infer::traits::Reveal; use rustc_middle::traits::solve::{ @@ -30,14 +31,41 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { &mut self, goal: Goal<'tcx, NormalizesTo<'tcx>>, ) -> QueryResult<'tcx> { - let def_id = goal.predicate.def_id(); - let def_kind = self.tcx().def_kind(def_id); - match def_kind { - DefKind::OpaqueTy => return self.normalize_opaque_type(goal), - _ => self.set_is_normalizes_to_goal(), - } - + self.set_is_normalizes_to_goal(); debug_assert!(self.term_is_fully_unconstrained(goal)); + let normalize_result = self + .probe(|&result| ProbeKind::TryNormalizeNonRigid { result }) + .enter(|this| this.normalize_at_least_one_step(goal)); + + match normalize_result { + Ok(res) => Ok(res), + Err(NoSolution) => { + let Goal { param_env, predicate: NormalizesTo { alias, term } } = goal; + if alias.opt_kind(self.tcx()).is_some() { + self.relate_rigid_alias_non_alias( + param_env, + alias, + ty::Variance::Invariant, + term, + )?; + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } else { + // FIXME(generic_const_exprs): we currently do not support rigid + // unevaluated constants. + Err(NoSolution) + } + } + } + } + + /// Normalize the given alias by at least one step. If the alias is rigid, this + /// returns `NoSolution`. + #[instrument(level = "debug", skip(self), ret)] + fn normalize_at_least_one_step( + &mut self, + goal: Goal<'tcx, NormalizesTo<'tcx>>, + ) -> QueryResult<'tcx> { + let def_id = goal.predicate.def_id(); match self.tcx().def_kind(def_id) { DefKind::AssocTy | DefKind::AssocConst => { match self.tcx().associated_item(def_id).container { @@ -52,35 +80,22 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } DefKind::AnonConst => self.normalize_anon_const(goal), DefKind::TyAlias => self.normalize_weak_type(goal), + DefKind::OpaqueTy => self.normalize_opaque_type(goal), kind => bug!("unknown DefKind {} in normalizes-to goal: {goal:#?}", kind.descr(def_id)), } } - /// When normalizing an associated item, constrain the result to `term`. + /// When normalizing an associated item, constrain the expected term to `term`. /// - /// While `NormalizesTo` goals have the normalized-to term as an argument, - /// this argument is always fully unconstrained for associated items. - /// It is therefore appropriate to instead think of these `NormalizesTo` goals - /// as function returning a term after normalizing. - /// - /// When equating an inference variable and an alias, we tend to emit `alias-relate` - /// goals and only actually instantiate the inference variable with an alias if the - /// alias is rigid. However, this means that constraining the expected term of - /// such goals ends up fully structurally normalizing the resulting type instead of - /// only by one step. To avoid this we instead use structural equality here, resulting - /// in each `NormalizesTo` only projects by a single step. - /// - /// Not doing so, currently causes issues because trying to normalize an opaque type - /// during alias-relate doesn't actually constrain the opaque if the concrete type - /// is an inference variable. This means that `NormalizesTo` for associated types - /// normalizing to an opaque type always resulted in ambiguity, breaking tests e.g. - /// tests/ui/type-alias-impl-trait/issue-78450.rs. + /// We know `term` to always be a fully unconstrained inference variable, so + /// `eq` should never fail here. However, in case `term` contains aliases, we + /// emit nested `AliasRelate` goals to structurally normalize the alias. pub fn instantiate_normalizes_to_term( &mut self, goal: Goal<'tcx, NormalizesTo<'tcx>>, term: ty::Term<'tcx>, ) { - self.eq_structurally_relating_aliases(goal.param_env, goal.predicate.term, term) + self.eq(goal.param_env, goal.predicate.term, term) .expect("expected goal term to be fully unconstrained"); } } diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs index 356c3776c04c..9fdb280cdc6d 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs @@ -58,12 +58,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } - let expected = self.structurally_normalize_ty(goal.param_env, expected)?; - if expected.is_ty_var() { - return self - .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); - } - // Otherwise, define a new opaque type self.insert_hidden_type(opaque_type_key, goal.param_env, expected)?; self.add_item_bounds_for_hidden_type( diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 90e337a53b65..8625ad378f78 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -477,7 +477,8 @@ fn plug_infer_with_placeholders<'tcx>( if ty.is_ty_var() { let Ok(InferOk { value: (), obligations }) = self.infcx.at(&ObligationCause::dummy(), ty::ParamEnv::empty()).eq( - DefineOpaqueTypes::No, + // Comparing against a type variable never registers hidden types anyway + DefineOpaqueTypes::Yes, ty, Ty::new_placeholder( self.infcx.tcx, @@ -504,7 +505,9 @@ fn plug_infer_with_placeholders<'tcx>( if ct.is_ct_infer() { let Ok(InferOk { value: (), obligations }) = self.infcx.at(&ObligationCause::dummy(), ty::ParamEnv::empty()).eq( - DefineOpaqueTypes::No, + // The types of the constants are the same, so there is no hidden type + // registration happening anyway. + DefineOpaqueTypes::Yes, ct, ty::Const::new_placeholder( self.infcx.tcx, @@ -532,7 +535,8 @@ fn plug_infer_with_placeholders<'tcx>( if r.is_var() { let Ok(InferOk { value: (), obligations }) = self.infcx.at(&ObligationCause::dummy(), ty::ParamEnv::empty()).eq( - DefineOpaqueTypes::No, + // Lifetimes don't contain opaque types (or any types for that matter). + DefineOpaqueTypes::Yes, r, ty::Region::new_placeholder( self.infcx.tcx, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs index c6f5af08013e..ddb582ffab0b 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs @@ -7,18 +7,21 @@ use rustc_span::{Span, DUMMY_SP}; use crate::traits::ObligationCtxt; -pub enum Ambiguity { +#[derive(Debug)] +pub enum CandidateSource { DefId(DefId), ParamEnv(Span), } -pub fn recompute_applicable_impls<'tcx>( +pub fn compute_applicable_impls_for_diagnostics<'tcx>( infcx: &InferCtxt<'tcx>, obligation: &PolyTraitObligation<'tcx>, -) -> Vec { +) -> Vec { let tcx = infcx.tcx; let param_env = obligation.param_env; + let predicate_polarity = obligation.predicate.skip_binder().polarity; + let impl_may_apply = |impl_def_id| { let ocx = ObligationCtxt::new(infcx); infcx.enter_forall(obligation.predicate, |placeholder_obligation| { @@ -40,6 +43,15 @@ pub fn recompute_applicable_impls<'tcx>( return false; } + let impl_trait_header = tcx.impl_trait_header(impl_def_id).unwrap(); + let impl_polarity = impl_trait_header.polarity; + + match (impl_polarity, predicate_polarity) { + (ty::ImplPolarity::Positive, ty::PredicatePolarity::Positive) + | (ty::ImplPolarity::Negative, ty::PredicatePolarity::Negative) => {} + _ => return false, + } + let impl_predicates = tcx.predicates_of(impl_def_id).instantiate(tcx, impl_args); ocx.register_obligations(impl_predicates.predicates.iter().map(|&predicate| { Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate) @@ -86,7 +98,7 @@ pub fn recompute_applicable_impls<'tcx>( obligation.predicate.skip_binder().trait_ref.self_ty(), |impl_def_id| { if infcx.probe(|_| impl_may_apply(impl_def_id)) { - ambiguities.push(Ambiguity::DefId(impl_def_id)) + ambiguities.push(CandidateSource::DefId(impl_def_id)) } }, ); @@ -101,9 +113,9 @@ pub fn recompute_applicable_impls<'tcx>( if kind.rebind(trait_pred.trait_ref) == ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_pred.def_id())) { - ambiguities.push(Ambiguity::ParamEnv(tcx.def_span(trait_pred.def_id()))) + ambiguities.push(CandidateSource::ParamEnv(tcx.def_span(trait_pred.def_id()))) } else { - ambiguities.push(Ambiguity::ParamEnv(span)) + ambiguities.push(CandidateSource::ParamEnv(span)) } } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 0515b09ae46a..10c03387a5b7 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1,6 +1,6 @@ // ignore-tidy-filelength :( -mod ambiguity; +pub mod ambiguity; mod infer_ctxt_ext; pub mod on_unimplemented; pub mod suggestions; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index fe2691e9d4db..af90372b97ce 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -3842,7 +3842,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { self.probe(|_| { match self .at(&ObligationCause::misc(expr.span, body_id), param_env) - .eq(DefineOpaqueTypes::No, expected, actual) + // Doesn't actually matter if we define opaque types here, this is just used for + // diagnostics, and the result is never kept around. + .eq(DefineOpaqueTypes::Yes, expected, actual) { Ok(_) => (), // We ignore nested obligations here for now. Err(err) => type_diffs.push(err), diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index aef98dbad5fe..144971b63c0a 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -10,7 +10,7 @@ use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::InferCtxtExt as _; use crate::infer::{self, InferCtxt}; use crate::traits::error_reporting::infer_ctxt_ext::InferCtxtExt; -use crate::traits::error_reporting::{ambiguity, ambiguity::Ambiguity::*}; +use crate::traits::error_reporting::{ambiguity, ambiguity::CandidateSource::*}; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::traits::specialize::to_pretty_impl_header; use crate::traits::NormalizeExt; @@ -2386,7 +2386,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ) }; - let mut ambiguities = ambiguity::recompute_applicable_impls( + let mut ambiguities = ambiguity::compute_applicable_impls_for_diagnostics( self.infcx, &obligation.with(self.tcx, trait_ref), ); @@ -2702,7 +2702,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn annotate_source_of_ambiguity( &self, err: &mut Diag<'_>, - ambiguities: &[ambiguity::Ambiguity], + ambiguities: &[ambiguity::CandidateSource], predicate: ty::Predicate<'tcx>, ) { let mut spans = vec![]; @@ -2711,7 +2711,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let mut has_param_env = false; for ambiguity in ambiguities { match ambiguity { - ambiguity::Ambiguity::DefId(impl_def_id) => { + ambiguity::CandidateSource::DefId(impl_def_id) => { match self.tcx.span_of_impl(*impl_def_id) { Ok(span) => spans.push(span), Err(name) => { @@ -2722,7 +2722,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } } - ambiguity::Ambiguity::ParamEnv(span) => { + ambiguity::CandidateSource::ParamEnv(span) => { has_param_env = true; spans.push(*span); } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index b5be9a2bcb35..a04a3bc6ebed 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -311,7 +311,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { let infcx = self.selcx.infcx; - if obligation.predicate.has_projections() { + if obligation.predicate.has_aliases() { let mut obligations = Vec::new(); let predicate = normalize_with_depth_to( &mut self.selcx, @@ -429,7 +429,8 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { // as the cause of an overflow. ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq( - DefineOpaqueTypes::No, + // Only really excercised by generic_const_exprs + DefineOpaqueTypes::Yes, ct.ty(), ty, ) { @@ -571,7 +572,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { if let Ok(new_obligations) = infcx .at(&obligation.cause, obligation.param_env) .trace(c1, c2) - .eq(DefineOpaqueTypes::No, a.args, b.args) + // Can define opaque types as this is only reachable with + // `generic_const_exprs` + .eq(DefineOpaqueTypes::Yes, a.args, b.args) { return ProcessResult::Changed(mk_pending( new_obligations.into_obligations(), @@ -582,7 +585,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { (_, _) => { if let Ok(new_obligations) = infcx .at(&obligation.cause, obligation.param_env) - .eq(DefineOpaqueTypes::No, c1, c2) + // Can define opaque types as this is only reachable with + // `generic_const_exprs` + .eq(DefineOpaqueTypes::Yes, c1, c2) { return ProcessResult::Changed(mk_pending( new_obligations.into_obligations(), @@ -623,7 +628,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { match (evaluate(c1), evaluate(c2)) { (Ok(c1), Ok(c2)) => { match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq( - DefineOpaqueTypes::No, + // Can define opaque types as this is only reachable with + // `generic_const_exprs` + DefineOpaqueTypes::Yes, c1, c2, ) { diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 15bfffef3ced..b4969926f642 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -101,6 +101,8 @@ pub(super) fn needs_normalization<'tcx, T: TypeVisitable>>( value: &T, reveal: Reveal, ) -> bool { + // This mirrors `ty::TypeFlags::HAS_ALIASES` except that we take `Reveal` into account. + let mut flags = ty::TypeFlags::HAS_TY_PROJECTION | ty::TypeFlags::HAS_TY_WEAK | ty::TypeFlags::HAS_TY_INHERENT diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 9d744d9a0321..9246a41a2bcd 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -431,7 +431,7 @@ pub(super) fn opt_normalize_projection_type<'a, 'b, 'tcx>( let projected_term = selcx.infcx.resolve_vars_if_possible(projected_term); - let mut result = if projected_term.has_projections() { + let mut result = if projected_term.has_aliases() { let normalized_ty = normalize_with_depth_to( selcx, param_env, @@ -595,7 +595,7 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>( let ty = tcx.type_of(alias_ty.def_id).instantiate(tcx, args); let mut ty = selcx.infcx.resolve_vars_if_possible(ty); - if ty.has_projections() { + if ty.has_aliases() { ty = normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, ty, obligations); } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs index 3b33f6e6144a..279d96dec728 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs @@ -15,7 +15,7 @@ where type QueryResponse = T; fn try_fast_path(_tcx: TyCtxt<'tcx>, key: &ParamEnvAnd<'tcx, Self>) -> Option { - if !key.value.value.has_projections() { Some(key.value.value) } else { None } + if !key.value.value.has_aliases() { Some(key.value.value) } else { None } } fn perform_query( diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 3fbe8e39d1e3..aa4ab9c7ee9c 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -60,6 +60,20 @@ use rustc_middle::ty::print::with_no_trimmed_paths; mod candidate_assembly; mod confirmation; +/// Whether to consider the binder of higher ranked goals for the `leak_check` when +/// evaluating higher-ranked goals. See #119820 for more info. +/// +/// While this is a bit hacky, it is necessary to match the behavior of the new solver: +/// We eagerly instantiate binders in the new solver, outside of candidate selection, so +/// the leak check inside of candidates does not consider any bound vars from the higher +/// ranked goal. However, we do exit the binder once we're completely finished with a goal, +/// so the leak-check can be used in evaluate by causing nested higher-ranked goals to fail. +#[derive(Debug, Copy, Clone)] +enum LeakCheckHigherRankedGoal { + No, + Yes, +} + #[derive(Clone, Debug, Eq, PartialEq, Hash)] pub enum IntercrateAmbiguityCause<'tcx> { DownstreamCrate { trait_ref: ty::TraitRef<'tcx>, self_ty: Option> }, @@ -384,7 +398,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut no_candidates_apply = true; for c in candidate_set.vec.iter() { - if self.evaluate_candidate(stack, c)?.may_apply() { + if self + .evaluate_candidate(stack, c, LeakCheckHigherRankedGoal::No)? + .may_apply() + { no_candidates_apply = false; break; } @@ -455,7 +472,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // is needed for specialization. Propagate overflow if it occurs. let mut candidates = candidates .into_iter() - .map(|c| match self.evaluate_candidate(stack, &c) { + .map(|c| match self.evaluate_candidate(stack, &c, LeakCheckHigherRankedGoal::No) { Ok(eval) if eval.may_apply() => { Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval })) } @@ -545,7 +562,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &PredicateObligation<'tcx>, ) -> Result { debug_assert!(!self.infcx.next_trait_solver()); - self.evaluation_probe(|this| { + self.evaluation_probe(|this, _outer_universe| { let goal = this.infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env)); let mut result = this.evaluate_predicate_recursively( @@ -561,13 +578,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }) } + /// Computes the evaluation result of `op`, discarding any constraints. + /// + /// This also runs for leak check to allow higher ranked region errors to impact + /// selection. By default it checks for leaks from all universes created inside of + /// `op`, but this can be overwritten if necessary. fn evaluation_probe( &mut self, - op: impl FnOnce(&mut Self) -> Result, + op: impl FnOnce(&mut Self, &mut ty::UniverseIndex) -> Result, ) -> Result { self.infcx.probe(|snapshot| -> Result { - let outer_universe = self.infcx.universe(); - let result = op(self)?; + let mut outer_universe = self.infcx.universe(); + let result = op(self, &mut outer_universe)?; match self.infcx.leak_check(outer_universe, Some(snapshot)) { Ok(()) => {} @@ -586,9 +608,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }) } - /// Evaluates the predicates in `predicates` recursively. Note that - /// this applies projections in the predicates, and therefore + /// Evaluates the predicates in `predicates` recursively. This may + /// guide inference. If this is not desired, run it inside of a /// is run within an inference probe. + /// `probe`. #[instrument(skip(self, stack), level = "debug")] fn evaluate_predicates_recursively<'o, I>( &mut self, @@ -883,7 +906,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .infcx .at(&obligation.cause, obligation.param_env) .trace(c1, c2) - .eq(DefineOpaqueTypes::No, a.args, b.args) + // Can define opaque types as this is only reachable with + // `generic_const_exprs` + .eq(DefineOpaqueTypes::Yes, a.args, b.args) { return self.evaluate_predicates_recursively( previous_stack, @@ -896,7 +921,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if let Ok(InferOk { obligations, value: () }) = self .infcx .at(&obligation.cause, obligation.param_env) - .eq(DefineOpaqueTypes::No, c1, c2) + // Can define opaque types as this is only reachable with + // `generic_const_exprs` + .eq(DefineOpaqueTypes::Yes, c1, c2) { return self.evaluate_predicates_recursively( previous_stack, @@ -926,7 +953,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match (evaluate(c1), evaluate(c2)) { (Ok(c1), Ok(c2)) => { match self.infcx.at(&obligation.cause, obligation.param_env).eq( - DefineOpaqueTypes::No, + // Can define opaque types as this is only reachable with + // `generic_const_exprs` + DefineOpaqueTypes::Yes, c1, c2, ) { @@ -959,7 +988,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig), ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { match self.infcx.at(&obligation.cause, obligation.param_env).eq( - DefineOpaqueTypes::No, + // Only really excercised by generic_const_exprs + DefineOpaqueTypes::Yes, ct.ty(), ty, ) { @@ -1030,7 +1060,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // so we will try to normalize the obligation and evaluate again. // we will replace it with new solver in the future. if EvaluationResult::EvaluatedToErr == result - && fresh_trait_pred.has_projections() + && fresh_trait_pred.has_aliases() && fresh_trait_pred.is_global() { let mut nested_obligations = Vec::new(); @@ -1194,7 +1224,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } match self.candidate_from_obligation(stack) { - Ok(Some(c)) => self.evaluate_candidate(stack, &c), + Ok(Some(c)) => self.evaluate_candidate(stack, &c, LeakCheckHigherRankedGoal::Yes), Ok(None) => Ok(EvaluatedToAmbig), Err(Overflow(OverflowError::Canonical)) => Err(OverflowError::Canonical), Err(..) => Ok(EvaluatedToErr), @@ -1219,6 +1249,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Further evaluates `candidate` to decide whether all type parameters match and whether nested /// obligations are met. Returns whether `candidate` remains viable after this further /// scrutiny. + /// + /// Depending on the value of [LeakCheckHigherRankedGoal], we may ignore the binder of the goal + /// when eagerly detecting higher ranked region errors via the `leak_check`. See that enum for + /// more info. #[instrument( level = "debug", skip(self, stack), @@ -1229,10 +1263,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, stack: &TraitObligationStack<'o, 'tcx>, candidate: &SelectionCandidate<'tcx>, + leak_check_higher_ranked_goal: LeakCheckHigherRankedGoal, ) -> Result { - let mut result = self.evaluation_probe(|this| { - let candidate = (*candidate).clone(); - match this.confirm_candidate(stack.obligation, candidate) { + let mut result = self.evaluation_probe(|this, outer_universe| { + // We eagerly instantiate higher ranked goals to prevent universe errors + // from impacting candidate selection. This matches the behavior of the new + // solver. This slightly weakens type inference. + // + // In case there are no unresolved type or const variables this + // should still not be necessary to select a unique impl as any overlap + // relying on a universe error from higher ranked goals should have resulted + // in an overlap error in coherence. + let p = self.infcx.enter_forall_and_leak_universe(stack.obligation.predicate); + let obligation = stack.obligation.with(this.tcx(), ty::Binder::dummy(p)); + match leak_check_higher_ranked_goal { + LeakCheckHigherRankedGoal::No => *outer_universe = self.infcx.universe(), + LeakCheckHigherRankedGoal::Yes => {} + } + + match this.confirm_candidate(&obligation, candidate.clone()) { Ok(selection) => { debug!(?selection); this.evaluate_predicates_recursively( @@ -1657,8 +1706,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { stack: &TraitObligationStack<'o, 'tcx>, where_clause_trait_ref: ty::PolyTraitRef<'tcx>, ) -> Result { - self.evaluation_probe(|this| { - match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) { + self.evaluation_probe(|this, outer_universe| { + // Eagerly instantiate higher ranked goals. + // + // See the comment in `evaluate_candidate` to see why. + let p = self.infcx.enter_forall_and_leak_universe(stack.obligation.predicate); + let obligation = stack.obligation.with(this.tcx(), ty::Binder::dummy(p)); + *outer_universe = self.infcx.universe(); + match this.match_where_clause_trait_ref(&obligation, where_clause_trait_ref) { Ok(obligations) => this.evaluate_predicates_recursively(stack.list(), obligations), Err(()) => Ok(EvaluatedToErr), } diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 43c750ebbb5b..46a0a4eb5ef8 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -247,7 +247,12 @@ fn fulfill_implication<'tcx>( // do the impls unify? If not, no specialization. let Ok(InferOk { obligations: more_obligations, .. }) = infcx .at(&ObligationCause::dummy(), param_env) - .eq(DefineOpaqueTypes::No, source_trait, target_trait) + // Ok to use `Yes`, as all the generic params are already replaced by inference variables, + // which will match the opaque type no matter if it is defining or not. + // Any concrete type that would match the opaque would already be handled by coherence rules, + // and thus either be ok to match here and already have errored, or it won't match, in which + // case there is no issue anyway. + .eq(DefineOpaqueTypes::Yes, source_trait, target_trait) else { debug!("fulfill_implication: {:?} does not unify with {:?}", source_trait, target_trait); return Err(()); @@ -402,10 +407,6 @@ fn report_conflicting_impls<'tcx>( impl_span: Span, err: &mut Diag<'_, G>, ) { - if (overlap.trait_ref, overlap.self_ty).references_error() { - err.downgrade_to_delayed_bug(); - } - match tcx.span_of_impl(overlap.with_impl) { Ok(span) => { err.span_label(span, "first implementation here"); @@ -458,6 +459,11 @@ fn report_conflicting_impls<'tcx>( ) }); + // Don't report overlap errors if the header references error + if let Err(err) = (overlap.trait_ref, overlap.self_ty).error_reported() { + return Err(err); + } + match used_to_be_allowed { None => { let reported = if overlap.with_impl.is_local() diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 7941a8fe95c8..a44a5ae0e6b4 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -647,6 +647,8 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { fn visit_ty(&mut self, t: as ty::Interner>::Ty) -> Self::Result { debug!("wf bounds for t={:?} t.kind={:#?}", t, t.kind()); + let tcx = self.tcx(); + match *t.kind() { ty::Bool | ty::Char @@ -707,6 +709,14 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { } ty::FnDef(did, args) => { + // HACK: Check the return type of function definitions for + // well-formedness to mostly fix #84533. This is still not + // perfect and there may be ways to abuse the fact that we + // ignore requirements with escaping bound vars. That's a + // more general issue however. + let fn_sig = tcx.fn_sig(did).instantiate(tcx, args); + fn_sig.output().skip_binder().visit_with(self); + let obligations = self.nominal_obligations(did, args); self.out.extend(obligations); } @@ -716,7 +726,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { if !r.has_escaping_bound_vars() && !rty.has_escaping_bound_vars() { let cause = self.cause(traits::ReferenceOutlivesReferent(t)); self.out.push(traits::Obligation::with_depth( - self.tcx(), + tcx, cause, self.recursion_depth, self.param_env, @@ -805,12 +815,12 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { // obligations that don't refer to Self and // checking those - let defer_to_coercion = self.tcx().features().object_safe_for_dispatch; + let defer_to_coercion = tcx.features().object_safe_for_dispatch; if !defer_to_coercion { if let Some(principal) = data.principal_def_id() { self.out.push(traits::Obligation::with_depth( - self.tcx(), + tcx, self.cause(traits::WellFormed(None)), self.recursion_depth, self.param_env, @@ -835,7 +845,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { ty::Infer(_) => { let cause = self.cause(traits::WellFormed(None)); self.out.push(traits::Obligation::with_depth( - self.tcx(), + tcx, cause, self.recursion_depth, self.param_env, @@ -850,6 +860,8 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { } fn visit_const(&mut self, c: as ty::Interner>::Const) -> Self::Result { + let tcx = self.tcx(); + match c.kind() { ty::ConstKind::Unevaluated(uv) => { if !c.has_escaping_bound_vars() { @@ -861,7 +873,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { )); let cause = self.cause(traits::WellFormed(None)); self.out.push(traits::Obligation::with_depth( - self.tcx(), + tcx, cause, self.recursion_depth, self.param_env, @@ -873,7 +885,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { let cause = self.cause(traits::WellFormed(None)); self.out.push(traits::Obligation::with_depth( - self.tcx(), + tcx, cause, self.recursion_depth, self.param_env, @@ -895,7 +907,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { )); let cause = self.cause(traits::WellFormed(None)); self.out.push(traits::Obligation::with_depth( - self.tcx(), + tcx, cause, self.recursion_depth, self.param_env, diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index dd1f2322c414..509727cdeabc 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -8,7 +8,9 @@ use rustc_middle::ty::layout::{ IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, MAX_SIMD_LANES, }; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, AdtDef, EarlyBinder, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{ + self, AdtDef, EarlyBinder, FieldDef, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, +}; use rustc_session::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo}; use rustc_span::sym; use rustc_span::symbol::Symbol; @@ -239,9 +241,9 @@ fn layout_of_uncached<'tcx>( // Arrays and slices. ty::Array(element, mut count) => { - if count.has_projections() { + if count.has_aliases() { count = tcx.normalize_erasing_regions(param_env, count); - if count.has_projections() { + if count.has_aliases() { return Err(error(cx, LayoutError::Unknown(ty))); } } @@ -506,6 +508,40 @@ fn layout_of_uncached<'tcx>( )); } + let err_if_unsized = |field: &FieldDef, err_msg: &str| { + let field_ty = tcx.type_of(field.did); + let is_unsized = tcx + .try_instantiate_and_normalize_erasing_regions(args, cx.param_env, field_ty) + .map(|f| !f.is_sized(tcx, cx.param_env)) + .map_err(|e| { + error( + cx, + LayoutError::NormalizationFailure(field_ty.instantiate_identity(), e), + ) + })?; + + if is_unsized { + cx.tcx.dcx().span_delayed_bug(tcx.def_span(def.did()), err_msg.to_owned()); + Err(error(cx, LayoutError::Unknown(ty))) + } else { + Ok(()) + } + }; + + if def.is_struct() { + if let Some((_, fields_except_last)) = + def.non_enum_variant().fields.raw.split_last() + { + for f in fields_except_last { + err_if_unsized(f, "only the last field of a struct can be unsized")?; + } + } + } else { + for f in def.all_fields() { + err_if_unsized(f, &format!("{}s cannot have unsized fields", def.descr()))?; + } + } + let get_discriminant_type = |min, max| Integer::repr_discr(tcx, ty, &def.repr(), min, max); diff --git a/compiler/rustc_ty_utils/src/sig_types.rs b/compiler/rustc_ty_utils/src/sig_types.rs index 63654a453dde..19c092c5ddf3 100644 --- a/compiler/rustc_ty_utils/src/sig_types.rs +++ b/compiler/rustc_ty_utils/src/sig_types.rs @@ -13,6 +13,7 @@ pub trait SpannedTypeVisitor<'tcx> { fn visit(&mut self, span: Span, value: impl TypeVisitable>) -> Self::Result; } +#[instrument(level = "trace", skip(tcx, visitor))] pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>( tcx: TyCtxt<'tcx>, item: LocalDefId, @@ -36,7 +37,7 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>( for (hir, ty) in hir_sig.inputs.iter().zip(ty_sig.inputs().iter()) { try_visit!(visitor.visit(hir.span, ty.map_bound(|x| *x))); } - for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) { + for (pred, span) in tcx.explicit_predicates_of(item).instantiate_identity(tcx) { try_visit!(visitor.visit(span, pred)); } } @@ -54,7 +55,7 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>( // Associated types in traits don't necessarily have a type that we can visit try_visit!(visitor.visit(ty.span, tcx.type_of(item).instantiate_identity())); } - for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) { + for (pred, span) in tcx.explicit_predicates_of(item).instantiate_identity(tcx) { try_visit!(visitor.visit(span, pred)); } } @@ -76,7 +77,7 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>( let ty = field.ty(tcx, args); try_visit!(visitor.visit(span, ty)); } - for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) { + for (pred, span) in tcx.explicit_predicates_of(item).instantiate_identity(tcx) { try_visit!(visitor.visit(span, pred)); } } @@ -95,12 +96,12 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>( _ => tcx.def_span(item), }; try_visit!(visitor.visit(span, tcx.type_of(item).instantiate_identity())); - for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) { + for (pred, span) in tcx.explicit_predicates_of(item).instantiate_identity(tcx) { try_visit!(visitor.visit(span, pred)); } } DefKind::TraitAlias | DefKind::Trait => { - for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) { + for (pred, span) in tcx.explicit_predicates_of(item).instantiate_identity(tcx) { try_visit!(visitor.visit(span, pred)); } } diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index cd199222d900..997b410f819e 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -78,8 +78,10 @@ bitflags! { /// Does this have `ConstKind::Unevaluated`? const HAS_CT_PROJECTION = 1 << 14; - /// Could this type be normalized further? - const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits() + /// Does this have `Alias` or `ConstKind::Unevaluated`? + /// + /// Rephrased, could this term be normalized further? + const HAS_ALIASES = TypeFlags::HAS_TY_PROJECTION.bits() | TypeFlags::HAS_TY_WEAK.bits() | TypeFlags::HAS_TY_OPAQUE.bits() | TypeFlags::HAS_TY_INHERENT.bits() diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index 839e75dba4cb..d6a3f9f07494 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -223,8 +223,8 @@ pub trait TypeVisitableExt: TypeVisitable { self.has_vars_bound_at_or_above(ty::INNERMOST) } - fn has_projections(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_PROJECTION) + fn has_aliases(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_ALIASES) } fn has_inherent_projections(&self) -> bool { diff --git a/library/alloc/benches/vec_deque_append.rs b/library/alloc/benches/vec_deque_append.rs index 5825bdc355f2..30b6e600e5ad 100644 --- a/library/alloc/benches/vec_deque_append.rs +++ b/library/alloc/benches/vec_deque_append.rs @@ -5,6 +5,11 @@ const WARMUP_N: usize = 100; const BENCH_N: usize = 1000; fn main() { + if cfg!(miri) { + // Don't benchmark Miri... + // (Due to bootstrap quirks, this gets picked up by `x.py miri library/alloc --no-doc`.) + return; + } let a: VecDeque = (0..VECDEQUE_LEN).collect(); let b: VecDeque = (0..VECDEQUE_LEN).collect(); diff --git a/library/alloc/src/lib.miri.rs b/library/alloc/src/lib.miri.rs new file mode 100644 index 000000000000..89d7f49f55d2 --- /dev/null +++ b/library/alloc/src/lib.miri.rs @@ -0,0 +1,4 @@ +//! Grep bootstrap for `MIRI_REPLACE_LIBRS_IF_NOT_TEST` to learn what this is about. +#![no_std] +extern crate alloc as realalloc; +pub use realalloc::*; diff --git a/library/core/src/lib.miri.rs b/library/core/src/lib.miri.rs new file mode 100644 index 000000000000..5c1027f20ba0 --- /dev/null +++ b/library/core/src/lib.miri.rs @@ -0,0 +1,4 @@ +//! Grep bootstrap for `MIRI_REPLACE_LIBRS_IF_NOT_TEST` to learn what this is about. +#![no_std] +extern crate core as realcore; +pub use realcore::*; diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index 9b5da935e07e..25a06f121cda 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -2,6 +2,7 @@ use crate::fmt; use crate::hash::{Hash, Hasher}; +use crate::marker::Freeze; /// Provides the pointer metadata type of any pointed-to type. /// @@ -57,7 +58,7 @@ pub trait Pointee { // NOTE: Keep trait bounds in `static_assert_expected_bounds_for_metadata` // in `library/core/src/ptr/metadata.rs` // in sync with those here: - type Metadata: fmt::Debug + Copy + Send + Sync + Ord + Hash + Unpin; + type Metadata: fmt::Debug + Copy + Send + Sync + Ord + Hash + Unpin + Freeze; } /// Pointers to types implementing this trait alias are “thin”. diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 175c27662d08..8c5e5ecf5fe9 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -38,6 +38,7 @@ #![feature(duration_constructors)] #![feature(exact_size_is_empty)] #![feature(extern_types)] +#![feature(freeze)] #![feature(flt2dec)] #![feature(fmt_internals)] #![feature(float_minimum_maximum)] diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs index f0656f997fd8..2c82eda9a58c 100644 --- a/library/core/tests/ptr.rs +++ b/library/core/tests/ptr.rs @@ -1,4 +1,5 @@ use core::cell::RefCell; +use core::marker::Freeze; use core::mem::{self, MaybeUninit}; use core::num::NonZero; use core::ptr; @@ -841,7 +842,7 @@ fn ptr_metadata_bounds() { fn static_assert_expected_bounds_for_metadata() where // Keep this in sync with the associated type in `library/core/src/ptr/metadata.rs` - Meta: Debug + Copy + Send + Sync + Ord + std::hash::Hash + Unpin, + Meta: Debug + Copy + Send + Sync + Ord + std::hash::Hash + Unpin + Freeze, { } } diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index e04bf69ef511..01c449563ee9 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -1360,7 +1360,7 @@ impl Literal { } /// Byte character literal. - #[unstable(feature = "proc_macro_byte_character", issue = "115268")] + #[stable(feature = "proc_macro_byte_character", since = "CURRENT_RUSTC_VERSION")] pub fn byte_character(byte: u8) -> Literal { let string = [byte].escape_ascii().to_string(); Literal::new(bridge::LitKind::Byte, &string, None) @@ -1374,7 +1374,7 @@ impl Literal { } /// C string literal. - #[unstable(feature = "proc_macro_c_str_literals", issue = "119750")] + #[stable(feature = "proc_macro_c_str_literals", since = "CURRENT_RUSTC_VERSION")] pub fn c_string(string: &CStr) -> Literal { let string = string.to_bytes().escape_ascii().to_string(); Literal::new(bridge::LitKind::CStr, &string, None) diff --git a/library/std/build.rs b/library/std/build.rs index ee3f3612d2e0..7a47b52e8e4e 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -22,6 +22,7 @@ fn main() { || target_os == "ios" || target_os == "tvos" || target_os == "watchos" + || target_os == "visionos" || target_os == "windows" || target_os == "fuchsia" || (target_vendor == "fortanix" && target_env == "sgx") diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 65dec3863cc6..6a92832fcdbd 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1644,8 +1644,8 @@ fn test_file_times() { use crate::os::macos::fs::FileTimesExt; #[cfg(target_os = "tvos")] use crate::os::tvos::fs::FileTimesExt; - #[cfg(target_os = "tvos")] - use crate::os::tvos::fs::FileTimesExt; + #[cfg(target_os = "visionos")] + use crate::os::visionos::fs::FileTimesExt; #[cfg(target_os = "watchos")] use crate::os::watchos::fs::FileTimesExt; #[cfg(windows)] @@ -1662,6 +1662,7 @@ fn test_file_times() { target_os = "macos", target_os = "ios", target_os = "watchos", + target_os = "visionos", target_os = "tvos", ))] let created = SystemTime::UNIX_EPOCH + Duration::from_secs(32123); @@ -1670,6 +1671,7 @@ fn test_file_times() { target_os = "macos", target_os = "ios", target_os = "watchos", + target_os = "visionos", target_os = "tvos", ))] { @@ -1701,6 +1703,7 @@ fn test_file_times() { target_os = "macos", target_os = "ios", target_os = "watchos", + target_os = "visionos", target_os = "tvos", ))] { @@ -1709,7 +1712,13 @@ fn test_file_times() { } #[test] -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] +#[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "tvos", + target_os = "watchos", + target_os = "visionos" +))] fn test_file_times_pre_epoch_with_nanos() { #[cfg(target_os = "ios")] use crate::os::ios::fs::FileTimesExt; @@ -1717,6 +1726,8 @@ fn test_file_times_pre_epoch_with_nanos() { use crate::os::macos::fs::FileTimesExt; #[cfg(target_os = "tvos")] use crate::os::tvos::fs::FileTimesExt; + #[cfg(target_os = "visionos")] + use crate::os::visionos::fs::FileTimesExt; #[cfg(target_os = "watchos")] use crate::os::watchos::fs::FileTimesExt; diff --git a/library/std/src/lib.miri.rs b/library/std/src/lib.miri.rs new file mode 100644 index 000000000000..1f9bfb5b1b5c --- /dev/null +++ b/library/std/src/lib.miri.rs @@ -0,0 +1,4 @@ +//! Grep bootstrap for `MIRI_REPLACE_LIBRS_IF_NOT_TEST` to learn what this is about. +#![no_std] +extern crate std as realstd; +pub use realstd::*; diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index bebf3a797d81..ca3584e82f91 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -149,6 +149,8 @@ pub mod solid; pub(crate) mod tvos; #[cfg(target_os = "uefi")] pub mod uefi; +#[cfg(target_os = "visionos")] +pub(crate) mod visionos; #[cfg(target_os = "vita")] pub mod vita; #[cfg(target_os = "vxworks")] diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs index b0633fd7bfcc..d7a622012a5a 100644 --- a/library/std/src/os/unix/mod.rs +++ b/library/std/src/os/unix/mod.rs @@ -79,6 +79,8 @@ mod platform { pub use crate::os::solaris::*; #[cfg(target_os = "tvos")] pub use crate::os::tvos::*; + #[cfg(target_os = "visionos")] + pub use crate::os::visionos::*; #[cfg(target_os = "vita")] pub use crate::os::vita::*; #[cfg(target_os = "vxworks")] diff --git a/library/std/src/os/unix/net/mod.rs b/library/std/src/os/unix/net/mod.rs index 28c1188677b6..16d9cd915acc 100644 --- a/library/std/src/os/unix/net/mod.rs +++ b/library/std/src/os/unix/net/mod.rs @@ -20,6 +20,7 @@ mod tests; target_os = "ios", target_os = "tvos", target_os = "watchos", + target_os = "visionos", target_os = "macos", target_os = "netbsd", target_os = "openbsd", @@ -46,6 +47,7 @@ pub use self::stream::*; target_os = "ios", target_os = "tvos", target_os = "watchos", + target_os = "visionos", target_os = "macos", target_os = "netbsd", target_os = "openbsd", diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index 9b01d2326112..82b24dca1c41 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -7,6 +7,7 @@ target_os = "tvos", target_os = "macos", target_os = "watchos", + target_os = "visionos", target_os = "netbsd", target_os = "openbsd", target_os = "nto" @@ -234,6 +235,7 @@ impl UnixStream { target_os = "tvos", target_os = "macos", target_os = "watchos", + target_os = "visionos", target_os = "netbsd", target_os = "openbsd", target_os = "nto" diff --git a/library/std/src/os/unix/net/ucred.rs b/library/std/src/os/unix/net/ucred.rs index 4c915c579066..3a752a53a506 100644 --- a/library/std/src/os/unix/net/ucred.rs +++ b/library/std/src/os/unix/net/ucred.rs @@ -35,7 +35,13 @@ pub(super) use self::impl_linux::peer_cred; ))] pub(super) use self::impl_bsd::peer_cred; -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] +#[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "tvos", + target_os = "watchos", + target_os = "visionos" +))] pub(super) use self::impl_mac::peer_cred; #[cfg(any(target_os = "linux", target_os = "android"))] @@ -97,7 +103,13 @@ mod impl_bsd { } } -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] +#[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "tvos", + target_os = "watchos", + target_os = "visionos" +))] mod impl_mac { use super::UCred; use crate::os::unix::io::AsRawFd; diff --git a/library/std/src/os/unix/net/ucred/tests.rs b/library/std/src/os/unix/net/ucred/tests.rs index dd99ecdd819a..2a0797877c6f 100644 --- a/library/std/src/os/unix/net/ucred/tests.rs +++ b/library/std/src/os/unix/net/ucred/tests.rs @@ -11,6 +11,7 @@ use libc::{getegid, geteuid, getpid}; target_os = "tvos", target_os = "macos", target_os = "watchos", + target_os = "visionos", target_os = "openbsd" ))] fn test_socket_pair() { @@ -32,6 +33,7 @@ fn test_socket_pair() { target_os = "ios", target_os = "macos", target_os = "watchos", + target_os = "visionos", target_os = "tvos", ))] fn test_socket_pair_pids(arg: Type) -> RetType { diff --git a/library/std/src/os/visionos/fs.rs b/library/std/src/os/visionos/fs.rs new file mode 100644 index 000000000000..e5df4de0b7f7 --- /dev/null +++ b/library/std/src/os/visionos/fs.rs @@ -0,0 +1,160 @@ +#![stable(feature = "metadata_ext", since = "1.1.0")] + +use crate::fs::{self, Metadata}; +use crate::sealed::Sealed; +use crate::sys_common::{AsInner, AsInnerMut, IntoInner}; +use crate::time::SystemTime; + +#[allow(deprecated)] +use super::raw; + +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: crate::fs::Metadata +#[stable(feature = "metadata_ext", since = "1.1.0")] +pub trait MetadataExt { + /// Gain a reference to the underlying `stat` structure which contains + /// the raw information returned by the OS. + /// + /// The contents of the returned `stat` are **not** consistent across + /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the + /// cross-Unix abstractions contained within the raw stat. + #[stable(feature = "metadata_ext", since = "1.1.0")] + #[deprecated( + since = "1.8.0", + note = "deprecated in favor of the accessor \ + methods of this trait" + )] + #[allow(deprecated)] + fn as_raw_stat(&self) -> &raw::stat; + + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_dev(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ino(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mode(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_nlink(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_uid(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_gid(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_rdev(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_size(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_birthtime(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_birthtime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blksize(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blocks(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_flags(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_gen(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_lspare(&self) -> u32; +} + +#[stable(feature = "metadata_ext", since = "1.1.0")] +impl MetadataExt for Metadata { + #[allow(deprecated)] + fn as_raw_stat(&self) -> &raw::stat { + unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) } + } + fn st_dev(&self) -> u64 { + self.as_inner().as_inner().st_dev as u64 + } + fn st_ino(&self) -> u64 { + self.as_inner().as_inner().st_ino as u64 + } + fn st_mode(&self) -> u32 { + self.as_inner().as_inner().st_mode as u32 + } + fn st_nlink(&self) -> u64 { + self.as_inner().as_inner().st_nlink as u64 + } + fn st_uid(&self) -> u32 { + self.as_inner().as_inner().st_uid as u32 + } + fn st_gid(&self) -> u32 { + self.as_inner().as_inner().st_gid as u32 + } + fn st_rdev(&self) -> u64 { + self.as_inner().as_inner().st_rdev as u64 + } + fn st_size(&self) -> u64 { + self.as_inner().as_inner().st_size as u64 + } + fn st_atime(&self) -> i64 { + self.as_inner().as_inner().st_atime as i64 + } + fn st_atime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_atime_nsec as i64 + } + fn st_mtime(&self) -> i64 { + self.as_inner().as_inner().st_mtime as i64 + } + fn st_mtime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_mtime_nsec as i64 + } + fn st_ctime(&self) -> i64 { + self.as_inner().as_inner().st_ctime as i64 + } + fn st_ctime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_ctime_nsec as i64 + } + fn st_birthtime(&self) -> i64 { + self.as_inner().as_inner().st_birthtime as i64 + } + fn st_birthtime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_birthtime_nsec as i64 + } + fn st_blksize(&self) -> u64 { + self.as_inner().as_inner().st_blksize as u64 + } + fn st_blocks(&self) -> u64 { + self.as_inner().as_inner().st_blocks as u64 + } + fn st_gen(&self) -> u32 { + self.as_inner().as_inner().st_gen as u32 + } + fn st_flags(&self) -> u32 { + self.as_inner().as_inner().st_flags as u32 + } + fn st_lspare(&self) -> u32 { + self.as_inner().as_inner().st_lspare as u32 + } +} + +/// OS-specific extensions to [`fs::FileTimes`]. +#[stable(feature = "file_set_times", since = "1.75.0")] +pub trait FileTimesExt: Sealed { + /// Set the creation time of a file. + #[stable(feature = "file_set_times", since = "1.75.0")] + fn set_created(self, t: SystemTime) -> Self; +} + +#[stable(feature = "file_set_times", since = "1.75.0")] +impl FileTimesExt for fs::FileTimes { + fn set_created(mut self, t: SystemTime) -> Self { + self.as_inner_mut().set_created(t.into_inner()); + self + } +} diff --git a/library/std/src/os/visionos/mod.rs b/library/std/src/os/visionos/mod.rs new file mode 100644 index 000000000000..f4b061ffda89 --- /dev/null +++ b/library/std/src/os/visionos/mod.rs @@ -0,0 +1,6 @@ +//! visionos-specific definitions + +#![stable(feature = "raw_ext", since = "1.1.0")] + +pub mod fs; +pub mod raw; diff --git a/library/std/src/os/visionos/raw.rs b/library/std/src/os/visionos/raw.rs new file mode 100644 index 000000000000..2b3eca6f493d --- /dev/null +++ b/library/std/src/os/visionos/raw.rs @@ -0,0 +1,83 @@ +//! visionos-specific raw type definitions + +#![stable(feature = "raw_ext", since = "1.1.0")] +#![deprecated( + since = "1.8.0", + note = "these type aliases are no longer supported by \ + the standard library, the `libc` crate on \ + crates.io should be used instead for the correct \ + definitions" +)] +#![allow(deprecated)] + +use crate::os::raw::c_long; + +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type blkcnt_t = u64; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type blksize_t = u64; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type dev_t = u64; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type ino_t = u64; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type mode_t = u32; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type nlink_t = u64; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type off_t = u64; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type time_t = i64; + +#[stable(feature = "pthread_t", since = "1.8.0")] +pub type pthread_t = usize; + +#[repr(C)] +#[derive(Clone)] +#[stable(feature = "raw_ext", since = "1.1.0")] +pub struct stat { + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_dev: i32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mode: u16, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_nlink: u16, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ino: u64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_uid: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_gid: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_rdev: i32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_birthtime: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_birthtime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_size: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blocks: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blksize: i32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_flags: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_gen: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_lspare: i32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_qspare: [i64; 2], +} diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index ff6e433ebce3..59e118f81ab1 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -16,8 +16,6 @@ #![deny(unsafe_op_in_unsafe_fn)] #![allow(unused_macros)] -use crate::ffi::CString; - // Re-export some of our utilities which are expected by other crates. pub use crate::panicking::{begin_panic, panic_count}; pub use core::panicking::{panic_display, panic_fmt}; @@ -96,7 +94,7 @@ unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { sys::init(argc, argv, sigpipe); // Set up the current thread to give it the right name. - let thread = Thread::new(Some(rtunwrap!(Ok, CString::new("main")))); + let thread = Thread::new_main(); thread::set_current(thread); } } diff --git a/library/std/src/sys/pal/hermit/thread.rs b/library/std/src/sys/pal/hermit/thread.rs index 40f88e33d4ad..4fe6b12a95b0 100644 --- a/library/std/src/sys/pal/hermit/thread.rs +++ b/library/std/src/sys/pal/hermit/thread.rs @@ -2,7 +2,7 @@ use super::abi; use super::thread_local_dtor::run_dtors; -use crate::ffi::{CStr, CString}; +use crate::ffi::CStr; use crate::io; use crate::mem; use crate::num::NonZero; @@ -71,10 +71,6 @@ impl Thread { // nope } - pub fn get_name() -> Option { - None - } - #[inline] pub fn sleep(dur: Duration) { unsafe { diff --git a/library/std/src/sys/pal/itron/thread.rs b/library/std/src/sys/pal/itron/thread.rs index 047513a67927..205226ce1da8 100644 --- a/library/std/src/sys/pal/itron/thread.rs +++ b/library/std/src/sys/pal/itron/thread.rs @@ -8,7 +8,7 @@ use super::{ }; use crate::{ cell::UnsafeCell, - ffi::{CStr, CString}, + ffi::CStr, hint, io, mem::ManuallyDrop, num::NonZero, @@ -204,10 +204,6 @@ impl Thread { // nope } - pub fn get_name() -> Option { - None - } - pub fn sleep(dur: Duration) { for timeout in dur2reltims(dur) { expect_success(unsafe { abi::dly_tsk(timeout) }, &"dly_tsk"); diff --git a/library/std/src/sys/pal/sgx/thread.rs b/library/std/src/sys/pal/sgx/thread.rs index ef07f6e6a263..e2df57b1a1f5 100644 --- a/library/std/src/sys/pal/sgx/thread.rs +++ b/library/std/src/sys/pal/sgx/thread.rs @@ -1,6 +1,6 @@ #![cfg_attr(test, allow(dead_code))] // why is this necessary? use super::unsupported; -use crate::ffi::{CStr, CString}; +use crate::ffi::CStr; use crate::io; use crate::num::NonZero; use crate::time::Duration; @@ -133,10 +133,6 @@ impl Thread { // which succeeds as-is with the SGX target. } - pub fn get_name() -> Option { - None - } - pub fn sleep(dur: Duration) { usercalls::wait_timeout(0, dur, || true); } diff --git a/library/std/src/sys/pal/teeos/thread.rs b/library/std/src/sys/pal/teeos/thread.rs index fb4b74ba3c36..ae2f58ca08e9 100644 --- a/library/std/src/sys/pal/teeos/thread.rs +++ b/library/std/src/sys/pal/teeos/thread.rs @@ -1,7 +1,7 @@ use core::convert::TryInto; use crate::cmp; -use crate::ffi::{CStr, CString}; +use crate::ffi::CStr; use crate::io; use crate::mem; use crate::num::NonZero; @@ -101,10 +101,6 @@ impl Thread { // contact the teeos rustzone team. } - pub fn get_name() -> Option { - None - } - /// only main thread could wait for sometime in teeos pub fn sleep(dur: Duration) { let sleep_millis = dur.as_millis(); diff --git a/library/std/src/sys/pal/uefi/thread.rs b/library/std/src/sys/pal/uefi/thread.rs index ca7b1efc2699..edc736978a12 100644 --- a/library/std/src/sys/pal/uefi/thread.rs +++ b/library/std/src/sys/pal/uefi/thread.rs @@ -1,5 +1,5 @@ use super::unsupported; -use crate::ffi::{CStr, CString}; +use crate::ffi::CStr; use crate::io; use crate::num::NonZero; use crate::ptr::NonNull; @@ -23,10 +23,6 @@ impl Thread { // nope } - pub fn get_name() -> Option { - None - } - pub fn sleep(dur: Duration) { let boot_services: NonNull = crate::os::uefi::env::boot_services().expect("can't sleep").cast(); diff --git a/library/std/src/sys/pal/unix/args.rs b/library/std/src/sys/pal/unix/args.rs index 78e82d9c194c..acf8100d47f2 100644 --- a/library/std/src/sys/pal/unix/args.rs +++ b/library/std/src/sys/pal/unix/args.rs @@ -170,7 +170,13 @@ mod imp { } } -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] +#[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "watchos", + target_os = "visionos", + target_os = "tvos" +))] mod imp { use super::Args; use crate::ffi::CStr; @@ -211,7 +217,12 @@ mod imp { // for i in (0..[args count]) // res.push([args objectAtIndex:i]) // res - #[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos"))] + #[cfg(any( + target_os = "ios", + target_os = "tvos", + target_os = "watchos", + target_os = "visionos" + ))] pub fn args() -> Args { use crate::ffi::{c_char, c_void, OsString}; use crate::mem; diff --git a/library/std/src/sys/pal/unix/env.rs b/library/std/src/sys/pal/unix/env.rs index 3d4ba509829d..fb1f868644d4 100644 --- a/library/std/src/sys/pal/unix/env.rs +++ b/library/std/src/sys/pal/unix/env.rs @@ -53,6 +53,17 @@ pub mod os { pub const EXE_EXTENSION: &str = ""; } +#[cfg(target_os = "visionos")] +pub mod os { + pub const FAMILY: &str = "unix"; + pub const OS: &str = "visionos"; + pub const DLL_PREFIX: &str = "lib"; + pub const DLL_SUFFIX: &str = ".dylib"; + pub const DLL_EXTENSION: &str = "dylib"; + pub const EXE_SUFFIX: &str = ""; + pub const EXE_EXTENSION: &str = ""; +} + #[cfg(target_os = "freebsd")] pub mod os { pub const FAMILY: &str = "unix"; diff --git a/library/std/src/sys/pal/unix/fd.rs b/library/std/src/sys/pal/unix/fd.rs index 9d8cc18b8389..48e83b04ef46 100644 --- a/library/std/src/sys/pal/unix/fd.rs +++ b/library/std/src/sys/pal/unix/fd.rs @@ -51,6 +51,7 @@ const READ_LIMIT: usize = libc::ssize_t::MAX as usize; target_os = "netbsd", target_os = "openbsd", target_os = "watchos", + target_os = "visionos", ))] const fn max_iov() -> usize { libc::IOV_MAX as usize @@ -81,6 +82,7 @@ const fn max_iov() -> usize { target_os = "horizon", target_os = "vita", target_os = "watchos", + target_os = "visionos", )))] const fn max_iov() -> usize { 16 // The minimum value required by POSIX. diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs index 99b6da60c146..96f64051cda5 100644 --- a/library/std/src/sys/pal/unix/fs.rs +++ b/library/std/src/sys/pal/unix/fs.rs @@ -23,6 +23,7 @@ use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; target_os = "ios", target_os = "tvos", target_os = "watchos", + target_os = "visionos", ))] use crate::sys::weak::syscall; #[cfg(any(target_os = "android", target_os = "macos", target_os = "solaris"))] @@ -35,6 +36,7 @@ use libc::{c_int, mode_t}; target_os = "ios", target_os = "tvos", target_os = "watchos", + target_os = "visionos", target_os = "solaris", all(target_os = "linux", target_env = "gnu") ))] @@ -377,7 +379,13 @@ pub struct FilePermissions { pub struct FileTimes { accessed: Option, modified: Option, - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos", target_os = "tvos"))] + #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "watchos", + target_os = "visionos", + target_os = "tvos" + ))] created: Option, } @@ -555,6 +563,7 @@ impl FileAttr { target_os = "ios", target_os = "tvos", target_os = "watchos", + target_os = "visionos", ))] pub fn created(&self) -> io::Result { SystemTime::new(self.stat.st_birthtime as i64, self.stat.st_birthtime_nsec as i64) @@ -567,6 +576,7 @@ impl FileAttr { target_os = "ios", target_os = "tvos", target_os = "watchos", + target_os = "visionos", target_os = "vita", )))] pub fn created(&self) -> io::Result { @@ -647,7 +657,13 @@ impl FileTimes { self.modified = Some(t); } - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos", target_os = "tvos"))] + #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "watchos", + target_os = "visionos", + target_os = "tvos" + ))] pub fn set_created(&mut self, t: SystemTime) { self.created = Some(t); } @@ -938,6 +954,7 @@ impl DirEntry { target_os = "ios", target_os = "tvos", target_os = "watchos", + target_os = "visionos", target_os = "linux", target_os = "emscripten", target_os = "android", @@ -974,6 +991,7 @@ impl DirEntry { target_os = "ios", target_os = "tvos", target_os = "watchos", + target_os = "visionos", target_os = "netbsd", target_os = "openbsd", target_os = "freebsd", @@ -993,6 +1011,7 @@ impl DirEntry { target_os = "ios", target_os = "tvos", target_os = "watchos", + target_os = "visionos", target_os = "netbsd", target_os = "openbsd", target_os = "freebsd", @@ -1162,6 +1181,7 @@ impl File { target_os = "ios", target_os = "tvos", target_os = "watchos", + target_os = "visionos", ))] unsafe fn os_fsync(fd: c_int) -> c_int { libc::fcntl(fd, libc::F_FULLFSYNC) @@ -1171,6 +1191,7 @@ impl File { target_os = "ios", target_os = "tvos", target_os = "watchos", + target_os = "visionos", )))] unsafe fn os_fsync(fd: c_int) -> c_int { libc::fsync(fd) @@ -1186,6 +1207,7 @@ impl File { target_os = "ios", target_os = "tvos", target_os = "watchos", + target_os = "visionos", ))] unsafe fn os_datasync(fd: c_int) -> c_int { libc::fcntl(fd, libc::F_FULLFSYNC) @@ -1212,6 +1234,7 @@ impl File { target_os = "netbsd", target_os = "openbsd", target_os = "watchos", + target_os = "visionos", target_os = "nto", target_os = "hurd", )))] @@ -1322,7 +1345,7 @@ impl File { io::ErrorKind::Unsupported, "setting file times not supported", )) - } else if #[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] { + } else if #[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))] { let mut buf = [mem::MaybeUninit::::uninit(); 3]; let mut num_times = 0; let mut attrlist: libc::attrlist = unsafe { mem::zeroed() }; @@ -1787,6 +1810,7 @@ fn open_to_and_set_permissions( target_os = "ios", target_os = "tvos", target_os = "watchos", + target_os = "visionos", )))] pub fn copy(from: &Path, to: &Path) -> io::Result { let (mut reader, reader_metadata) = open_from(from)?; @@ -1813,7 +1837,13 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { } } -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] +#[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "watchos", + target_os = "visionos", + target_os = "tvos" +))] pub fn copy(from: &Path, to: &Path) -> io::Result { use crate::sync::atomic::{AtomicBool, Ordering}; diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index f608ae47a21f..4ae76518c4f6 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -83,6 +83,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { target_os = "ios", target_os = "tvos", target_os = "watchos", + target_os = "visionos", target_os = "redox", target_os = "l4re", target_os = "horizon", @@ -405,7 +406,7 @@ cfg_if::cfg_if! { } else if #[cfg(target_os = "macos")] { #[link(name = "System")] extern "C" {} - } else if #[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos"))] { + } else if #[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))] { #[link(name = "System")] #[link(name = "objc")] #[link(name = "Foundation", kind = "framework")] diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index 0b9c8027e6fc..96492fedece7 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -69,7 +69,8 @@ extern "C" { target_os = "ios", target_os = "tvos", target_os = "freebsd", - target_os = "watchos" + target_os = "watchos", + target_os = "visionos", ), link_name = "__error" )] @@ -430,7 +431,13 @@ pub fn current_exe() -> io::Result { Ok(PathBuf::from(OsString::from_vec(e))) } -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] +#[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "watchos", + target_os = "visionos", + target_os = "tvos" +))] pub fn current_exe() -> io::Result { unsafe { let mut sz: u32 = 0; @@ -699,6 +706,7 @@ pub fn home_dir() -> Option { target_os = "ios", target_os = "tvos", target_os = "watchos", + target_os = "visionos", target_os = "emscripten", target_os = "redox", target_os = "vxworks", @@ -714,6 +722,7 @@ pub fn home_dir() -> Option { target_os = "ios", target_os = "tvos", target_os = "watchos", + target_os = "visionos", target_os = "emscripten", target_os = "redox", target_os = "vxworks", diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs index f017d39d804a..e798510f9e64 100644 --- a/library/std/src/sys/pal/unix/process/process_unix.rs +++ b/library/std/src/sys/pal/unix/process/process_unix.rs @@ -14,6 +14,7 @@ use crate::os::unix::io::AsRawFd; #[cfg(any( target_os = "macos", target_os = "watchos", + target_os = "visionos", target_os = "tvos", target_os = "freebsd", all(target_os = "linux", target_env = "gnu"), diff --git a/library/std/src/sys/pal/unix/rand.rs b/library/std/src/sys/pal/unix/rand.rs index c9ed6825f6c2..de087d98eb8b 100644 --- a/library/std/src/sys/pal/unix/rand.rs +++ b/library/std/src/sys/pal/unix/rand.rs @@ -16,6 +16,7 @@ pub fn hashmap_random_keys() -> (u64, u64) { not(target_os = "ios"), not(target_os = "tvos"), not(target_os = "watchos"), + not(target_os = "visionos"), not(target_os = "openbsd"), not(target_os = "netbsd"), not(target_os = "fuchsia"), @@ -62,17 +63,23 @@ mod imp { unsafe { getrandom(buf.as_mut_ptr().cast(), buf.len(), libc::GRND_NONBLOCK) } } - #[cfg(any( - target_os = "espidf", - target_os = "horizon", - target_os = "freebsd", - target_os = "dragonfly", - netbsd10 - ))] + #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "freebsd", netbsd10))] fn getrandom(buf: &mut [u8]) -> libc::ssize_t { unsafe { libc::getrandom(buf.as_mut_ptr().cast(), buf.len(), 0) } } + #[cfg(target_os = "dragonfly")] + fn getrandom(buf: &mut [u8]) -> libc::ssize_t { + extern "C" { + fn getrandom( + buf: *mut libc::c_void, + buflen: libc::size_t, + flags: libc::c_uint, + ) -> libc::ssize_t; + } + unsafe { getrandom(buf.as_mut_ptr().cast(), buf.len(), 0) } + } + #[cfg(not(any( target_os = "linux", target_os = "android", diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 7d25c974ed36..f56e64c35058 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -1,5 +1,5 @@ use crate::cmp; -use crate::ffi::{CStr, CString}; +use crate::ffi::CStr; use crate::io; use crate::mem; use crate::num::NonZero; @@ -150,7 +150,13 @@ impl Thread { } } - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] + #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "watchos", + target_os = "visionos", + target_os = "tvos" + ))] pub fn set_name(name: &CStr) { unsafe { let name = truncate_cstr::<{ libc::MAXTHREADNAMESIZE }>(name); @@ -228,78 +234,6 @@ impl Thread { // Newlib, Emscripten, and VxWorks have no way to set a thread name. } - #[cfg(any( - target_os = "linux", - target_os = "freebsd", - target_os = "netbsd", - target_os = "solaris", - target_os = "illumos" - ))] - pub fn get_name() -> Option { - #[cfg(target_os = "linux")] - const TASK_COMM_LEN: usize = 16; - #[cfg(target_os = "freebsd")] - const TASK_COMM_LEN: usize = libc::MAXCOMLEN + 1; - #[cfg(any(target_os = "netbsd", target_os = "solaris", target_os = "illumos"))] - const TASK_COMM_LEN: usize = 32; - let mut name = vec![0u8; TASK_COMM_LEN]; - let res = unsafe { - libc::pthread_getname_np(libc::pthread_self(), name.as_mut_ptr().cast(), name.len()) - }; - if res != 0 { - return None; - } - name.truncate(name.iter().position(|&c| c == 0)?); - CString::new(name).ok() - } - - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))] - pub fn get_name() -> Option { - let mut name = vec![0u8; libc::MAXTHREADNAMESIZE]; - let res = unsafe { - libc::pthread_getname_np(libc::pthread_self(), name.as_mut_ptr().cast(), name.len()) - }; - if res != 0 { - return None; - } - name.truncate(name.iter().position(|&c| c == 0)?); - CString::new(name).ok() - } - - #[cfg(target_os = "haiku")] - pub fn get_name() -> Option { - unsafe { - let mut tinfo = mem::MaybeUninit::::uninit(); - // See BeOS teams group and threads api. - // https://www.haiku-os.org/legacy-docs/bebook/TheKernelKit_ThreadsAndTeams_Overview.html - let thread_self = libc::find_thread(ptr::null_mut()); - let res = libc::get_thread_info(thread_self, tinfo.as_mut_ptr()); - if res != libc::B_OK { - return None; - } - let info = tinfo.assume_init(); - let name = - core::slice::from_raw_parts(info.name.as_ptr() as *const u8, info.name.len()); - CStr::from_bytes_until_nul(name).map(CStr::to_owned).ok() - } - } - - #[cfg(not(any( - target_os = "linux", - target_os = "freebsd", - target_os = "netbsd", - target_os = "macos", - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - target_os = "haiku", - target_os = "solaris", - target_os = "illumos" - )))] - pub fn get_name() -> Option { - None - } - #[cfg(not(target_os = "espidf"))] pub fn sleep(dur: Duration) { let mut secs = dur.as_secs(); @@ -371,6 +305,7 @@ impl Drop for Thread { target_os = "ios", target_os = "tvos", target_os = "watchos", + target_os = "visionos", target_os = "nto", target_os = "solaris", target_os = "illumos", diff --git a/library/std/src/sys/pal/unix/thread_local_dtor.rs b/library/std/src/sys/pal/unix/thread_local_dtor.rs index e367ce5f9067..1164c1782f4b 100644 --- a/library/std/src/sys/pal/unix/thread_local_dtor.rs +++ b/library/std/src/sys/pal/unix/thread_local_dtor.rs @@ -76,7 +76,13 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { // workaround below is to register, via _tlv_atexit, a custom DTOR list once per // thread. thread_local dtors are pushed to the DTOR list without calling // _tlv_atexit. -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos", target_os = "tvos"))] +#[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "watchos", + target_os = "visionos", + target_os = "tvos" +))] pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { use crate::cell::{Cell, RefCell}; use crate::ptr; diff --git a/library/std/src/sys/pal/unix/thread_parking/mod.rs b/library/std/src/sys/pal/unix/thread_parking/mod.rs index 185333c072f4..3348d4b366d2 100644 --- a/library/std/src/sys/pal/unix/thread_parking/mod.rs +++ b/library/std/src/sys/pal/unix/thread_parking/mod.rs @@ -16,6 +16,7 @@ cfg_if::cfg_if! { target_os = "macos", target_os = "ios", target_os = "watchos", + target_os = "visionos", target_os = "tvos", ), not(miri), diff --git a/library/std/src/sys/pal/unix/thread_parking/pthread.rs b/library/std/src/sys/pal/unix/thread_parking/pthread.rs index bb79cf9548e6..d0ad3e2ce3ee 100644 --- a/library/std/src/sys/pal/unix/thread_parking/pthread.rs +++ b/library/std/src/sys/pal/unix/thread_parking/pthread.rs @@ -48,6 +48,7 @@ unsafe fn wait_timeout( target_os = "ios", target_os = "tvos", target_os = "watchos", + target_os = "visionos", target_os = "espidf", target_os = "horizon", ))] @@ -76,6 +77,7 @@ unsafe fn wait_timeout( target_os = "ios", target_os = "tvos", target_os = "watchos", + target_os = "visionos", target_os = "espidf", target_os = "horizon", )))] @@ -124,6 +126,7 @@ impl Parker { target_os = "ios", target_os = "tvos", target_os = "watchos", + target_os = "visionos", target_os = "l4re", target_os = "android", target_os = "redox", diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs index 0440f33ded13..e69775be8cf8 100644 --- a/library/std/src/sys/pal/unix/time.rs +++ b/library/std/src/sys/pal/unix/time.rs @@ -90,7 +90,8 @@ impl Timespec { target_os = "macos", target_os = "ios", target_os = "tvos", - target_os = "watchos" + target_os = "watchos", + target_os = "visionos", ))] let (tv_sec, tv_nsec) = if (tv_sec <= 0 && tv_sec > i64::MIN) && (tv_nsec < 0 && tv_nsec > -1_000_000_000) { @@ -278,6 +279,7 @@ impl Instant { target_os = "macos", target_os = "ios", target_os = "watchos", + target_os = "visionos", target_os = "tvos" ))] const clock_id: libc::clockid_t = libc::CLOCK_UPTIME_RAW; @@ -285,6 +287,7 @@ impl Instant { target_os = "macos", target_os = "ios", target_os = "watchos", + target_os = "visionos", target_os = "tvos" )))] const clock_id: libc::clockid_t = libc::CLOCK_MONOTONIC; diff --git a/library/std/src/sys/pal/unsupported/thread.rs b/library/std/src/sys/pal/unsupported/thread.rs index d3f2fa35b929..ea939247199c 100644 --- a/library/std/src/sys/pal/unsupported/thread.rs +++ b/library/std/src/sys/pal/unsupported/thread.rs @@ -1,5 +1,5 @@ use super::unsupported; -use crate::ffi::{CStr, CString}; +use crate::ffi::CStr; use crate::io; use crate::num::NonZero; use crate::time::Duration; @@ -22,10 +22,6 @@ impl Thread { // nope } - pub fn get_name() -> Option { - None - } - pub fn sleep(_dur: Duration) { panic!("can't sleep"); } diff --git a/library/std/src/sys/pal/wasi/thread.rs b/library/std/src/sys/pal/wasi/thread.rs index 940f0c8423af..d45fb28b67e6 100644 --- a/library/std/src/sys/pal/wasi/thread.rs +++ b/library/std/src/sys/pal/wasi/thread.rs @@ -1,4 +1,4 @@ -use crate::ffi::{CStr, CString}; +use crate::ffi::CStr; use crate::io; use crate::mem; use crate::num::NonZero; @@ -134,10 +134,6 @@ impl Thread { // nope } - pub fn get_name() -> Option { - None - } - pub fn sleep(dur: Duration) { let nanos = dur.as_nanos(); assert!(nanos <= u64::MAX as u128); diff --git a/library/std/src/sys/pal/wasm/atomics/thread.rs b/library/std/src/sys/pal/wasm/atomics/thread.rs index 3923ff821d9d..49f936f14498 100644 --- a/library/std/src/sys/pal/wasm/atomics/thread.rs +++ b/library/std/src/sys/pal/wasm/atomics/thread.rs @@ -1,5 +1,4 @@ use crate::ffi::CStr; -use crate::ffi::CString; use crate::io; use crate::num::NonZero; use crate::sys::unsupported; @@ -18,9 +17,6 @@ impl Thread { pub fn yield_now() {} pub fn set_name(_name: &CStr) {} - pub fn get_name() -> Option { - None - } pub fn sleep(dur: Duration) { use crate::arch::wasm32; diff --git a/library/std/src/sys/pal/windows/stack_overflow.rs b/library/std/src/sys/pal/windows/stack_overflow.rs index 627763da8561..f93f31026f81 100644 --- a/library/std/src/sys/pal/windows/stack_overflow.rs +++ b/library/std/src/sys/pal/windows/stack_overflow.rs @@ -3,21 +3,12 @@ use crate::sys::c; use crate::thread; -use super::api; - -pub struct Handler; - -impl Handler { - pub unsafe fn new() -> Handler { - // This API isn't available on XP, so don't panic in that case and just - // pray it works out ok. - if c::SetThreadStackGuarantee(&mut 0x5000) == 0 - && api::get_last_error().code != c::ERROR_CALL_NOT_IMPLEMENTED - { - panic!("failed to reserve stack space for exception handling"); - } - Handler - } +/// Reserve stack space for use in stack overflow exceptions. +pub unsafe fn reserve_stack() { + let result = c::SetThreadStackGuarantee(&mut 0x5000); + // Reserving stack space is not critical so we allow it to fail in the released build of libstd. + // We still use debug assert here so that CI will test that we haven't made a mistake calling the function. + debug_assert_ne!(result, 0, "failed to reserve stack space for exception handling"); } unsafe extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POINTERS) -> c::LONG { @@ -36,9 +27,10 @@ unsafe extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POIN } pub unsafe fn init() { - if c::AddVectoredExceptionHandler(0, Some(vectored_handler)).is_null() { - panic!("failed to install exception handler"); - } + let result = c::AddVectoredExceptionHandler(0, Some(vectored_handler)); + // Similar to the above, adding the stack overflow handler is allowed to fail + // but a debug assert is used so CI will still test that it normally works. + debug_assert!(!result.is_null(), "failed to install exception handler"); // Set the thread stack guarantee for the main thread. - let _h = Handler::new(); + reserve_stack(); } diff --git a/library/std/src/sys/pal/windows/stack_overflow_uwp.rs b/library/std/src/sys/pal/windows/stack_overflow_uwp.rs index afdf7f566ae5..9e9b3efaf1b1 100644 --- a/library/std/src/sys/pal/windows/stack_overflow_uwp.rs +++ b/library/std/src/sys/pal/windows/stack_overflow_uwp.rs @@ -1,11 +1,4 @@ #![cfg_attr(test, allow(dead_code))] -pub struct Handler; - -impl Handler { - pub fn new() -> Handler { - Handler - } -} - +pub unsafe fn reserve_stack() {} pub unsafe fn init() {} diff --git a/library/std/src/sys/pal/windows/thread.rs b/library/std/src/sys/pal/windows/thread.rs index 80eee4e078db..c0c63c3340f4 100644 --- a/library/std/src/sys/pal/windows/thread.rs +++ b/library/std/src/sys/pal/windows/thread.rs @@ -9,7 +9,6 @@ use crate::sys::handle::Handle; use crate::sys::stack_overflow; use crate::sys_common::FromInner; use crate::time::Duration; -use alloc::ffi::CString; use core::ffi::c_void; use super::time::WaitableTimer; @@ -48,9 +47,8 @@ impl Thread { extern "system" fn thread_start(main: *mut c_void) -> c::DWORD { unsafe { - // Next, set up our stack overflow handler which may get triggered if we run - // out of stack. - let _handler = stack_overflow::Handler::new(); + // Next, reserve some stack space for if we otherwise run out of stack. + stack_overflow::reserve_stack(); // Finally, let's run some code. Box::from_raw(main as *mut Box)(); } @@ -68,29 +66,6 @@ impl Thread { }; } - pub fn get_name() -> Option { - unsafe { - let mut ptr = core::ptr::null_mut(); - let result = c::GetThreadDescription(c::GetCurrentThread(), &mut ptr); - if result < 0 { - return None; - } - let name = String::from_utf16_lossy({ - let mut len = 0; - while *ptr.add(len) != 0 { - len += 1; - } - core::slice::from_raw_parts(ptr, len) - }) - .into_bytes(); - // Attempt to free the memory. - // This should never fail but if it does then there's not much we can do about it. - let result = c::LocalFree(ptr.cast::()); - debug_assert!(result.is_null()); - if name.is_empty() { None } else { Some(CString::from_vec_unchecked(name)) } - } - } - pub fn join(self) { let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE) }; if rc == c::WAIT_FAILED { diff --git a/library/std/src/sys/pal/xous/thread.rs b/library/std/src/sys/pal/xous/thread.rs index c1fd1c0d6534..da7d722cc708 100644 --- a/library/std/src/sys/pal/xous/thread.rs +++ b/library/std/src/sys/pal/xous/thread.rs @@ -1,4 +1,4 @@ -use crate::ffi::{CStr, CString}; +use crate::ffi::CStr; use crate::io; use crate::num::NonZero; use crate::os::xous::ffi::{ @@ -113,10 +113,6 @@ impl Thread { // nope } - pub fn get_name() -> Option { - None - } - pub fn sleep(dur: Duration) { // Because the sleep server works on units of `usized milliseconds`, split // the messages up into these chunks. This means we may run into issues diff --git a/library/std/src/sys/personality/gcc.rs b/library/std/src/sys/personality/gcc.rs index 6f317131145a..b0f744dd9660 100644 --- a/library/std/src/sys/personality/gcc.rs +++ b/library/std/src/sys/personality/gcc.rs @@ -92,7 +92,7 @@ const UNWIND_DATA_REG: (i32, i32) = (4, 5); // a0, a1 // https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c cfg_if::cfg_if! { - if #[cfg(all(target_arch = "arm", not(target_os = "ios"), not(target_os = "tvos"), not(target_os = "watchos"), not(target_os = "netbsd")))] { + if #[cfg(all(target_arch = "arm", not(target_os = "ios"), not(target_os = "tvos"), not(target_os = "watchos"), not(target_os = "visionos"), not(target_os = "netbsd")))] { // ARM EHABI personality routine. // https://web.archive.org/web/20190728160938/https://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf // diff --git a/library/std/src/sys/sync/condvar/pthread.rs b/library/std/src/sys/sync/condvar/pthread.rs index 728371685eee..0475f9850786 100644 --- a/library/std/src/sys/sync/condvar/pthread.rs +++ b/library/std/src/sys/sync/condvar/pthread.rs @@ -34,6 +34,7 @@ impl LazyInit for AllocatedCondvar { target_os = "ios", target_os = "tvos", target_os = "watchos", + target_os = "visionos", target_os = "l4re", target_os = "android", target_os = "redox" @@ -127,6 +128,7 @@ impl Condvar { target_os = "ios", target_os = "tvos", target_os = "watchos", + target_os = "visionos", target_os = "android", target_os = "espidf", target_os = "horizon" @@ -162,6 +164,7 @@ impl Condvar { target_os = "ios", target_os = "tvos", target_os = "watchos", + target_os = "visionos", target_os = "android", target_os = "espidf", target_os = "horizon" diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index 2d785064245d..8c9885974b48 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -18,7 +18,7 @@ use crate::ffi::{c_int, c_void}; cfg_if::cfg_if! { if #[cfg(any( target_os = "dragonfly", target_os = "freebsd", - target_os = "ios", target_os = "tvos", target_os = "macos", target_os = "watchos", + target_os = "ios", target_os = "tvos", target_os = "macos", target_os = "watchos", target_os = "visionos", target_os = "openbsd", target_os = "netbsd", target_os = "illumos", target_os = "solaris", target_os = "haiku", target_os = "l4re", target_os = "nto"))] { use crate::sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP; diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index f7eb92bc61e2..f792a27dd694 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -694,9 +694,7 @@ pub(crate) fn set_current(thread: Thread) { /// In contrast to the public `current` function, this will not panic if called /// from inside a TLS destructor. pub(crate) fn try_current() -> Option { - CURRENT - .try_with(|current| current.get_or_init(|| Thread::new(imp::Thread::get_name())).clone()) - .ok() + CURRENT.try_with(|current| current.get_or_init(|| Thread::new(None)).clone()).ok() } /// Gets a handle to the thread that invokes it. @@ -1247,9 +1245,16 @@ impl ThreadId { // Thread //////////////////////////////////////////////////////////////////////////////// +/// The internal representation of a `Thread`'s name. +enum ThreadName { + Main, + Other(CString), + Unnamed, +} + /// The internal representation of a `Thread` handle struct Inner { - name: Option, // Guaranteed to be UTF-8 + name: ThreadName, // Guaranteed to be UTF-8 id: ThreadId, parker: Parker, } @@ -1286,8 +1291,20 @@ pub struct Thread { impl Thread { // Used only internally to construct a thread object without spawning - // Panics if the name contains nuls. pub(crate) fn new(name: Option) -> Thread { + if let Some(name) = name { + Self::new_inner(ThreadName::Other(name)) + } else { + Self::new_inner(ThreadName::Unnamed) + } + } + + // Used in runtime to construct main thread + pub(crate) fn new_main() -> Thread { + Self::new_inner(ThreadName::Main) + } + + fn new_inner(name: ThreadName) -> Thread { // We have to use `unsafe` here to construct the `Parker` in-place, // which is required for the UNIX implementation. // @@ -1414,7 +1431,11 @@ impl Thread { } fn cname(&self) -> Option<&CStr> { - self.inner.name.as_deref() + match &self.inner.name { + ThreadName::Main => Some(c"main"), + ThreadName::Other(other) => Some(&other), + ThreadName::Unnamed => None, + } } } diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs index 589a5fdad1d7..494513f2c75c 100644 --- a/library/std/src/thread/tests.rs +++ b/library/std/src/thread/tests.rs @@ -43,7 +43,8 @@ fn test_named_thread() { target_os = "macos", target_os = "ios", target_os = "tvos", - target_os = "watchos" + target_os = "watchos", + target_os = "visionos", ))] #[test] fn test_named_thread_truncation() { @@ -69,26 +70,6 @@ fn test_named_thread_truncation() { result.unwrap().join().unwrap(); } -#[cfg(any( - all(target_os = "windows", not(target_vendor = "win7")), - target_os = "linux", - target_os = "macos", - target_os = "ios", - target_os = "tvos", - target_os = "watchos" -))] -#[test] -fn test_get_os_named_thread() { - use crate::sys::thread::Thread; - // Spawn a new thread to avoid interfering with other tests running on this thread. - let handler = thread::spawn(|| { - let name = c"test me please"; - Thread::set_name(name); - assert_eq!(name, Thread::get_name().unwrap().as_c_str()); - }); - handler.join().unwrap(); -} - #[test] #[should_panic] fn test_invalid_named_thread() { diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index 0a0dc9438b30..57ce3d0fa5c3 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -123,7 +123,7 @@ extern "C" { } cfg_if::cfg_if! { -if #[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "netbsd", not(target_arch = "arm")))] { +if #[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos", target_os = "netbsd", not(target_arch = "arm")))] { // Not ARM EHABI #[repr(C)] #[derive(Copy, Clone, PartialEq)] diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 30d728aa2300..39add60e705f 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -1038,6 +1038,7 @@ class RustBuild(object): sync_dirs = "--sync ./src/tools/cargo/Cargo.toml " \ "--sync ./src/tools/rust-analyzer/Cargo.toml " \ "--sync ./compiler/rustc_codegen_cranelift/Cargo.toml " \ + "--sync ./compiler/rustc_codegen_gcc/Cargo.toml " \ "--sync ./src/bootstrap/Cargo.toml " eprint('ERROR: vendoring required, but vendor directory does not exist.') eprint(' Run `cargo vendor {}` to initialize the ' diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index ecea62140a2e..b51d3e157887 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -1011,6 +1011,8 @@ impl Step for PlainSourceTarball { .arg("--sync") .arg(builder.src.join("./compiler/rustc_codegen_cranelift/Cargo.toml")) .arg("--sync") + .arg(builder.src.join("./compiler/rustc_codegen_gcc/Cargo.toml")) + .arg("--sync") .arg(builder.src.join("./src/bootstrap/Cargo.toml")) // Will read the libstd Cargo.toml // which uses the unstable `public-dependency` feature. diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index e461e11677fa..420336fee149 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -365,10 +365,11 @@ impl Step for Llvm { cfg.define("LLVM_ENABLE_ZLIB", "OFF"); } - // Are we compiling for iOS/tvOS/watchOS? + // Are we compiling for iOS/tvOS/watchOS/visionOS? if target.contains("apple-ios") || target.contains("apple-tvos") || target.contains("apple-watchos") + || target.contains("apple-visionos") { // These two defines prevent CMake from automatically trying to add a MacOSX sysroot, which leads to a compiler error. cfg.define("CMAKE_OSX_SYSROOT", "/"); diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 8a79c28fc6c6..bacf5f0d33ce 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -595,7 +595,7 @@ impl Step for Miri { // This is for the tests so everything is done with the target compiler. let miri_sysroot = Miri::build_miri_sysroot(builder, target_compiler, target); builder.ensure(compile::Std::new(target_compiler, host)); - let sysroot = builder.sysroot(target_compiler); + let host_sysroot = builder.sysroot(target_compiler); // # Run `cargo test`. // This is with the Miri crate, so it uses the host compiler. @@ -618,7 +618,7 @@ impl Step for Miri { // miri tests need to know about the stage sysroot cargo.env("MIRI_SYSROOT", &miri_sysroot); - cargo.env("MIRI_HOST_SYSROOT", &sysroot); + cargo.env("MIRI_HOST_SYSROOT", &host_sysroot); cargo.env("MIRI", &miri); // Set the target. @@ -681,10 +681,6 @@ impl Step for Miri { } } - // Tell `cargo miri` where to find the sysroots. - cargo.env("MIRI_SYSROOT", &miri_sysroot); - cargo.env("MIRI_HOST_SYSROOT", sysroot); - // Finally, pass test-args and run everything. cargo.arg("--").args(builder.config.test_args()); let mut cargo = Command::from(cargo); @@ -2540,9 +2536,14 @@ fn prepare_cargo_test( // // Note that to run the compiler we need to run with the *host* libraries, // but our wrapper scripts arrange for that to be the case anyway. - let mut dylib_path = dylib_path(); - dylib_path.insert(0, PathBuf::from(&*builder.sysroot_libdir(compiler, target))); - cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap()); + // + // We skip everything on Miri as then this overwrites the libdir set up + // by `Cargo::new` and that actually makes things go wrong. + if builder.kind != Kind::Miri { + let mut dylib_path = dylib_path(); + dylib_path.insert(0, PathBuf::from(&*builder.sysroot_libdir(compiler, target))); + cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap()); + } if builder.remote_tested(target) { cargo.env( @@ -2598,28 +2599,62 @@ impl Step for Crate { let target = self.target; let mode = self.mode; + // Prepare sysroot // See [field@compile::Std::force_recompile]. builder.ensure(compile::Std::force_recompile(compiler, compiler.host)); - if builder.config.build != target { - builder.ensure(compile::Std::force_recompile(compiler, target)); - builder.ensure(RemoteCopyLibs { compiler, target }); - } - // If we're not doing a full bootstrap but we're testing a stage2 // version of libstd, then what we're actually testing is the libstd // produced in stage1. Reflect that here by updating the compiler that // we're working with automatically. let compiler = builder.compiler_for(compiler.stage, compiler.host, target); - let mut cargo = builder::Cargo::new( - builder, - compiler, - mode, - SourceType::InTree, - target, - builder.kind.as_str(), - ); + let mut cargo = if builder.kind == Kind::Miri { + if builder.top_stage == 0 { + eprintln!("ERROR: `x.py miri` requires stage 1 or higher"); + std::process::exit(1); + } + + // Build `cargo miri test` command + // (Implicitly prepares target sysroot) + let mut cargo = builder::Cargo::new( + builder, + compiler, + mode, + SourceType::InTree, + target, + "miri-test", + ); + // This hack helps bootstrap run standard library tests in Miri. The issue is as + // follows: when running `cargo miri test` on libcore, cargo builds a local copy of core + // and makes it a dependency of the integration test crate. This copy duplicates all the + // lang items, so the build fails. (Regular testing avoids this because the sysroot is a + // literal copy of what `cargo build` produces, but since Miri builds its own sysroot + // this does not work for us.) So we need to make it so that the locally built libcore + // contains all the items from `core`, but does not re-define them -- we want to replace + // the entire crate but a re-export of the sysroot crate. We do this by swapping out the + // source file: if `MIRI_REPLACE_LIBRS_IF_NOT_TEST` is set and we are building a + // `lib.rs` file, and a `lib.miri.rs` file exists in the same folder, we build that + // instead. But crucially we only do that for the library, not the test builds. + cargo.env("MIRI_REPLACE_LIBRS_IF_NOT_TEST", "1"); + cargo + } else { + // Also prepare a sysroot for the target. + if builder.config.build != target { + builder.ensure(compile::Std::force_recompile(compiler, target)); + builder.ensure(RemoteCopyLibs { compiler, target }); + } + + // Build `cargo test` command + builder::Cargo::new( + builder, + compiler, + mode, + SourceType::InTree, + target, + builder.kind.as_str(), + ) + }; match mode { Mode::Std => { diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 0cce5130f648..9555be481e69 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -631,6 +631,7 @@ pub enum Kind { Format, #[value(alias = "t")] Test, + Miri, Bench, #[value(alias = "d")] Doc, @@ -673,6 +674,7 @@ impl Kind { Kind::Fix => "fix", Kind::Format => "fmt", Kind::Test => "test", + Kind::Miri => "miri", Kind::Bench => "bench", Kind::Doc => "doc", Kind::Clean => "clean", @@ -822,6 +824,7 @@ impl<'a> Builder<'a> { // Run run-make last, since these won't pass without make on Windows test::RunMake, ), + Kind::Miri => describe!(test::Crate), Kind::Bench => describe!(test::Crate, test::CrateLibrustc), Kind::Doc => describe!( doc::UnstableBook, @@ -970,6 +973,7 @@ impl<'a> Builder<'a> { Subcommand::Fix => (Kind::Fix, &paths[..]), Subcommand::Doc { .. } => (Kind::Doc, &paths[..]), Subcommand::Test { .. } => (Kind::Test, &paths[..]), + Subcommand::Miri { .. } => (Kind::Miri, &paths[..]), Subcommand::Bench { .. } => (Kind::Bench, &paths[..]), Subcommand::Dist => (Kind::Dist, &paths[..]), Subcommand::Install => (Kind::Install, &paths[..]), @@ -1226,6 +1230,7 @@ impl<'a> Builder<'a> { assert!(run_compiler.stage > 0, "miri can not be invoked at stage 0"); let build_compiler = self.compiler(run_compiler.stage - 1, self.build.build); + // Prepare the tools let miri = self.ensure(tool::Miri { compiler: build_compiler, target: self.build.build, @@ -1236,7 +1241,7 @@ impl<'a> Builder<'a> { target: self.build.build, extra_features: Vec::new(), }); - // Invoke cargo-miri, make sure we can find miri and cargo. + // Invoke cargo-miri, make sure it can find miri and cargo. let mut cmd = Command::new(cargo_miri); cmd.env("MIRI", &miri); cmd.env("CARGO", &self.initial_cargo); @@ -1299,7 +1304,11 @@ impl<'a> Builder<'a> { if cmd == "clippy" { cargo = self.cargo_clippy_cmd(compiler); cargo.arg(cmd); - } else if let Some(subcmd) = cmd.strip_prefix("miri-") { + } else if let Some(subcmd) = cmd.strip_prefix("miri") { + // Command must be "miri-X". + let subcmd = subcmd + .strip_prefix("-") + .unwrap_or_else(|| panic!("expected `miri-$subcommand`, but got {}", cmd)); cargo = self.cargo_miri_cmd(compiler); cargo.arg("miri").arg(subcmd); } else { @@ -1702,6 +1711,15 @@ impl<'a> Builder<'a> { cargo.env("RUSTC_WRAPPER_REAL", existing_wrapper); } + // If this is for `miri-test`, prepare the sysroots. + if cmd == "miri-test" { + self.ensure(compile::Std::new(compiler, compiler.host)); + let host_sysroot = self.sysroot(compiler); + let miri_sysroot = test::Miri::build_miri_sysroot(self, compiler, target); + cargo.env("MIRI_SYSROOT", &miri_sysroot); + cargo.env("MIRI_HOST_SYSROOT", &host_sysroot); + } + cargo.env(profile_var("STRIP"), self.config.rust_strip.to_string()); if let Some(stack_protector) = &self.config.rust_stack_protector { @@ -2084,12 +2102,10 @@ impl<'a> Builder<'a> { rustdocflags.arg("--cfg=parallel_compiler"); } - // set rustc args passed from command line - let rustc_args = - self.config.cmd.rustc_args().iter().map(|s| s.to_string()).collect::>(); - if !rustc_args.is_empty() { - cargo.env("RUSTFLAGS", &rustc_args.join(" ")); - } + // Pass the value of `--rustc-args` from test command. If it's not a test command, this won't set anything. + self.config.cmd.rustc_args().iter().for_each(|v| { + rustflags.arg(v); + }); Cargo { command: cargo, diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 67cde01ccdb6..96dec9752504 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -2022,7 +2022,7 @@ impl Config { Subcommand::Build { .. } => { flags.stage.or(build_stage).unwrap_or(if download_rustc { 2 } else { 1 }) } - Subcommand::Test { .. } => { + Subcommand::Test { .. } | Subcommand::Miri { .. } => { flags.stage.or(test_stage).unwrap_or(if download_rustc { 2 } else { 1 }) } Subcommand::Bench { .. } => flags.stage.or(bench_stage).unwrap_or(2), @@ -2044,6 +2044,7 @@ impl Config { if flags.stage.is_none() && crate::CiEnv::current() != crate::CiEnv::None { match config.cmd { Subcommand::Test { .. } + | Subcommand::Miri { .. } | Subcommand::Doc { .. } | Subcommand::Build { .. } | Subcommand::Bench { .. } @@ -2099,7 +2100,9 @@ impl Config { pub(crate) fn test_args(&self) -> Vec<&str> { let mut test_args = match self.cmd { - Subcommand::Test { ref test_args, .. } | Subcommand::Bench { ref test_args, .. } => { + Subcommand::Test { ref test_args, .. } + | Subcommand::Bench { ref test_args, .. } + | Subcommand::Miri { ref test_args, .. } => { test_args.iter().flat_map(|s| s.split_whitespace()).collect() } _ => vec![], diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index a66f743a1c51..aaa2a2c47e07 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -379,6 +379,25 @@ pub enum Subcommand { /// `//rustfix_missing_coverage.txt` rustfix_coverage: bool, }, + /// Build and run some test suites *in Miri* + Miri { + #[arg(long)] + /// run all tests regardless of failure + no_fail_fast: bool, + #[arg(long, value_name = "ARGS", allow_hyphen_values(true))] + /// extra arguments to be passed for the test tool being used + /// (e.g. libtest, compiletest or rustdoc) + test_args: Vec, + /// extra options to pass the compiler when running tests + #[arg(long, value_name = "ARGS", allow_hyphen_values(true))] + rustc_args: Vec, + #[arg(long)] + /// do not run doc tests + no_doc: bool, + #[arg(long)] + /// only run doc tests + doc: bool, + }, /// Build and run some benchmarks Bench { #[arg(long, allow_hyphen_values(true))] @@ -450,6 +469,7 @@ impl Subcommand { Subcommand::Fix { .. } => Kind::Fix, Subcommand::Format { .. } => Kind::Format, Subcommand::Test { .. } => Kind::Test, + Subcommand::Miri { .. } => Kind::Miri, Subcommand::Clean { .. } => Kind::Clean, Subcommand::Dist { .. } => Kind::Dist, Subcommand::Install { .. } => Kind::Install, @@ -461,7 +481,7 @@ impl Subcommand { pub fn rustc_args(&self) -> Vec<&str> { match *self { - Subcommand::Test { ref rustc_args, .. } => { + Subcommand::Test { ref rustc_args, .. } | Subcommand::Miri { ref rustc_args, .. } => { rustc_args.iter().flat_map(|s| s.split_whitespace()).collect() } _ => vec![], @@ -470,14 +490,16 @@ impl Subcommand { pub fn fail_fast(&self) -> bool { match *self { - Subcommand::Test { no_fail_fast, .. } => !no_fail_fast, + Subcommand::Test { no_fail_fast, .. } | Subcommand::Miri { no_fail_fast, .. } => { + !no_fail_fast + } _ => false, } } pub fn doc_tests(&self) -> DocTests { match *self { - Subcommand::Test { doc, no_doc, .. } => { + Subcommand::Test { doc, no_doc, .. } | Subcommand::Miri { no_doc, doc, .. } => { if doc { DocTests::Only } else if no_doc { diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 44452446eb87..bcb8260b15aa 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -92,8 +92,9 @@ const EXTRA_CHECK_CFGS: &[(Option, &str, Option<&[&'static str]>)] = &[ (Some(Mode::Std), "backtrace_in_libstd", None), /* Extra values not defined in the built-in targets yet, but used in std */ (Some(Mode::Std), "target_env", Some(&["libnx", "p2"])), - // (Some(Mode::Std), "target_os", Some(&[])), + (Some(Mode::Std), "target_os", Some(&["visionos"])), (Some(Mode::Std), "target_arch", Some(&["arm64ec", "spirv", "nvptx", "xtensa"])), + (Some(Mode::ToolStd), "target_os", Some(&["visionos"])), /* Extra names used by dependencies */ // FIXME: Used by serde_json, but we should not be triggering on external dependencies. (Some(Mode::Rustc), "no_btreemap_remove_entry", None), diff --git a/src/bootstrap/src/utils/render_tests.rs b/src/bootstrap/src/utils/render_tests.rs index 70f25b2cc87c..95cd55c9a3d7 100644 --- a/src/bootstrap/src/utils/render_tests.rs +++ b/src/bootstrap/src/utils/render_tests.rs @@ -231,14 +231,16 @@ impl<'a> Renderer<'a> { print!("\ntest result: "); self.builder.colored_stdout(|stdout| outcome.write_long(stdout)).unwrap(); println!( - ". {} passed; {} failed; {} ignored; {} measured; {} filtered out; \ - finished in {:.2?}\n", + ". {} passed; {} failed; {} ignored; {} measured; {} filtered out{time}\n", suite.passed, suite.failed, suite.ignored, suite.measured, suite.filtered_out, - Duration::from_secs_f64(suite.exec_time) + time = match suite.exec_time { + Some(t) => format!("; finished in {:.2?}", Duration::from_secs_f64(t)), + None => format!(""), + } ); } @@ -374,7 +376,9 @@ struct SuiteOutcome { ignored: usize, measured: usize, filtered_out: usize, - exec_time: f64, + /// The time it took to execute this test suite, or `None` if time measurement was not possible + /// (e.g. due to running inside Miri). + exec_time: Option, } #[derive(serde_derive::Deserialize)] diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version index 07feb8234926..14a8c2457569 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version @@ -1 +1 @@ -0.17.0 \ No newline at end of file +0.17.1 \ No newline at end of file diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh index 10ae7f17db7a..38c5b173ae31 100755 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh @@ -62,3 +62,8 @@ case $HOST_TARGET in exit 1 ;; esac +# Also smoke-test `x.py miri`. This doesn't run any actual tests (that would take too long), +# but it ensures that the crates build properly when tested with Miri. +python3 "$X_PY" miri --stage 2 library/core --test-args notest +python3 "$X_PY" miri --stage 2 library/alloc --test-args notest +python3 "$X_PY" miri --stage 2 library/std --test-args notest diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 83acce80f969..db85753145d4 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -21,6 +21,7 @@ - [arm64ec-pc-windows-msvc](platform-support/arm64ec-pc-windows-msvc.md) - [\*-apple-tvos](platform-support/apple-tvos.md) - [\*-apple-watchos\*](platform-support/apple-watchos.md) + - [aarch64-apple-visionos\*](platform-support/apple-visionos.md) - [aarch64-nintendo-switch-freestanding](platform-support/aarch64-nintendo-switch-freestanding.md) - [armeb-unknown-linux-gnueabi](platform-support/armeb-unknown-linux-gnueabi.md) - [arm-none-eabi](platform-support/arm-none-eabi.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index aa982a445033..f7836f18cf9d 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -243,6 +243,8 @@ target | std | host | notes [`aarch64-apple-tvos-sim`](platform-support/apple-tvos.md) | ? | | ARM64 tvOS Simulator [`aarch64-apple-watchos`](platform-support/apple-watchos.md) | ✓ | | ARM64 Apple WatchOS [`aarch64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ | | ARM64 Apple WatchOS Simulator +[`aarch64-apple-visionos`](platform-support/apple-visionos.md) | ✓ | | ARM64 Apple visionOS +[`aarch64-apple-visionos-sim`](platform-support/apple-visionos.md) | ✓ | | ARM64 Apple visionOS Simulator [`aarch64-kmc-solid_asp3`](platform-support/kmc-solid.md) | ✓ | | ARM64 SOLID with TOPPERS/ASP3 [`aarch64-nintendo-switch-freestanding`](platform-support/aarch64-nintendo-switch-freestanding.md) | * | | ARM64 Nintendo Switch, Horizon [`aarch64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ | diff --git a/src/doc/rustc/src/platform-support/apple-visionos.md b/src/doc/rustc/src/platform-support/apple-visionos.md new file mode 100644 index 000000000000..9874126e42fe --- /dev/null +++ b/src/doc/rustc/src/platform-support/apple-visionos.md @@ -0,0 +1,53 @@ +# aarch64-apple-visionos\* + +- aarch64-apple-visionos +- aarch64-apple-visionos-sim + +**Tier: 3** + +Apple visionOS targets: + +- Apple visionOS on arm64 +- Apple visionOS Simulator on arm64 + +## Target maintainers + +- [@agg23](https://github.com/agg23) +- [@madsmtm](https://github.com/madsmtm) + +## Requirements + +These targets are cross-compiled. +To build these targets Xcode 15 or higher on macOS is required, along with LLVM 18. + +## Building the target + +The targets can be built by enabling them for a `rustc` build, for example: + +```toml +[build] +build-stage = 1 +target = ["aarch64-apple-visionos-sim"] +``` + +## Building Rust programs + +_Note: Building for this target requires the corresponding visionOS SDK, as provided by Xcode 15+._ + +Rust programs can be built for these targets, if `rustc` has been built with support for them, for example: + +```text +rustc --target aarch64-apple-visionos-sim your-code.rs +``` + +## Testing + +There is no support for running the Rust testsuite on visionOS or the simulators. + +There is no easy way to run simple programs on visionOS or the visionOS simulators. Static library builds can be embedded into visionOS applications. + +## Cross-compilation toolchains and C code + +This target can be cross-compiled from x86_64 or aarch64 macOS hosts. + +Other hosts are not supported for cross-compilation, but might work when also providing the required Xcode SDK. diff --git a/src/doc/rustdoc/src/what-is-rustdoc.md b/src/doc/rustdoc/src/what-is-rustdoc.md index 7179ee0cf037..cb4ec51caf20 100644 --- a/src/doc/rustdoc/src/what-is-rustdoc.md +++ b/src/doc/rustdoc/src/what-is-rustdoc.md @@ -34,6 +34,9 @@ the main page is located in `doc/lib/index.html`. If you open that up in a web browser, you will see a page with a search bar, and "Crate lib" at the top, with no contents. +You can also use `cargo doc` to generate documentation for the whole project. +See [Using rustdoc with Cargo](#using-rustdoc-with-cargo). + ## Configuring rustdoc There are two problems with this: first, why does it @@ -79,7 +82,13 @@ docs. Instead of the `rustdoc` command, we could have done this: $ cargo doc ``` -Internally, this calls out to `rustdoc` like this: +If you want `cargo` to automatically open the generated documentation, you can use: + +```bash +$ cargo doc --open +``` + +Internally, `cargo doc` calls out to `rustdoc` like this: ```bash $ rustdoc --crate-name docs src/lib.rs -o /docs/target/doc -L diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish index c95516494ae7..5ae27bc8c91c 100644 --- a/src/etc/completions/x.py.fish +++ b/src/etc/completions/x.py.fish @@ -39,6 +39,7 @@ complete -c x.py -n "__fish_use_subcommand" -f -a "fix" -d 'Run cargo fix' complete -c x.py -n "__fish_use_subcommand" -f -a "fmt" -d 'Run rustfmt' complete -c x.py -n "__fish_use_subcommand" -f -a "doc" -d 'Build documentation' complete -c x.py -n "__fish_use_subcommand" -f -a "test" -d 'Build and run some test suites' +complete -c x.py -n "__fish_use_subcommand" -f -a "miri" -d 'Build and run some test suites *in Miri*' complete -c x.py -n "__fish_use_subcommand" -f -a "bench" -d 'Build and run some benchmarks' complete -c x.py -n "__fish_use_subcommand" -f -a "clean" -d 'Clean out build directories' complete -c x.py -n "__fish_use_subcommand" -f -a "dist" -d 'Build distribution artifacts' @@ -308,6 +309,45 @@ complete -c x.py -n "__fish_seen_subcommand_from test" -l llvm-profile-generate complete -c x.py -n "__fish_seen_subcommand_from test" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_seen_subcommand_from test" -l skip-stage0-validation -d 'Skip stage0 compiler validation' complete -c x.py -n "__fish_seen_subcommand_from test" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c x.py -n "__fish_seen_subcommand_from miri" -l test-args -d 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)' -r +complete -c x.py -n "__fish_seen_subcommand_from miri" -l rustc-args -d 'extra options to pass the compiler when running tests' -r +complete -c x.py -n "__fish_seen_subcommand_from miri" -l config -d 'TOML configuration file for build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from miri" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from miri" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_seen_subcommand_from miri" -l host -d 'host targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from miri" -l target -d 'target targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from miri" -l exclude -d 'build paths to exclude' -r -F +complete -c x.py -n "__fish_seen_subcommand_from miri" -l skip -d 'build paths to skip' -r -F +complete -c x.py -n "__fish_seen_subcommand_from miri" -l rustc-error-format -r -f +complete -c x.py -n "__fish_seen_subcommand_from miri" -l on-fail -d 'command to run on failure' -r -f -a "(__fish_complete_command)" +complete -c x.py -n "__fish_seen_subcommand_from miri" -l stage -d 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from miri" -l keep-stage -d 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from miri" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from miri" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from miri" -s j -l jobs -d 'number of jobs to run in parallel' -r -f +complete -c x.py -n "__fish_seen_subcommand_from miri" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny '',warn '',default ''}" +complete -c x.py -n "__fish_seen_subcommand_from miri" -l error-format -d 'rustc error format' -r -f +complete -c x.py -n "__fish_seen_subcommand_from miri" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always '',never '',auto ''}" +complete -c x.py -n "__fish_seen_subcommand_from miri" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true '',false ''}" +complete -c x.py -n "__fish_seen_subcommand_from miri" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from miri" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from miri" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from miri" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r +complete -c x.py -n "__fish_seen_subcommand_from miri" -l set -d 'override options in config.toml' -r -f +complete -c x.py -n "__fish_seen_subcommand_from miri" -l no-fail-fast -d 'run all tests regardless of failure' +complete -c x.py -n "__fish_seen_subcommand_from miri" -l no-doc -d 'do not run doc tests' +complete -c x.py -n "__fish_seen_subcommand_from miri" -l doc -d 'only run doc tests' +complete -c x.py -n "__fish_seen_subcommand_from miri" -s v -l verbose -d 'use verbose output (-vv for very verbose)' +complete -c x.py -n "__fish_seen_subcommand_from miri" -s i -l incremental -d 'use incremental compilation' +complete -c x.py -n "__fish_seen_subcommand_from miri" -l include-default-paths -d 'include default paths in addition to the provided ones' +complete -c x.py -n "__fish_seen_subcommand_from miri" -l dry-run -d 'dry run; don\'t build anything' +complete -c x.py -n "__fish_seen_subcommand_from miri" -l dump-bootstrap-shims -d 'Indicates whether to dump the work done from bootstrap shims' +complete -c x.py -n "__fish_seen_subcommand_from miri" -l json-output -d 'use message-format=json' +complete -c x.py -n "__fish_seen_subcommand_from miri" -l bypass-bootstrap-lock -d 'Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)' +complete -c x.py -n "__fish_seen_subcommand_from miri" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_seen_subcommand_from miri" -l enable-bolt-settings -d 'Enable BOLT link flags' +complete -c x.py -n "__fish_seen_subcommand_from miri" -l skip-stage0-validation -d 'Skip stage0 compiler validation' +complete -c x.py -n "__fish_seen_subcommand_from miri" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_seen_subcommand_from bench" -l test-args -r complete -c x.py -n "__fish_seen_subcommand_from bench" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_seen_subcommand_from bench" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)" diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1 index 8e505afaf759..d39639a1f91d 100644 --- a/src/etc/completions/x.py.ps1 +++ b/src/etc/completions/x.py.ps1 @@ -66,6 +66,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('fmt', 'fmt', [CompletionResultType]::ParameterValue, 'Run rustfmt') [CompletionResult]::new('doc', 'doc', [CompletionResultType]::ParameterValue, 'Build documentation') [CompletionResult]::new('test', 'test', [CompletionResultType]::ParameterValue, 'Build and run some test suites') + [CompletionResult]::new('miri', 'miri', [CompletionResultType]::ParameterValue, 'Build and run some test suites *in Miri*') [CompletionResult]::new('bench', 'bench', [CompletionResultType]::ParameterValue, 'Build and run some benchmarks') [CompletionResult]::new('clean', 'clean', [CompletionResultType]::ParameterValue, 'Clean out build directories') [CompletionResult]::new('dist', 'dist', [CompletionResultType]::ParameterValue, 'Build distribution artifacts') @@ -386,6 +387,52 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break } + 'x.py;miri' { + [CompletionResult]::new('--test-args', 'test-args', [CompletionResultType]::ParameterName, 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)') + [CompletionResult]::new('--rustc-args', 'rustc-args', [CompletionResultType]::ParameterName, 'extra options to pass the compiler when running tests') + [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') + [CompletionResult]::new('--build-dir', 'build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `config.toml`') + [CompletionResult]::new('--build', 'build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--host', 'host', [CompletionResultType]::ParameterName, 'host targets to build') + [CompletionResult]::new('--target', 'target', [CompletionResultType]::ParameterName, 'target targets to build') + [CompletionResult]::new('--exclude', 'exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') + [CompletionResult]::new('--skip', 'skip', [CompletionResultType]::ParameterName, 'build paths to skip') + [CompletionResult]::new('--rustc-error-format', 'rustc-error-format', [CompletionResultType]::ParameterName, 'rustc-error-format') + [CompletionResult]::new('--on-fail', 'on-fail', [CompletionResultType]::ParameterName, 'command to run on failure') + [CompletionResult]::new('--stage', 'stage', [CompletionResultType]::ParameterName, 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)') + [CompletionResult]::new('--keep-stage', 'keep-stage', [CompletionResultType]::ParameterName, 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--keep-stage-std', 'keep-stage-std', [CompletionResultType]::ParameterName, 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--src', 'src', [CompletionResultType]::ParameterName, 'path to the root of the rust checkout') + [CompletionResult]::new('-j', 'j', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--jobs', 'jobs', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--warnings', 'warnings', [CompletionResultType]::ParameterName, 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour') + [CompletionResult]::new('--error-format', 'error-format', [CompletionResultType]::ParameterName, 'rustc error format') + [CompletionResult]::new('--color', 'color', [CompletionResultType]::ParameterName, 'whether to use color in cargo and rustc output') + [CompletionResult]::new('--llvm-skip-rebuild', 'llvm-skip-rebuild', [CompletionResultType]::ParameterName, 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml') + [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build') + [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') + [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') + [CompletionResult]::new('--reproducible-artifact', 'reproducible-artifact', [CompletionResultType]::ParameterName, 'Additional reproducible artifacts that should be added to the reproducible artifacts archive') + [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml') + [CompletionResult]::new('--no-fail-fast', 'no-fail-fast', [CompletionResultType]::ParameterName, 'run all tests regardless of failure') + [CompletionResult]::new('--no-doc', 'no-doc', [CompletionResultType]::ParameterName, 'do not run doc tests') + [CompletionResult]::new('--doc', 'doc', [CompletionResultType]::ParameterName, 'only run doc tests') + [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--incremental', 'incremental', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--include-default-paths', 'include-default-paths', [CompletionResultType]::ParameterName, 'include default paths in addition to the provided ones') + [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') + [CompletionResult]::new('--dump-bootstrap-shims', 'dump-bootstrap-shims', [CompletionResultType]::ParameterName, 'Indicates whether to dump the work done from bootstrap shims') + [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') + [CompletionResult]::new('--bypass-bootstrap-lock', 'bypass-bootstrap-lock', [CompletionResultType]::ParameterName, 'Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)') + [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--enable-bolt-settings', 'enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') + [CompletionResult]::new('--skip-stage0-validation', 'skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') + break + } 'x.py;bench' { [CompletionResult]::new('--test-args', 'test-args', [CompletionResultType]::ParameterName, 'test-args') [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh index 742f61f16221..1f1a9a70767f 100644 --- a/src/etc/completions/x.py.sh +++ b/src/etc/completions/x.py.sh @@ -42,6 +42,9 @@ _x.py() { bootstrap,install) cmd="bootstrap__install" ;; + bootstrap,miri) + cmd="bootstrap__miri" + ;; bootstrap,run) cmd="bootstrap__run" ;; @@ -61,7 +64,7 @@ _x.py() { case "${cmd}" in x.py) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]... build check clippy fix fmt doc test bench clean dist install run setup suggest" + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]... build check clippy fix fmt doc test miri bench clean dist install run setup suggest" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1290,6 +1293,124 @@ _x.py() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + x.py__miri) + opts="-v -i -j -h --no-fail-fast --test-args --rustc-args --no-doc --doc --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --test-args) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rustc-args) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --config) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build-dir) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build) + COMPREPLY=("${cur}") + return 0 + ;; + --host) + COMPREPLY=("${cur}") + return 0 + ;; + --target) + COMPREPLY=("${cur}") + return 0 + ;; + --exclude) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --skip) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rustc-error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --on-fail) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage-std) + COMPREPLY=("${cur}") + return 0 + ;; + --src) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=("${cur}") + return 0 + ;; + -j) + COMPREPLY=("${cur}") + return 0 + ;; + --warnings) + COMPREPLY=($(compgen -W "deny warn default" -- "${cur}")) + return 0 + ;; + --error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --color) + COMPREPLY=($(compgen -W "always never auto" -- "${cur}")) + return 0 + ;; + --llvm-skip-rebuild) + COMPREPLY=($(compgen -W "true false" -- "${cur}")) + return 0 + ;; + --rust-profile-generate) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rust-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --reproducible-artifact) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --set) + COMPREPLY=("${cur}") + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; x.py__run) opts="-v -i -j -h --args --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh index eec610629a14..b920309ac2c1 100644 --- a/src/etc/completions/x.py.zsh +++ b/src/etc/completions/x.py.zsh @@ -389,6 +389,54 @@ _arguments "${_arguments_options[@]}" \ '*::paths -- paths for the subcommand:_files' \ && ret=0 ;; +(miri) +_arguments "${_arguments_options[@]}" \ +'*--test-args=[extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)]:ARGS: ' \ +'*--rustc-args=[extra options to pass the compiler when running tests]:ARGS: ' \ +'--config=[TOML configuration file for build]:FILE:_files' \ +'--build-dir=[Build directory, overrides \`build.build-dir\` in \`config.toml\`]:DIR:_files -/' \ +'--build=[build target of the stage0 compiler]:BUILD:( )' \ +'--host=[host targets to build]:HOST:( )' \ +'--target=[target targets to build]:TARGET:( )' \ +'*--exclude=[build paths to exclude]:PATH:_files' \ +'*--skip=[build paths to skip]:PATH:_files' \ +'--rustc-error-format=[]:RUSTC_ERROR_FORMAT:( )' \ +'--on-fail=[command to run on failure]:CMD:_cmdstring' \ +'--stage=[stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)]:N:( )' \ +'*--keep-stage=[stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'*--keep-stage-std=[stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'--src=[path to the root of the rust checkout]:DIR:_files -/' \ +'-j+[number of jobs to run in parallel]:JOBS:( )' \ +'--jobs=[number of jobs to run in parallel]:JOBS:( )' \ +'--warnings=[if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour]:deny|warn:(deny warn default)' \ +'--error-format=[rustc error format]:FORMAT:( )' \ +'--color=[whether to use color in cargo and rustc output]:STYLE:(always never auto)' \ +'--llvm-skip-rebuild=[whether rebuilding llvm should be skipped, overriding \`skip-rebuld\` in config.toml]:VALUE:(true false)' \ +'--rust-profile-generate=[generate PGO profile with rustc build]:PROFILE:_files' \ +'--rust-profile-use=[use PGO profile for rustc build]:PROFILE:_files' \ +'--llvm-profile-use=[use PGO profile for LLVM build]:PROFILE:_files' \ +'*--reproducible-artifact=[Additional reproducible artifacts that should be added to the reproducible artifacts archive]:REPRODUCIBLE_ARTIFACT: ' \ +'*--set=[override options in config.toml]:section.option=value:( )' \ +'--no-fail-fast[run all tests regardless of failure]' \ +'--no-doc[do not run doc tests]' \ +'--doc[only run doc tests]' \ +'*-v[use verbose output (-vv for very verbose)]' \ +'*--verbose[use verbose output (-vv for very verbose)]' \ +'-i[use incremental compilation]' \ +'--incremental[use incremental compilation]' \ +'--include-default-paths[include default paths in addition to the provided ones]' \ +'--dry-run[dry run; don'\''t build anything]' \ +'--dump-bootstrap-shims[Indicates whether to dump the work done from bootstrap shims]' \ +'--json-output[use message-format=json]' \ +'--bypass-bootstrap-lock[Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)]' \ +'--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ +'--enable-bolt-settings[Enable BOLT link flags]' \ +'--skip-stage0-validation[Skip stage0 compiler validation]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'*::paths -- paths for the subcommand:_files' \ +&& ret=0 +;; (bench) _arguments "${_arguments_options[@]}" \ '*--test-args=[]:TEST_ARGS: ' \ @@ -710,6 +758,7 @@ _x.py_commands() { 'fmt:Run rustfmt' \ 'doc:Build documentation' \ 'test:Build and run some test suites' \ +'miri:Build and run some test suites *in Miri*' \ 'bench:Build and run some benchmarks' \ 'clean:Clean out build directories' \ 'dist:Build distribution artifacts' \ @@ -770,6 +819,11 @@ _x.py__install_commands() { local commands; commands=() _describe -t commands 'x.py install commands' commands "$@" } +(( $+functions[_x.py__miri_commands] )) || +_x.py__miri_commands() { + local commands; commands=() + _describe -t commands 'x.py miri commands' commands "$@" +} (( $+functions[_x.py__run_commands] )) || _x.py__run_commands() { local commands; commands=() diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 47cfe651e319..72d4cc7c4659 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -47,7 +47,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { // Require the type the impl is implemented on to match // our type, and ignore the impl if there was a mismatch. let Ok(eq_result) = infcx.at(&traits::ObligationCause::dummy(), param_env).eq( - DefineOpaqueTypes::No, + DefineOpaqueTypes::Yes, impl_trait_ref.self_ty(), impl_ty, ) else { diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 277db90df9aa..2814e83dcd75 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -511,6 +511,7 @@ impl<'a> fmt::Display for Display<'a> { "wasi" => "WASI", "watchos" => "watchOS", "windows" => "Windows", + "visionos" => "visionOS", _ => "", }, (sym::target_arch, Some(arch)) => match arch.as_str() { diff --git a/src/librustdoc/html/static/css/noscript.css b/src/librustdoc/html/static/css/noscript.css index f425f3ec95c3..ccb97d7df4c3 100644 --- a/src/librustdoc/html/static/css/noscript.css +++ b/src/librustdoc/html/static/css/noscript.css @@ -34,7 +34,7 @@ nav.sub { in rustdoc.css */ /* Begin theme: light */ -:root { +:root, :root:not([data-theme]) { --main-background-color: white; --main-color: black; --settings-input-color: #2196f3; @@ -140,7 +140,7 @@ nav.sub { @media (prefers-color-scheme: dark) { /* Begin theme: dark */ - :root { + :root, :root:not([data-theme]) { --main-background-color: #353535; --main-color: #ddd; --settings-input-color: #2196f3; diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 9993dfb1d8c2..0bb073b1ceac 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -2315,8 +2315,14 @@ in src-script.js and main.js tooling to ensure different themes all define all the variables. Do not alter their formatting. */ +/* +About `:root:not([data-theme])`: if for any reason the JS is enabled but cannot be loaded, +`noscript` won't be enabled and the doc will have no color applied. To do around this, we +add a selector check that if `data-theme` is not defined, then we apply the light theme +by default. +*/ /* Begin theme: light */ -:root[data-theme="light"] { +:root[data-theme="light"], :root:not([data-theme]) { --main-background-color: white; --main-color: black; --settings-input-color: #2196f3; diff --git a/src/tools/cargo b/src/tools/cargo index 0637083df5bb..28e7b2bc0a81 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 0637083df5bbdcc951845f0d2eff6999cdb6d30a +Subproject commit 28e7b2bc0a812f90126be30f48a00a4ada990eaa diff --git a/src/tools/clippy/.gitignore b/src/tools/clippy/.gitignore index 503ae3c50903..181b71a658b9 100644 --- a/src/tools/clippy/.gitignore +++ b/src/tools/clippy/.gitignore @@ -1,3 +1,6 @@ +# Generated by ui-test +rustc-ice-* + # Used by CI to be able to push: /.github/deploy_key out diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index 76ef84a48b81..f7e7ed86eed8 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -5379,6 +5379,7 @@ Released 2018-09-13 [`large_stack_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays [`large_stack_frames`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_frames [`large_types_passed_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value +[`legacy_numeric_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#legacy_numeric_constants [`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty [`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero [`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return @@ -5481,6 +5482,7 @@ Released 2018-09-13 [`missing_safety_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_safety_doc [`missing_spin_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_spin_loop [`missing_trait_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_trait_methods +[`missing_transmute_annotations`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_transmute_annotations [`mistyped_literal_suffixes`]: https://rust-lang.github.io/rust-clippy/master/index.html#mistyped_literal_suffixes [`mixed_attributes_style`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_attributes_style [`mixed_case_hex_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_case_hex_literals diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml index 2b37b54c0048..43f20ecedc21 100644 --- a/src/tools/clippy/Cargo.toml +++ b/src/tools/clippy/Cargo.toml @@ -31,7 +31,6 @@ anstream = "0.6.0" [dev-dependencies] ui_test = "0.22.2" -tester = "0.9" regex = "1.5.5" toml = "0.7.3" walkdir = "2.3" diff --git a/src/tools/clippy/book/src/SUMMARY.md b/src/tools/clippy/book/src/SUMMARY.md index a048fbbd8acf..be13fcbe260f 100644 --- a/src/tools/clippy/book/src/SUMMARY.md +++ b/src/tools/clippy/book/src/SUMMARY.md @@ -32,3 +32,4 @@ - [Proposals](development/proposals/README.md) - [Roadmap 2021](development/proposals/roadmap-2021.md) - [Syntax Tree Patterns](development/proposals/syntax-tree-patterns.md) + - [The Team](development/the_team.md) diff --git a/src/tools/clippy/book/src/development/defining_lints.md b/src/tools/clippy/book/src/development/defining_lints.md index 54f77b00190b..806ed0845f03 100644 --- a/src/tools/clippy/book/src/development/defining_lints.md +++ b/src/tools/clippy/book/src/development/defining_lints.md @@ -62,9 +62,8 @@ $ cargo dev new_lint --name=lint_name --pass=late --category=pedantic There are two things to note here: 1. `--pass`: We set `--pass=late` in this command to do a late lint pass. The - alternative is an `early` lint pass. We will discuss this difference in a - later chapter. - + alternative is an `early` lint pass. We will discuss this difference in the + [Lint Passes] chapter. 2. `--category`: If not provided, the `category` of this new lint will default to `nursery`. @@ -194,8 +193,7 @@ store.register_late_pass(|_| Box::new(foo_functions::FooFunctions)); As you might have guessed, where there's something late, there is something early: in Clippy there is a `register_early_pass` method as well. More on early -vs. late passes in a later chapter. - +vs. late passes in the [Lint Passes] chapter. Without a call to one of `register_early_pass` or `register_late_pass`, the lint pass in question will not be run. @@ -203,3 +201,4 @@ pass in question will not be run. [all_lints]: https://rust-lang.github.io/rust-clippy/master/ [lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints +[Lint Passes]: lint_passes.md diff --git a/src/tools/clippy/book/src/development/lint_passes.md b/src/tools/clippy/book/src/development/lint_passes.md index 621fc20972ea..dde9e1a273bc 100644 --- a/src/tools/clippy/book/src/development/lint_passes.md +++ b/src/tools/clippy/book/src/development/lint_passes.md @@ -50,7 +50,7 @@ questions already, but the parser is okay with it. This is what we mean when we say `EarlyLintPass` deals with only syntax on the AST level. Alternatively, think of the `foo_functions` lint we mentioned in -define new lints chapter. +the [Define New Lints](defining_lints.md) chapter. We want the `foo_functions` lint to detect functions with `foo` as their name. Writing a lint that only checks for the name of a function means that we only diff --git a/src/tools/clippy/book/src/development/the_team.md b/src/tools/clippy/book/src/development/the_team.md new file mode 100644 index 000000000000..10341791cec4 --- /dev/null +++ b/src/tools/clippy/book/src/development/the_team.md @@ -0,0 +1,130 @@ +# The team + +Everyone who contributes to Clippy makes the project what it is. Collaboration +and discussions are the lifeblood of every open-source project. Clippy has a +very flat hierarchy. The teams mainly have additional access rights to the repo. + +This document outlines the onboarding process, as well as duties, and access +rights for members of a group. + +All regular events mentioned in this chapter are tracked in the [calendar repository]. +The calendar file is also available for download: [clippy.ics] + +## Everyone + +Everyone, including you, is welcome to join discussions and contribute in other +ways, like PRs. + +You also have some triage rights, using `@rustbot` to add labels and claim +issues. See [labeling with @rustbot]. + +A rule for everyone should be to keep a healthy work-life balance. Take a break +when you need one. + +## Clippy-Contributors + +This is a group of regular contributors to Clippy to help with triaging. + +### Duties + +This team exists to make contributing easier for regular members. It doesn't +carry any duties that need to be done. However, we want to encourage members of +this group to help with triaging, which can include: + +1. **Labeling issues** + + For the `good-first-issue` label, it can still be good to use `@rustbot` to + subscribe to the issue and help interested parties, if they post questions + in the comments. + +2. **Closing duplicate or resolved issues** + + When you manually close an issue, it's often a good idea, to add a short + comment explaining the reason. + +3. **Ping people after two weeks of inactivity** + + We try to keep issue assignments and PRs fairly up-to-date. After two weeks, + it can be good to send a friendly ping to the delaying party. + + You might close a PR with the `I-inactive-closed` label if the author is + busy or wants to abandon it. If the reviewer is busy, the PR can be + reassigned to someone else. + + Checkout: https://triage.rust-lang.org/triage/rust-lang/rust-clippy to + monitor PRs. + +While not part of their duties, contributors are encouraged to review PRs +and help on Zulip. The team always appreciates help! + +### Membership + +If you have been contributing to Clippy for some time, we'll probably ask you if +you want to join this team. Members of this team are also welcome to suggest +people who they think would make a great addition to this group. + +For this group, there is no direct onboarding process. You're welcome to just +continue what you've been doing. If you like, you can ask for someone to mentor +you, either in the Clippy stream on Zulip or privately via a PM. + +If you have been inactive in Clippy for over three months, we'll probably move +you to the alumni group. You're always welcome to come back. + +## The Clippy Team + +[The Clippy team](https://www.rust-lang.org/governance/teams/dev-tools#Clippy%20team) +is responsible for maintaining Clippy. + +### Duties + +1. **Respond to PRs in a timely manner** + + It's totally fine, if you don't have the time for reviews right now. + You can reassign the PR to a random member by commenting `r? clippy`. + +2. **Take a break when you need one** + + You are valuable! Clippy wouldn't be what it is without you. So take a break + early and recharge some energy when you need to. + +3. **Be responsive on Zulip** + + This means in a reasonable time frame, so responding within one or two days + is totally fine. + + It's also good, if you answer threads on Zulip and take part in our Clippy + meetings, every two weeks. The meeting dates are tracked in the [calendar repository]. + + +4. **Sync Clippy with the rust-lang/rust repo** + + This is done every two weeks, usually by @flip1995. + +5. **Update the changelog** + + This needs to be done for every release, every six weeks. This is usually + done by @xFrednet. + +### Membership + +If you have been active for some time, we'll probably reach out and ask +if you want to help with reviews and eventually join the Clippy team. + +During the onboarding process, you'll be assigned pull requests to review. +You'll also have an active team member as a mentor who'll stay in contact via +Zulip DMs to provide advice and feedback. If you have questions, you're always +welcome to ask, that is the best way to learn. Once you're done with the review, +you can ping your mentor for a full review and to r+ the PR in both of your names. + +When your mentor is confident that you can handle reviews on your own, they'll +start an informal vote among the active team members to officially add you to +the team. This vote is usually accepted unanimously. Then you'll be added to +the team once you've confirmed that you're still interested in joining. The +onboarding phase typically takes a couple of weeks to a few months. + +If you have been inactive in Clippy for over three months, we'll probably move +you to the alumni group. You're always welcome to come back. + +[calendar repository]: https://github.com/rust-lang/calendar/blob/main/clippy.toml +[clippy.ics]: https://rust-lang.github.io/calendar/clippy.ics +[labeling with @rustbot]: https://forge.rust-lang.org/triagebot/labeling.html diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md index a92348997464..4a2727c5197f 100644 --- a/src/tools/clippy/book/src/lint_configuration.md +++ b/src/tools/clippy/book/src/lint_configuration.md @@ -616,6 +616,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio * [`if_then_some_else_none`](https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none) * [`index_refutable_slice`](https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice) * [`iter_kv_map`](https://rust-lang.github.io/rust-clippy/master/index.html#iter_kv_map) +* [`legacy_numeric_constants`](https://rust-lang.github.io/rust-clippy/master/index.html#legacy_numeric_constants) * [`manual_bits`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits) * [`manual_c_str_literals`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_c_str_literals) * [`manual_clamp`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_clamp) diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs index 3218fe7f4562..53c10f7cee8b 100644 --- a/src/tools/clippy/clippy_config/src/conf.rs +++ b/src/tools/clippy/clippy_config/src/conf.rs @@ -262,7 +262,7 @@ define_Conf! { /// /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), - /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE, ITER_KV_MAP, MANUAL_C_STR_LITERALS, ASSIGNING_CLONES. + /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE, ITER_KV_MAP, MANUAL_C_STR_LITERALS, ASSIGNING_CLONES, LEGACY_NUMERIC_CONSTANTS. /// /// The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml` #[default_text = ""] @@ -856,11 +856,6 @@ mod tests { } } - assert!( - names.remove("allow-one-hash-in-raw-strings"), - "remove this when #11481 is fixed" - ); - assert!( names.is_empty(), "Configuration variable lacks test: {names:?}\nAdd a test to `tests/ui-toml`" diff --git a/src/tools/clippy/clippy_config/src/lib.rs b/src/tools/clippy/clippy_config/src/lib.rs index 01e2aa6e0a60..ff7fa7241cb9 100644 --- a/src/tools/clippy/clippy_config/src/lib.rs +++ b/src/tools/clippy/clippy_config/src/lib.rs @@ -1,6 +1,12 @@ #![feature(rustc_private, let_chains)] #![cfg_attr(feature = "deny-warnings", deny(warnings))] -#![warn(rust_2018_idioms, unused_lifetimes)] +#![warn( + trivial_casts, + trivial_numeric_casts, + rust_2018_idioms, + unused_lifetimes, + unused_qualifications +)] #![allow( clippy::must_use_candidate, clippy::missing_panics_doc, diff --git a/src/tools/clippy/clippy_config/src/msrvs.rs b/src/tools/clippy/clippy_config/src/msrvs.rs index 149c4776dc9c..59dd5b334b84 100644 --- a/src/tools/clippy/clippy_config/src/msrvs.rs +++ b/src/tools/clippy/clippy_config/src/msrvs.rs @@ -36,7 +36,7 @@ msrv_aliases! { 1,47,0 { TAU, IS_ASCII_DIGIT_CONST, ARRAY_IMPL_ANY_LEN } 1,46,0 { CONST_IF_MATCH } 1,45,0 { STR_STRIP_PREFIX } - 1,43,0 { LOG2_10, LOG10_2 } + 1,43,0 { LOG2_10, LOG10_2, NUMERIC_ASSOCIATED_CONSTANTS } 1,42,0 { MATCHES_MACRO, SLICE_PATTERNS, PTR_SLICE_RAW_PARTS } 1,41,0 { RE_REBALANCING_COHERENCE, RESULT_MAP_OR_ELSE } 1,40,0 { MEM_TAKE, NON_EXHAUSTIVE, OPTION_AS_DEREF } diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs index c4ae4f0e2bdd..bb62e902cd54 100644 --- a/src/tools/clippy/clippy_dev/src/lib.rs +++ b/src/tools/clippy/clippy_dev/src/lib.rs @@ -2,8 +2,13 @@ #![feature(let_chains)] #![feature(rustc_private)] #![cfg_attr(feature = "deny-warnings", deny(warnings))] -// warn on lints, that are included in `rust-lang/rust`s bootstrap -#![warn(rust_2018_idioms, unused_lifetimes)] +#![warn( + trivial_casts, + trivial_numeric_casts, + rust_2018_idioms, + unused_lifetimes, + unused_qualifications +)] // The `rustc_driver` crate seems to be required in order to use the `rust_lexer` crate. #[allow(unused_extern_crates)] diff --git a/src/tools/clippy/clippy_dev/src/lint.rs b/src/tools/clippy/clippy_dev/src/lint.rs index 906a97278109..f308f5dfdfd8 100644 --- a/src/tools/clippy/clippy_dev/src/lint.rs +++ b/src/tools/clippy/clippy_dev/src/lint.rs @@ -20,6 +20,8 @@ pub fn run<'a>(path: &str, args: impl Iterator) { .args(["--edition", "2021"]) .arg(path) .args(args) + // Prevent rustc from creating `rustc-ice-*` files the console output is enough. + .env("RUSTC_ICE", "0") .status(), ); } else { @@ -32,6 +34,8 @@ pub fn run<'a>(path: &str, args: impl Iterator) { 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(); diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs index 76ae26dddf4d..625b13395913 100644 --- a/src/tools/clippy/clippy_dev/src/update_lints.rs +++ b/src/tools/clippy/clippy_dev/src/update_lints.rs @@ -992,7 +992,7 @@ fn replace_region_in_text<'a>( } fn try_rename_file(old_name: &Path, new_name: &Path) -> bool { - match fs::OpenOptions::new().create_new(true).write(true).open(new_name) { + match OpenOptions::new().create_new(true).write(true).open(new_name) { Ok(file) => drop(file), Err(e) if matches!(e.kind(), io::ErrorKind::AlreadyExists | io::ErrorKind::NotFound) => return false, Err(e) => panic_file(e, new_name, "create"), @@ -1016,7 +1016,7 @@ fn panic_file(error: io::Error, name: &Path, action: &str) -> ! { } fn rewrite_file(path: &Path, f: impl FnOnce(&str) -> Option) { - let mut file = fs::OpenOptions::new() + let mut file = OpenOptions::new() .write(true) .read(true) .open(path) diff --git a/src/tools/clippy/clippy_lints/src/approx_const.rs b/src/tools/clippy/clippy_lints/src/approx_const.rs index 25606f4253e4..ec28fd461118 100644 --- a/src/tools/clippy/clippy_lints/src/approx_const.rs +++ b/src/tools/clippy/clippy_lints/src/approx_const.rs @@ -95,7 +95,7 @@ impl ApproxConstant { cx, APPROX_CONSTANT, e.span, - &format!("approximate value of `{module}::consts::{}` found", &name), + format!("approximate value of `{module}::consts::{}` found", &name), None, "consider using the constant directly", ); diff --git a/src/tools/clippy/clippy_lints/src/asm_syntax.rs b/src/tools/clippy/clippy_lints/src/asm_syntax.rs index c2fa56e13603..7c88bfc97ca4 100644 --- a/src/tools/clippy/clippy_lints/src/asm_syntax.rs +++ b/src/tools/clippy/clippy_lints/src/asm_syntax.rs @@ -53,9 +53,9 @@ fn check_asm_syntax( cx, lint, span, - &format!("{style} x86 assembly syntax used"), + format!("{style} x86 assembly syntax used"), None, - &format!("use {} x86 assembly syntax", !style), + format!("use {} x86 assembly syntax", !style), ); } } diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs index 9365fbfaed08..2003dd1fb0e2 100644 --- a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs +++ b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs @@ -58,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants { cx, ASSERTIONS_ON_CONSTANTS, macro_call.span, - &format!( + format!( "`{}!(true)` will be optimized out by the compiler", cx.tcx.item_name(macro_call.def_id) ), @@ -74,9 +74,9 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants { cx, ASSERTIONS_ON_CONSTANTS, macro_call.span, - &format!("`assert!(false{assert_arg})` should probably be replaced"), + format!("`assert!(false{assert_arg})` should probably be replaced"), None, - &format!("use `panic!({panic_arg})` or `unreachable!({panic_arg})`"), + format!("use `panic!({panic_arg})` or `unreachable!({panic_arg})`"), ); } } diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs index 8e27b3ccefdc..dc7f44af2b74 100644 --- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs +++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs @@ -65,7 +65,7 @@ impl AssigningClones { impl_lint_pass!(AssigningClones => [ASSIGNING_CLONES]); impl<'tcx> LateLintPass<'tcx> for AssigningClones { - fn check_expr(&mut self, cx: &LateContext<'tcx>, assign_expr: &'tcx hir::Expr<'_>) { + fn check_expr(&mut self, cx: &LateContext<'tcx>, assign_expr: &'tcx Expr<'_>) { // Do not fire the lint in macros let expn_data = assign_expr.span().ctxt().outer_expn_data(); match expn_data.kind { @@ -181,6 +181,23 @@ fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallC return false; } + // If the call expression is inside an impl block that contains the method invoked by the + // call expression, we bail out to avoid suggesting something that could result in endless + // recursion. + if let Some(local_block_id) = impl_block.as_local() + && let Some(block) = cx.tcx.hir_node_by_def_id(local_block_id).as_owner() + { + let impl_block_owner = block.def_id(); + if cx + .tcx + .hir() + .parent_id_iter(lhs.hir_id) + .any(|parent| parent.owner == impl_block_owner) + { + return false; + } + } + // Find the function for which we want to check that it is implemented. let provided_fn = match call.target { TargetTrait::Clone => cx.tcx.get_diagnostic_item(sym::Clone).and_then(|clone| { @@ -205,14 +222,9 @@ fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallC implemented_fns.contains_key(&provided_fn.def_id) } -fn suggest<'tcx>( - cx: &LateContext<'tcx>, - assign_expr: &hir::Expr<'tcx>, - lhs: &hir::Expr<'tcx>, - call: &CallCandidate<'tcx>, -) { +fn suggest<'tcx>(cx: &LateContext<'tcx>, assign_expr: &Expr<'tcx>, lhs: &Expr<'tcx>, call: &CallCandidate<'tcx>) { span_lint_and_then(cx, ASSIGNING_CLONES, assign_expr.span, call.message(), |diag| { - let mut applicability = Applicability::MachineApplicable; + let mut applicability = Applicability::Unspecified; diag.span_suggestion( assign_expr.span, @@ -263,7 +275,7 @@ impl<'tcx> CallCandidate<'tcx> { fn suggested_replacement( &self, cx: &LateContext<'tcx>, - lhs: &hir::Expr<'tcx>, + lhs: &Expr<'tcx>, applicability: &mut Applicability, ) -> String { match self.target { diff --git a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs index df00f23e37e8..4a22e17463fc 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs @@ -30,7 +30,7 @@ pub(super) fn check<'cx>(cx: &LateContext<'cx>, name: Symbol, items: &[NestedMet cx, ALLOW_ATTRIBUTES_WITHOUT_REASON, attr.span, - &format!("`{}` attribute without specifying a reason", name.as_str()), + format!("`{}` attribute without specifying a reason", name.as_str()), None, "try adding a reason at the end with `, reason = \"..\"`", ); diff --git a/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs index 3c5ac597fd5d..3a8844d07548 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs @@ -31,6 +31,9 @@ fn check_duplicated_attr( attr_paths: &mut FxHashMap, parent: &mut Vec, ) { + if attr.span.from_expansion() { + return; + } let Some(ident) = attr.ident() else { return }; let name = ident.name; if name == sym::doc || name == sym::cfg_attr { @@ -38,6 +41,14 @@ fn check_duplicated_attr( // conditions are the same. return; } + if let Some(direct_parent) = parent.last() + && ["cfg", "cfg_attr"].contains(&direct_parent.as_str()) + && [sym::all, sym::not, sym::any].contains(&name) + { + // FIXME: We don't correctly check `cfg`s for now, so if it's more complex than just a one + // level `cfg`, we leave. + return; + } if let Some(value) = attr.value_str() { emit_if_duplicated(cx, attr, attr_paths, format!("{}:{name}={value}", parent.join(":"))); } else if let Some(sub_attrs) = attr.meta_item_list() { diff --git a/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs b/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs index cfcd2cc6a00b..3b5b80ffefaf 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs @@ -21,7 +21,7 @@ pub(super) fn check(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Att cx, INLINE_ALWAYS, attr.span, - &format!("you have declared `#[inline(always)]` on `{name}`. This is usually a bad idea"), + format!("you have declared `#[inline(always)]` on `{name}`. This is usually a bad idea"), ); } } diff --git a/src/tools/clippy/clippy_lints/src/attrs/maybe_misused_cfg.rs b/src/tools/clippy/clippy_lints/src/attrs/maybe_misused_cfg.rs index 5a70866eda58..e6b2e835be86 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/maybe_misused_cfg.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/maybe_misused_cfg.rs @@ -40,7 +40,7 @@ fn check_nested_misused_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) { cx, MAYBE_MISUSED_CFG, meta.span, - &format!("'test' may be misspelled as '{}'", ident.name.as_str()), + format!("'test' may be misspelled as '{}'", ident.name.as_str()), "did you mean", "test".to_string(), Applicability::MaybeIncorrect, diff --git a/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs b/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs index c2e21cfd3300..5d2ea36b366c 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs @@ -1,30 +1,85 @@ use super::MIXED_ATTRIBUTES_STYLE; use clippy_utils::diagnostics::span_lint; -use rustc_ast::AttrStyle; -use rustc_lint::EarlyContext; +use rustc_ast::{AttrKind, AttrStyle, Attribute}; +use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::sync::Lrc; +use rustc_lint::{LateContext, LintContext}; +use rustc_span::source_map::SourceMap; +use rustc_span::{SourceFile, Span, Symbol}; -pub(super) fn check(cx: &EarlyContext<'_>, item: &rustc_ast::Item) { - let mut has_outer = false; - let mut has_inner = false; +#[derive(Hash, PartialEq, Eq)] +enum SimpleAttrKind { + Doc, + /// A normal attribute, with its name symbols. + Normal(Vec), +} - for attr in &item.attrs { - if attr.span.from_expansion() { +impl From<&AttrKind> for SimpleAttrKind { + fn from(value: &AttrKind) -> Self { + match value { + AttrKind::Normal(attr) => { + let path_symbols = attr + .item + .path + .segments + .iter() + .map(|seg| seg.ident.name) + .collect::>(); + Self::Normal(path_symbols) + }, + AttrKind::DocComment(..) => Self::Doc, + } + } +} + +pub(super) fn check(cx: &LateContext<'_>, item_span: Span, attrs: &[Attribute]) { + let mut inner_attr_kind: FxHashSet = FxHashSet::default(); + let mut outer_attr_kind: FxHashSet = FxHashSet::default(); + + let source_map = cx.sess().source_map(); + let item_src = source_map.lookup_source_file(item_span.lo()); + + for attr in attrs { + if attr.span.from_expansion() || !attr_in_same_src_as_item(source_map, &item_src, attr.span) { continue; } + + let kind: SimpleAttrKind = (&attr.kind).into(); match attr.style { - AttrStyle::Inner => has_inner = true, - AttrStyle::Outer => has_outer = true, - } + AttrStyle::Inner => { + if outer_attr_kind.contains(&kind) { + lint_mixed_attrs(cx, attrs); + return; + } + inner_attr_kind.insert(kind); + }, + AttrStyle::Outer => { + if inner_attr_kind.contains(&kind) { + lint_mixed_attrs(cx, attrs); + return; + } + outer_attr_kind.insert(kind); + }, + }; } - if !has_outer || !has_inner { +} + +fn lint_mixed_attrs(cx: &LateContext<'_>, attrs: &[Attribute]) { + let mut attrs_iter = attrs.iter().filter(|attr| !attr.span.from_expansion()); + let span = if let (Some(first), Some(last)) = (attrs_iter.next(), attrs_iter.last()) { + first.span.with_hi(last.span.hi()) + } else { return; - } - let mut attrs_iter = item.attrs.iter().filter(|attr| !attr.span.from_expansion()); - let span = attrs_iter.next().unwrap().span; + }; span_lint( cx, MIXED_ATTRIBUTES_STYLE, - span.with_hi(attrs_iter.last().unwrap().span.hi()), + span, "item has both inner and outer attributes", ); } + +fn attr_in_same_src_as_item(source_map: &SourceMap, item_src: &Lrc, attr_span: Span) -> bool { + let attr_src = source_map.lookup_source_file(attr_span.lo()); + Lrc::ptr_eq(item_src, &attr_src) +} diff --git a/src/tools/clippy/clippy_lints/src/attrs/mod.rs b/src/tools/clippy/clippy_lints/src/attrs/mod.rs index 675c428948f6..684ad7de2f05 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/mod.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/mod.rs @@ -465,10 +465,20 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks that an item has only one kind of attributes. + /// Checks for items that have the same kind of attributes with mixed styles (inner/outer). /// /// ### Why is this bad? - /// Having both kinds of attributes makes it more complicated to read code. + /// Having both style of said attributes makes it more complicated to read code. + /// + /// ### Known problems + /// This lint currently has false-negatives when mixing same attributes + /// but they have different path symbols, for example: + /// ```ignore + /// #[custom_attribute] + /// pub fn foo() { + /// #![my_crate::custom_attribute] + /// } + /// ``` /// /// ### Example /// ```no_run @@ -486,7 +496,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.78.0"] pub MIXED_ATTRIBUTES_STYLE, - suspicious, + style, "item has both inner and outer attributes" } @@ -523,6 +533,7 @@ declare_lint_pass!(Attributes => [ USELESS_ATTRIBUTE, BLANKET_CLIPPY_RESTRICTION_LINTS, SHOULD_PANIC_WITHOUT_EXPECT, + MIXED_ATTRIBUTES_STYLE, ]); impl<'tcx> LateLintPass<'tcx> for Attributes { @@ -566,6 +577,7 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { ItemKind::ExternCrate(..) | ItemKind::Use(..) => useless_attribute::check(cx, item, attrs), _ => {}, } + mixed_attributes_style::check(cx, item.span, attrs); } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { @@ -594,7 +606,6 @@ impl_lint_pass!(EarlyAttributes => [ MAYBE_MISUSED_CFG, DEPRECATED_CLIPPY_CFG_ATTR, UNNECESSARY_CLIPPY_CFG, - MIXED_ATTRIBUTES_STYLE, DUPLICATED_ATTRIBUTES, ]); @@ -605,7 +616,6 @@ impl EarlyLintPass for EarlyAttributes { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &rustc_ast::Item) { empty_line_after::check(cx, item); - mixed_attributes_style::check(cx, item); duplicated_attributes::check(cx, &item.attrs); } diff --git a/src/tools/clippy/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs b/src/tools/clippy/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs index 05da69636c62..486e7c6ec4f4 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs @@ -58,7 +58,7 @@ pub(super) fn check( clippy_lints, "no need to put clippy lints behind a `clippy` cfg", None, - &format!( + format!( "write instead: `#{}[{}({})]`", if attr.style == AttrStyle::Inner { "!" } else { "" }, ident.name, diff --git a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs index 765cc7c0a54f..f25a474d9bbd 100644 --- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs +++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs @@ -267,7 +267,7 @@ fn emit_invalid_type(cx: &LateContext<'_>, span: Span, disallowed: &DisallowedPa cx, AWAIT_HOLDING_INVALID_TYPE, span, - &format!( + format!( "`{}` may not be held across an `await` point per `clippy.toml`", disallowed.path() ), diff --git a/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs b/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs index 2eb0dac97425..171f30318601 100644 --- a/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs +++ b/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs @@ -72,7 +72,7 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInConditions { else { return; }; - let complex_block_message = &format!( + let complex_block_message = format!( "in {desc}, avoid complex blocks or closures with blocks; \ instead, move the block or closure higher and bind it with a `let`", ); @@ -141,7 +141,7 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInConditions { let ex = &body.value; if let ExprKind::Block(block, _) = ex.kind { if !body.value.span.from_expansion() && !block.stmts.is_empty() { - span_lint(cx, BLOCKS_IN_CONDITIONS, ex.span, complex_block_message); + span_lint(cx, BLOCKS_IN_CONDITIONS, ex.span, complex_block_message.clone()); return ControlFlow::Continue(Descend::No); } } diff --git a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs index 74201e9cc304..58c1a2f27062 100644 --- a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs +++ b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs @@ -121,7 +121,7 @@ impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison { cx, BOOL_ASSERT_COMPARISON, macro_call.span, - &format!("used `{macro_name}!` with a literal bool"), + format!("used `{macro_name}!` with a literal bool"), |diag| { // assert_eq!(...) // ^^^^^^^^^ diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs index a474356608fb..6edfebb5534f 100644 --- a/src/tools/clippy/clippy_lints/src/booleans.rs +++ b/src/tools/clippy/clippy_lints/src/booleans.rs @@ -392,13 +392,13 @@ fn simple_negate(b: Bool) -> Bool { t @ Term(_) => Not(Box::new(t)), And(mut v) => { for el in &mut v { - *el = simple_negate(::std::mem::replace(el, True)); + *el = simple_negate(std::mem::replace(el, True)); } Or(v) }, Or(mut v) => { for el in &mut v { - *el = simple_negate(::std::mem::replace(el, True)); + *el = simple_negate(std::mem::replace(el, True)); } And(v) }, diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs index 8683cb86e8ac..4062212f408e 100644 --- a/src/tools/clippy/clippy_lints/src/box_default.rs +++ b/src/tools/clippy/clippy_lints/src/box_default.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::macro_backtrace; -use clippy_utils::source::snippet_opt; use clippy_utils::ty::expr_sig; use clippy_utils::{is_default_equivalent, path_def_id}; use rustc_errors::Applicability; @@ -9,20 +8,16 @@ use rustc_hir::intravisit::{walk_ty, Visitor}; use rustc_hir::{Block, Expr, ExprKind, LetStmt, Node, QPath, Ty, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_middle::ty::print::with_forced_trimmed_paths; -use rustc_middle::ty::IsSuggestable; use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { /// ### What it does - /// checks for `Box::new(T::default())`, which is better written as - /// `Box::::default()`. + /// checks for `Box::new(Default::default())`, which can be written as + /// `Box::default()`. /// /// ### Why is this bad? - /// First, it's more complex, involving two calls instead of one. - /// Second, `Box::default()` can be faster - /// [in certain cases](https://nnethercote.github.io/perf-book/standard-library-types.html#box). + /// `Box::default()` is equivalent and more concise. /// /// ### Example /// ```no_run @@ -34,7 +29,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.66.0"] pub BOX_DEFAULT, - perf, + style, "Using Box::new(T::default()) instead of Box::default()" } @@ -53,14 +48,14 @@ impl LateLintPass<'_> for BoxDefault { && path_def_id(cx, ty).map_or(false, |id| Some(id) == cx.tcx.lang_items().owned_box()) // And the single argument to the call is another function call // This is the `T::default()` of `Box::new(T::default())` - && let ExprKind::Call(arg_path, inner_call_args) = arg.kind + && let ExprKind::Call(arg_path, _) = arg.kind // And we are not in a foreign crate's macro && !in_external_macro(cx.sess(), expr.span) // And the argument expression has the same context as the outer call expression // or that we are inside a `vec!` macro expansion && (expr.span.eq_ctxt(arg.span) || is_local_vec_expn(cx, arg, expr)) - // And the argument is equivalent to `Default::default()` - && is_default_equivalent(cx, arg) + // And the argument is `Default::default()` or the type is specified + && (is_plain_default(cx, arg_path) || (given_type(cx, expr) && is_default_equivalent(cx, arg))) { span_lint_and_sugg( cx, @@ -68,25 +63,7 @@ impl LateLintPass<'_> for BoxDefault { expr.span, "`Box::new(_)` of default value", "try", - if is_plain_default(cx, arg_path) || given_type(cx, expr) { - "Box::default()".into() - } else if let Some(arg_ty) = - cx.typeck_results().expr_ty(arg).make_suggestable(cx.tcx, true, None) - { - // Check if we can copy from the source expression in the replacement. - // We need the call to have no argument (see `explicit_default_type`). - if inner_call_args.is_empty() - && let Some(ty) = explicit_default_type(arg_path) - && let Some(s) = snippet_opt(cx, ty.span) - { - format!("Box::<{s}>::default()") - } else { - // Otherwise, use the inferred type's formatting. - with_forced_trimmed_paths!(format!("Box::<{arg_ty}>::default()")) - } - } else { - return; - }, + "Box::default()".into(), Applicability::MachineApplicable, ); } @@ -105,20 +82,6 @@ fn is_plain_default(cx: &LateContext<'_>, arg_path: &Expr<'_>) -> bool { } } -// Checks whether the call is of the form `A::B::f()`. Returns `A::B` if it is. -// -// In the event we have this kind of construct, it's easy to use `A::B` as a replacement in the -// quickfix. `f` must however have no parameter. Should `f` have some, then some of the type of -// `A::B` may be inferred from the arguments. This would be the case for `Vec::from([0; false])`, -// where the argument to `from` allows inferring this is a `Vec` -fn explicit_default_type<'a>(arg_path: &'a Expr<'_>) -> Option<&'a Ty<'a>> { - if let ExprKind::Path(QPath::TypeRelative(ty, _)) = &arg_path.kind { - Some(ty) - } else { - None - } -} - fn is_local_vec_expn(cx: &LateContext<'_>, expr: &Expr<'_>, ref_expr: &Expr<'_>) -> bool { macro_backtrace(expr.span).next().map_or(false, |call| { cx.tcx.is_diagnostic_item(sym::vec_macro, call.def_id) && call.span.eq_ctxt(ref_expr.span) @@ -129,7 +92,7 @@ fn is_local_vec_expn(cx: &LateContext<'_>, expr: &Expr<'_>, ref_expr: &Expr<'_>) struct InferVisitor(bool); impl<'tcx> Visitor<'tcx> for InferVisitor { - fn visit_ty(&mut self, t: &rustc_hir::Ty<'_>) { + fn visit_ty(&mut self, t: &Ty<'_>) { self.0 |= matches!(t.kind, TyKind::Infer | TyKind::OpaqueDef(..) | TyKind::TraitObject(..)); if !self.0 { walk_ty(self, t); diff --git a/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs b/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs index 99fe6c1e790e..3af2d8c02568 100644 --- a/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs +++ b/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs @@ -41,7 +41,7 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata, ignore_publish: b fn missing_warning(cx: &LateContext<'_>, package: &cargo_metadata::Package, field: &str) { let message = format!("package `{}` is missing `{field}` metadata", package.name); - span_lint(cx, CARGO_COMMON_METADATA, DUMMY_SP, &message); + span_lint(cx, CARGO_COMMON_METADATA, DUMMY_SP, message); } fn is_empty_str>(value: &Option) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/cargo/feature_name.rs b/src/tools/clippy/clippy_lints/src/cargo/feature_name.rs index 9e69919c7273..6982b96dd3b3 100644 --- a/src/tools/clippy/clippy_lints/src/cargo/feature_name.rs +++ b/src/tools/clippy/clippy_lints/src/cargo/feature_name.rs @@ -56,13 +56,13 @@ fn lint(cx: &LateContext<'_>, feature: &str, substring: &str, is_prefix: bool) { REDUNDANT_FEATURE_NAMES }, DUMMY_SP, - &format!( + format!( "the \"{substring}\" {} in the feature name \"{feature}\" is {}", if is_prefix { "prefix" } else { "suffix" }, if is_negative { "negative" } else { "redundant" } ), None, - &format!( + format!( "consider renaming the feature to \"{}\"{}", if is_prefix { feature.strip_prefix(substring) diff --git a/src/tools/clippy/clippy_lints/src/cargo/lint_groups_priority.rs b/src/tools/clippy/clippy_lints/src/cargo/lint_groups_priority.rs index a39b972b56a2..a3291c9da109 100644 --- a/src/tools/clippy/clippy_lints/src/cargo/lint_groups_priority.rs +++ b/src/tools/clippy/clippy_lints/src/cargo/lint_groups_priority.rs @@ -102,7 +102,7 @@ fn check_table(cx: &LateContext<'_>, table: LintTable, groups: &FxHashSet<&str>, cx, LINT_GROUPS_PRIORITY, toml_span(group.span(), file), - &format!( + format!( "lint group `{}` has the same priority ({priority}) as a lint", group.as_ref() ), diff --git a/src/tools/clippy/clippy_lints/src/cargo/mod.rs b/src/tools/clippy/clippy_lints/src/cargo/mod.rs index 95d5449781b4..ca7fa4e5a410 100644 --- a/src/tools/clippy/clippy_lints/src/cargo/mod.rs +++ b/src/tools/clippy/clippy_lints/src/cargo/mod.rs @@ -241,7 +241,7 @@ impl LateLintPass<'_> for Cargo { }, Err(e) => { for lint in NO_DEPS_LINTS { - span_lint(cx, lint, DUMMY_SP, &format!("could not read cargo metadata: {e}")); + span_lint(cx, lint, DUMMY_SP, format!("could not read cargo metadata: {e}")); } }, } @@ -257,7 +257,7 @@ impl LateLintPass<'_> for Cargo { }, Err(e) => { for lint in WITH_DEPS_LINTS { - span_lint(cx, lint, DUMMY_SP, &format!("could not read cargo metadata: {e}")); + span_lint(cx, lint, DUMMY_SP, format!("could not read cargo metadata: {e}")); } }, } diff --git a/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs b/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs index 3f30a77fcfe4..2769463c8a53 100644 --- a/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs +++ b/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs @@ -52,7 +52,7 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata, allowed_duplicate cx, MULTIPLE_CRATE_VERSIONS, DUMMY_SP, - &format!("multiple versions for dependency `{name}`: {versions}"), + format!("multiple versions for dependency `{name}`: {versions}"), ); } } diff --git a/src/tools/clippy/clippy_lints/src/cargo/wildcard_dependencies.rs b/src/tools/clippy/clippy_lints/src/cargo/wildcard_dependencies.rs index 244e98eb6666..0cf687d01928 100644 --- a/src/tools/clippy/clippy_lints/src/cargo/wildcard_dependencies.rs +++ b/src/tools/clippy/clippy_lints/src/cargo/wildcard_dependencies.rs @@ -17,7 +17,7 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata) { cx, WILDCARD_DEPENDENCIES, DUMMY_SP, - &format!("wildcard dependency for `{}`", dep.name), + format!("wildcard dependency for `{}`", dep.name), ); } } diff --git a/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs b/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs index a667ea04af0a..f05fd3fcde50 100644 --- a/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs +++ b/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs @@ -28,7 +28,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cx, AS_PTR_CAST_MUT, expr.span, - &format!("casting the result of `as_ptr` to *mut {ptrty}"), + format!("casting the result of `as_ptr` to *mut {ptrty}"), "replace with", format!("{recv}.as_mut_ptr()"), applicability, diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs index c16633483214..d4d5ee37bccb 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs @@ -34,7 +34,7 @@ pub(super) fn check( cx, CAST_ABS_TO_UNSIGNED, span, - &format!("casting the result of `{cast_from}::abs()` to {cast_to}"), + format!("casting the result of `{cast_from}::abs()` to {cast_to}"), "replace with", format!("{}.unsigned_abs()", Sugg::hir(cx, receiver, "..").maybe_par()), Applicability::MachineApplicable, diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs index 86f4332d05aa..d52ad1c6f23f 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs @@ -68,7 +68,7 @@ pub(super) fn check( cx, CAST_LOSSLESS, expr.span, - &message, + message, "try", format!("{cast_to_fmt}::from({sugg})"), app, diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs b/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs index da756129db3a..1743ce71adde 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs @@ -12,7 +12,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cx, CAST_NAN_TO_INT, expr.span, - &format!("casting a known NaN to {to_ty}"), + format!("casting a known NaN to {to_ty}"), None, "this always evaluates to 0", ); diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs index 2c0a3d482960..dbfa8e1ee91b 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs @@ -41,7 +41,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b }) }, BinOpKind::Rem | BinOpKind::BitAnd => get_constant_bits(cx, right) - .unwrap_or(u64::max_value()) + .unwrap_or(u64::MAX) .min(apply_reductions(cx, nbits, left, signed)), BinOpKind::Shr => apply_reductions(cx, nbits, left, signed) .saturating_sub(constant_int(cx, right).map_or(0, |s| u64::try_from(s).unwrap_or_default())), @@ -56,7 +56,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b } else { None }; - apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::max_value())) + apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::MAX)) }, ExprKind::MethodCall(method, _, [lo, hi], _) => { if method.ident.as_str() == "clamp" { @@ -142,7 +142,7 @@ pub(super) fn check( cx, CAST_ENUM_TRUNCATION, expr.span, - &format!( + format!( "casting `{cast_from}::{}` to `{cast_to}` will truncate the value{suffix}", variant.name, ), @@ -163,7 +163,7 @@ pub(super) fn check( _ => return, }; - span_lint_and_then(cx, CAST_POSSIBLE_TRUNCATION, expr.span, &msg, |diag| { + span_lint_and_then(cx, CAST_POSSIBLE_TRUNCATION, expr.span, msg, |diag| { diag.help("if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ..."); if !cast_from.is_floating_point() { offer_suggestion(cx, expr, cast_expr, cast_to_span, diag); diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs index 2ddb0f00ecdd..11274383595a 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs @@ -79,7 +79,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca ), }; - span_lint_and_then(cx, CAST_POSSIBLE_WRAP, expr.span, &message, |diag| { + span_lint_and_then(cx, CAST_POSSIBLE_WRAP, expr.span, message, |diag| { if let EmitState::LintOnPtrSize(16) = should_lint { diag .note("`usize` and `isize` may be as small as 16 bits on some platforms") diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs index 334e1646cd4f..035666e4d4c9 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs @@ -38,7 +38,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca cx, CAST_PRECISION_LOSS, expr.span, - &format!( + format!( "casting `{0}` to `{1}` causes a loss of precision {2}(`{0}` is {3} bits wide, \ but `{1}`'s mantissa is only {4} bits wide)", cast_from, diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs index 4d1a0f678f4b..960c81045e36 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs @@ -48,7 +48,7 @@ fn lint_cast_ptr_alignment<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, cast_f cx, CAST_PTR_ALIGNMENT, expr.span, - &format!( + format!( "casting from `{cast_from}` to a more-strictly-aligned pointer (`{cast_to}`) ({} < {} bytes)", from_layout.align.abi.bytes(), to_layout.align.abi.bytes(), diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs index 8fd95d9654cf..2b6e17dc1030 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs @@ -47,7 +47,7 @@ pub(super) fn check<'cx>( cx, CAST_SIGN_LOSS, expr.span, - &format!("casting `{cast_from}` to `{cast_to}` may lose the sign of the value"), + format!("casting `{cast_from}` to `{cast_to}` may lose the sign of the value"), ); } } @@ -118,7 +118,7 @@ enum Sign { Uncertain, } -fn expr_sign<'cx>(cx: &LateContext<'cx>, expr: &Expr<'_>, ty: impl Into>>) -> Sign { +fn expr_sign<'cx, 'tcx>(cx: &LateContext<'cx>, mut expr: &'tcx Expr<'tcx>, ty: impl Into>>) -> Sign { // Try evaluate this expr first to see if it's positive if let Some(val) = get_const_signed_int_eval(cx, expr, ty) { return if val >= 0 { Sign::ZeroOrPositive } else { Sign::Negative }; @@ -134,11 +134,12 @@ fn expr_sign<'cx>(cx: &LateContext<'cx>, expr: &Expr<'_>, ty: impl Into(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: &Msrv cx, CAST_SLICE_DIFFERENT_SIZES, expr.span, - &format!( + format!( "casting between raw pointers to `[{}]` (element size {from_size}) and `[{}]` (element size {to_size}) does not adjust the count", start_ty.ty, end_ty.ty, ), diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs b/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs index 48629b6c5ccd..1d89f6c75e18 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs @@ -46,7 +46,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cx, CAST_SLICE_FROM_RAW_PARTS, span, - &format!("casting the result of `{func}` to {cast_to}"), + format!("casting the result of `{func}` to {cast_to}"), "replace with", format!("core::ptr::slice_{func}({ptr}, {len})"), applicability, diff --git a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs index a26bfab4e7c1..f263bec1576d 100644 --- a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs +++ b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs @@ -25,7 +25,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cx, FN_TO_NUMERIC_CAST, expr.span, - &format!("casting function pointer `{from_snippet}` to `{cast_to}`"), + format!("casting function pointer `{from_snippet}` to `{cast_to}`"), "try", format!("{from_snippet} as usize"), applicability, diff --git a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs index 75654129408e..826589bf303b 100644 --- a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs +++ b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs @@ -23,7 +23,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cx, FN_TO_NUMERIC_CAST_ANY, expr.span, - &format!("casting function pointer `{from_snippet}` to `{cast_to}`"), + format!("casting function pointer `{from_snippet}` to `{cast_to}`"), "did you mean to invoke the function?", format!("{from_snippet}() as {cast_to}"), applicability, diff --git a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs index 556be1d15066..0e11bcfb8ecd 100644 --- a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs +++ b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs @@ -24,7 +24,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cx, FN_TO_NUMERIC_CAST_WITH_TRUNCATION, expr.span, - &format!("casting function pointer `{from_snippet}` to `{cast_to}`, which truncates the value"), + format!("casting function pointer `{from_snippet}` to `{cast_to}`, which truncates the value"), "try", format!("{from_snippet} as usize"), applicability, 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 5a121e6a7eb3..68841076f770 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 @@ -62,8 +62,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) { // we omit following `cast`: let omit_cast = if let ExprKind::Call(func, []) = cast_expr.kind && let ExprKind::Path(ref qpath @ QPath::Resolved(None, path)) = func.kind + && let Some(method_defid) = path.res.opt_def_id() { - let method_defid = path.res.def_id(); if cx.tcx.is_diagnostic_item(sym::ptr_null, method_defid) { OmitFollowedCastReason::Null(qpath) } else if cx.tcx.is_diagnostic_item(sym::ptr_null_mut, method_defid) { diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs index e88146331cae..921693567fcd 100644 --- a/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs +++ b/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs @@ -36,7 +36,7 @@ pub(super) fn check<'tcx>( PTR_CAST_CONSTNESS, expr.span, "`as` casting between raw pointers while changing only its constness", - &format!("try `pointer::cast_{constness}`, a safer alternative"), + format!("try `pointer::cast_{constness}`, a safer alternative"), format!("{}.cast_{constness}()", sugg.maybe_par()), Applicability::MachineApplicable, ); diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs index 148d52cb5ddc..a7f7bf7854e6 100644 --- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs +++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs @@ -51,7 +51,7 @@ pub(super) fn check<'tcx>( cx, UNNECESSARY_CAST, expr.span, - &format!( + format!( "casting raw pointers to the same type and constness is unnecessary (`{cast_from}` -> `{cast_to}`)" ), "try", @@ -166,7 +166,7 @@ pub(super) fn check<'tcx>( cx, UNNECESSARY_CAST, expr.span, - &format!("casting to the same type is unnecessary (`{cast_from}` -> `{cast_to}`)"), + format!("casting to the same type is unnecessary (`{cast_from}` -> `{cast_to}`)"), "try", if needs_block { format!("{{ {cast_str} }}") @@ -209,7 +209,7 @@ fn lint_unnecessary_cast( cx, UNNECESSARY_CAST, expr.span, - &format!("casting {literal_kind_name} literal to `{cast_to}` is unnecessary"), + format!("casting {literal_kind_name} literal to `{cast_to}` is unnecessary"), "try", sugg, Applicability::MachineApplicable, diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs index 7dac3c5d9dab..ee1bb63b50d3 100644 --- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs +++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs @@ -121,7 +121,7 @@ impl CognitiveComplexity { cx, COGNITIVE_COMPLEXITY, fn_span, - &format!( + format!( "the function has a cognitive complexity of ({cc}/{})", self.limit.limit() ), diff --git a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs index e921b9b46a67..6942ca536404 100644 --- a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs +++ b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs @@ -70,7 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for CollectionIsNeverRead { } } -fn match_acceptable_type(cx: &LateContext<'_>, local: &LetStmt<'_>, collections: &[rustc_span::Symbol]) -> bool { +fn match_acceptable_type(cx: &LateContext<'_>, local: &LetStmt<'_>, collections: &[Symbol]) -> bool { let ty = cx.typeck_results().pat_ty(local.pat); collections.iter().any(|&sym| is_type_diagnostic_item(cx, ty, sym)) // String type is a lang item but not a diagnostic item for now so we need a separate check diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index c8e148598a27..5ff7d8e51343 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -254,6 +254,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::large_include_file::LARGE_INCLUDE_FILE_INFO, crate::large_stack_arrays::LARGE_STACK_ARRAYS_INFO, crate::large_stack_frames::LARGE_STACK_FRAMES_INFO, + crate::legacy_numeric_constants::LEGACY_NUMERIC_CONSTANTS_INFO, crate::len_zero::COMPARISON_TO_EMPTY_INFO, crate::len_zero::LEN_WITHOUT_IS_EMPTY_INFO, crate::len_zero::LEN_ZERO_INFO, @@ -678,6 +679,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::trait_bounds::TYPE_REPETITION_IN_BOUNDS_INFO, crate::transmute::CROSSPOINTER_TRANSMUTE_INFO, crate::transmute::EAGER_TRANSMUTE_INFO, + crate::transmute::MISSING_TRANSMUTE_ANNOTATIONS_INFO, crate::transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS_INFO, crate::transmute::TRANSMUTE_BYTES_TO_STR_INFO, crate::transmute::TRANSMUTE_FLOAT_TO_INT_INFO, diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs index 98a6d9370c34..2b3f4854255c 100644 --- a/src/tools/clippy/clippy_lints/src/default.rs +++ b/src/tools/clippy/clippy_lints/src/default.rs @@ -100,7 +100,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { cx, DEFAULT_TRAIT_ACCESS, expr.span, - &format!("calling `{replacement}` is more clear than this expression"), + format!("calling `{replacement}` is more clear than this expression"), "try", replacement, Applicability::Unspecified, // First resolve the TODO above @@ -243,7 +243,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { first_assign.unwrap().span, "field assignment outside of initializer for an instance created with Default::default()", Some(local.span), - &format!("consider initializing the variable with `{sugg}` and removing relevant reassignments"), + format!("consider initializing the variable with `{sugg}` and removing relevant reassignments"), ); self.reassigned_linted.insert(span); } diff --git a/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs b/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs index 71e1a25c2bce..137781754966 100644 --- a/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs +++ b/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs @@ -56,7 +56,7 @@ fn is_alias(ty: hir::Ty<'_>) -> bool { impl LateLintPass<'_> for DefaultConstructedUnitStructs { fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { - if let hir::ExprKind::Call(fn_expr, &[]) = expr.kind + if let ExprKind::Call(fn_expr, &[]) = expr.kind // make sure we have a call to `Default::default` && let ExprKind::Path(ref qpath @ hir::QPath::TypeRelative(base, _)) = fn_expr.kind // make sure this isn't a type alias: diff --git a/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs b/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs index e617c19eff09..ac49e6f1a482 100644 --- a/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs +++ b/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs @@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultIterEmpty { cx, DEFAULT_INSTEAD_OF_ITER_EMPTY, expr.span, - &format!("`{path}()` is the more idiomatic way"), + format!("`{path}()` is the more idiomatic way"), "try", sugg, applicability, @@ -60,7 +60,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultIterEmpty { fn make_sugg( cx: &LateContext<'_>, - ty_path: &rustc_hir::QPath<'_>, + ty_path: &QPath<'_>, ctxt: SyntaxContext, applicability: &mut Applicability, path: &str, diff --git a/src/tools/clippy/clippy_lints/src/default_union_representation.rs b/src/tools/clippy/clippy_lints/src/default_union_representation.rs index bfd89bfd2c72..3f87ed8df2bf 100644 --- a/src/tools/clippy/clippy_lints/src/default_union_representation.rs +++ b/src/tools/clippy/clippy_lints/src/default_union_representation.rs @@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultUnionRepresentation { item.span, "this union has the default representation", None, - &format!( + format!( "consider annotating `{}` with `#[repr(C)]` to explicitly specify memory layout", cx.tcx.def_path_str(item.owner_id) ), diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs index b0f46f5c646c..80327586fedc 100644 --- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs +++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs @@ -79,7 +79,7 @@ fn is_path_self(e: &Expr<'_>) -> bool { fn contains_trait_object(ty: Ty<'_>) -> bool { match ty.kind() { ty::Ref(_, ty, _) => contains_trait_object(*ty), - ty::Adt(def, args) => def.is_box() && args[0].as_type().map_or(false, contains_trait_object), + Adt(def, args) => def.is_box() && args[0].as_type().map_or(false, contains_trait_object), ty::Dynamic(..) => true, _ => false, } diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index c554edc8fceb..5f9700b76d94 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -11,8 +11,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::traits::Reveal; use rustc_middle::ty::{ - self, ClauseKind, GenericArgKind, GenericParamDefKind, ParamEnv, ToPredicate, TraitPredicate, Ty, - TyCtxt, + self, ClauseKind, GenericArgKind, GenericParamDefKind, ParamEnv, ToPredicate, TraitPredicate, Ty, TyCtxt, }; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; diff --git a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs index 4a617ba34d57..871f529da6c4 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs @@ -102,11 +102,11 @@ impl DisallowedMacros { DISALLOWED_MACROS, cx.tcx.local_def_id_to_hir_id(derive_src.def_id), mac.span, - &msg, + msg, add_note, ); } else { - span_lint_and_then(cx, DISALLOWED_MACROS, mac.span, &msg, add_note); + span_lint_and_then(cx, DISALLOWED_MACROS, mac.span, msg, add_note); } } } diff --git a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs index 1868d3cd3915..9de879604e2e 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs @@ -99,7 +99,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods { None => return, }; let msg = format!("use of a disallowed method `{}`", conf.path()); - span_lint_and_then(cx, DISALLOWED_METHODS, expr.span, &msg, |diag| { + span_lint_and_then(cx, DISALLOWED_METHODS, expr.span, msg, |diag| { if let Some(reason) = conf.reason() { diag.note(reason); } diff --git a/src/tools/clippy/clippy_lints/src/disallowed_names.rs b/src/tools/clippy/clippy_lints/src/disallowed_names.rs index 09dad5554ad7..2afbf184117e 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_names.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_names.rs @@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedNames { cx, DISALLOWED_NAMES, ident.span, - &format!("use of a disallowed/placeholder name `{}`", ident.name), + format!("use of a disallowed/placeholder name `{}`", ident.name), ); } } diff --git a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs index 0c1bb2da7e89..def4b5932b4b 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs @@ -98,7 +98,7 @@ impl EarlyLintPass for DisallowedScriptIdents { cx, DISALLOWED_SCRIPT_IDENTS, span, - &format!( + format!( "identifier `{symbol_str}` has a Unicode script that is not allowed by configuration: {}", script.full_name() ), diff --git a/src/tools/clippy/clippy_lints/src/disallowed_types.rs b/src/tools/clippy/clippy_lints/src/disallowed_types.rs index 130f56b698ff..4196309a22a4 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_types.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_types.rs @@ -127,7 +127,7 @@ fn emit(cx: &LateContext<'_>, name: &str, span: Span, conf: &DisallowedPath) { cx, DISALLOWED_TYPES, span, - &format!("`{name}` is not allowed according to config"), + format!("`{name}` is not allowed according to config"), |diag| { if let Some(reason) = conf.reason() { diag.note(reason); diff --git a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs index bf6f54c1e72a..119473c2454b 100644 --- a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs +++ b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs @@ -129,9 +129,9 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { cx, lint, expr.span, - &msg, + msg, note_span, - &format!("argument has type `{arg_ty}`"), + format!("argument has type `{arg_ty}`"), ); } } diff --git a/src/tools/clippy/clippy_lints/src/duplicate_mod.rs b/src/tools/clippy/clippy_lints/src/duplicate_mod.rs index 471335c098fc..ed27e38ef2d1 100644 --- a/src/tools/clippy/clippy_lints/src/duplicate_mod.rs +++ b/src/tools/clippy/clippy_lints/src/duplicate_mod.rs @@ -119,7 +119,7 @@ impl EarlyLintPass for DuplicateMod { cx, DUPLICATE_MOD, multi_span, - &format!("file is loaded as a module multiple times: `{}`", local_path.display()), + format!("file is loaded as a module multiple times: `{}`", local_path.display()), None, "replace all but one `mod` item with `use` items", ); diff --git a/src/tools/clippy/clippy_lints/src/endian_bytes.rs b/src/tools/clippy/clippy_lints/src/endian_bytes.rs index b8a817e21b14..dd03df797de3 100644 --- a/src/tools/clippy/clippy_lints/src/endian_bytes.rs +++ b/src/tools/clippy/clippy_lints/src/endian_bytes.rs @@ -197,7 +197,7 @@ fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix cx, lint.as_lint(), expr.span, - &format!( + format!( "usage of the {}`{ty}::{}`{}", if prefix == Prefix::From { "function " } else { "" }, lint.as_name(prefix), diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs index dafbf6c88469..b7c9d3d03852 100644 --- a/src/tools/clippy/clippy_lints/src/entry.rs +++ b/src/tools/clippy/clippy_lints/src/entry.rs @@ -186,7 +186,7 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass { cx, MAP_ENTRY, expr.span, - &format!("usage of `contains_key` followed by `insert` on a `{}`", map_ty.name()), + format!("usage of `contains_key` followed by `insert` on a `{}`", map_ty.name()), "try", sugg, app, diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs index ad589dad350b..386d4c3c317f 100644 --- a/src/tools/clippy/clippy_lints/src/escape.rs +++ b/src/tools/clippy/clippy_lints/src/escape.rs @@ -177,7 +177,7 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { } } - fn fake_read(&mut self, _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} + fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} } impl<'a, 'tcx> EscapeDelegate<'a, 'tcx> { diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs index eccfc31fdd3e..850a4f0eec8e 100644 --- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs +++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs @@ -3,14 +3,14 @@ use clippy_utils::higher::VecArgs; use clippy_utils::source::snippet_opt; use clippy_utils::ty::type_diagnostic_name; use clippy_utils::usage::{local_used_after_expr, local_used_in}; -use clippy_utils::{get_path_from_caller_to_method_type, higher, is_adjusted, path_to_local, path_to_local_id}; +use clippy_utils::{get_path_from_caller_to_method_type, is_adjusted, path_to_local, path_to_local_id}; use rustc_errors::Applicability; use rustc_hir::{BindingAnnotation, Expr, ExprKind, FnRetTy, Param, PatKind, QPath, TyKind, Unsafety}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{ - self, Binder, ClosureArgs, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, RegionKind, - Ty, TypeVisitableExt, TypeckResults, + self, Binder, ClosureArgs, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, RegionKind, Ty, + TypeVisitableExt, TypeckResults, }; use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; @@ -88,7 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { if body.value.span.from_expansion() { if body.params.is_empty() { - if let Some(VecArgs::Vec(&[])) = higher::VecArgs::hir(cx, body.value) { + if let Some(VecArgs::Vec(&[])) = VecArgs::hir(cx, body.value) { // replace `|| vec![]` with `Vec::new` span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_lints/src/excessive_bools.rs b/src/tools/clippy/clippy_lints/src/excessive_bools.rs index c5f7212c4c08..62d5ce24d40a 100644 --- a/src/tools/clippy/clippy_lints/src/excessive_bools.rs +++ b/src/tools/clippy/clippy_lints/src/excessive_bools.rs @@ -120,7 +120,7 @@ impl ExcessiveBools { cx, FN_PARAMS_EXCESSIVE_BOOLS, span, - &format!("more than {} bools in function parameters", self.max_fn_params_bools), + format!("more than {} bools in function parameters", self.max_fn_params_bools), None, "consider refactoring bools into two-variant enums", ); @@ -145,7 +145,7 @@ impl<'tcx> LateLintPass<'tcx> for ExcessiveBools { cx, STRUCT_EXCESSIVE_BOOLS, item.span, - &format!("more than {} bools in a struct", self.max_struct_bools), + format!("more than {} bools in a struct", self.max_struct_bools), None, "consider using a state machine or refactoring bools into two-variant enums", ); diff --git a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs index 3a621d967f43..9ffda6457424 100644 --- a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs +++ b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs @@ -38,7 +38,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Warns on any exported `structs`s that are not tagged `#[non_exhaustive]` + /// Warns on any exported `struct`s that are not tagged `#[non_exhaustive]` /// /// ### Why is this bad? /// Exhaustive structs are typically fine, but a project which does diff --git a/src/tools/clippy/clippy_lints/src/explicit_write.rs b/src/tools/clippy/clippy_lints/src/explicit_write.rs index 2e9bec6a7b08..33bd5a5a9d3a 100644 --- a/src/tools/clippy/clippy_lints/src/explicit_write.rs +++ b/src/tools/clippy/clippy_lints/src/explicit_write.rs @@ -88,7 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { cx, EXPLICIT_WRITE, expr.span, - &format!("use of `{used}.unwrap()`"), + format!("use of `{used}.unwrap()`"), "try", format!("{prefix}{sugg_mac}!({inputs_snippet})"), applicability, diff --git a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs index 538d29eb43dc..7484f772e082 100644 --- a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs +++ b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs @@ -110,11 +110,11 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> { .map_or(param.span, |bound_span| param.span.with_hi(bound_span.hi())) } - fn emit_help(&self, spans: Vec, msg: &str, help: &'static str) { + fn emit_help(&self, spans: Vec, msg: String, help: &'static str) { span_lint_and_help(self.cx, EXTRA_UNUSED_TYPE_PARAMETERS, spans, msg, None, help); } - fn emit_sugg(&self, spans: Vec, msg: &str, help: &'static str) { + fn emit_sugg(&self, spans: Vec, msg: String, help: &'static str) { let suggestions: Vec<(Span, String)> = spans.iter().copied().zip(std::iter::repeat(String::new())).collect(); span_lint_and_then(self.cx, EXTRA_UNUSED_TYPE_PARAMETERS, spans, msg, |diag| { diag.multipart_suggestion(help, suggestions, Applicability::MachineApplicable); @@ -167,7 +167,7 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> { .iter() .map(|(_, param)| self.get_bound_span(param)) .collect::>(); - self.emit_help(spans, &msg, help); + self.emit_help(spans, msg, help); } else { let spans = if explicit_params.len() == extra_params.len() { vec![self.generics.span] // Remove the entire list of generics @@ -196,7 +196,7 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> { }) .collect() }; - self.emit_sugg(spans, &msg, help); + self.emit_sugg(spans, msg, help); }; } } diff --git a/src/tools/clippy/clippy_lints/src/float_literal.rs b/src/tools/clippy/clippy_lints/src/float_literal.rs index 981a76d683d2..2cd4e9e99a56 100644 --- a/src/tools/clippy/clippy_lints/src/float_literal.rs +++ b/src/tools/clippy/clippy_lints/src/float_literal.rs @@ -83,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral { LitFloatType::Unsuffixed => None, }; let (is_whole, is_inf, mut float_str) = match fty { - FloatTy::F16 => { + FloatTy::F16 | FloatTy::F128 => { // FIXME(f16_f128): do a check like the others when parsing is available return; }, @@ -97,10 +97,6 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral { (value.fract() == 0.0, value.is_infinite(), formatter.format(value)) }, - FloatTy::F128 => { - // FIXME(f16_f128): do a check like the others when parsing is available - return; - }, }; if is_inf { diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs index c8b87e510ed6..46d47e217b04 100644 --- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs @@ -552,9 +552,9 @@ fn is_testing_negative(cx: &LateContext<'_>, expr: &Expr<'_>, test: &Expr<'_>) - /// Returns true iff expr is some zero literal fn is_zero(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { match constant_simple(cx, cx.typeck_results(), expr) { - Some(Constant::Int(i)) => i == 0, - Some(Constant::F32(f)) => f == 0.0, - Some(Constant::F64(f)) => f == 0.0, + Some(Int(i)) => i == 0, + Some(F32(f)) => f == 0.0, + Some(F64(f)) => f == 0.0, _ => false, } } diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs index 61f550ce0beb..80db617c639a 100644 --- a/src/tools/clippy/clippy_lints/src/format_args.rs +++ b/src/tools/clippy/clippy_lints/src/format_args.rs @@ -401,7 +401,7 @@ impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> { self.cx, FORMAT_IN_FORMAT_ARGS, self.macro_call.span, - &format!("`format!` in `{name}!` args"), + format!("`format!` in `{name}!` args"), |diag| { diag.help(format!( "combine the `format!(..)` arguments with the outer `{name}!(..)` call" @@ -431,7 +431,7 @@ impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> { cx, TO_STRING_IN_FORMAT_ARGS, to_string_span.with_lo(receiver.span.hi()), - &format!("`to_string` applied to a type that implements `Display` in `{name}!` args"), + format!("`to_string` applied to a type that implements `Display` in `{name}!` args"), "remove this", String::new(), Applicability::MachineApplicable, @@ -441,7 +441,7 @@ impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> { cx, TO_STRING_IN_FORMAT_ARGS, value.span, - &format!("`to_string` applied to a type that implements `Display` in `{name}!` args"), + format!("`to_string` applied to a type that implements `Display` in `{name}!` args"), "use this", format!( "{}{:*>n_needed_derefs$}{receiver_snippet}", diff --git a/src/tools/clippy/clippy_lints/src/format_impl.rs b/src/tools/clippy/clippy_lints/src/format_impl.rs index 93517076cda0..0a52347940ab 100644 --- a/src/tools/clippy/clippy_lints/src/format_impl.rs +++ b/src/tools/clippy/clippy_lints/src/format_impl.rs @@ -214,7 +214,7 @@ impl<'a, 'tcx> FormatImplExpr<'a, 'tcx> { self.cx, RECURSIVE_FORMAT_IMPL, self.expr.span, - &format!("using `self` as `{name}` in `impl {name}` will cause infinite recursion"), + format!("using `self` as `{name}` in `impl {name}` will cause infinite recursion"), ); } } @@ -235,7 +235,7 @@ impl<'a, 'tcx> FormatImplExpr<'a, 'tcx> { self.cx, PRINT_IN_FORMAT_IMPL, macro_call.span, - &format!("use of `{name}!` in `{}` impl", self.format_trait_impl.name), + format!("use of `{name}!` in `{}` impl", self.format_trait_impl.name), "replace with", if let Some(formatter_name) = self.format_trait_impl.formatter_name { format!("{replacement}!({formatter_name}, ..)") diff --git a/src/tools/clippy/clippy_lints/src/formatting.rs b/src/tools/clippy/clippy_lints/src/formatting.rs index c3ef6f180c9f..34e93bdb9b9b 100644 --- a/src/tools/clippy/clippy_lints/src/formatting.rs +++ b/src/tools/clippy/clippy_lints/src/formatting.rs @@ -151,12 +151,12 @@ fn check_assign(cx: &EarlyContext<'_>, expr: &Expr) { cx, SUSPICIOUS_ASSIGNMENT_FORMATTING, eqop_span, - &format!( + format!( "this looks like you are trying to use `.. {op}= ..`, but you \ really are doing `.. = ({op} ..)`" ), None, - &format!("to remove this lint, use either `{op}=` or `= {op}`"), + format!("to remove this lint, use either `{op}=` or `= {op}`"), ); } } @@ -187,12 +187,12 @@ fn check_unop(cx: &EarlyContext<'_>, expr: &Expr) { cx, SUSPICIOUS_UNARY_OP_FORMATTING, eqop_span, - &format!( + format!( "by not having a space between `{binop_str}` and `{unop_str}` it looks like \ `{binop_str}{unop_str}` is a single operator" ), None, - &format!("put a space between `{binop_str}` and `{unop_str}` and remove the space after `{unop_str}`"), + format!("put a space between `{binop_str}` and `{unop_str}` and remove the space after `{unop_str}`"), ); } } @@ -215,6 +215,7 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) { // it’s bad when there is a ‘\n’ after the “else” && let Some(else_snippet) = snippet_opt(cx, else_span) && let Some((pre_else, post_else)) = else_snippet.split_once("else") + && !else_snippet.contains('/') && let Some((_, post_else_post_eol)) = post_else.split_once('\n') { // Allow allman style braces `} \n else \n {` @@ -238,9 +239,9 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) { cx, SUSPICIOUS_ELSE_FORMATTING, else_span, - &format!("this is an `else {else_desc}` but the formatting might hide it"), + format!("this is an `else {else_desc}` but the formatting might hide it"), None, - &format!( + format!( "to remove this lint, remove the `else` or remove the new line between \ `else` and `{else_desc}`", ), @@ -308,9 +309,9 @@ fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) { cx, SUSPICIOUS_ELSE_FORMATTING, else_span, - &format!("this looks like {looks_like} but the `else` is missing"), + format!("this looks like {looks_like} but the `else` is missing"), None, - &format!("to remove this lint, add the missing `else` or add a new line before {next_thing}",), + format!("to remove this lint, add the missing `else` or add a new line before {next_thing}",), ); } } diff --git a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs index 286ba2306c92..ba2495c17a21 100644 --- a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs @@ -4,7 +4,7 @@ use clippy_utils::ty::is_c_void; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{RawPtr}; +use rustc_middle::ty::RawPtr; use rustc_session::declare_lint_pass; use rustc_span::sym; @@ -52,7 +52,7 @@ impl LateLintPass<'_> for FromRawWithVoidPtr { cx, FROM_RAW_WITH_VOID_PTR, expr.span, - &msg, + msg, Some(arg.span), "cast this to a pointer of the appropriate type", ); diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index d752d010f9fe..d0c66900c006 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -142,7 +142,7 @@ fn check_must_use_candidate<'tcx>( item_span: Span, item_id: hir::OwnerId, fn_span: Span, - msg: &str, + msg: &'static str, ) { if has_mutable_arg(cx, body) || mutates_static(cx, body) @@ -207,9 +207,7 @@ fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, tys: &mut DefIdSet) }, ty::Tuple(args) => args.iter().any(|ty| is_mutable_ty(cx, ty, tys)), ty::Array(ty, _) | ty::Slice(ty) => is_mutable_ty(cx, ty, tys), - ty::RawPtr(ty, mutbl) | ty::Ref(_, ty, mutbl) => { - mutbl == hir::Mutability::Mut || is_mutable_ty(cx, ty, tys) - }, + ty::RawPtr(ty, mutbl) | ty::Ref(_, ty, mutbl) => mutbl == hir::Mutability::Mut || is_mutable_ty(cx, ty, tys), // calling something constitutes a side effect, so return true on all callables // also never calls need not be used, so return true for them, too _ => true, diff --git a/src/tools/clippy/clippy_lints/src/functions/result.rs b/src/tools/clippy/clippy_lints/src/functions/result.rs index 37fbf2c7d596..93f088d3e339 100644 --- a/src/tools/clippy/clippy_lints/src/functions/result.rs +++ b/src/tools/clippy/clippy_lints/src/functions/result.rs @@ -2,7 +2,7 @@ use rustc_errors::Diag; use rustc_hir as hir; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_middle::ty::{self, Adt, Ty}; +use rustc_middle::ty::{Adt, Ty}; use rustc_span::{sym, Span}; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; @@ -25,7 +25,7 @@ fn result_err_ty<'tcx>( .tcx .instantiate_bound_regions_with_erased(cx.tcx.fn_sig(id).instantiate_identity().output()) && is_type_diagnostic_item(cx, ty, sym::Result) - && let ty::Adt(_, args) = ty.kind() + && let Adt(_, args) = ty.kind() { let err_ty = args.type_at(1); Some((hir_ty, err_ty)) diff --git a/src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs b/src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs index 1e08922a6166..e72a2ad49d82 100644 --- a/src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs +++ b/src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs @@ -59,7 +59,7 @@ fn check_arg_number(cx: &LateContext<'_>, decl: &hir::FnDecl<'_>, fn_span: Span, cx, TOO_MANY_ARGUMENTS, fn_span, - &format!("this function has too many arguments ({args}/{too_many_arguments_threshold})"), + format!("this function has too many arguments ({args}/{too_many_arguments_threshold})"), ); } } 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 34f1bf3b2b1d..586ca58d60dd 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 @@ -77,7 +77,7 @@ pub(super) fn check_fn( cx, TOO_MANY_LINES, span, - &format!("this function has too many lines ({line_count}/{too_many_lines_threshold})"), + format!("this function has too many lines ({line_count}/{too_many_lines_threshold})"), ); } } diff --git a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs index 8f48941c4a91..f5ba62ae432e 100644 --- a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs +++ b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs @@ -117,9 +117,9 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { cx, IF_THEN_SOME_ELSE_NONE, expr.span, - &format!("this could be simplified with `bool::{method_name}`"), + format!("this could be simplified with `bool::{method_name}`"), None, - &help, + help, ); } } diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs index 8acb138332cf..a46aae36d5c5 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs @@ -141,7 +141,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { cx, IMPLICIT_HASHER, target.span(), - &format!( + format!( "impl for `{}` should be generalized over different hashers", target.type_name() ), @@ -187,7 +187,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { cx, IMPLICIT_HASHER, target.span(), - &format!( + format!( "parameter of type `{}` should be generalized over different hashers", target.type_name() ), diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs index 9f4d7b51271b..7b97fc15caaf 100644 --- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs +++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs @@ -56,7 +56,7 @@ fn emit_lint( index: usize, // The bindings that were implied, used for suggestion purposes since removing a bound with associated types // means we might need to then move it to a different bound - implied_bindings: &[rustc_hir::TypeBinding<'_>], + implied_bindings: &[TypeBinding<'_>], bound: &ImplTraitBound<'_>, ) { let implied_by = snippet(cx, bound.span, ".."); @@ -65,7 +65,7 @@ fn emit_lint( cx, IMPLIED_BOUNDS_IN_IMPLS, poly_trait.span, - &format!("this bound is already specified as the supertrait of `{implied_by}`"), + format!("this bound is already specified as the supertrait of `{implied_by}`"), |diag| { // If we suggest removing a bound, we may also need to extend the span // to include the `+` token that is ahead or behind, diff --git a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs index cd000fcd1844..35b4481bfee7 100644 --- a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs +++ b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs @@ -33,7 +33,7 @@ declare_clippy_lint! { /// /// To fix this problem, either increase your MSRV or use another item /// available in your current MSRV. - #[clippy::version = "1.77.0"] + #[clippy::version = "1.78.0"] pub INCOMPATIBLE_MSRV, suspicious, "ensures that all items used in the crate are available for the current MSRV" @@ -104,7 +104,7 @@ impl IncompatibleMsrv { cx, INCOMPATIBLE_MSRV, span, - &format!( + format!( "current MSRV (Minimum Supported Rust Version) is `{}` but this item is stable since `{version}`", self.msrv ), diff --git a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs index ca2ac60306b3..157f61059847 100644 --- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs +++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs @@ -132,20 +132,20 @@ fn show_lint(cx: &LateContext<'_>, item: &ImplItem<'_>) { cx, INHERENT_TO_STRING_SHADOW_DISPLAY, item.span, - &format!( + format!( "type `{self_type}` implements inherent method `to_string(&self) -> String` which shadows the implementation of `Display`" ), None, - &format!("remove the inherent method from type `{self_type}`"), + format!("remove the inherent method from type `{self_type}`"), ); } else { span_lint_and_help( cx, INHERENT_TO_STRING, item.span, - &format!("implementation of inherent method `to_string(&self) -> String` for type `{self_type}`"), + format!("implementation of inherent method `to_string(&self) -> String` for type `{self_type}`"), None, - &format!("implement trait `Display` for type `{self_type}` instead"), + format!("implement trait `Display` for type `{self_type}` instead"), ); } } diff --git a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs index 83ecaeef9825..860258fd030e 100644 --- a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs +++ b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs @@ -51,7 +51,7 @@ fn check_attrs(cx: &LateContext<'_>, name: Symbol, attrs: &[Attribute]) { cx, INLINE_FN_WITHOUT_BODY, attr.span, - &format!("use of `#[inline]` on trait method `{name}` which has no body"), + format!("use of `#[inline]` on trait method `{name}` which has no body"), |diag| { diag.suggest_remove_item(cx, attr.span, "remove", Applicability::MachineApplicable); }, diff --git a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs index 17b6256f982b..10b00f632bb0 100644 --- a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs +++ b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs @@ -1,5 +1,5 @@ use clippy_config::msrvs::{self, Msrv}; -use clippy_utils::diagnostics::{self, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; use clippy_utils::sugg::Sugg; use clippy_utils::ty; @@ -149,7 +149,7 @@ fn print_unchecked_duration_subtraction_sugg( let left_expr = snippet_with_context(cx, left_expr.span, ctxt, "", &mut applicability).0; let right_expr = snippet_with_context(cx, right_expr.span, ctxt, "", &mut applicability).0; - diagnostics::span_lint_and_sugg( + span_lint_and_sugg( cx, UNCHECKED_DURATION_SUBTRACTION, expr.span, diff --git a/src/tools/clippy/clippy_lints/src/integer_division_remainder_used.rs b/src/tools/clippy/clippy_lints/src/integer_division_remainder_used.rs index 36dc45ca788d..a3577b765c03 100644 --- a/src/tools/clippy/clippy_lints/src/integer_division_remainder_used.rs +++ b/src/tools/clippy/clippy_lints/src/integer_division_remainder_used.rs @@ -43,7 +43,7 @@ impl LateLintPass<'_> for IntegerDivisionRemainderUsed { cx, INTEGER_DIVISION_REMAINDER_USED, expr.span.source_callsite(), - &format!("use of {} has been disallowed in this context", op.node.as_str()), + format!("use of {} has been disallowed in this context", op.node.as_str()), ); } } diff --git a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs index 8bcd9b532bd1..30f2285bdd23 100644 --- a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs +++ b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs @@ -76,7 +76,7 @@ fn err_upcast_comparison(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, alwa cx, INVALID_UPCAST_COMPARISONS, span, - &format!( + format!( "because of the numeric bounds on `{}` prior to casting, this expression is always {}", snippet(cx, cast_val.span, "the expression"), if always { "true" } else { "false" }, @@ -88,7 +88,7 @@ fn err_upcast_comparison(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, alwa fn upcast_comparison_bounds_err<'tcx>( cx: &LateContext<'tcx>, span: Span, - rel: comparisons::Rel, + rel: Rel, lhs_bounds: Option<(FullInt, FullInt)>, lhs: &'tcx Expr<'_>, rhs: &'tcx Expr<'_>, diff --git a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs index 0b4c416d94db..6615122567dc 100644 --- a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs +++ b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs @@ -240,9 +240,9 @@ fn check_fields(cx: &LateContext<'_>, threshold: u64, item: &Item<'_>, fields: & cx, STRUCT_FIELD_NAMES, item.span, - &format!("all fields have the same {what}fix: `{value}`"), + format!("all fields have the same {what}fix: `{value}`"), None, - &format!("remove the {what}fixes"), + format!("remove the {what}fixes"), ); } } @@ -370,9 +370,9 @@ fn check_variant(cx: &LateContext<'_>, threshold: u64, def: &EnumDef<'_>, item_n cx, ENUM_VARIANT_NAMES, span, - &format!("all variants have the same {what}fix: `{value}`"), + format!("all variants have the same {what}fix: `{value}`"), None, - &format!( + format!( "remove the {what}fixes and use full paths to \ the variants instead of glob imports" ), diff --git a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs index 32ae6be56873..1b5f1b499475 100644 --- a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs +++ b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs @@ -84,7 +84,7 @@ fn check_sig(cx: &LateContext<'_>, name: &str, sig: &FnSig<'_>, fn_id: LocalDefI cx, ITER_NOT_RETURNING_ITERATOR, sig.span, - &format!("this method is named `{name}` but its return type does not implement `Iterator`"), + format!("this method is named `{name}` but its return type does not implement `Iterator`"), ); } } diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs index cf0ab88032c1..c749a7123303 100644 --- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs +++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs @@ -182,7 +182,7 @@ impl LateLintPass<'_> for IterWithoutIntoIter { cx, INTO_ITER_WITHOUT_ITER, item.span, - &format!("`IntoIterator` implemented for a reference type without an `{expected_method_name}` method"), + format!("`IntoIterator` implemented for a reference type without an `{expected_method_name}` method"), |diag| { // The suggestion forwards to the `IntoIterator` impl and uses a form of UFCS // to avoid name ambiguities, as there might be an inherent into_iter method @@ -258,7 +258,7 @@ impl {self_ty_without_ref} {{ cx, ITER_WITHOUT_INTO_ITER, item.span, - &format!( + format!( "`{}` method without an `IntoIterator` impl for `{self_ty_snippet}`", item.ident ), diff --git a/src/tools/clippy/clippy_lints/src/large_futures.rs b/src/tools/clippy/clippy_lints/src/large_futures.rs index eb7570e9b44e..07488a512a37 100644 --- a/src/tools/clippy/clippy_lints/src/large_futures.rs +++ b/src/tools/clippy/clippy_lints/src/large_futures.rs @@ -71,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeFuture { cx, LARGE_FUTURES, expr.span, - &format!("large future with a size of {} bytes", size.bytes()), + format!("large future with a size of {} bytes", size.bytes()), "consider `Box::pin` on it", format!("Box::pin({})", snippet(cx, expr.span, "..")), Applicability::Unspecified, diff --git a/src/tools/clippy/clippy_lints/src/large_include_file.rs b/src/tools/clippy/clippy_lints/src/large_include_file.rs index 1b5981ecc281..0599afca09f8 100644 --- a/src/tools/clippy/clippy_lints/src/large_include_file.rs +++ b/src/tools/clippy/clippy_lints/src/large_include_file.rs @@ -74,7 +74,7 @@ impl LateLintPass<'_> for LargeIncludeFile { expr.span, "attempted to include a large file", None, - &format!( + format!( "the configuration allows a maximum size of {} bytes", self.max_file_size ), diff --git a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs index fd33ba91bfd7..afcb67459476 100644 --- a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs +++ b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs @@ -58,12 +58,12 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { cx, LARGE_STACK_ARRAYS, expr.span, - &format!( + format!( "allocating a local array larger than {} bytes", self.maximum_allowed_size ), None, - &format!( + format!( "consider allocating on the heap with `vec!{}.into_boxed_slice()`", snippet(cx, expr.span, "[...]") ), diff --git a/src/tools/clippy/clippy_lints/src/large_stack_frames.rs b/src/tools/clippy/clippy_lints/src/large_stack_frames.rs index b397180a69c5..49408d7e2435 100644 --- a/src/tools/clippy/clippy_lints/src/large_stack_frames.rs +++ b/src/tools/clippy/clippy_lints/src/large_stack_frames.rs @@ -1,10 +1,12 @@ -use std::ops::AddAssign; +use std::{fmt, ops}; -use clippy_utils::diagnostics::span_lint_and_note; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::fn_has_unsatisfiable_preds; +use clippy_utils::source::snippet_opt; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl}; +use rustc_lexer::is_ident; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; use rustc_span::Span; @@ -108,13 +110,25 @@ impl Space { } } -impl AddAssign for Space { - fn add_assign(&mut self, rhs: u64) { - if let Self::Used(lhs) = self { - match lhs.checked_add(rhs) { - Some(sum) => *self = Self::Used(sum), - None => *self = Self::Overflow, - } +impl fmt::Display for Space { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Space::Used(1) => write!(f, "1 byte"), + Space::Used(n) => write!(f, "{n} bytes"), + Space::Overflow => write!(f, "over 2⁶⁴-1 bytes"), + } + } +} + +impl ops::Add for Space { + type Output = Self; + fn add(self, rhs: u64) -> Self { + match self { + Self::Used(lhs) => match lhs.checked_add(rhs) { + Some(sum) => Self::Used(sum), + None => Self::Overflow, + }, + Self::Overflow => self, } } } @@ -123,10 +137,10 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackFrames { fn check_fn( &mut self, cx: &LateContext<'tcx>, - _: FnKind<'tcx>, + fn_kind: FnKind<'tcx>, _: &'tcx FnDecl<'tcx>, _: &'tcx Body<'tcx>, - span: Span, + entire_fn_span: Span, local_def_id: LocalDefId, ) { let def_id = local_def_id.to_def_id(); @@ -138,22 +152,68 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackFrames { let mir = cx.tcx.optimized_mir(def_id); let param_env = cx.tcx.param_env(def_id); - let mut frame_size = Space::Used(0); + let sizes_of_locals = || { + mir.local_decls.iter().filter_map(|local| { + let layout = cx.tcx.layout_of(param_env.and(local.ty)).ok()?; + Some((local, layout.size.bytes())) + }) + }; - for local in &mir.local_decls { - if let Ok(layout) = cx.tcx.layout_of(param_env.and(local.ty)) { - frame_size += layout.size.bytes(); - } - } + let frame_size = sizes_of_locals().fold(Space::Used(0), |sum, (_, size)| sum + size); - if frame_size.exceeds_limit(self.maximum_allowed_size) { - span_lint_and_note( + let limit = self.maximum_allowed_size; + if frame_size.exceeds_limit(limit) { + // Point at just the function name if possible, because lints that span + // the entire body and don't have to are less legible. + let fn_span = match fn_kind { + FnKind::ItemFn(ident, _, _) | FnKind::Method(ident, _) => ident.span, + FnKind::Closure => entire_fn_span, + }; + + span_lint_and_then( cx, LARGE_STACK_FRAMES, - span, - "this function allocates a large amount of stack space", - None, - "allocating large amounts of stack space can overflow the stack", + fn_span, + format!("this function may allocate {frame_size} on the stack"), + |diag| { + // Point out the largest individual contribution to this size, because + // it is the most likely to be unintentionally large. + if let Some((local, size)) = sizes_of_locals().max_by_key(|&(_, size)| size) { + let local_span: Span = local.source_info.span; + let size = Space::Used(size); // pluralizes for us + let ty = local.ty; + + // TODO: Is there a cleaner, robust way to ask this question? + // The obvious `LocalDecl::is_user_variable()` panics on "unwrapping cross-crate data", + // and that doesn't get us the true name in scope rather than the span text either. + if let Some(name) = snippet_opt(cx, local_span) + && is_ident(&name) + { + // If the local is an ordinary named variable, + // print its name rather than relying solely on the span. + diag.span_label( + local_span, + format!("`{name}` is the largest part, at {size} for type `{ty}`"), + ); + } else { + diag.span_label( + local_span, + format!("this is the largest part, at {size} for type `{ty}`"), + ); + } + } + + // Explain why we are linting this and not other functions. + diag.note(format!( + "{frame_size} is larger than Clippy's configured `stack-size-threshold` of {limit}" + )); + + // Explain why the user should care, briefly. + diag.note_once( + "allocating large amounts of stack space can overflow the stack \ + and cause the program to abort", + ); + }, ); } } diff --git a/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs new file mode 100644 index 000000000000..c5f1afe68c3f --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs @@ -0,0 +1,293 @@ +use clippy_config::msrvs::{Msrv, NUMERIC_ASSOCIATED_CONSTANTS}; +use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; +use clippy_utils::{get_parent_expr, is_from_proc_macro}; +use hir::def_id::DefId; +use rustc_errors::{Applicability, SuggestionStyle}; +use rustc_hir as hir; +use rustc_hir::{ExprKind, Item, ItemKind, QPath, UseKind}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_session::impl_lint_pass; +use rustc_span::symbol::kw; +use rustc_span::{sym, Symbol}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `::max_value()`, `std::::MAX`, + /// `std::::EPSILON`, etc. + /// + /// ### Why is this bad? + /// All of these have been superceded by the associated constants on their respective types, + /// such as `i128::MAX`. These legacy items may be deprecated in a future version of rust. + /// + /// ### Example + /// ```rust + /// let eps = std::f32::EPSILON; + /// ``` + /// Use instead: + /// ```rust + /// let eps = f32::EPSILON; + /// ``` + #[clippy::version = "1.72.0"] + pub LEGACY_NUMERIC_CONSTANTS, + style, + "checks for usage of legacy std numeric constants and methods" +} +pub struct LegacyNumericConstants { + msrv: Msrv, +} + +impl LegacyNumericConstants { + #[must_use] + pub fn new(msrv: Msrv) -> Self { + Self { msrv } + } +} + +impl_lint_pass!(LegacyNumericConstants => [LEGACY_NUMERIC_CONSTANTS]); + +impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + let Self { msrv } = self; + + if !msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS) || in_external_macro(cx.sess(), item.span) { + return; + } + + // Integer modules are "TBD" deprecated, and the contents are too, + // so lint on the `use` statement directly. + if let ItemKind::Use(path, kind @ (UseKind::Single | UseKind::Glob)) = item.kind + && let Some(def_id) = path.res[0].opt_def_id() + { + let module = if is_integer_module(cx, def_id) { + true + } else if is_numeric_const(cx, def_id) { + false + } else { + return; + }; + + span_lint_and_then( + cx, + LEGACY_NUMERIC_CONSTANTS, + path.span, + if module { + "importing legacy numeric constants" + } else { + "importing a legacy numeric constant" + }, + |diag| { + if item.ident.name == kw::Underscore { + diag.help("remove this import"); + return; + } + + let def_path = cx.get_def_path(def_id); + + if module && let [.., module_name] = &*def_path { + if kind == UseKind::Glob { + diag.help(format!("remove this import and use associated constants `{module_name}::` from the primitive type instead")); + } else { + diag.help("remove this import").note(format!( + "then `{module_name}::` will resolve to the respective associated constant" + )); + } + } else if let [.., module_name, name] = &*def_path { + diag.help( + format!("remove this import and use the associated constant `{module_name}::{name}` from the primitive type instead") + ); + } + }, + ); + } + } + + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) { + let Self { msrv } = self; + + if !msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS) || in_external_macro(cx.sess(), expr.span) { + return; + } + let ExprKind::Path(qpath) = expr.kind else { + return; + }; + + // `std::::` check + let (span, sugg, msg) = if let QPath::Resolved(None, path) = qpath + && let Some(def_id) = path.res.opt_def_id() + && is_numeric_const(cx, def_id) + && let def_path = cx.get_def_path(def_id) + && let [.., mod_name, name] = &*def_path + // Skip linting if this usage looks identical to the associated constant, + // since this would only require removing a `use` import (which is already linted). + && !is_numeric_const_path_canonical(path, [*mod_name, *name]) + { + ( + expr.span, + format!("{mod_name}::{name}"), + "usage of a legacy numeric constant", + ) + // `::xxx_value` check + } else if let QPath::TypeRelative(_, last_segment) = qpath + && let Some(def_id) = cx.qpath_res(&qpath, expr.hir_id).opt_def_id() + && is_integer_method(cx, def_id) + && let Some(par_expr) = get_parent_expr(cx, expr) + && let ExprKind::Call(_, _) = par_expr.kind + { + let name = last_segment.ident.name.as_str(); + + ( + last_segment.ident.span.with_hi(par_expr.span.hi()), + name[..=2].to_ascii_uppercase(), + "usage of a legacy numeric method", + ) + } else { + return; + }; + + if is_from_proc_macro(cx, expr) { + return; + } + + span_lint_hir_and_then(cx, LEGACY_NUMERIC_CONSTANTS, expr.hir_id, span, msg, |diag| { + diag.span_suggestion_with_style( + span, + "use the associated constant instead", + sugg, + Applicability::MaybeIncorrect, + SuggestionStyle::ShowAlways, + ); + }); + } + + extract_msrv_attr!(LateContext); +} + +fn is_integer_module(cx: &LateContext<'_>, did: DefId) -> bool { + matches!( + cx.tcx.get_diagnostic_name(did), + Some( + sym::isize_legacy_mod + | sym::i128_legacy_mod + | sym::i64_legacy_mod + | sym::i32_legacy_mod + | sym::i16_legacy_mod + | sym::i8_legacy_mod + | sym::usize_legacy_mod + | sym::u128_legacy_mod + | sym::u64_legacy_mod + | sym::u32_legacy_mod + | sym::u16_legacy_mod + | sym::u8_legacy_mod + ) + ) +} + +fn is_numeric_const(cx: &LateContext<'_>, did: DefId) -> bool { + matches!( + cx.tcx.get_diagnostic_name(did), + Some( + sym::isize_legacy_const_max + | sym::isize_legacy_const_min + | sym::i128_legacy_const_max + | sym::i128_legacy_const_min + | sym::i16_legacy_const_max + | sym::i16_legacy_const_min + | sym::i32_legacy_const_max + | sym::i32_legacy_const_min + | sym::i64_legacy_const_max + | sym::i64_legacy_const_min + | sym::i8_legacy_const_max + | sym::i8_legacy_const_min + | sym::usize_legacy_const_max + | sym::usize_legacy_const_min + | sym::u128_legacy_const_max + | sym::u128_legacy_const_min + | sym::u16_legacy_const_max + | sym::u16_legacy_const_min + | sym::u32_legacy_const_max + | sym::u32_legacy_const_min + | sym::u64_legacy_const_max + | sym::u64_legacy_const_min + | sym::u8_legacy_const_max + | sym::u8_legacy_const_min + | sym::f32_legacy_const_digits + | sym::f32_legacy_const_epsilon + | sym::f32_legacy_const_infinity + | sym::f32_legacy_const_mantissa_dig + | sym::f32_legacy_const_max + | sym::f32_legacy_const_max_10_exp + | sym::f32_legacy_const_max_exp + | sym::f32_legacy_const_min + | sym::f32_legacy_const_min_10_exp + | sym::f32_legacy_const_min_exp + | sym::f32_legacy_const_min_positive + | sym::f32_legacy_const_nan + | sym::f32_legacy_const_neg_infinity + | sym::f32_legacy_const_radix + | sym::f64_legacy_const_digits + | sym::f64_legacy_const_epsilon + | sym::f64_legacy_const_infinity + | sym::f64_legacy_const_mantissa_dig + | sym::f64_legacy_const_max + | sym::f64_legacy_const_max_10_exp + | sym::f64_legacy_const_max_exp + | sym::f64_legacy_const_min + | sym::f64_legacy_const_min_10_exp + | sym::f64_legacy_const_min_exp + | sym::f64_legacy_const_min_positive + | sym::f64_legacy_const_nan + | sym::f64_legacy_const_neg_infinity + | sym::f64_legacy_const_radix + ) + ) +} + +// Whether path expression looks like `i32::MAX` +fn is_numeric_const_path_canonical(expr_path: &hir::Path<'_>, [mod_name, name]: [Symbol; 2]) -> bool { + let [ + hir::PathSegment { + ident: one, args: None, .. + }, + hir::PathSegment { + ident: two, args: None, .. + }, + ] = expr_path.segments + else { + return false; + }; + + one.name == mod_name && two.name == name +} + +fn is_integer_method(cx: &LateContext<'_>, did: DefId) -> bool { + matches!( + cx.tcx.get_diagnostic_name(did), + Some( + sym::isize_legacy_fn_max_value + | sym::isize_legacy_fn_min_value + | sym::i128_legacy_fn_max_value + | sym::i128_legacy_fn_min_value + | sym::i16_legacy_fn_max_value + | sym::i16_legacy_fn_min_value + | sym::i32_legacy_fn_max_value + | sym::i32_legacy_fn_min_value + | sym::i64_legacy_fn_max_value + | sym::i64_legacy_fn_min_value + | sym::i8_legacy_fn_max_value + | sym::i8_legacy_fn_min_value + | sym::usize_legacy_fn_max_value + | sym::usize_legacy_fn_min_value + | sym::u128_legacy_fn_max_value + | sym::u128_legacy_fn_min_value + | sym::u16_legacy_fn_max_value + | sym::u16_legacy_fn_min_value + | sym::u32_legacy_fn_max_value + | sym::u32_legacy_fn_min_value + | sym::u64_legacy_fn_max_value + | sym::u64_legacy_fn_min_value + | sym::u8_legacy_fn_max_value + | sym::u8_legacy_fn_min_value + ) + ) +} diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index cae9ada5a33c..97a245b76d44 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::snippet_with_context; -use clippy_utils::sugg::Sugg; +use clippy_utils::source::{snippet_opt, snippet_with_context}; +use clippy_utils::sugg::{has_enclosing_paren, Sugg}; use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, peel_ref_operators}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -192,7 +192,7 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { if let ExprKind::Binary(Spanned { node: cmp, .. }, left, right) = expr.kind { // expr.span might contains parenthesis, see issue #10529 - let actual_span = left.span.with_hi(right.span.hi()); + let actual_span = span_without_enclosing_paren(cx, expr.span); match cmp { BinOpKind::Eq => { check_cmp(cx, actual_span, left, right, "", 0); // len == 0 @@ -218,6 +218,20 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { } } +fn span_without_enclosing_paren(cx: &LateContext<'_>, span: Span) -> Span { + let Some(snippet) = snippet_opt(cx, span) else { + return span; + }; + if has_enclosing_paren(snippet) { + let source_map = cx.tcx.sess.source_map(); + let left_paren = source_map.start_point(span); + let right_parent = source_map.end_point(span); + left_paren.between(right_parent) + } else { + span + } +} + fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items: &[TraitItemRef]) { fn is_named_self(cx: &LateContext<'_>, item: &TraitItemRef, name: Symbol) -> bool { item.ident.name == name @@ -256,7 +270,7 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items .items() .flat_map(|&i| cx.tcx.associated_items(i).filter_by_name_unhygienic(is_empty)) .any(|i| { - i.kind == ty::AssocKind::Fn + i.kind == AssocKind::Fn && i.fn_has_self_parameter && cx.tcx.fn_sig(i.def_id).skip_binder().inputs().skip_binder().len() == 1 }); @@ -266,7 +280,7 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items cx, LEN_WITHOUT_IS_EMPTY, visited_trait.span, - &format!( + format!( "trait `{}` has a `len` method but no (possibly inherited) `is_empty` method", visited_trait.ident.name ), @@ -484,7 +498,7 @@ fn check_for_is_empty( Some(_) => return, }; - span_lint_and_then(cx, LEN_WITHOUT_IS_EMPTY, span, &msg, |db| { + span_lint_and_then(cx, LEN_WITHOUT_IS_EMPTY, span, msg, |db| { if let Some(span) = is_empty_span { db.span_note(span, "`is_empty` defined here"); } @@ -495,6 +509,10 @@ fn check_for_is_empty( } fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) { + if method.span.from_expansion() { + return; + } + if let (&ExprKind::MethodCall(method_path, receiver, args, _), ExprKind::Lit(lit)) = (&method.kind, &lit.kind) { // check if we are in an is_empty() method if let Some(name) = get_item_name(cx, method) { @@ -542,8 +560,8 @@ fn check_len( cx, LEN_ZERO, span, - &format!("length comparison to {}", if compare_to == 0 { "zero" } else { "one" }), - &format!("using `{op}is_empty` is clearer and more explicit"), + format!("length comparison to {}", if compare_to == 0 { "zero" } else { "one" }), + format!("using `{op}is_empty` is clearer and more explicit"), format!( "{op}{}.is_empty()", snippet_with_context(cx, receiver.span, span.ctxt(), "_", &mut applicability).0, @@ -566,7 +584,7 @@ fn check_empty_expr(cx: &LateContext<'_>, span: Span, lit1: &Expr<'_>, lit2: &Ex COMPARISON_TO_EMPTY, span, "comparison to empty slice", - &format!("using `{op}is_empty` is clearer and more explicit"), + format!("using `{op}is_empty` is clearer and more explicit"), format!("{op}{lit_str}.is_empty()"), applicability, ); @@ -594,7 +612,7 @@ fn is_empty_array(expr: &Expr<'_>) -> bool { fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { /// Gets an `AssocItem` and return true if it matches `is_empty(self)`. fn is_is_empty(cx: &LateContext<'_>, item: &ty::AssocItem) -> bool { - if item.kind == ty::AssocKind::Fn { + if item.kind == AssocKind::Fn { let sig = cx.tcx.fn_sig(item.def_id).skip_binder(); let ty = sig.skip_binder(); ty.inputs().len() == 1 diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 57fac3510427..b92364a9d147 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -16,11 +16,14 @@ rustc::diagnostic_outside_of_impl, rustc::untranslatable_diagnostic )] -#![warn(trivial_casts, trivial_numeric_casts)] -// warn on lints, that are included in `rust-lang/rust`s bootstrap -#![warn(rust_2018_idioms, unused_lifetimes)] -// warn on rustc internal lints -#![warn(rustc::internal)] +#![warn( + trivial_casts, + trivial_numeric_casts, + rust_2018_idioms, + unused_lifetimes, + unused_qualifications, + rustc::internal +)] // Disable this rustc lint for now, as it was also done in rustc #![allow(rustc::potential_query_instability)] @@ -186,6 +189,7 @@ mod large_futures; mod large_include_file; mod large_stack_arrays; mod large_stack_frames; +mod legacy_numeric_constants; mod len_zero; mod let_if_seq; mod let_underscore; @@ -1080,6 +1084,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { allow_one_hash_in_raw_strings, }) }); + store.register_late_pass(move |_| Box::new(legacy_numeric_constants::LegacyNumericConstants::new(msrv()))); store.register_late_pass(|_| Box::new(manual_range_patterns::ManualRangePatterns)); store.register_early_pass(|| Box::new(visibility::Visibility)); store.register_late_pass(move |_| Box::new(tuple_array_conversions::TupleArrayConversions { msrv: msrv() })); diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index 2b73663d229e..a60a40a2a471 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -216,7 +216,7 @@ fn check_fn_inner<'tcx>( None })) .collect_vec(), - &format!("the following explicit lifetimes could be elided: {lts}"), + format!("the following explicit lifetimes could be elided: {lts}"), |diag| { if sig.header.is_async() { // async functions have usages whose spans point at the lifetime declaration which messes up diff --git a/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs b/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs index 29957e423b0b..3d1c666dfea0 100644 --- a/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs +++ b/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs @@ -70,7 +70,7 @@ impl LateLintPass<'_> for LinesFilterMapOk { cx, LINES_FILTER_MAP_OK, fm_span, - &format!("`{fm_method_str}()` will run forever if the iterator repeatedly produces an `Err`",), + format!("`{fm_method_str}()` will run forever if the iterator repeatedly produces an `Err`",), |diag| { diag.span_note( fm_receiver.span, diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs index f33151cf4c59..2348dd18220f 100644 --- a/src/tools/clippy/clippy_lints/src/literal_representation.rs +++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs @@ -158,7 +158,7 @@ enum WarningType { } impl WarningType { - fn display(&self, suggested_format: String, cx: &EarlyContext<'_>, span: rustc_span::Span) { + fn display(&self, suggested_format: String, cx: &EarlyContext<'_>, span: Span) { match self { Self::MistypedLiteralSuffix => span_lint_and_sugg( cx, @@ -302,11 +302,7 @@ impl LiteralDigitGrouping { } // Returns `false` if the check fails - fn check_for_mistyped_suffix( - cx: &EarlyContext<'_>, - span: rustc_span::Span, - num_lit: &mut NumericLiteral<'_>, - ) -> bool { + fn check_for_mistyped_suffix(cx: &EarlyContext<'_>, span: Span, num_lit: &mut NumericLiteral<'_>) -> bool { if num_lit.suffix.is_some() { return true; } diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs index 277062a84901..f0ee64d714e0 100644 --- a/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs @@ -42,7 +42,7 @@ pub(super) fn check<'tcx>( cx, EXPLICIT_COUNTER_LOOP, span, - &format!("the variable `{name}` is used as a loop counter"), + format!("the variable `{name}` is used as a loop counter"), "consider using", format!( "for ({name}, {}) in {}.enumerate()", @@ -62,7 +62,7 @@ pub(super) fn check<'tcx>( cx, EXPLICIT_COUNTER_LOOP, span, - &format!("the variable `{name}` is used as a loop counter"), + format!("the variable `{name}` is used as a loop counter"), |diag| { diag.span_suggestion( span, diff --git a/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs b/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs index 94c951fc10a6..6922533fbe9d 100644 --- a/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs +++ b/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs @@ -37,7 +37,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx cx, FOR_KV_MAP, arg_span, - &format!("you seem to want to iterate on a map's {kind}s"), + format!("you seem to want to iterate on a map's {kind}s"), |diag| { let map = sugg::Sugg::hir(cx, arg, "map"); multispan_sugg( diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs index 36de9021f499..dbc094a6d73f 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs @@ -62,7 +62,7 @@ pub(super) fn check<'tcx>( "...and remove the `if let` statement in the for loop" }; - span_lint_and_then(cx, MANUAL_FLATTEN, span, &msg, |diag| { + span_lint_and_then(cx, MANUAL_FLATTEN, span, msg, |diag| { diag.span_suggestion(arg.span, "try", sugg, applicability); diag.span_help(inner_expr.span, help_msg); }); diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs index c4e60e98ad46..94330001e4f1 100644 --- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs +++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs @@ -109,7 +109,7 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> { } } - fn fake_read(&mut self, _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} + fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} } impl MutatePairDelegate<'_, '_> { @@ -141,7 +141,7 @@ impl BreakAfterExprVisitor { } } -impl<'tcx> intravisit::Visitor<'tcx> for BreakAfterExprVisitor { +impl<'tcx> Visitor<'tcx> for BreakAfterExprVisitor { fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { if self.past_candidate { return; diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs index cf34c904dfe9..de7ec81bc010 100644 --- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs @@ -143,7 +143,7 @@ pub(super) fn check<'tcx>( cx, NEEDLESS_RANGE_LOOP, arg.span, - &format!("the loop variable `{}` is used to index `{indexed}`", ident.name), + format!("the loop variable `{}` is used to index `{indexed}`", ident.name), |diag| { multispan_sugg( diag, @@ -169,7 +169,7 @@ pub(super) fn check<'tcx>( cx, NEEDLESS_RANGE_LOOP, arg.span, - &format!("the loop variable `{}` is only used to index `{indexed}`", ident.name), + format!("the loop variable `{}` is only used to index `{indexed}`", ident.name), |diag| { multispan_sugg( diag, @@ -357,7 +357,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { let def_id = self.cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap(); for (ty, expr) in iter::zip( self.cx.tcx.fn_sig(def_id).instantiate_identity().inputs().skip_binder(), - std::iter::once(receiver).chain(args.iter()), + iter::once(receiver).chain(args.iter()), ) { self.prefer_mutable = false; if let ty::Ref(_, _, mutbl) = *ty.kind() { diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs index 8aae7be45936..313a5bfefbc8 100644 --- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs @@ -159,12 +159,9 @@ fn never_loop_expr<'tcx>( | ExprKind::DropTemps(e) => never_loop_expr(cx, e, local_labels, main_loop_id), ExprKind::Let(let_expr) => never_loop_expr(cx, let_expr.init, local_labels, main_loop_id), ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(cx, es.iter(), local_labels, main_loop_id), - ExprKind::MethodCall(_, receiver, es, _) => never_loop_expr_all( - cx, - std::iter::once(receiver).chain(es.iter()), - local_labels, - main_loop_id, - ), + ExprKind::MethodCall(_, receiver, es, _) => { + never_loop_expr_all(cx, once(receiver).chain(es.iter()), local_labels, main_loop_id) + }, ExprKind::Struct(_, fields, base) => { let fields = never_loop_expr_all(cx, fields.iter().map(|f| f.expr), local_labels, main_loop_id); if let Some(base) = base { diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs index 670a78d58c3c..1d90d4a58f5e 100644 --- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs +++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs @@ -31,7 +31,7 @@ pub(super) fn check<'tcx>( vec.span, "it looks like the same item is being pushed into this Vec", None, - &format!("consider using vec![{item_str};SIZE] or {vec_str}.resize(NEW_SIZE, {item_str})"), + format!("consider using vec![{item_str};SIZE] or {vec_str}.resize(NEW_SIZE, {item_str})"), ); } diff --git a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs index 4773a1454b7a..108fdb697752 100644 --- a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs @@ -42,7 +42,7 @@ pub(super) fn check<'tcx>( }, [], _, - ) if method.ident.name == rustc_span::sym::iter => (arg, "&"), + ) if method.ident.name == sym::iter => (arg, "&"), ExprKind::MethodCall( method, Expr { @@ -60,7 +60,7 @@ pub(super) fn check<'tcx>( }, [], _, - ) if method.ident.name == rustc_span::sym::into_iter => (arg, ""), + ) if method.ident.name == sym::into_iter => (arg, ""), // Only check for arrays edition 2021 or later, as this case will trigger a compiler error otherwise. ExprKind::Array([arg]) if cx.tcx.sess.edition() >= Edition::Edition2021 => (arg, ""), _ => return, @@ -95,7 +95,7 @@ pub(super) fn check<'tcx>( cx, SINGLE_ELEMENT_LOOP, arg.span, - format!("this loops only once with `{pat_snip}` being `{range_expr}`").as_str(), + format!("this loops only once with `{pat_snip}` being `{range_expr}`"), "did you mean to iterate over the range instead?", sugg.to_string(), Applicability::Unspecified, diff --git a/src/tools/clippy/clippy_lints/src/main_recursion.rs b/src/tools/clippy/clippy_lints/src/main_recursion.rs index a381b35cf2e2..72807b4b284e 100644 --- a/src/tools/clippy/clippy_lints/src/main_recursion.rs +++ b/src/tools/clippy/clippy_lints/src/main_recursion.rs @@ -51,7 +51,7 @@ impl LateLintPass<'_> for MainRecursion { cx, MAIN_RECURSION, func.span, - &format!("recursing into entrypoint `{}`", snippet(cx, func.span, "main")), + format!("recursing into entrypoint `{}`", snippet(cx, func.span, "main")), None, "consider using another function for this recursion", ); diff --git a/src/tools/clippy/clippy_lints/src/manual_assert.rs b/src/tools/clippy/clippy_lints/src/manual_assert.rs index 4f6a2cf017ca..76edbe8b755b 100644 --- a/src/tools/clippy/clippy_lints/src/manual_assert.rs +++ b/src/tools/clippy/clippy_lints/src/manual_assert.rs @@ -1,7 +1,7 @@ use crate::rustc_lint::LintContext; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::root_macro_call; -use clippy_utils::{is_else_clause, peel_blocks_with_stmt, span_extract_comment, sugg}; +use clippy_utils::{is_else_clause, is_parent_stmt, peel_blocks_with_stmt, span_extract_comment, sugg}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; @@ -63,7 +63,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualAssert { _ => (cond, "!"), }; let cond_sugg = sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par(); - let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip});"); + let semicolon = if is_parent_stmt(cx, expr.hir_id) { ";" } else { "" }; + let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip}){semicolon}"); // we show to the user the suggestion without the comments, but when applying the fix, include the // comments in the block span_lint_and_then( diff --git a/src/tools/clippy/clippy_lints/src/manual_bits.rs b/src/tools/clippy/clippy_lints/src/manual_bits.rs index aa02e4e7a434..24fc2b4faeac 100644 --- a/src/tools/clippy/clippy_lints/src/manual_bits.rs +++ b/src/tools/clippy/clippy_lints/src/manual_bits.rs @@ -139,7 +139,7 @@ fn is_ty_conversion(expr: &Expr<'_>) -> bool { if let ExprKind::Cast(..) = expr.kind { true } else if let ExprKind::MethodCall(path, _, [], _) = expr.kind - && path.ident.name == rustc_span::sym::try_into + && path.ident.name == sym::try_into { // This is only called for `usize` which implements `TryInto`. Therefore, // we don't have to check here if `self` implements the `TryInto` trait. diff --git a/src/tools/clippy/clippy_lints/src/manual_clamp.rs b/src/tools/clippy/clippy_lints/src/manual_clamp.rs index 830af77968c0..1eadc200bedc 100644 --- a/src/tools/clippy/clippy_lints/src/manual_clamp.rs +++ b/src/tools/clippy/clippy_lints/src/manual_clamp.rs @@ -1,4 +1,5 @@ use clippy_config::msrvs::{self, Msrv}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::higher::If; use clippy_utils::sugg::Sugg; @@ -17,6 +18,7 @@ use rustc_middle::ty::Ty; use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; use rustc_span::Span; +use std::cmp::Ordering; use std::ops::Deref; declare_clippy_lint! { @@ -26,6 +28,11 @@ declare_clippy_lint! { /// ### Why is this bad? /// clamp is much shorter, easier to read, and doesn't use any control flow. /// + /// ### Limitations + /// + /// This lint will only trigger if max and min are known at compile time, and max is + /// greater than min. + /// /// ### Known issue(s) /// If the clamped variable is NaN this suggestion will cause the code to propagate NaN /// rather than returning either `max` or `min`. @@ -80,7 +87,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.66.0"] pub MANUAL_CLAMP, - nursery, + complexity, "using a clamp pattern instead of the clamp function" } impl_lint_pass!(ManualClamp => [MANUAL_CLAMP]); @@ -103,6 +110,26 @@ struct ClampSuggestion<'tcx> { hir_with_ignore_attr: Option, } +impl<'tcx> ClampSuggestion<'tcx> { + /// This function will return true if and only if you can demonstrate at compile time that min + /// is less than max. + fn min_less_than_max(&self, cx: &LateContext<'tcx>) -> bool { + let max_type = cx.typeck_results().expr_ty(self.params.max); + let min_type = cx.typeck_results().expr_ty(self.params.min); + if max_type != min_type { + return false; + } + if let Some(max) = constant(cx, cx.typeck_results(), self.params.max) + && let Some(min) = constant(cx, cx.typeck_results(), self.params.min) + && let Some(ord) = Constant::partial_cmp(cx.tcx, max_type, &min, &max) + { + ord != Ordering::Greater + } else { + false + } + } +} + #[derive(Debug)] struct InputMinMax<'tcx> { input: &'tcx Expr<'tcx>, @@ -123,7 +150,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualClamp { .or_else(|| is_match_pattern(cx, expr)) .or_else(|| is_if_elseif_pattern(cx, expr)); if let Some(suggestion) = suggestion { - emit_suggestion(cx, &suggestion); + maybe_emit_suggestion(cx, &suggestion); } } } @@ -133,13 +160,16 @@ impl<'tcx> LateLintPass<'tcx> for ManualClamp { return; } for suggestion in is_two_if_pattern(cx, block) { - emit_suggestion(cx, &suggestion); + maybe_emit_suggestion(cx, &suggestion); } } extract_msrv_attr!(LateContext); } -fn emit_suggestion<'tcx>(cx: &LateContext<'tcx>, suggestion: &ClampSuggestion<'tcx>) { +fn maybe_emit_suggestion<'tcx>(cx: &LateContext<'tcx>, suggestion: &ClampSuggestion<'tcx>) { + if !suggestion.min_less_than_max(cx) { + return; + } let ClampSuggestion { params: InputMinMax { input, diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs index bcd024360024..45af9f07718d 100644 --- a/src/tools/clippy/clippy_lints/src/manual_strip.rs +++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs @@ -106,12 +106,12 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip { cx, MANUAL_STRIP, strippings[0], - &format!("stripping a {kind_word} manually"), + format!("stripping a {kind_word} manually"), |diag| { diag.span_note(test_span, format!("the {kind_word} was tested here")); multispan_sugg( diag, - &format!("try using the `strip_{kind_word}` method"), + format!("try using the `strip_{kind_word}` method"), vec![( test_span, format!( diff --git a/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs b/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs index ddaf97c463ae..c562ceb5bcee 100644 --- a/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs +++ b/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs @@ -1,14 +1,15 @@ +use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{Arm, Expr, ExprKind, HirId, LangItem, MatchSource, Pat, PatKind, QPath}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::declare_lint_pass; use rustc_span::sym; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_default_equivalent; use clippy_utils::source::snippet_opt; use clippy_utils::ty::implements_trait; +use clippy_utils::{in_constant, is_default_equivalent, peel_blocks, span_contains_comment}; declare_clippy_lint! { /// ### What it does @@ -118,22 +119,27 @@ fn handle_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { // We now get the bodies for both the `Some` and `None` arms. && let Some(((body_some, binding_id), body_none)) = get_some_and_none_bodies(cx, arm1, arm2) // We check that the `Some(x) => x` doesn't do anything apart "returning" the value in `Some`. - && let ExprKind::Path(QPath::Resolved(_, path)) = body_some.peel_blocks().kind + && let ExprKind::Path(QPath::Resolved(_, path)) = peel_blocks(body_some).kind && let Res::Local(local_id) = path.res && local_id == binding_id // We now check the `None` arm is calling a method equivalent to `Default::default`. - && let body_none = body_none.peel_blocks() + && let body_none = peel_blocks(body_none) && is_default_equivalent(cx, body_none) - && let Some(match_expr_snippet) = snippet_opt(cx, match_expr.span) + && let Some(receiver) = Sugg::hir_opt(cx, match_expr).map(Sugg::maybe_par) { + let applicability = if span_contains_comment(cx.sess().source_map(), expr.span) { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable + }; span_lint_and_sugg( cx, MANUAL_UNWRAP_OR_DEFAULT, expr.span, "match can be simplified with `.unwrap_or_default()`", "replace it with", - format!("{match_expr_snippet}.unwrap_or_default()"), - Applicability::MachineApplicable, + format!("{receiver}.unwrap_or_default()"), + applicability, ); } true @@ -149,14 +155,19 @@ fn handle_if_let<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { && implements_trait(cx, match_ty, default_trait_id, &[]) && let Some(binding_id) = get_some(cx, let_.pat) // We check that the `Some(x) => x` doesn't do anything apart "returning" the value in `Some`. - && let ExprKind::Path(QPath::Resolved(_, path)) = if_block.peel_blocks().kind + && let ExprKind::Path(QPath::Resolved(_, path)) = peel_blocks(if_block).kind && let Res::Local(local_id) = path.res && local_id == binding_id // We now check the `None` arm is calling a method equivalent to `Default::default`. - && let body_else = else_expr.peel_blocks() + && let body_else = peel_blocks(else_expr) && is_default_equivalent(cx, body_else) && let Some(if_let_expr_snippet) = snippet_opt(cx, let_.init.span) { + let applicability = if span_contains_comment(cx.sess().source_map(), expr.span) { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable + }; span_lint_and_sugg( cx, MANUAL_UNWRAP_OR_DEFAULT, @@ -164,14 +175,14 @@ fn handle_if_let<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { "if let can be simplified with `.unwrap_or_default()`", "replace it with", format!("{if_let_expr_snippet}.unwrap_or_default()"), - Applicability::MachineApplicable, + applicability, ); } } impl<'tcx> LateLintPass<'tcx> for ManualUnwrapOrDefault { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if expr.span.from_expansion() { + if expr.span.from_expansion() || in_constant(cx, expr.hir_id) { return; } if !handle_match(cx, expr) { diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs index c9eab7109ebc..9db04b615be7 100644 --- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs +++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs @@ -221,13 +221,13 @@ fn lint_map_unit_fn( binding = let_binding_name(cx, var_arg) ); - span_lint_and_then(cx, lint, expr.span, &msg, |diag| { + span_lint_and_then(cx, lint, expr.span, msg, |diag| { diag.span_suggestion(stmt.span, "try", suggestion, applicability); }); } else if let Some((binding, closure_expr)) = unit_closure(cx, fn_arg) { let msg = suggestion_msg("closure", map_type); - span_lint_and_then(cx, lint, expr.span, &msg, |diag| { + span_lint_and_then(cx, lint, expr.span, msg, |diag| { if let Some(reduced_expr_span) = reduce_unit_expression(cx, closure_expr) { let mut applicability = Applicability::MachineApplicable; let suggestion = format!( diff --git a/src/tools/clippy/clippy_lints/src/match_result_ok.rs b/src/tools/clippy/clippy_lints/src/match_result_ok.rs index 62cedc8847b2..2a5fc8b66091 100644 --- a/src/tools/clippy/clippy_lints/src/match_result_ok.rs +++ b/src/tools/clippy/clippy_lints/src/match_result_ok.rs @@ -76,7 +76,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchResultOk { MATCH_RESULT_OK, expr.span.with_hi(let_expr.span.hi()), "matching on `Some` with `ok()` is redundant", - &format!("consider matching on `Ok({some_expr_string})` and removing the call to `ok` instead"), + format!("consider matching on `Ok({some_expr_string})` and removing the call to `ok` instead"), sugg, applicability, ); diff --git a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs index 5fef5930fab2..6746920edc51 100644 --- a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs @@ -97,7 +97,7 @@ fn check_arm<'tcx>( } else { String::new() }; - span_lint_and_then(cx, COLLAPSIBLE_MATCH, inner_expr.span, &msg, |diag| { + span_lint_and_then(cx, COLLAPSIBLE_MATCH, inner_expr.span, msg, |diag| { let mut help_span = MultiSpan::from_spans(vec![binding_span, inner_then_pat.span]); help_span.push_span_label(binding_span, "replace this binding"); help_span.push_span_label(inner_then_pat.span, format!("with this pattern{replace_msg}")); diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs index 3e79cabd795f..9edd6c954042 100644 --- a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs +++ b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs @@ -34,7 +34,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, scrutinee: cx, MANUAL_UNWRAP_OR, expr.span, - &format!("this pattern reimplements `{ty_name}::unwrap_or`"), + format!("this pattern reimplements `{ty_name}::unwrap_or`"), "replace with", format!("{suggestion}.unwrap_or({reindented_or_body})",), app, diff --git a/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs b/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs index 6b484ff2749b..f5da8ec61874 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs @@ -43,7 +43,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: cx, MATCH_AS_REF, expr.span, - &format!("use `{suggestion}()` instead"), + format!("use `{suggestion}()` instead"), "try", format!( "{}.{suggestion}(){cast}", diff --git a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs index b062e81cefdd..64cb7a06ce9c 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs @@ -122,7 +122,7 @@ where cx, MATCH_LIKE_MATCHES_MACRO, expr.span, - &format!( + format!( "{} expression looks like `matches!` macro", if is_if_let { "if let .. else" } else { "match" } ), 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 bd38648bcf1b..322e9c3ebe5b 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 @@ -111,7 +111,7 @@ fn lint(cx: &LateContext<'_>, case_method: &CaseMethod, bad_case_span: Span, bad MATCH_STR_CASE_MISMATCH, bad_case_span, "this `match` arm has a differing case than its expression", - &format!("consider changing the case of this arm to respect `{method_str}`"), + format!("consider changing the case of this arm to respect `{method_str}`"), format!("\"{suggestion}\""), Applicability::MachineApplicable, ); diff --git a/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs b/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs index 8a4c0ab90627..d1f637ec78c6 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs @@ -43,7 +43,7 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<' cx, MATCH_WILD_ERR_ARM, arm.pat.span, - &format!("`Err({ident_bind_name})` matches all errors"), + format!("`Err({ident_bind_name})` matches all errors"), None, "match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable", ); diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs index 580d4a642963..fae2c4e4af92 100644 --- a/src/tools/clippy/clippy_lints/src/matches/mod.rs +++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs @@ -25,14 +25,13 @@ mod try_err; mod wild_in_or_pats; use clippy_config::msrvs::{self, Msrv}; -use clippy_utils::source::{snippet_opt, walk_span_to_context}; -use clippy_utils::{higher, in_constant, is_direct_expn_of, is_span_match, tokenize_with_text}; +use clippy_utils::source::walk_span_to_context; +use clippy_utils::{higher, in_constant, is_direct_expn_of, is_span_match, span_contains_cfg}; use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat}; -use rustc_lexer::TokenKind; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; -use rustc_span::{Span, SpanData, SyntaxContext}; +use rustc_span::{SpanData, SyntaxContext}; declare_clippy_lint! { /// ### What it does @@ -1196,28 +1195,3 @@ fn contains_cfg_arm(cx: &LateContext<'_>, e: &Expr<'_>, scrutinee: &Expr<'_>, ar Err(()) => true, } } - -/// Checks if the given span contains a `#[cfg(..)]` attribute -fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool { - let Some(snip) = snippet_opt(cx, s) else { - // Assume true. This would require either an invalid span, or one which crosses file boundaries. - return true; - }; - let mut iter = tokenize_with_text(&snip); - - // Search for the token sequence [`#`, `[`, `cfg`] - while iter.any(|(t, _)| matches!(t, TokenKind::Pound)) { - let mut iter = iter.by_ref().skip_while(|(t, _)| { - matches!( - t, - TokenKind::Whitespace | TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } - ) - }); - if matches!(iter.next(), Some((TokenKind::OpenBracket, _))) - && matches!(iter.next(), Some((TokenKind::Ident, "cfg"))) - { - return true; - } - } - false -} diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs index b5870d94d996..78973984fb0b 100644 --- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs @@ -72,7 +72,7 @@ fn find_match_true<'tcx>( pat: &'tcx Pat<'_>, scrutinee: &'tcx Expr<'_>, span: Span, - message: &str, + message: &'static str, ) { if let PatKind::Lit(lit) = pat.kind && let ExprKind::Lit(lit) = lit.kind @@ -98,7 +98,7 @@ fn find_match_true<'tcx>( span, message, "consider using the condition directly", - sugg.to_string(), + sugg.into_string(), applicability, ); } @@ -227,7 +227,7 @@ fn find_method_sugg_for_if_let<'tcx>( cx, REDUNDANT_PATTERN_MATCHING, let_pat.span, - &format!("redundant pattern matching, consider using `{good_method}`"), + format!("redundant pattern matching, consider using `{good_method}`"), |diag| { // if/while let ... = ... { ... } // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -304,7 +304,7 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op cx, REDUNDANT_PATTERN_MATCHING, span, - &format!("redundant pattern matching, consider using `{good_method}`"), + format!("redundant pattern matching, consider using `{good_method}`"), "try", sugg, Applicability::MachineApplicable, diff --git a/src/tools/clippy/clippy_lints/src/mem_replace.rs b/src/tools/clippy/clippy_lints/src/mem_replace.rs index 1cdb7921f816..578aa7989e71 100644 --- a/src/tools/clippy/clippy_lints/src/mem_replace.rs +++ b/src/tools/clippy/clippy_lints/src/mem_replace.rs @@ -193,7 +193,7 @@ fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr< cx, MEM_REPLACE_WITH_DEFAULT, expr_span, - &format!( + format!( "replacing a value of type `T` with `T::default()` is better expressed using `{top_crate}::mem::take`" ), |diag| { diff --git a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs index 08bfa2e009b3..fb440ce656ed 100644 --- a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs @@ -84,7 +84,7 @@ pub(crate) trait BindInsteadOfMap { "{option_snip}.{}({closure_args_snip} {some_inner_snip})", Self::GOOD_METHOD_NAME ); - span_lint_and_sugg(cx, BIND_INSTEAD_OF_MAP, expr.span, &msg, "try", note, app); + span_lint_and_sugg(cx, BIND_INSTEAD_OF_MAP, expr.span, msg, "try", note, app); true } else { false @@ -114,7 +114,7 @@ pub(crate) trait BindInsteadOfMap { } else { return false; }; - span_lint_and_then(cx, BIND_INSTEAD_OF_MAP, expr.span, &msg, |diag| { + span_lint_and_then(cx, BIND_INSTEAD_OF_MAP, expr.span, msg, |diag| { multispan_sugg_with_applicability( diag, "try", @@ -157,7 +157,7 @@ pub(crate) trait BindInsteadOfMap { cx, BIND_INSTEAD_OF_MAP, expr.span, - &msg, + msg, "use the expression directly", snippet(cx, recv.span, "..").into(), Applicability::MachineApplicable, diff --git a/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs b/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs index baafb7030aa1..a82abc79f2a2 100644 --- a/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs +++ b/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs @@ -31,7 +31,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E cx, BYTES_NTH, parent.span, - &format!("called `.bytes().nth().unwrap()` on a `{caller_type}`"), + format!("called `.bytes().nth().unwrap()` on a `{caller_type}`"), "try", format!("{receiver}.as_bytes()[{n}]",), applicability, @@ -41,7 +41,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E cx, BYTES_NTH, expr.span, - &format!("called `.bytes().nth()` on a `{caller_type}`"), + format!("called `.bytes().nth()` on a `{caller_type}`"), "try", format!("{receiver}.as_bytes().get({n}).copied()"), applicability, diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs b/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs index c99cec067bf1..4ae0aeea2d1c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs +++ b/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs @@ -30,7 +30,7 @@ pub(super) fn check( cx, lint, info.expr.span, - &format!("you should use the `{suggest}` method"), + format!("you should use the `{suggest}` method"), "like this", format!( "{}{}.{suggest}({})", diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs index d07e45434a7c..9c45ec2e56cb 100644 --- a/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs @@ -23,7 +23,7 @@ pub(super) fn check( cx, lint, info.expr.span, - &format!("you should use the `{suggest}` method"), + format!("you should use the `{suggest}` method"), "like this", format!( "{}{}.{suggest}('{}')", diff --git a/src/tools/clippy/clippy_lints/src/methods/clear_with_drain.rs b/src/tools/clippy/clippy_lints/src/methods/clear_with_drain.rs index 67ad58d5a8c6..5389861245a2 100644 --- a/src/tools/clippy/clippy_lints/src/methods/clear_with_drain.rs +++ b/src/tools/clippy/clippy_lints/src/methods/clear_with_drain.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_range_full; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use rustc_errors::Applicability; -use rustc_hir as hir; use rustc_hir::{Expr, ExprKind, LangItem, QPath}; use rustc_lint::LateContext; use rustc_span::symbol::sym; @@ -28,7 +27,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span } } -fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, types: &[rustc_span::Symbol]) -> bool { +fn match_acceptable_type(cx: &LateContext<'_>, expr: &Expr<'_>, types: &[rustc_span::Symbol]) -> bool { let expr_ty = cx.typeck_results().expr_ty(expr).peel_refs(); types.iter().any(|&ty| is_type_diagnostic_item(cx, expr_ty, ty)) // String type is a lang item but not a diagnostic item for now so we need a separate check @@ -44,7 +43,7 @@ fn suggest(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span) { cx, CLEAR_WITH_DRAIN, span.with_hi(expr.span.hi()), - &format!("`drain` used to clear a `{ty_name}`"), + format!("`drain` used to clear a `{ty_name}`"), "try", "clear()".to_string(), Applicability::MachineApplicable, diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs index 3e099004c479..4e6823e8220b 100644 --- a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs +++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs @@ -94,7 +94,7 @@ pub(super) fn check( cx, CLONE_ON_COPY, expr.span, - &with_forced_trimmed_paths!(format!( + with_forced_trimmed_paths!(format!( "using `clone` on type `{ty}` which implements the `Copy` trait" )), help, diff --git a/src/tools/clippy/clippy_lints/src/methods/drain_collect.rs b/src/tools/clippy/clippy_lints/src/methods/drain_collect.rs index 3a8ca37610a9..56171a134522 100644 --- a/src/tools/clippy/clippy_lints/src/methods/drain_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/drain_collect.rs @@ -70,7 +70,7 @@ pub(super) fn check(cx: &LateContext<'_>, args: &[Expr<'_>], expr: &Expr<'_>, re cx, DRAIN_COLLECT, expr.span, - &format!("you seem to be trying to move all elements into a new `{typename}`"), + format!("you seem to be trying to move all elements into a new `{typename}`"), "consider using `mem::take`", sugg, Applicability::MachineApplicable, 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 4d8fb217f7f5..fba76852344f 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 @@ -142,7 +142,7 @@ pub(super) fn check<'tcx>( cx, EXPECT_FUN_CALL, span_replace_word, - &format!("use of `{name}` followed by a function call"), + format!("use of `{name}` followed by a function call"), "try", format!("unwrap_or_else({closure_args} panic!({sugg}))"), applicability, @@ -160,7 +160,7 @@ pub(super) fn check<'tcx>( cx, EXPECT_FUN_CALL, span_replace_word, - &format!("use of `{name}` followed by a function call"), + format!("use of `{name}` followed by a function call"), "try", format!("unwrap_or_else({closure_args} {{ panic!(\"{{}}\", {arg_root_snippet}) }})"), applicability, diff --git a/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs b/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs index b05361ab2120..eab536b88a5b 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs @@ -34,5 +34,5 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr } let lint_msg = format!("`{lint_unary}FileType::is_file()` only {verb} regular files"); let help_msg = format!("use `{help_unary}FileType::is_dir()` instead"); - span_lint_and_help(cx, FILETYPE_IS_FILE, span, &lint_msg, None, &help_msg); + span_lint_and_help(cx, FILETYPE_IS_FILE, span, lint_msg, None, help_msg); } 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 9b656531957f..581e3b308c3c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs @@ -16,20 +16,18 @@ use std::borrow::Cow; use super::{MANUAL_FILTER_MAP, MANUAL_FIND_MAP, OPTION_FILTER_MAP, RESULT_FILTER_MAP}; -fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) -> bool { +fn is_method(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol) -> bool { match &expr.kind { - hir::ExprKind::Path(QPath::TypeRelative(_, mname)) => mname.ident.name == method_name, - hir::ExprKind::Path(QPath::Resolved(_, segments)) => { - segments.segments.last().unwrap().ident.name == method_name - }, - hir::ExprKind::MethodCall(segment, _, _, _) => segment.ident.name == method_name, - hir::ExprKind::Closure(&hir::Closure { body, .. }) => { + ExprKind::Path(QPath::TypeRelative(_, mname)) => mname.ident.name == method_name, + ExprKind::Path(QPath::Resolved(_, segments)) => segments.segments.last().unwrap().ident.name == method_name, + ExprKind::MethodCall(segment, _, _, _) => segment.ident.name == method_name, + ExprKind::Closure(&Closure { body, .. }) => { let body = cx.tcx.hir().body(body); let closure_expr = peel_blocks(body.value); match closure_expr.kind { - hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, receiver, ..) => { + ExprKind::MethodCall(PathSegment { ident, .. }, receiver, ..) => { if ident.name == method_name - && let hir::ExprKind::Path(path) = &receiver.kind + && let ExprKind::Path(path) = &receiver.kind && let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id) && !body.params.is_empty() { @@ -45,10 +43,10 @@ fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) -> } } -fn is_option_filter_map(cx: &LateContext<'_>, filter_arg: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) -> bool { +fn is_option_filter_map(cx: &LateContext<'_>, filter_arg: &Expr<'_>, map_arg: &Expr<'_>) -> bool { is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym!(is_some)) } -fn is_ok_filter_map(cx: &LateContext<'_>, filter_arg: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) -> bool { +fn is_ok_filter_map(cx: &LateContext<'_>, filter_arg: &Expr<'_>, map_arg: &Expr<'_>) -> bool { is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym!(is_ok)) } @@ -267,10 +265,10 @@ impl<'tcx> OffendingFilterExpr<'tcx> { /// is `filter(|x| x.is_some()).map(|x| x.unwrap())` fn is_filter_some_map_unwrap( cx: &LateContext<'_>, - expr: &hir::Expr<'_>, - filter_recv: &hir::Expr<'_>, - filter_arg: &hir::Expr<'_>, - map_arg: &hir::Expr<'_>, + expr: &Expr<'_>, + filter_recv: &Expr<'_>, + filter_arg: &Expr<'_>, + map_arg: &Expr<'_>, ) -> bool { let iterator = is_trait_method(cx, expr, sym::Iterator); let option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(filter_recv), sym::Option); @@ -279,12 +277,7 @@ fn is_filter_some_map_unwrap( } /// is `filter(|x| x.is_ok()).map(|x| x.unwrap())` -fn is_filter_ok_map_unwrap( - cx: &LateContext<'_>, - expr: &hir::Expr<'_>, - filter_arg: &hir::Expr<'_>, - map_arg: &hir::Expr<'_>, -) -> bool { +fn is_filter_ok_map_unwrap(cx: &LateContext<'_>, expr: &Expr<'_>, filter_arg: &Expr<'_>, map_arg: &Expr<'_>) -> bool { // result has no filter, so we only check for iterators let iterator = is_trait_method(cx, expr, sym::Iterator); iterator && is_ok_filter_map(cx, filter_arg, map_arg) @@ -294,12 +287,12 @@ fn is_filter_ok_map_unwrap( #[allow(clippy::too_many_arguments)] pub(super) fn check( cx: &LateContext<'_>, - expr: &hir::Expr<'_>, - filter_recv: &hir::Expr<'_>, - filter_arg: &hir::Expr<'_>, + expr: &Expr<'_>, + filter_recv: &Expr<'_>, + filter_arg: &Expr<'_>, filter_span: Span, - map_recv: &hir::Expr<'_>, - map_arg: &hir::Expr<'_>, + map_recv: &Expr<'_>, + map_arg: &Expr<'_>, map_span: Span, is_find: bool, ) { @@ -393,7 +386,7 @@ pub(super) fn check( ) }, }; - span_lint_and_then(cx, lint, span, &msg, |diag| { + span_lint_and_then(cx, lint, span, msg, |diag| { diag.span_suggestion(span, "try", sugg, applicability); if let Some((note, span)) = note_and_span { @@ -405,9 +398,9 @@ pub(super) fn check( fn is_find_or_filter<'a>( cx: &LateContext<'a>, - map_recv: &hir::Expr<'_>, - filter_arg: &hir::Expr<'_>, - map_arg: &hir::Expr<'_>, + map_recv: &Expr<'_>, + filter_arg: &Expr<'_>, + map_arg: &Expr<'_>, ) -> Option<(Ident, CheckResult<'a>)> { if is_trait_method(cx, map_recv, sym::Iterator) // filter(|x| ...is_some())... diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs index 8291c373f371..999df875c753 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::{is_expr_untyped_identity_function, is_trait_method}; +use clippy_utils::{is_expr_identity_function, is_expr_untyped_identity_function, is_trait_method}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -7,8 +7,20 @@ use rustc_span::{sym, Span}; use super::FILTER_MAP_IDENTITY; +fn is_identity(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option { + if is_expr_untyped_identity_function(cx, expr) { + return Some(Applicability::MachineApplicable); + } + if is_expr_identity_function(cx, expr) { + return Some(Applicability::Unspecified); + } + None +} + pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_map_arg: &hir::Expr<'_>, filter_map_span: Span) { - if is_trait_method(cx, expr, sym::Iterator) && is_expr_untyped_identity_function(cx, filter_map_arg) { + if is_trait_method(cx, expr, sym::Iterator) + && let Some(applicability) = is_identity(cx, filter_map_arg) + { span_lint_and_sugg( cx, FILTER_MAP_IDENTITY, @@ -16,7 +28,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_map_arg: "use of `filter_map` with an identity function", "try", "flatten()".to_string(), - Applicability::MachineApplicable, + applicability, ); } } diff --git a/src/tools/clippy/clippy_lints/src/methods/get_first.rs b/src/tools/clippy/clippy_lints/src/methods/get_first.rs index 55fcf3728940..f4465e654c2e 100644 --- a/src/tools/clippy/clippy_lints/src/methods/get_first.rs +++ b/src/tools/clippy/clippy_lints/src/methods/get_first.rs @@ -32,7 +32,7 @@ pub(super) fn check<'tcx>( cx, GET_FIRST, expr.span, - &format!("accessing first element with `{slice_name}.get(0)`"), + format!("accessing first element with `{slice_name}.get(0)`"), "try", format!("{slice_name}.first()"), app, @@ -44,7 +44,7 @@ pub(super) fn check<'tcx>( cx, GET_FIRST, expr.span, - &format!("accessing first element with `{slice_name}.get(0)`"), + format!("accessing first element with `{slice_name}.get(0)`"), "try", format!("{slice_name}.front()"), app, diff --git a/src/tools/clippy/clippy_lints/src/methods/get_last_with_len.rs b/src/tools/clippy/clippy_lints/src/methods/get_last_with_len.rs index 3bdc154df049..620376511342 100644 --- a/src/tools/clippy/clippy_lints/src/methods/get_last_with_len.rs +++ b/src/tools/clippy/clippy_lints/src/methods/get_last_with_len.rs @@ -44,7 +44,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: cx, GET_LAST_WITH_LEN, expr.span, - &format!("accessing last element with `{recv_snippet}.get({recv_snippet}.len() - 1)`"), + format!("accessing last element with `{recv_snippet}.get({recv_snippet}.len() - 1)`"), "try", format!("{recv_snippet}.{method}()"), applicability, diff --git a/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs index afdcb3b65492..455274a44285 100644 --- a/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs @@ -70,7 +70,7 @@ pub(super) fn check<'tcx>( cx, GET_UNWRAP, span, - &format!("called `.get{mut_str}().unwrap()` on a {caller_type}. Using `[]` is more clear and more concise"), + format!("called `.get{mut_str}().unwrap()` on a {caller_type}. Using `[]` is more clear and more concise"), "try", format!( "{borrow_str}{}[{get_args_str}]", diff --git a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs index 78a553eb8c0d..c510cd915d0c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs +++ b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs @@ -27,7 +27,7 @@ pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv cx, IMPLICIT_CLONE, expr.span, - &format!("implicitly cloning a `{ty_name}` by calling `{method_name}` on its dereferenced type"), + format!("implicitly cloning a `{ty_name}` by calling `{method_name}` on its dereferenced type"), "consider using", if ref_count > 1 { format!("({}{recv_snip}).clone()", "*".repeat(ref_count - 1)) diff --git a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs index efc3ddd20b4b..230a8eb2ec47 100644 --- a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs +++ b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs @@ -32,7 +32,7 @@ pub fn check( cx, INEFFICIENT_TO_STRING, expr.span, - &format!("calling `to_string` on `{arg_ty}`"), + format!("calling `to_string` on `{arg_ty}`"), |diag| { diag.help(format!( "`{self_ty}` implements `ToString` through a slower blanket impl, but `{deref_self_ty}` has a fast specialization of `ToString`" diff --git a/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs b/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs index 80160d17c82d..bbc7ce8d78ab 100644 --- a/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs +++ b/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs @@ -27,7 +27,7 @@ pub(super) fn check( cx, INTO_ITER_ON_REF, method_span, - &format!("this `.into_iter()` call is equivalent to `.{method_name}()` and will not consume the `{kind}`",), + format!("this `.into_iter()` call is equivalent to `.{method_name}()` and will not consume the `{kind}`",), "call directly", method_name.to_string(), Applicability::MachineApplicable, diff --git a/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs b/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs index e963950960ae..210e4ae0a7bc 100644 --- a/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs +++ b/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs @@ -36,7 +36,7 @@ pub(super) fn check<'tcx>( cx, IS_DIGIT_ASCII_RADIX, expr.span, - &format!("use of `char::is_digit` with literal radix of {num}"), + format!("use of `char::is_digit` with literal radix of {num}"), "try", format!( "{}.{replacement}()", diff --git a/src/tools/clippy/clippy_lints/src/methods/is_empty.rs b/src/tools/clippy/clippy_lints/src/methods/is_empty.rs index 7fe66062251b..d921b7ea14f5 100644 --- a/src/tools/clippy/clippy_lints/src/methods/is_empty.rs +++ b/src/tools/clippy/clippy_lints/src/methods/is_empty.rs @@ -23,7 +23,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, receiver: &Expr<'_ cx, CONST_IS_EMPTY, expr.span, - &format!("this expression always evaluates to {init_is_empty:?}"), + format!("this expression always evaluates to {init_is_empty:?}"), ); } } diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs b/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs index dd741cd43f94..49de83885a1c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs @@ -17,7 +17,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, method_name: &str, expr: &hir: cx, ITER_CLONED_COLLECT, to_replace, - &format!( + format!( "called `iter().{method_name}().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \ more readable" ), diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_count.rs b/src/tools/clippy/clippy_lints/src/methods/iter_count.rs index bcddc7c786a5..209cf2fcc0a4 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_count.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_count.rs @@ -37,7 +37,7 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E cx, ITER_COUNT, expr.span, - &format!("called `.{iter_method}().count()` on a `{caller_type}`"), + format!("called `.{iter_method}().count()` on a `{caller_type}`"), "try", format!( "{}.len()", diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs b/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs index 9f84321ced4a..12647ea1ffcb 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs @@ -55,7 +55,7 @@ fn is_method( } } match expr.kind { - hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, recv, ..) => { + ExprKind::MethodCall(hir::PathSegment { ident, .. }, recv, ..) => { // compare the identifier of the receiver to the parameter // we are in a filter => closure has a single parameter and a single, non-block // expression, this means that the parameter shadows all outside variables with @@ -73,7 +73,7 @@ fn is_method( // This is used to check for complete paths via `|a| std::option::Option::is_some(a)` // this then unwraps to a path with `QPath::TypeRelative` // we pass the params as they've been passed to the current call through the closure - hir::ExprKind::Call(expr, [param]) => { + ExprKind::Call(expr, [param]) => { // this will hit the `QPath::TypeRelative` case and check that the method name is correct if is_method(cx, expr, type_symbol, method_name, params) // we then check that this is indeed passing the parameter of the closure @@ -85,7 +85,7 @@ fn is_method( } false }, - hir::ExprKind::Path(QPath::TypeRelative(ty, mname)) => { + ExprKind::Path(QPath::TypeRelative(ty, mname)) => { let ty = cx.typeck_results().node_type(ty.hir_id); if let Some(did) = cx.tcx.get_diagnostic_item(type_symbol) && ty.ty_adt_def() == cx.tcx.type_of(did).skip_binder().ty_adt_def() @@ -94,7 +94,7 @@ fn is_method( } false }, - hir::ExprKind::Closure(&hir::Closure { body, .. }) => { + ExprKind::Closure(&hir::Closure { body, .. }) => { let body = cx.tcx.hir().body(body); let closure_expr = peel_blocks(body.value); let params = body.params.iter().map(|param| param.pat).collect::>(); @@ -107,8 +107,8 @@ fn is_method( fn parent_is_map(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { if let Some(expr) = get_parent_expr(cx, expr) && is_trait_method(cx, expr, sym::Iterator) - && let hir::ExprKind::MethodCall(path, _, _, _) = expr.kind - && path.ident.name == rustc_span::sym::map + && let ExprKind::MethodCall(path, _, _, _) = expr.kind + && path.ident.name == sym::map { return true; } @@ -148,7 +148,7 @@ fn expression_type( { return None; } - if let hir::ExprKind::MethodCall(_, receiver, _, _) = expr.kind + if let ExprKind::MethodCall(_, receiver, _, _) = expr.kind && let receiver_ty = cx.typeck_results().expr_ty(receiver) && let Some(iter_item_ty) = get_iterator_item_ty(cx, receiver_ty) { diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs index 1431a5db2d96..b9fec0c4f80a 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs @@ -54,7 +54,7 @@ pub(super) fn check<'tcx>( cx, ITER_KV_MAP, expr.span, - &format!("iterating on a map's {replacement_kind}s"), + format!("iterating on a map's {replacement_kind}s"), "try", format!("{recv_snippet}.{into_prefix}{replacement_kind}s()"), applicability, @@ -64,7 +64,7 @@ pub(super) fn check<'tcx>( cx, ITER_KV_MAP, expr.span, - &format!("iterating on a map's {replacement_kind}s"), + format!("iterating on a map's {replacement_kind}s"), "try", format!( "{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{}{bound_ident}| {})", diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs b/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs index 5b0b70b4b965..e31fa2f777d8 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs @@ -28,7 +28,7 @@ pub(super) fn check<'tcx>( cx, ITER_NTH, expr.span, - &format!("called `.{iter_method}().nth()` on a {caller_type}"), + format!("called `.{iter_method}().nth()` on a {caller_type}"), |diag| { let get_method = if iter_method == "iter_mut" { "get_mut" } else { "get" }; diag.span_suggestion_verbose( diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs index 19b7e97339de..6c9bdcff8262 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs @@ -69,7 +69,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: &str, re cx, ITER_ON_SINGLE_ITEMS, expr.span, - &format!("`{method_name}` call on a collection with only one item"), + format!("`{method_name}` call on a collection with only one item"), "try", sugg, Applicability::MaybeIncorrect, @@ -79,7 +79,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: &str, re cx, ITER_ON_EMPTY_COLLECTIONS, expr.span, - &format!("`{method_name}` call on an empty collection"), + format!("`{method_name}` call on an empty collection"), "try", format!("{top_crate}::iter::empty()"), Applicability::MaybeIncorrect, diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs index b2fe129cd951..4729481320eb 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs @@ -60,7 +60,7 @@ pub(super) fn check<'tcx>( } if let Op::NeedlessMove(expr) = op { - let rustc_hir::ExprKind::Closure(closure) = expr.kind else { + let ExprKind::Closure(closure) = expr.kind else { return; }; let body @ Body { params: [p], .. } = cx.tcx.hir().body(closure.body) else { diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs b/src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs index 2ab721ace848..1378a07cbc47 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs @@ -20,7 +20,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span cx, ITER_WITH_DRAIN, span.with_hi(expr.span.hi()), - &format!("`drain(..)` used on a `{ty_name}`"), + format!("`drain(..)` used on a `{ty_name}`"), "try", "into_iter()".to_string(), Applicability::MaybeIncorrect, diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs index bf437db7e72a..9e3b313156eb 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -50,7 +50,7 @@ pub fn check( super::MANUAL_SATURATING_ARITHMETIC, expr.span, "manual saturating arithmetic", - &format!("consider using `saturating_{arith}`"), + format!("consider using `saturating_{arith}`"), format!( "{}.saturating_{arith}({})", snippet_with_applicability(cx, arith_lhs.span, "..", &mut applicability), diff --git a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs index c3c7a3a00330..0901268e9bdc 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs @@ -1,7 +1,7 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::{is_copy, is_type_diagnostic_item}; +use clippy_utils::ty::{is_copy, is_type_diagnostic_item, should_call_clone_as_function}; use clippy_utils::{is_diag_trait_item, match_def_path, paths, peel_blocks}; use rustc_errors::Applicability; use rustc_hir as hir; @@ -50,7 +50,7 @@ pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_ let closure_body = cx.tcx.hir().body(body); let closure_expr = peel_blocks(closure_body.value); match closure_body.params[0].pat.kind { - hir::PatKind::Ref(inner, hir::Mutability::Not) => { + hir::PatKind::Ref(inner, Mutability::Not) => { if let hir::PatKind::Binding(hir::BindingAnnotation::NONE, .., name, None) = inner.kind { if ident_eq(name, closure_expr) { lint_explicit_closure(cx, e.span, recv.span, true, msrv); @@ -124,6 +124,7 @@ fn handle_path( && let ty::Ref(_, ty, Mutability::Not) = ty.kind() && let ty::FnDef(_, lst) = cx.typeck_results().expr_ty(arg).kind() && lst.iter().all(|l| l.as_type() == Some(*ty)) + && !should_call_clone_as_function(cx, *ty) { lint_path(cx, e.span, recv.span, is_copy(cx, ty.peel_refs())); } @@ -160,7 +161,7 @@ fn lint_path(cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool) { MAP_CLONE, replace, "you are explicitly cloning with `.map()`", - &format!("consider calling the dedicated `{replacement}` method"), + format!("consider calling the dedicated `{replacement}` method"), format!( "{}.{replacement}()", snippet_with_applicability(cx, root, "..", &mut applicability), @@ -183,7 +184,7 @@ fn lint_explicit_closure(cx: &LateContext<'_>, replace: Span, root: Span, is_cop MAP_CLONE, replace, message, - &format!("consider calling the dedicated `{sugg_method}` method"), + format!("consider calling the dedicated `{sugg_method}` method"), format!( "{}.{sugg_method}()", snippet_with_applicability(cx, root, "..", &mut applicability), diff --git a/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs b/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs index 26ef0d10fed4..def8be2ef73d 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs @@ -21,8 +21,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, map_ cx, MAP_FLATTEN, expr.span.with_lo(map_span.lo()), - &format!("called `map(..).flatten()` on `{caller_ty_name}`"), - &format!("try replacing `map` with `{method_to_use}` and remove the `.flatten()`"), + format!("called `map(..).flatten()` on `{caller_ty_name}`"), + format!("try replacing `map` with `{method_to_use}` and remove the `.flatten()`"), format!("{method_to_use}({closure_snippet})"), applicability, ); diff --git a/src/tools/clippy/clippy_lints/src/methods/map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/map_identity.rs index 6da9a87f5eec..5dd7b1b02ade 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_identity.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_identity.rs @@ -29,7 +29,7 @@ pub(super) fn check( MAP_IDENTITY, sugg_span, "unnecessary map of the identity function", - &format!("remove the call to `{name}`"), + format!("remove the call to `{name}`"), String::new(), Applicability::MachineApplicable, ); diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index b6c474212cd4..2fb317c8c68e 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -231,8 +231,12 @@ declare_clippy_lint! { /// used instead. /// /// ### Why is this bad? - /// When applicable, `filter_map()` is more clear since it shows that - /// `Option` is used to produce 0 or 1 items. + /// `filter_map()` is known to always produce 0 or 1 output items per input item, + /// rather than however many the inner iterator type produces. + /// Therefore, it maintains the upper bound in `Iterator::size_hint()`, + /// and communicates to the reader that the input items are not being expanded into + /// multiple output items without their having to notice that the mapping function + /// returns an `Option`. /// /// ### Example /// ```no_run @@ -2998,13 +3002,22 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Looks for calls to ` as Any>::type_id`. + /// Looks for calls to `.type_id()` on a `Box`. /// /// ### Why is this bad? - /// This most certainly does not do what the user expects and is very easy to miss. - /// Calling `type_id` on a `Box` calls `type_id` on the `Box<..>` itself, - /// so this will return the `TypeId` of the `Box` type (not the type id - /// of the value referenced by the box!). + /// This almost certainly does not do what the user expects and can lead to subtle bugs. + /// Calling `.type_id()` on a `Box` returns a fixed `TypeId` of the `Box` itself, + /// rather than returning the `TypeId` of the underlying type behind the trait object. + /// + /// For `Box` specifically (and trait objects that have `Any` as its supertrait), + /// this lint will provide a suggestion, which is to dereference the receiver explicitly + /// to go from `Box` to `dyn Any`. + /// This makes sure that `.type_id()` resolves to a dynamic call on the trait object + /// and not on the box. + /// + /// If the fixed `TypeId` of the `Box` is the intended behavior, it's better to be explicit about it + /// and write `TypeId::of::>()`: + /// this makes it clear that a fixed `TypeId` is returned and not the `TypeId` of the implementor. /// /// ### Example /// ```rust,ignore @@ -3024,7 +3037,7 @@ declare_clippy_lint! { #[clippy::version = "1.73.0"] pub TYPE_ID_ON_BOX, suspicious, - "calling `.type_id()` on `Box`" + "calling `.type_id()` on a boxed trait object" } declare_clippy_lint! { @@ -4236,8 +4249,8 @@ impl_lint_pass!(Methods => [ /// Extracts a method call name, args, and `Span` of the method name. pub fn method_call<'tcx>( - recv: &'tcx hir::Expr<'tcx>, -) -> Option<(&'tcx str, &'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>], Span, Span)> { + recv: &'tcx Expr<'tcx>, +) -> Option<(&'tcx str, &'tcx Expr<'tcx>, &'tcx [Expr<'tcx>], Span, Span)> { if let ExprKind::MethodCall(path, receiver, args, call_span) = recv.kind { if !args.iter().any(|e| e.span.from_expansion()) && !receiver.span.from_expansion() { let name = path.ident.name.as_str(); @@ -4248,7 +4261,7 @@ pub fn method_call<'tcx>( } impl<'tcx> LateLintPass<'tcx> for Methods { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if expr.span.from_expansion() { return; } @@ -4256,12 +4269,12 @@ impl<'tcx> LateLintPass<'tcx> for Methods { self.check_methods(cx, expr); match expr.kind { - hir::ExprKind::Call(func, args) => { + ExprKind::Call(func, args) => { from_iter_instead_of_collect::check(cx, expr, args, func); unnecessary_fallible_conversions::check_function(cx, expr, func); manual_c_str_literals::check(cx, expr, func, args, &self.msrv); }, - hir::ExprKind::MethodCall(method_call, receiver, args, _) => { + ExprKind::MethodCall(method_call, receiver, args, _) => { let method_span = method_call.ident.span; or_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args); expect_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args); @@ -4273,7 +4286,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { single_char_pattern::check(cx, expr, method_call.ident.name, receiver, args); unnecessary_to_owned::check(cx, expr, method_call.ident.name, receiver, args, &self.msrv); }, - hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => { + ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => { let mut info = BinaryExprInfo { expr, chain: lhs, @@ -4320,12 +4333,12 @@ impl<'tcx> LateLintPass<'tcx> for Methods { cx, SHOULD_IMPLEMENT_TRAIT, impl_item.span, - &format!( + format!( "method `{}` can be confused for the standard trait method `{}::{}`", method_config.method_name, method_config.trait_name, method_config.method_name ), None, - &format!( + format!( "consider implementing the trait `{}` or choosing a less ambiguous method name", method_config.trait_name ), @@ -4995,9 +5008,9 @@ fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, /// Used for `lint_binary_expr_with_method_call`. #[derive(Copy, Clone)] struct BinaryExprInfo<'a> { - expr: &'a hir::Expr<'a>, - chain: &'a hir::Expr<'a>, - other: &'a hir::Expr<'a>, + expr: &'a Expr<'a>, + chain: &'a Expr<'a>, + other: &'a Expr<'a>, eq: bool, } diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs index 9e2fd92255e1..662e7746496a 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs @@ -107,7 +107,7 @@ pub(super) fn check<'tcx>( span.push_span_label(iter_call.span, "the iterator could be used here instead"); span_lint_hir_and_then( cx, - super::NEEDLESS_COLLECT, + NEEDLESS_COLLECT, collect_expr.hir_id, span, NEEDLESS_COLLECT_MSG, diff --git a/src/tools/clippy/clippy_lints/src/methods/open_options.rs b/src/tools/clippy/clippy_lints/src/methods/open_options.rs index 77484ab91a9d..d425b505a760 100644 --- a/src/tools/clippy/clippy_lints/src/methods/open_options.rs +++ b/src/tools/clippy/clippy_lints/src/methods/open_options.rs @@ -151,7 +151,7 @@ fn check_open_options(cx: &LateContext<'_>, settings: &[(OpenOption, Argument, S cx, NONSENSICAL_OPEN_OPTIONS, prev_span, - &format!("the method `{}` is called more than once", &option), + format!("the method `{}` is called more than once", &option), ); } } diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_cloned.rs index d7fec360fa2a..ba167f9d9c23 100644 --- a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_cloned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_cloned.rs @@ -15,7 +15,7 @@ pub(super) fn check(cx: &LateContext<'_>, cloned_recv: &Expr<'_>, cloned_ident_s cx, OPTION_AS_REF_CLONED, as_ref_ident_span.to(cloned_ident_span), - &format!("cloning an `Option<_>` using `.{method}().cloned()`"), + format!("cloning an `Option<_>` using `.{method}().cloned()`"), "this can be written more concisely by cloning the `Option<_>` directly", "clone".into(), Applicability::MachineApplicable, diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs index 88e2af15658f..cb57689b0c41 100644 --- a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs @@ -104,8 +104,8 @@ pub(super) fn check( cx, OPTION_AS_REF_DEREF, expr.span, - &msg, - &suggestion, + msg, + suggestion, hint, Applicability::MachineApplicable, ); diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs index ab36f854fcb1..efec9dd716dc 100644 --- a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -97,7 +97,7 @@ pub(super) fn check<'tcx>( } else { "map_or(, )" }; - let msg = &format!("called `map().unwrap_or({arg})` on an `Option` value"); + let msg = format!("called `map().unwrap_or({arg})` on an `Option` value"); span_lint_and_then(cx, MAP_UNWRAP_OR, expr.span, msg, |diag| { let map_arg_span = map_arg.span; diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs index 0602eeaa7041..583e04fb4b18 100644 --- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs +++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs @@ -97,7 +97,7 @@ pub(super) fn check<'tcx>( cx, UNWRAP_OR_DEFAULT, method_span.with_hi(span.hi()), - &format!("use of `{name}` to construct default value"), + format!("use of `{name}` to construct default value"), "try", format!("{sugg}()"), Applicability::MachineApplicable, @@ -167,7 +167,7 @@ pub(super) fn check<'tcx>( cx, OR_FUN_CALL, span_replace_word, - &format!("use of `{name}` followed by a function call"), + format!("use of `{name}` followed by a function call"), "try", format!("{name}_{suffix}({sugg})"), app, diff --git a/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs b/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs index 1148628b0844..28ca76832eb3 100644 --- a/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs +++ b/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs @@ -24,7 +24,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &' cx, RANGE_ZIP_WITH_LEN, expr.span, - &format!( + format!( "it is more idiomatic to use `{}.iter().enumerate()`", snippet(cx, recv.span, "_") ), diff --git a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs index ef1baa6c9882..ac5cc2f01e53 100644 --- a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs +++ b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs @@ -39,7 +39,7 @@ pub(super) fn check<'tcx>( && let closure_body = cx.tcx.hir().body(body) && let Some(closure_arg) = closure_body.params.first() { - if let hir::PatKind::Ref(..) = closure_arg.pat.kind { + if let PatKind::Ref(..) = closure_arg.pat.kind { Some(search_snippet.replacen('&', "", 1)) } else if let PatKind::Binding(..) = strip_pat_refs(closure_arg.pat).kind { // `find()` provides a reference to the item, but `any` does not, @@ -62,7 +62,7 @@ pub(super) fn check<'tcx>( cx, SEARCH_IS_SOME, method_span.with_hi(expr.span.hi()), - &msg, + msg, "consider using", format!( "any({})", @@ -76,7 +76,7 @@ pub(super) fn check<'tcx>( cx, SEARCH_IS_SOME, expr.span, - &msg, + msg, "consider using", format!( "!{iter}.any({})", @@ -94,7 +94,7 @@ pub(super) fn check<'tcx>( "" } ); - span_lint_and_help(cx, SEARCH_IS_SOME, expr.span, &msg, None, &hint); + span_lint_and_help(cx, SEARCH_IS_SOME, expr.span, msg, None, hint); } } // lint if `find()` is called by `String` or `&str` @@ -117,7 +117,7 @@ pub(super) fn check<'tcx>( cx, SEARCH_IS_SOME, method_span.with_hi(expr.span.hi()), - &msg, + msg, "consider using", format!("contains({find_arg})"), applicability, @@ -131,7 +131,7 @@ pub(super) fn check<'tcx>( cx, SEARCH_IS_SOME, expr.span, - &msg, + msg, "consider using", format!("!{string}.contains({find_arg})"), applicability, diff --git a/src/tools/clippy/clippy_lints/src/methods/stable_sort_primitive.rs b/src/tools/clippy/clippy_lints/src/methods/stable_sort_primitive.rs index 0f4c97022dbe..aef14435d8af 100644 --- a/src/tools/clippy/clippy_lints/src/methods/stable_sort_primitive.rs +++ b/src/tools/clippy/clippy_lints/src/methods/stable_sort_primitive.rs @@ -17,7 +17,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx cx, STABLE_SORT_PRIMITIVE, e.span, - &format!("used `sort` on primitive type `{slice_type}`"), + format!("used `sort` on primitive type `{slice_type}`"), |diag| { let mut app = Applicability::MachineApplicable; let recv_snip = snippet_with_context(cx, recv.span, e.span.ctxt(), "..", &mut app).0; diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs index 946cdb49d274..55ae9746298f 100644 --- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs +++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs @@ -53,7 +53,7 @@ fn lint_needless(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_ cx, NEEDLESS_SPLITN, expr.span, - &format!("unnecessary use of `{r}splitn`"), + format!("unnecessary use of `{r}splitn`"), "try", format!( "{}.{r}split({})", @@ -154,7 +154,7 @@ fn check_manual_split_once_indirect( let self_snip = snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0; let pat_snip = snippet_with_context(cx, pat_arg.span, ctxt, "..", &mut app).0; - span_lint_and_then(cx, MANUAL_SPLIT_ONCE, local.span, &msg, |diag| { + span_lint_and_then(cx, MANUAL_SPLIT_ONCE, local.span, msg, |diag| { diag.span_label(first.span, "first usage here"); diag.span_label(second.span, "second usage here"); diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs index c45212581eed..ff5c1d1a4019 100644 --- a/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs +++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs @@ -37,6 +37,6 @@ pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, se ) }; - span_lint_and_note(cx, SUSPICIOUS_SPLITN, expr.span, &msg, None, note_msg); + span_lint_and_note(cx, SUSPICIOUS_SPLITN, expr.span, msg, None, note_msg); } } diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs index 60864902a489..ce7aefed01f4 100644 --- a/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs @@ -23,7 +23,7 @@ pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) - cx, SUSPICIOUS_TO_OWNED, expr.span, - &with_forced_trimmed_paths!(format!( + with_forced_trimmed_paths!(format!( "this `to_owned` call clones the {input_type} itself and does not cause the {input_type} contents to become owned" )), |diag| { diff --git a/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs b/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs index 4917936a9322..6f9b38fcf83c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs +++ b/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs @@ -5,13 +5,33 @@ use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; +use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::{self, ExistentialPredicate, Ty}; use rustc_span::{sym, Span}; -fn is_dyn_any(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { +/// Checks if the given type is `dyn Any`, or a trait object that has `Any` as a supertrait. +/// Only in those cases will its vtable have a `type_id` method that returns the implementor's +/// `TypeId`, and only in those cases can we give a proper suggestion to dereference the box. +/// +/// If this returns false, then `.type_id()` likely (this may have FNs) will not be what the user +/// expects in any case and dereferencing it won't help either. It will likely require some +/// other changes, but it is still worth emitting a lint. +/// See for more details. +fn is_subtrait_of_any(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { if let ty::Dynamic(preds, ..) = ty.kind() { preds.iter().any(|p| match p.skip_binder() { - ExistentialPredicate::Trait(tr) => cx.tcx.is_diagnostic_item(sym::Any, tr.def_id), + ExistentialPredicate::Trait(tr) => { + cx.tcx.is_diagnostic_item(sym::Any, tr.def_id) + || cx + .tcx + .super_predicates_of(tr.def_id) + .predicates + .iter() + .any(|(clause, _)| { + matches!(clause.kind().skip_binder(), ty::ClauseKind::Trait(super_tr) + if cx.tcx.is_diagnostic_item(sym::Any, super_tr.def_id())) + }) + }, _ => false, }) } else { @@ -26,36 +46,42 @@ pub(super) fn check(cx: &LateContext<'_>, receiver: &Expr<'_>, call_span: Span) && let ty::Ref(_, ty, _) = recv_ty.kind() && let ty::Adt(adt, args) = ty.kind() && adt.is_box() - && is_dyn_any(cx, args.type_at(0)) + && let inner_box_ty = args.type_at(0) + && let ty::Dynamic(..) = inner_box_ty.kind() { + let ty_name = with_forced_trimmed_paths!(ty.to_string()); + span_lint_and_then( cx, TYPE_ID_ON_BOX, call_span, - "calling `.type_id()` on a `Box`", + format!("calling `.type_id()` on `{ty_name}`"), |diag| { let derefs = recv_adjusts .iter() .filter(|adj| matches!(adj.kind, Adjust::Deref(None))) .count(); - let mut sugg = "*".repeat(derefs + 1); - sugg += &snippet(cx, receiver.span, ""); - diag.note( - "this returns the type id of the literal type `Box` instead of the \ + "this returns the type id of the literal type `Box<_>` instead of the \ type id of the boxed value, which is most likely not what you want", ) - .note( - "if this is intentional, use `TypeId::of::>()` instead, \ - which makes it more clear", - ) - .span_suggestion( - receiver.span, - "consider dereferencing first", - format!("({sugg})"), - Applicability::MaybeIncorrect, - ); + .note(format!( + "if this is intentional, use `TypeId::of::<{ty_name}>()` instead, \ + which makes it more clear" + )); + + if is_subtrait_of_any(cx, inner_box_ty) { + let mut sugg = "*".repeat(derefs + 1); + sugg += &snippet(cx, receiver.span, ""); + + diag.span_suggestion( + receiver.span, + "consider dereferencing first", + format!("({sugg})"), + Applicability::MaybeIncorrect, + ); + } }, ); } diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs index fabf3fa0c0c8..daf99d986142 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -60,7 +60,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a UNNECESSARY_FIND_MAP }, expr.span, - &format!("this `.{name}` can be written more simply using `.{sugg}`"), + format!("this `.{name}` can be written more simply using `.{sugg}`"), ); } } diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_get_then_check.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_get_then_check.rs index cc8053ef507a..f6184222d8e9 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_get_then_check.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_get_then_check.rs @@ -58,7 +58,7 @@ pub(super) fn check( cx, UNNECESSARY_GET_THEN_CHECK, both_calls_span, - &format!("unnecessary use of `{snippet}`"), + format!("unnecessary use of `{snippet}`"), "replace it with", suggestion, Applicability::MaybeIncorrect, @@ -70,7 +70,7 @@ pub(super) fn check( cx, UNNECESSARY_GET_THEN_CHECK, both_calls_span, - &format!("unnecessary use of `{snippet}`"), + format!("unnecessary use of `{snippet}`"), |diag| { diag.span_suggestion( full_span, diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs index 36497d59a5a8..520dcb2d52dc 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -61,7 +61,7 @@ pub fn check_for_loop_iter( cx, UNNECESSARY_TO_OWNED, expr.span, - &format!("unnecessary use of `{method_name}`"), + format!("unnecessary use of `{method_name}`"), |diag| { // If `check_into_iter_call_arg` called `check_for_loop_iter` because a call to // a `to_owned`-like function was removed, then the next suggestion may be diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs index 1b2bfbf4090e..494d71fc053f 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs @@ -63,7 +63,7 @@ pub(super) fn check( let help_message = format!("used `{method}()` on `{constructor}` value"); let suggestion_message = format!("remove the `{constructor}` and `{method}()`"); - span_lint_and_then(cx, UNNECESSARY_LITERAL_UNWRAP, expr.span, &help_message, |diag| { + span_lint_and_then(cx, UNNECESSARY_LITERAL_UNWRAP, expr.span, help_message, |diag| { let suggestions = match (constructor, method, ty) { ("None", "unwrap", _) => Some(vec![(expr.span, "panic!()".to_string())]), ("None", "expect", _) => Some(vec![ diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index e58d47764279..23fc323446e0 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -18,8 +18,7 @@ use rustc_lint::LateContext; use rustc_middle::mir::Mutability; use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref}; use rustc_middle::ty::{ - self, ClauseKind, GenericArg, GenericArgKind, GenericArgsRef, ParamTy, ProjectionPredicate, - TraitPredicate, Ty, + self, ClauseKind, GenericArg, GenericArgKind, GenericArgsRef, ParamTy, ProjectionPredicate, TraitPredicate, Ty, }; use rustc_span::{sym, Symbol}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; @@ -138,7 +137,7 @@ fn check_addr_of_expr( cx, UNNECESSARY_TO_OWNED, parent.span, - &format!("unnecessary use of `{method_name}`"), + format!("unnecessary use of `{method_name}`"), "use", format!( "{:&>width$}{receiver_snippet}", @@ -163,7 +162,7 @@ fn check_addr_of_expr( cx, UNNECESSARY_TO_OWNED, parent.span, - &format!("unnecessary use of `{method_name}`"), + format!("unnecessary use of `{method_name}`"), "use", receiver_snippet, Applicability::MachineApplicable, @@ -173,7 +172,7 @@ fn check_addr_of_expr( cx, UNNECESSARY_TO_OWNED, expr.span.with_lo(receiver.span.hi()), - &format!("unnecessary use of `{method_name}`"), + format!("unnecessary use of `{method_name}`"), "remove this", String::new(), Applicability::MachineApplicable, @@ -188,7 +187,7 @@ fn check_addr_of_expr( cx, UNNECESSARY_TO_OWNED, parent.span, - &format!("unnecessary use of `{method_name}`"), + format!("unnecessary use of `{method_name}`"), "use", format!("{receiver_snippet}.as_ref()"), Applicability::MachineApplicable, @@ -232,7 +231,7 @@ fn check_into_iter_call_arg( cx, UNNECESSARY_TO_OWNED, parent.span, - &format!("unnecessary use of `{method_name}`"), + format!("unnecessary use of `{method_name}`"), "use", format!("{receiver_snippet}.iter().{cloned_or_copied}()"), Applicability::MaybeIncorrect, @@ -271,7 +270,7 @@ fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symb cx, UNNECESSARY_TO_OWNED, parent.span, - &format!("unnecessary use of `{method_name}`"), + format!("unnecessary use of `{method_name}`"), "use", format!("{receiver_snippet}{as_ref}.split({arg_snippet})"), Applicability::MaybeIncorrect, @@ -350,7 +349,7 @@ fn check_other_call_arg<'tcx>( cx, UNNECESSARY_TO_OWNED, maybe_arg.span, - &format!("unnecessary use of `{method_name}`"), + format!("unnecessary use of `{method_name}`"), "use", format!("{:&>n_refs$}{receiver_snippet}", ""), Applicability::MachineApplicable, @@ -642,7 +641,7 @@ fn check_if_applicable_to_argument<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'tcx cx, UNNECESSARY_TO_OWNED, arg.span, - &format!("unnecessary use of `{method_name}`"), + format!("unnecessary use of `{method_name}`"), "replace it with", if original_arg_ty.is_array() { format!("{snippet}.as_slice()") diff --git a/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs b/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs index 7bd16b473ce4..516b8984ad79 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs @@ -69,7 +69,7 @@ pub(super) fn check( cx, variant.lint(), expr.span, - &format!("used `{}()` on {kind} value", variant.method_name(is_err)), + format!("used `{}()` on {kind} value", variant.method_name(is_err)), |diag| { diag.note(format!("if this value is {none_prefix}`{none_value}`, it will panic")); diff --git a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs index b8baad18cc8d..ae2b6e6347eb 100644 --- a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs +++ b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::walk_ptrs_ty_depth; +use clippy_utils::ty::{should_call_clone_as_function, walk_ptrs_ty_depth}; use clippy_utils::{ get_parent_expr, is_diag_trait_item, match_def_path, path_to_local_id, paths, peel_blocks, strip_pat_refs, }; @@ -68,7 +68,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, cx, USELESS_ASREF, expr.span, - &format!("this call to `{call_name}` does nothing"), + format!("this call to `{call_name}` does nothing"), "try", snippet_with_applicability(cx, recvr.span, "..", &mut applicability).to_string(), applicability, @@ -93,6 +93,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, // And that it only has one argument. && let [arg] = args && is_calling_clone(cx, arg) + // And that we are not recommending recv.clone() over Arc::clone() or similar + && !should_call_clone_as_function(cx, rcv_ty) { lint_as_ref_clone(cx, expr.span.with_hi(parent.span.hi()), recvr, call_name); } @@ -157,7 +159,7 @@ fn lint_as_ref_clone(cx: &LateContext<'_>, span: Span, recvr: &hir::Expr<'_>, ca cx, USELESS_ASREF, span, - &format!("this call to `{call_name}.map(...)` does nothing"), + format!("this call to `{call_name}.map(...)` does nothing"), "try", format!( "{}.clone()", diff --git a/src/tools/clippy/clippy_lints/src/methods/utils.rs b/src/tools/clippy/clippy_lints/src/methods/utils.rs index 3a0305b4d553..ef00c812d510 100644 --- a/src/tools/clippy/clippy_lints/src/methods/utils.rs +++ b/src/tools/clippy/clippy_lints/src/methods/utils.rs @@ -3,7 +3,6 @@ use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{get_parent_expr, path_to_local_id, usage}; use rustc_ast::ast; use rustc_errors::Applicability; -use rustc_hir as hir; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, Mutability, Pat}; use rustc_lint::LateContext; @@ -13,9 +12,9 @@ use rustc_span::symbol::sym; pub(super) fn derefs_to_slice<'tcx>( cx: &LateContext<'tcx>, - expr: &'tcx hir::Expr<'tcx>, + expr: &'tcx Expr<'tcx>, ty: Ty<'tcx>, -) -> Option<&'tcx hir::Expr<'tcx>> { +) -> Option<&'tcx Expr<'tcx>> { fn may_slice<'a>(cx: &LateContext<'a>, ty: Ty<'a>) -> bool { match ty.kind() { ty::Slice(_) => true, @@ -27,7 +26,7 @@ pub(super) fn derefs_to_slice<'tcx>( } } - if let hir::ExprKind::MethodCall(path, self_arg, ..) = &expr.kind { + if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind { if path.ident.name == sym::iter && may_slice(cx, cx.typeck_results().expr_ty(self_arg)) { Some(self_arg) } else { @@ -51,10 +50,10 @@ pub(super) fn derefs_to_slice<'tcx>( pub(super) fn get_hint_if_single_char_arg( cx: &LateContext<'_>, - arg: &hir::Expr<'_>, + arg: &Expr<'_>, applicability: &mut Applicability, ) -> Option { - if let hir::ExprKind::Lit(lit) = &arg.kind + if let ExprKind::Lit(lit) = &arg.kind && let ast::LitKind::Str(r, style) = lit.node && let string = r.as_str() && string.chars().count() == 1 diff --git a/src/tools/clippy/clippy_lints/src/methods/verbose_file_reads.rs b/src/tools/clippy/clippy_lints/src/methods/verbose_file_reads.rs index 2fe5ae9a9ad8..181b413a1828 100644 --- a/src/tools/clippy/clippy_lints/src/methods/verbose_file_reads.rs +++ b/src/tools/clippy/clippy_lints/src/methods/verbose_file_reads.rs @@ -17,7 +17,7 @@ pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, - (msg, help): (&str, &str), + (msg, help): (&'static str, &'static str), ) { if is_trait_method(cx, expr, sym::IoRead) && matches!(recv.kind, ExprKind::Path(QPath::Resolved(None, _))) diff --git a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs index 0a810a13f3f9..28068c634732 100644 --- a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs +++ b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs @@ -137,7 +137,7 @@ pub(super) fn check<'tcx>( cx, WRONG_SELF_CONVENTION, first_arg_span, - &format!( + format!( "{suggestion} usually take {}", &self_kinds .iter() diff --git a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs index 0016fb335173..c6b7f5b0ce27 100644 --- a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs +++ b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs @@ -181,7 +181,7 @@ fn emit_min_ident_chars(conf: &MinIdentChars, cx: &impl LintContext, ident: &str conf.min_ident_chars_threshold, )) }; - span_lint(cx, MIN_IDENT_CHARS, span, &help); + span_lint(cx, MIN_IDENT_CHARS, span, help); } /// Attempt to convert the node to an [`ItemKind::Use`] node. diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs index 11fecb7d72e2..f5ce8dd29b1a 100644 --- a/src/tools/clippy/clippy_lints/src/misc.rs +++ b/src/tools/clippy/clippy_lints/src/misc.rs @@ -246,7 +246,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { cx, USED_UNDERSCORE_BINDING, expr.span, - &format!( + format!( "used binding `{name}` which is prefixed with an underscore. A leading \ underscore signals that a binding will not be used" ), diff --git a/src/tools/clippy/clippy_lints/src/misc_early/builtin_type_shadow.rs b/src/tools/clippy/clippy_lints/src/misc_early/builtin_type_shadow.rs index 9f6b0bdc7a45..662f7cd8500c 100644 --- a/src/tools/clippy/clippy_lints/src/misc_early/builtin_type_shadow.rs +++ b/src/tools/clippy/clippy_lints/src/misc_early/builtin_type_shadow.rs @@ -12,7 +12,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, param: &GenericParam) { cx, BUILTIN_TYPE_SHADOW, param.ident.span, - &format!("this generic shadows the built-in type `{}`", prim_ty.name()), + format!("this generic shadows the built-in type `{}`", prim_ty.name()), ); } } diff --git a/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs b/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs index eda4376f200e..e0a5e401a50a 100644 --- a/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs +++ b/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs @@ -16,7 +16,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit_span: Span, lit_snip: &str, suffi cx, SEPARATED_LITERAL_SUFFIX, lit_span, - &format!("{sugg_type} type suffix should not be separated by an underscore"), + format!("{sugg_type} type suffix should not be separated by an underscore"), "remove the underscore", format!("{}{suffix}", &lit_snip[..maybe_last_sep_idx]), Applicability::MachineApplicable, @@ -26,7 +26,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit_span: Span, lit_snip: &str, suffi cx, UNSEPARATED_LITERAL_SUFFIX, lit_span, - &format!("{sugg_type} type suffix should be separated by an underscore"), + format!("{sugg_type} type suffix should be separated by an underscore"), "add an underscore", format!("{}_{suffix}", &lit_snip[..=maybe_last_sep_idx]), Applicability::MachineApplicable, 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 abe5b00e888a..2f5499d7656f 100644 --- a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs +++ b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs @@ -394,7 +394,7 @@ impl EarlyLintPass for MiscEarlyLints { cx, DUPLICATE_UNDERSCORE_ARGUMENT, *correspondence, - &format!( + format!( "`{arg_name}` already exists, having another argument having almost the same \ name makes code comprehension and documentation more difficult" ), diff --git a/src/tools/clippy/clippy_lints/src/misc_early/redundant_pattern.rs b/src/tools/clippy/clippy_lints/src/misc_early/redundant_pattern.rs index d7bb0616acb0..d5b5b2bf2dd1 100644 --- a/src/tools/clippy/clippy_lints/src/misc_early/redundant_pattern.rs +++ b/src/tools/clippy/clippy_lints/src/misc_early/redundant_pattern.rs @@ -12,7 +12,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { cx, REDUNDANT_PATTERN, pat.span, - &format!( + format!( "the `{} @ _` pattern can be written as just `{}`", ident.name, ident.name, ), diff --git a/src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs b/src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs index 676e5d40bb77..cb305cf5582d 100644 --- a/src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs +++ b/src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs @@ -27,7 +27,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { pat.span, "all the struct fields are matched to a wildcard pattern, consider using `..`", None, - &format!("try with `{type_name} {{ .. }}` instead"), + format!("try with `{type_name} {{ .. }}` instead"), ); return; } @@ -63,7 +63,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { "you matched a field with a wildcard pattern, consider using `..` \ instead", None, - &format!("try with `{type_name} {{ {}, .. }}`", normal[..].join(", ")), + format!("try with `{type_name} {{ {}, .. }}`", normal[..].join(", ")), ); } } diff --git a/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs b/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs index 0739b49fe190..0842a8728247 100644 --- a/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs +++ b/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs @@ -101,7 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeParamMismatch { "try `{}`, or a name that does not conflict with `{type_name}`'s generic params", type_param_names[i] ); - span_lint_and_help(cx, MISMATCHING_TYPE_PARAM_ORDER, *impl_param_span, &msg, None, &help); + span_lint_and_help(cx, MISMATCHING_TYPE_PARAM_ORDER, *impl_param_span, msg, None, help); } } } diff --git a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs index 39d4ea74b312..c29e46b941c6 100644 --- a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs @@ -65,7 +65,7 @@ declare_clippy_lint! { } declare_lint_pass!(MissingAssertsForIndexing => [MISSING_ASSERTS_FOR_INDEXING]); -fn report_lint(cx: &LateContext<'_>, full_span: Span, msg: &str, indexes: &[Span], f: F) +fn report_lint(cx: &LateContext<'_>, full_span: Span, msg: &'static str, indexes: &[Span], f: F) where F: FnOnce(&mut Diag<'_, ()>), { diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs index 2773427e72d5..2fb784dae1cd 100644 --- a/src/tools/clippy/clippy_lints/src/missing_doc.rs +++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs @@ -127,7 +127,7 @@ impl MissingDoc { cx, MISSING_DOCS_IN_PRIVATE_ITEMS, sp, - &format!("missing documentation for {article} {desc}"), + format!("missing documentation for {article} {desc}"), ); } } diff --git a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs index 3bf9f75e2261..a64faa124f08 100644 --- a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs +++ b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs @@ -198,7 +198,7 @@ fn check_struct<'tcx>( } impl<'tcx> LateLintPass<'tcx> for MissingFieldsInDebug { - fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx rustc_hir::Item<'tcx>) { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { // is this an `impl Debug for X` block? if let ItemKind::Impl(Impl { of_trait: Some(trait_ref), self_ty, items, .. }) = item.kind && let Res::Def(DefKind::Trait, trait_def_id) = trait_ref.path.res diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs index 7393b39c8f60..c6a76478806a 100644 --- a/src/tools/clippy/clippy_lints/src/missing_inline.rs +++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs @@ -64,7 +64,7 @@ fn check_missing_inline_attrs(cx: &LateContext<'_>, attrs: &[ast::Attribute], sp cx, MISSING_INLINE_IN_PUBLIC_ITEMS, sp, - &format!("missing `#[inline]` for {desc}"), + format!("missing `#[inline]` for {desc}"), ); } } diff --git a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs index 6bbf18d52d11..6f844bc646a2 100644 --- a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs +++ b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs @@ -89,7 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingTraitMethods { cx, MISSING_TRAIT_METHODS, source_map.guess_head_span(item.span), - &format!("missing trait method provided by default: `{}`", assoc.name), + format!("missing trait method provided by default: `{}`", assoc.name), Some(definition_span), "implement the method", ); 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 656fb907fcda..181351910db6 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 @@ -325,7 +325,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> { self.cx, MIXED_READ_WRITE_IN_EXPRESSION, expr.span, - &format!("unsequenced read of `{}`", self.cx.tcx.hir().name(self.var)), + format!("unsequenced read of `{}`", self.cx.tcx.hir().name(self.var)), Some(self.write_expr.span), "whether read occurs before this write depends on evaluation order", ); diff --git a/src/tools/clippy/clippy_lints/src/module_style.rs b/src/tools/clippy/clippy_lints/src/module_style.rs index 0226b31dd190..6c031c081750 100644 --- a/src/tools/clippy/clippy_lints/src/module_style.rs +++ b/src/tools/clippy/clippy_lints/src/module_style.rs @@ -129,9 +129,9 @@ impl EarlyLintPass for ModStyle { cx, SELF_NAMED_MODULE_FILES, Span::new(file.start_pos, file.start_pos, SyntaxContext::root(), None), - &format!("`mod.rs` files are required, found `{}`", path.display()), + format!("`mod.rs` files are required, found `{}`", path.display()), None, - &format!("move `{}` to `{}`", path.display(), correct.display(),), + format!("move `{}` to `{}`", path.display(), correct.display(),), ); } } @@ -169,9 +169,9 @@ fn check_self_named_mod_exists(cx: &EarlyContext<'_>, path: &Path, file: &Source cx, MOD_MODULE_FILES, Span::new(file.start_pos, file.start_pos, SyntaxContext::root(), None), - &format!("`mod.rs` files are not allowed, found `{}`", path.display()), + format!("`mod.rs` files are not allowed, found `{}`", path.display()), None, - &format!("move `{}` to `{}`", path.display(), mod_file.display()), + format!("move `{}` to `{}`", path.display(), mod_file.display()), ); } } diff --git a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs index 648d780ac093..0e1380667805 100644 --- a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -77,7 +77,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleUnsafeOpsPerBlock { cx, MULTIPLE_UNSAFE_OPS_PER_BLOCK, block.span, - &format!( + format!( "this `unsafe` block contains {} unsafe operations, expected only one", unsafe_ops.len() ), diff --git a/src/tools/clippy/clippy_lints/src/mut_reference.rs b/src/tools/clippy/clippy_lints/src/mut_reference.rs index 14a1e6be7388..6867f76a7235 100644 --- a/src/tools/clippy/clippy_lints/src/mut_reference.rs +++ b/src/tools/clippy/clippy_lints/src/mut_reference.rs @@ -60,7 +60,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed { let method_type = cx.tcx.type_of(def_id).instantiate(cx.tcx, args); check_arguments( cx, - std::iter::once(receiver).chain(arguments.iter()).collect(), + iter::once(receiver).chain(arguments.iter()).collect(), method_type, path.ident.as_str(), "method", @@ -83,14 +83,13 @@ fn check_arguments<'tcx>( let parameters = type_definition.fn_sig(cx.tcx).skip_binder().inputs(); for (argument, parameter) in iter::zip(arguments, parameters) { match parameter.kind() { - ty::Ref(_, _, Mutability::Not) - | ty::RawPtr(_, Mutability::Not) => { + ty::Ref(_, _, Mutability::Not) | ty::RawPtr(_, Mutability::Not) => { if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _) = argument.kind { span_lint( cx, UNNECESSARY_MUT_PASSED, argument.span, - &format!("the {fn_kind} `{name}` doesn't need a mutable reference"), + format!("the {fn_kind} `{name}` doesn't need a mutable reference"), ); } }, diff --git a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs index 96cd81ecdf31..e92ba93942ef 100644 --- a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs +++ b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs @@ -60,7 +60,7 @@ impl<'tcx> LateLintPass<'tcx> for DebugAssertWithMutCall { cx, DEBUG_ASSERT_WITH_MUT_CALL, span, - &format!("do not call a function with mutable arguments inside of `{macro_name}!`"), + format!("do not call a function with mutable arguments inside of `{macro_name}!`"), ); } } diff --git a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs index 61243c837316..7ecc86176942 100644 --- a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs +++ b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs @@ -92,9 +92,9 @@ impl<'tcx> LateLintPass<'tcx> for Mutex { behavior and not the internal type, consider using `Mutex<()>`" ); match *mutex_param.kind() { - ty::Uint(t) if t != ty::UintTy::Usize => span_lint(cx, MUTEX_INTEGER, expr.span, &msg), - ty::Int(t) if t != ty::IntTy::Isize => span_lint(cx, MUTEX_INTEGER, expr.span, &msg), - _ => span_lint(cx, MUTEX_ATOMIC, expr.span, &msg), + ty::Uint(t) if t != UintTy::Usize => span_lint(cx, MUTEX_INTEGER, expr.span, msg), + ty::Int(t) if t != IntTy::Isize => span_lint(cx, MUTEX_INTEGER, expr.span, msg), + _ => span_lint(cx, MUTEX_ATOMIC, expr.span, msg), }; } } diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs index 166a7f71d695..f9ee4a3dc93a 100644 --- a/src/tools/clippy/clippy_lints/src/needless_bool.rs +++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs @@ -6,11 +6,12 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; use clippy_utils::{ - higher, is_else_clause, is_expn_of, peel_blocks, peel_blocks_with_stmt, span_extract_comment, SpanlessEq, + higher, is_else_clause, is_expn_of, is_parent_stmt, peel_blocks, peel_blocks_with_stmt, span_extract_comment, + SpanlessEq, }; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, Node, UnOp}; +use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; @@ -135,13 +136,6 @@ fn condition_needs_parentheses(e: &Expr<'_>) -> bool { false } -fn is_parent_stmt(cx: &LateContext<'_>, id: HirId) -> bool { - matches!( - cx.tcx.parent_hir_node(id), - Node::Stmt(..) | Node::Block(Block { stmts: &[], .. }) - ) -} - impl<'tcx> LateLintPass<'tcx> for NeedlessBool { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { use self::Expression::{Bool, RetBool}; @@ -323,11 +317,11 @@ fn one_side_is_unary_not<'tcx>(left_side: &'tcx Expr<'_>, right_side: &'tcx Expr fn check_comparison<'a, 'tcx>( cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, - left_true: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &str)>, - left_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &str)>, - right_true: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &str)>, - right_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &str)>, - no_literal: Option<(impl FnOnce(Sugg<'a>, Sugg<'a>) -> Sugg<'a>, &str)>, + left_true: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &'static str)>, + left_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &'static str)>, + right_true: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &'static str)>, + right_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &'static str)>, + no_literal: Option<(impl FnOnce(Sugg<'a>, Sugg<'a>) -> Sugg<'a>, &'static str)>, ) { if let ExprKind::Binary(op, left_side, right_side) = e.kind { let (l_ty, r_ty) = ( @@ -397,7 +391,7 @@ fn check_comparison<'a, 'tcx>( binop_span, m, "try simplifying it as shown", - h(left_side, right_side).to_string(), + h(left_side, right_side).into_string(), applicability, ); }), @@ -412,7 +406,7 @@ fn suggest_bool_comparison<'a, 'tcx>( span: Span, expr: &Expr<'_>, mut app: Applicability, - message: &str, + message: &'static str, conv_hint: impl FnOnce(Sugg<'a>) -> Sugg<'a>, ) { let hint = Sugg::hir_with_context(cx, expr, span.ctxt(), "..", &mut app); @@ -422,7 +416,7 @@ fn suggest_bool_comparison<'a, 'tcx>( span, message, "try simplifying it as shown", - conv_hint(hint).to_string(), + conv_hint(hint).into_string(), app, ); } diff --git a/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs b/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs index 4710a69443b4..d91329eadcb4 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs @@ -119,7 +119,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowedRef { fn check_subpatterns<'tcx>( cx: &LateContext<'tcx>, - message: &str, + message: &'static str, ref_pat: &Pat<'_>, pat: &Pat<'_>, subpatterns: impl IntoIterator>, 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 a32bca3d0381..c555fc8675c8 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 @@ -381,7 +381,7 @@ fn replace_types<'tcx>( fn_sig: FnSig<'tcx>, arg_index: usize, projection_predicates: &[ProjectionPredicate<'tcx>], - args: &mut [ty::GenericArg<'tcx>], + args: &mut [GenericArg<'tcx>], ) -> bool { let mut replaced = BitSet::new_empty(args.len()); @@ -399,7 +399,7 @@ fn replace_types<'tcx>( return false; } - args[param_ty.index as usize] = ty::GenericArg::from(new_ty); + args[param_ty.index as usize] = GenericArg::from(new_ty); // The `replaced.insert(...)` check provides some protection against infinite loops. if replaced.insert(param_ty.index) { @@ -414,7 +414,7 @@ fn replace_types<'tcx>( )); if let Ok(projected_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, projection) - && args[term_param_ty.index as usize] != ty::GenericArg::from(projected_ty) + && args[term_param_ty.index as usize] != GenericArg::from(projected_ty) { deque.push_back((*term_param_ty, projected_ty)); } diff --git a/src/tools/clippy/clippy_lints/src/needless_continue.rs b/src/tools/clippy/clippy_lints/src/needless_continue.rs index ff72b5e69ef1..8b4a12bb7664 100644 --- a/src/tools/clippy/clippy_lints/src/needless_continue.rs +++ b/src/tools/clippy/clippy_lints/src/needless_continue.rs @@ -313,7 +313,7 @@ fn emit_warning(cx: &EarlyContext<'_>, data: &LintData<'_>, header: &str, typ: L expr.span, message, None, - &format!("{header}\n{snip}"), + format!("{header}\n{snip}"), ); } diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs index d7adf22ff32a..37463cfec9a2 100644 --- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs @@ -131,7 +131,7 @@ fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { NEEDLESS_QUESTION_MARK, expr.span, "question mark operator is useless here", - &format!("try removing question mark and `{sugg_remove}`"), + format!("try removing question mark and `{sugg_remove}`"), format!("{}", snippet(cx, inner_expr.span, r#""...""#)), Applicability::MachineApplicable, ); diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs index 627b4968d9f6..78dd1e051627 100644 --- a/src/tools/clippy/clippy_lints/src/new_without_default.rs +++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs @@ -134,9 +134,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { NEW_WITHOUT_DEFAULT, id.into(), impl_item.span, - &format!( - "you should consider adding a `Default` implementation for `{self_type_snip}`" - ), + format!("you should consider adding a `Default` implementation for `{self_type_snip}`"), |diag| { diag.suggest_prepend_item( cx, diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs index 43810ec0ec74..f915145e794b 100644 --- a/src/tools/clippy/clippy_lints/src/no_effect.rs +++ b/src/tools/clippy/clippy_lints/src/no_effect.rs @@ -107,7 +107,7 @@ impl<'tcx> LateLintPass<'tcx> for NoEffect { } } - fn check_expr(&mut self, _: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) { + fn check_expr(&mut self, _: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if let Some(def_id) = path_to_local(expr) { // FIXME(rust/#120456) - is `swap_remove` correct? self.underscore_bindings.swap_remove(&def_id); 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 6cb84bb78b6d..73fc34c2450f 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -285,7 +285,7 @@ impl NonCopyConst { let def_id = body_id.hir_id.owner.to_def_id(); let args = ty::GenericArgs::identity_for_item(cx.tcx, def_id); let instance = ty::Instance::new(def_id, args); - let cid = rustc_middle::mir::interpret::GlobalId { + let cid = GlobalId { instance, promoted: None, }; @@ -534,7 +534,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { } } -fn ignored_macro(cx: &LateContext<'_>, it: &rustc_hir::Item<'_>) -> bool { +fn ignored_macro(cx: &LateContext<'_>, it: &Item<'_>) -> bool { macro_backtrace(it.span).any(|macro_call| { matches!( cx.tcx.get_diagnostic_name(macro_call.def_id), 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 b8c3c7fa65ae..7b26235291a5 100644 --- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs +++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs @@ -111,7 +111,7 @@ impl<'a, 'tcx> SimilarNamesLocalVisitor<'a, 'tcx> { self.cx, MANY_SINGLE_CHAR_NAMES, span, - &format!("{num_single_char_names} bindings with single-character names in scope"), + format!("{num_single_char_names} bindings with single-character names in scope"), ); } } diff --git a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs index 408216229a41..74e6c57b52d4 100644 --- a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs +++ b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs @@ -119,7 +119,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy { cx, NON_SEND_FIELDS_IN_SEND_TY, item.span, - &format!( + format!( "some fields in `{}` are not safe to be sent to another thread", snippet(cx, hir_impl.self_ty.span, "Unknown") ), diff --git a/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs b/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs index 1c6069e9c650..88f2eabaccba 100644 --- a/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs +++ b/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs @@ -121,7 +121,7 @@ fn emit_help(cx: &EarlyContext<'_>, snip: &str, (open, close): (char, char), spa cx, NONSTANDARD_MACRO_BRACES, span, - &format!("use of irregular braces for `{macro_name}!` macro"), + format!("use of irregular braces for `{macro_name}!` macro"), "consider writing", format!("{macro_name}!{open}{macro_args}{close}"), Applicability::MachineApplicable, diff --git a/src/tools/clippy/clippy_lints/src/octal_escapes.rs b/src/tools/clippy/clippy_lints/src/octal_escapes.rs index 8822dfeedddb..2fc039ae886e 100644 --- a/src/tools/clippy/clippy_lints/src/octal_escapes.rs +++ b/src/tools/clippy/clippy_lints/src/octal_escapes.rs @@ -94,7 +94,7 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) { cx, OCTAL_ESCAPES, span, - &format!( + format!( "octal-looking escape in {} literal", if is_string { "string" } else { "byte string" } ), diff --git a/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs b/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs index f4863600ccc0..9769da6d3e9b 100644 --- a/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs +++ b/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs @@ -42,7 +42,7 @@ pub(super) fn check<'tcx>( } ); - span_lint_and_help(cx, ABSURD_EXTREME_COMPARISONS, expr.span, msg, None, &help); + span_lint_and_help(cx, ABSURD_EXTREME_COMPARISONS, expr.span, msg, None, help); } } diff --git a/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs b/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs index 2e026c369ee3..545e680ce0de 100644 --- a/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs +++ b/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs @@ -64,7 +64,7 @@ fn check_bit_mask( cx, BAD_BIT_MASK, span, - &format!("incompatible bit mask: `_ & {mask_value}` can never be equal to `{cmp_value}`"), + format!("incompatible bit mask: `_ & {mask_value}` can never be equal to `{cmp_value}`"), ); } } else if mask_value == 0 { @@ -77,7 +77,7 @@ fn check_bit_mask( cx, BAD_BIT_MASK, span, - &format!("incompatible bit mask: `_ | {mask_value}` can never be equal to `{cmp_value}`"), + format!("incompatible bit mask: `_ | {mask_value}` can never be equal to `{cmp_value}`"), ); } }, @@ -90,7 +90,7 @@ fn check_bit_mask( cx, BAD_BIT_MASK, span, - &format!("incompatible bit mask: `_ & {mask_value}` will always be lower than `{cmp_value}`"), + format!("incompatible bit mask: `_ & {mask_value}` will always be lower than `{cmp_value}`"), ); } else if mask_value == 0 { span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero"); @@ -102,7 +102,7 @@ fn check_bit_mask( cx, BAD_BIT_MASK, span, - &format!("incompatible bit mask: `_ | {mask_value}` will never be lower than `{cmp_value}`"), + format!("incompatible bit mask: `_ | {mask_value}` will never be lower than `{cmp_value}`"), ); } else { check_ineffective_lt(cx, span, mask_value, cmp_value, "|"); @@ -118,7 +118,7 @@ fn check_bit_mask( cx, BAD_BIT_MASK, span, - &format!("incompatible bit mask: `_ & {mask_value}` will never be higher than `{cmp_value}`"), + format!("incompatible bit mask: `_ & {mask_value}` will never be higher than `{cmp_value}`"), ); } else if mask_value == 0 { span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero"); @@ -130,7 +130,7 @@ fn check_bit_mask( cx, BAD_BIT_MASK, span, - &format!("incompatible bit mask: `_ | {mask_value}` will always be higher than `{cmp_value}`"), + format!("incompatible bit mask: `_ | {mask_value}` will always be higher than `{cmp_value}`"), ); } else { check_ineffective_gt(cx, span, mask_value, cmp_value, "|"); @@ -149,7 +149,7 @@ fn check_ineffective_lt(cx: &LateContext<'_>, span: Span, m: u128, c: u128, op: cx, INEFFECTIVE_BIT_MASK, span, - &format!("ineffective bit mask: `x {op} {m}` compared to `{c}`, is the same as x compared directly"), + format!("ineffective bit mask: `x {op} {m}` compared to `{c}`, is the same as x compared directly"), ); } } @@ -160,7 +160,7 @@ fn check_ineffective_gt(cx: &LateContext<'_>, span: Span, m: u128, c: u128, op: cx, INEFFECTIVE_BIT_MASK, span, - &format!("ineffective bit mask: `x {op} {m}` compared to `{c}`, is the same as x compared directly"), + format!("ineffective bit mask: `x {op} {m}` compared to `{c}`, is the same as x compared directly"), ); } } diff --git a/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs b/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs index e278cf9835a9..7bf9b8ef866a 100644 --- a/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs +++ b/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs @@ -89,7 +89,7 @@ pub(super) fn check<'tcx>( span, "left-hand side of `&&` operator has no effect", Some(left_cond.span.until(right_cond.span)), - &format!("`if `{rhs_str}` evaluates to true, {lhs_str}` will always evaluate to true as well"), + format!("`if `{rhs_str}` evaluates to true, {lhs_str}` will always evaluate to true as well"), ); } else { span_lint_and_note( @@ -98,7 +98,7 @@ pub(super) fn check<'tcx>( span, "right-hand side of `&&` operator has no effect", Some(and_op.span.to(right_cond.span)), - &format!("`if `{lhs_str}` evaluates to true, {rhs_str}` will always evaluate to true as well"), + format!("`if `{lhs_str}` evaluates to true, {rhs_str}` will always evaluate to true as well"), ); } // We could autofix this error but choose not to, @@ -124,7 +124,7 @@ pub(super) fn check<'tcx>( span, "boolean expression will never evaluate to 'true'", None, - ¬e, + note, ); }; } diff --git a/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs b/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs index f120be13836d..ca3112ce5c46 100644 --- a/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs +++ b/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs @@ -31,7 +31,7 @@ pub(crate) fn check<'tcx>( cx, DURATION_SUBSEC, expr.span, - &format!("calling `{suggested_fn}()` is more concise than this calculation"), + format!("calling `{suggested_fn}()` is more concise than this calculation"), "try", format!( "{}.{suggested_fn}()", diff --git a/src/tools/clippy/clippy_lints/src/operators/eq_op.rs b/src/tools/clippy/clippy_lints/src/operators/eq_op.rs index 01dd418c38be..1421893274f5 100644 --- a/src/tools/clippy/clippy_lints/src/operators/eq_op.rs +++ b/src/tools/clippy/clippy_lints/src/operators/eq_op.rs @@ -24,7 +24,7 @@ pub(crate) fn check_assert<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { cx, EQ_OP, lhs.span.to(rhs.span), - &format!("identical args used in this `{macro_name}!` macro call"), + format!("identical args used in this `{macro_name}!` macro call"), ); } } @@ -41,7 +41,7 @@ pub(crate) fn check<'tcx>( cx, EQ_OP, e.span, - &format!("equal expressions as operands to `{}`", op.as_str()), + format!("equal expressions as operands to `{}`", op.as_str()), |diag| { if let BinOpKind::Ne = op && cx.typeck_results().expr_ty(left).is_floating_point() diff --git a/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs index 2a933a11e12c..c56518ac72a4 100644 --- a/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs @@ -113,7 +113,7 @@ fn check_const_operands<'tcx>( cx, MODULO_ARITHMETIC, expr.span, - &format!( + format!( "you are using modulo operator on constants with different signs: `{} % {}`", lhs_operand.string_representation.as_ref().unwrap(), rhs_operand.string_representation.as_ref().unwrap() diff --git a/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs b/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs index a69989e400be..607930561e0f 100644 --- a/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs +++ b/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs @@ -30,7 +30,7 @@ pub(super) fn check<'tcx>( cx, PTR_EQ, expr.span, - &format!("use `{top_crate}::ptr::eq` when comparing raw pointers"), + format!("use `{top_crate}::ptr::eq` when comparing raw pointers"), "try", format!("{top_crate}::ptr::eq({left_snip}, {right_snip})"), Applicability::MachineApplicable, diff --git a/src/tools/clippy/clippy_lints/src/operators/self_assignment.rs b/src/tools/clippy/clippy_lints/src/operators/self_assignment.rs index 7c9d5320a3a8..a932378fbb52 100644 --- a/src/tools/clippy/clippy_lints/src/operators/self_assignment.rs +++ b/src/tools/clippy/clippy_lints/src/operators/self_assignment.rs @@ -14,7 +14,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, lhs: &'tcx cx, SELF_ASSIGNMENT, e.span, - &format!("self-assignment of `{rhs}` to `{lhs}`"), + format!("self-assignment of `{rhs}` to `{lhs}`"), ); } } diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs index 556c493d36c8..3cbd03a58c55 100644 --- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs @@ -304,7 +304,7 @@ impl<'tcx> LateLintPass<'tcx> for OptionIfLetElse { cx, OPTION_IF_LET_ELSE, expr.span, - format!("use Option::{} instead of an if let/else", det.method_sugg).as_str(), + format!("use Option::{} instead of an if let/else", det.method_sugg), "try", format!( "{}.{}({}, {})", 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 ec03ab0e41ab..bb4a1de9f77d 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 @@ -206,7 +206,7 @@ impl<'tcx> PassByRefOrValue { cx, TRIVIALLY_COPY_PASS_BY_REF, input.span, - &format!( + format!( "this argument ({size} byte) is passed by reference, but would be more efficient if passed by value (limit: {} byte)", self.ref_min_size ), @@ -236,7 +236,7 @@ impl<'tcx> PassByRefOrValue { cx, LARGE_TYPES_PASSED_BY_VALUE, input.span, - &format!( + format!( "this argument ({size} byte) is passed by value, but might be more efficient if passed by reference (limit: {} byte)", self.value_max_size ), diff --git a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs index 127801de7def..44db061b8bee 100644 --- a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs +++ b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs @@ -1,5 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_help; -use rustc_hir::{intravisit, Body, Expr, ExprKind, FnDecl, LetExpr, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind}; +use rustc_hir::{ + intravisit, Body, Expr, ExprKind, FnDecl, LetExpr, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind, +}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; @@ -138,7 +140,7 @@ fn apply_lint(cx: &LateContext<'_>, pat: &Pat<'_>, deref_possible: DerefPossible span, "type of pattern does not match the expression type", None, - &format!( + format!( "{}explicitly match against a `{}` pattern and adjust the enclosed variable bindings", match (deref_possible, level) { (DerefPossible::Possible, Level::Top) => "use `*` to dereference the match expression or ", diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index 896c99a71046..83b32000a9f9 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -177,7 +177,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { ) .filter(|arg| arg.mutability() == Mutability::Not) { - span_lint_hir_and_then(cx, PTR_ARG, arg.emission_id, arg.span, &arg.build_msg(), |diag| { + span_lint_hir_and_then(cx, PTR_ARG, arg.emission_id, arg.span, arg.build_msg(), |diag| { diag.span_suggestion( arg.span, "change this to", @@ -237,7 +237,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { let results = check_ptr_arg_usage(cx, body, &lint_args); for (result, args) in results.iter().zip(lint_args.iter()).filter(|(r, _)| !r.skip) { - span_lint_hir_and_then(cx, PTR_ARG, args.emission_id, args.span, &args.build_msg(), |diag| { + span_lint_hir_and_then(cx, PTR_ARG, args.emission_id, args.span, args.build_msg(), |diag| { diag.multipart_suggestion( "change this to", iter::once((args.span, format!("{}{}", args.ref_prefix, args.deref_ty.display(cx)))) @@ -628,7 +628,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: } }, ExprKind::MethodCall(name, self_arg, expr_args, _) => { - let i = std::iter::once(self_arg) + let i = iter::once(self_arg) .chain(expr_args.iter()) .position(|arg| arg.hir_id == child_id) .unwrap_or(0); diff --git a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs index ff8ec2ad57c3..7c82895d6091 100644 --- a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs +++ b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs @@ -64,13 +64,13 @@ impl<'tcx> LateLintPass<'tcx> for PtrOffsetWithCast { cx, PTR_OFFSET_WITH_CAST, expr.span, - &msg, + msg, "try", sugg, Applicability::MachineApplicable, ); } else { - span_lint(cx, PTR_OFFSET_WITH_CAST, expr.span, &msg); + span_lint(cx, PTR_OFFSET_WITH_CAST, expr.span, msg); } } } diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs index b57220e6cf0a..927c6f1d519e 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark.rs @@ -4,7 +4,7 @@ use clippy_config::msrvs::Msrv; use clippy_config::types::MatchLintBehaviour; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use clippy_utils::{ eq_expr_value, higher, in_constant, is_else_clause, is_lint_allowed, is_path_lang_item, is_res_lang_ctor, pat_and_expr_can_be_question_mark, path_to_local, path_to_local_id, peel_blocks, peel_blocks_with_stmt, @@ -14,7 +14,8 @@ use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::{ - BindingAnnotation, Block, ByRef, Expr, ExprKind, LetStmt, Mutability, Node, PatKind, PathSegment, QPath, Stmt, StmtKind, + BindingAnnotation, Block, Body, ByRef, Expr, ExprKind, LetStmt, Mutability, Node, PatKind, PathSegment, QPath, + Stmt, StmtKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; @@ -109,12 +110,31 @@ fn find_let_else_ret_expression<'hir>(block: &'hir Block<'hir>) -> Option<&'hir } fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) { + /// Make sure the init expr implements try trait so a valid suggestion could be given. + /// + /// Because the init expr could have the type of `&Option` which does not implements `Try`. + /// + /// NB: This conveniently prevents the cause of + /// issue [#12412](https://github.com/rust-lang/rust-clippy/issues/12412), + /// since accessing an `Option` field from a borrowed struct requires borrow, such as + /// `&some_struct.opt`, which is type of `&Option`. And we can't suggest `&some_struct.opt?` + /// or `(&some_struct.opt)?` since the first one has different semantics and the later does + /// not implements `Try`. + fn init_expr_can_use_question_mark(cx: &LateContext<'_>, init_expr: &Expr<'_>) -> bool { + let init_ty = cx.typeck_results().expr_ty_adjusted(init_expr); + cx.tcx + .lang_items() + .try_trait() + .map_or(false, |did| implements_trait(cx, init_ty, did, &[])) + } + if let StmtKind::Let(LetStmt { pat, init: Some(init_expr), els: Some(els), .. }) = stmt.kind + && init_expr_can_use_question_mark(cx, init_expr) && let Some(ret) = find_let_else_ret_expression(els) && let Some(inner_pat) = pat_and_expr_can_be_question_mark(cx, pat, ret) && !span_contains_comment(cx.tcx.sess.source_map(), els.span) @@ -310,9 +330,9 @@ impl QuestionMark { } } -fn is_try_block(cx: &LateContext<'_>, bl: &rustc_hir::Block<'_>) -> bool { +fn is_try_block(cx: &LateContext<'_>, bl: &Block<'_>) -> bool { if let Some(expr) = bl.expr - && let rustc_hir::ExprKind::Call(callee, _) = expr.kind + && let ExprKind::Call(callee, _) = expr.kind { is_path_lang_item(cx, callee, LangItem::TryTraitFromOutput) } else { @@ -341,7 +361,7 @@ impl<'tcx> LateLintPass<'tcx> for QuestionMark { } } - fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx rustc_hir::Block<'tcx>) { + fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) { if is_try_block(cx, block) { *self .try_block_depth_stack @@ -350,15 +370,15 @@ impl<'tcx> LateLintPass<'tcx> for QuestionMark { } } - fn check_body(&mut self, _: &LateContext<'tcx>, _: &'tcx rustc_hir::Body<'tcx>) { + fn check_body(&mut self, _: &LateContext<'tcx>, _: &'tcx Body<'tcx>) { self.try_block_depth_stack.push(0); } - fn check_body_post(&mut self, _: &LateContext<'tcx>, _: &'tcx rustc_hir::Body<'tcx>) { + fn check_body_post(&mut self, _: &LateContext<'tcx>, _: &'tcx Body<'tcx>) { self.try_block_depth_stack.pop(); } - fn check_block_post(&mut self, cx: &LateContext<'tcx>, block: &'tcx rustc_hir::Block<'tcx>) { + fn check_block_post(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) { if is_try_block(cx, block) { *self .try_block_depth_stack diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs index 6b54258dd617..186e548d3730 100644 --- a/src/tools/clippy/clippy_lints/src/ranges.rs +++ b/src/tools/clippy/clippy_lints/src/ranges.rs @@ -242,7 +242,7 @@ fn check_possible_range_contains( cx, MANUAL_RANGE_CONTAINS, span, - &format!("manual `{range_type}::contains` implementation"), + format!("manual `{range_type}::contains` implementation"), "use", format!("({lo}{space}{range_op}{hi}).contains(&{name})"), applicability, @@ -272,7 +272,7 @@ fn check_possible_range_contains( cx, MANUAL_RANGE_CONTAINS, span, - &format!("manual `!{range_type}::contains` implementation"), + format!("manual `!{range_type}::contains` implementation"), "use", format!("!({lo}{space}{range_op}{hi}).contains(&{name})"), applicability, diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs index 435899ddaa78..2863eb190d34 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs @@ -56,7 +56,7 @@ impl ReturnVisitor { impl<'tcx> Visitor<'tcx> for ReturnVisitor { fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) { - if let hir::ExprKind::Ret(_) | hir::ExprKind::Match(.., hir::MatchSource::TryDesugar(_)) = ex.kind { + if let ExprKind::Ret(_) | ExprKind::Match(.., hir::MatchSource::TryDesugar(_)) = ex.kind { self.found_return = true; } else { hir_visit::walk_expr(self, ex); @@ -68,7 +68,7 @@ impl<'tcx> Visitor<'tcx> for ReturnVisitor { /// Returns true for `async || whatever_expression`, but false for `|| async { whatever_expression /// }`. fn is_async_closure(body: &hir::Body<'_>) -> bool { - if let hir::ExprKind::Closure(innermost_closure_generated_by_desugar) = body.value.kind + if let ExprKind::Closure(innermost_closure_generated_by_desugar) = body.value.kind // checks whether it is `async || whatever_expression` && let ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Closure)) = innermost_closure_generated_by_desugar.kind @@ -99,7 +99,7 @@ fn find_innermost_closure<'tcx>( )> { let mut data = None; - while let hir::ExprKind::Closure(closure) = expr.kind + while let ExprKind::Closure(closure) = expr.kind && let body = cx.tcx.hir().body(closure.body) && { let mut visitor = ReturnVisitor::new(); @@ -137,7 +137,7 @@ fn get_parent_call_exprs<'tcx>( ) -> (&'tcx hir::Expr<'tcx>, usize) { let mut depth = 1; while let Some(parent) = get_parent_expr(cx, expr) - && let hir::ExprKind::Call(recv, _) = parent.kind + && let ExprKind::Call(recv, _) = parent.kind && expr.span == recv.span { expr = parent; @@ -152,13 +152,13 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { return; } - if let hir::ExprKind::Call(recv, _) = expr.kind + if let ExprKind::Call(recv, _) = expr.kind // don't lint if the receiver is a call, too. // we do this in order to prevent linting multiple times; consider: // `(|| || 1)()()` // ^^ we only want to lint for this call (but we walk up the calls to consider both calls). // without this check, we'd end up linting twice. - && !matches!(recv.kind, hir::ExprKind::Call(..)) + && !matches!(recv.kind, ExprKind::Call(..)) // Check if `recv` comes from a macro expansion. If it does, make sure that it's an expansion that is // the same as the one the call is in. // For instance, let's assume `x!()` returns a closure: @@ -185,7 +185,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { Sugg::hir_with_context(cx, body, full_expr.span.ctxt(), "..", &mut applicability); if coroutine_kind.is_async() - && let hir::ExprKind::Closure(closure) = body.kind + && let ExprKind::Closure(closure) = body.kind { // Like `async fn`, async closures are wrapped in an additional block // to move all of the closure's arguments into the future. @@ -202,7 +202,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { }; // `async x` is a syntax error, so it becomes `async { x }` - if !matches!(body_expr.kind, hir::ExprKind::Block(_, _)) { + if !matches!(body_expr.kind, ExprKind::Block(_, _)) { hint = hint.blockify(); } @@ -210,7 +210,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { } let is_in_fn_call_arg = if let Node::Expr(expr) = cx.tcx.parent_hir_node(expr.hir_id) { - matches!(expr.kind, hir::ExprKind::Call(_, _)) + matches!(expr.kind, ExprKind::Call(_, _)) } else { false }; @@ -238,12 +238,12 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { path: &'tcx hir::Path<'tcx>, count: usize, } - impl<'a, 'tcx> hir_visit::Visitor<'tcx> for ClosureUsageCount<'a, 'tcx> { + impl<'a, 'tcx> Visitor<'tcx> for ClosureUsageCount<'a, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { - if let hir::ExprKind::Call(closure, _) = expr.kind - && let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = closure.kind + if let ExprKind::Call(closure, _) = expr.kind + && let ExprKind::Path(hir::QPath::Resolved(_, path)) = closure.kind && self.path.segments[0].ident == path.segments[0].ident && self.path.res == path.res { @@ -263,13 +263,13 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { for w in block.stmts.windows(2) { if let hir::StmtKind::Let(local) = w[0].kind - && let Option::Some(t) = local.init - && let hir::ExprKind::Closure { .. } = t.kind + && let Some(t) = local.init + && let ExprKind::Closure { .. } = t.kind && let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind && let hir::StmtKind::Semi(second) = w[1].kind - && let hir::ExprKind::Assign(_, call, _) = second.kind - && let hir::ExprKind::Call(closure, _) = call.kind - && let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = closure.kind + && let ExprKind::Assign(_, call, _) = second.kind + && let ExprKind::Call(closure, _) = call.kind + && let ExprKind::Path(hir::QPath::Resolved(_, path)) = closure.kind && ident == path.segments[0].ident && count_closure_usage(cx, block, path) == 1 { diff --git a/src/tools/clippy/clippy_lints/src/redundant_locals.rs b/src/tools/clippy/clippy_lints/src/redundant_locals.rs index 0f579f779dfd..7202266deeb2 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_locals.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_locals.rs @@ -77,9 +77,9 @@ impl<'tcx> LateLintPass<'tcx> for RedundantLocals { cx, REDUNDANT_LOCALS, local.span, - &format!("redundant redefinition of a binding `{ident}`"), + format!("redundant redefinition of a binding `{ident}`"), Some(binding_pat.span), - &format!("`{ident}` is initially defined here"), + format!("`{ident}` is initially defined here"), ); } } 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 0e43e4a7ee53..1b557730ecad 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs @@ -56,7 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate { cx, REDUNDANT_PUB_CRATE, span, - &format!("pub(crate) {descr} inside private module"), + format!("pub(crate) {descr} inside private module"), |diag| { diag.span_suggestion( item.vis_span, diff --git a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs index 07b604f2326b..136e7db83bd6 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs @@ -48,7 +48,7 @@ impl_lint_pass!(RedundantStaticLifetimes => [REDUNDANT_STATIC_LIFETIMES]); impl RedundantStaticLifetimes { // Recursively visit types - fn visit_type(ty: &Ty, cx: &EarlyContext<'_>, reason: &str) { + fn visit_type(ty: &Ty, cx: &EarlyContext<'_>, reason: &'static str) { match ty.kind { // Be careful of nested structures (arrays and tuples) TyKind::Array(ref ty, _) | TyKind::Slice(ref ty) => { diff --git a/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs b/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs index 96f6f0ec36fc..11b95ee3a54c 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs @@ -59,7 +59,7 @@ fn is_same_type<'tcx>(cx: &LateContext<'tcx>, ty_resolved_path: hir::def::Res, f fn func_hir_id_to_func_ty<'tcx>(cx: &LateContext<'tcx>, hir_id: hir::hir_id::HirId) -> Option> { if let Some((defkind, func_defid)) = cx.typeck_results().type_dependent_def(hir_id) - && defkind == hir::def::DefKind::AssocFn + && defkind == DefKind::AssocFn && let Some(init_ty) = cx.tcx.type_of(func_defid).no_bound_vars() { Some(init_ty) diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs index 687bad35a368..e925ec0271cf 100644 --- a/src/tools/clippy/clippy_lints/src/regex.rs +++ b/src/tools/clippy/clippy_lints/src/regex.rs @@ -134,13 +134,13 @@ fn lint_syntax_error(cx: &LateContext<'_>, error: ®ex_syntax::Error, unescape vec![convert_span(primary)] }; - span_lint(cx, INVALID_REGEX, spans, &format!("regex syntax error: {kind}")); + span_lint(cx, INVALID_REGEX, spans, format!("regex syntax error: {kind}")); } else { span_lint_and_help( cx, INVALID_REGEX, base, - &error.to_string(), + error.to_string(), None, "consider using a raw string literal: `r\"..\"`", ); @@ -223,7 +223,7 @@ fn check_regex<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) { span_lint_and_help(cx, TRIVIAL_REGEX, expr.span, "trivial regex", None, repl); } }, - Err(e) => span_lint(cx, INVALID_REGEX, expr.span, &e.to_string()), + Err(e) => span_lint(cx, INVALID_REGEX, expr.span, e.to_string()), } } } diff --git a/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs b/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs index fcb79f6d694e..a358881bf80e 100644 --- a/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs +++ b/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs @@ -55,7 +55,7 @@ fn emit_lint(cx: &LateContext<'_>, span: Span, kind: &str, note: &'static str, s cx, REPEAT_VEC_WITH_CAPACITY, span, - &format!("repeating `Vec::with_capacity` using `{kind}`, which does not retain capacity"), + format!("repeating `Vec::with_capacity` using `{kind}`, which does not retain capacity"), |diag| { diag.note(note); diag.span_suggestion_verbose(span, sugg_msg, sugg, Applicability::MaybeIncorrect); diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index 8bc24eda4659..e8f9d4381047 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -3,7 +3,7 @@ use clippy_utils::source::{snippet_opt, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; use clippy_utils::visitors::{for_each_expr_with_closures, Descend}; use clippy_utils::{ - fn_def_id, is_from_proc_macro, is_inside_let_else, is_res_lang_ctor, path_res, path_to_local_id, + fn_def_id, is_from_proc_macro, is_inside_let_else, is_res_lang_ctor, path_res, path_to_local_id, span_contains_cfg, span_find_starting_semi, }; use core::ops::ControlFlow; @@ -232,6 +232,7 @@ impl<'tcx> LateLintPass<'tcx> for Return { && !in_external_macro(cx.sess(), initexpr.span) && !in_external_macro(cx.sess(), retexpr.span) && !local.span.from_expansion() + && !span_contains_cfg(cx, stmt.span.between(retexpr.span)) { span_lint_hir_and_then( cx, diff --git a/src/tools/clippy/clippy_lints/src/self_named_constructors.rs b/src/tools/clippy/clippy_lints/src/self_named_constructors.rs index 85a2b1a67352..23b47606f8aa 100644 --- a/src/tools/clippy/clippy_lints/src/self_named_constructors.rs +++ b/src/tools/clippy/clippy_lints/src/self_named_constructors.rs @@ -81,7 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructors { cx, SELF_NAMED_CONSTRUCTORS, impl_item.span, - &format!("constructor `{}` has the same name as the type", impl_item.ident.name), + format!("constructor `{}` has the same name as the type", impl_item.ident.name), ); } } diff --git a/src/tools/clippy/clippy_lints/src/serde_api.rs b/src/tools/clippy/clippy_lints/src/serde_api.rs index b4278d879e54..f1ec91d7affc 100644 --- a/src/tools/clippy/clippy_lints/src/serde_api.rs +++ b/src/tools/clippy/clippy_lints/src/serde_api.rs @@ -9,7 +9,7 @@ declare_clippy_lint! { /// Checks for misuses of the serde API. /// /// ### Why is this bad? - /// Serde is very finnicky about how its API should be + /// Serde is very finicky about how its API should be /// used, but the type system can't be used to enforce it (yet?). /// /// ### Example diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs index d98b37bda355..9db08acb03b2 100644 --- a/src/tools/clippy/clippy_lints/src/shadow.rs +++ b/src/tools/clippy/clippy_lints/src/shadow.rs @@ -194,7 +194,7 @@ fn lint_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, shadowed: HirId, span: Span) cx, lint, span, - &msg, + msg, Some(cx.tcx.hir().span(shadowed)), "previous binding is here", ); diff --git a/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs b/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs index 95b4a11a7834..0a9a3c6307a7 100644 --- a/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs +++ b/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs @@ -122,7 +122,7 @@ impl LateLintPass<'_> for SingleRangeInVecInit { cx, SINGLE_RANGE_IN_VEC_INIT, span, - &format!("{suggested_type} of `Range` that is only one element"), + format!("{suggested_type} of `Range` that is only one element"), |diag| { if should_emit_every_value { diag.span_suggestion( diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs index ff8e8fe70217..8a9f02b6dcb1 100644 --- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs @@ -196,7 +196,7 @@ impl SlowVectorInit { }; } - fn emit_lint(cx: &LateContext<'_>, slow_fill: &Expr<'_>, vec_alloc: &VecAllocation<'_>, msg: &str) { + fn emit_lint(cx: &LateContext<'_>, slow_fill: &Expr<'_>, vec_alloc: &VecAllocation<'_>, msg: &'static str) { let len_expr = Sugg::hir( cx, match vec_alloc.size_expr { diff --git a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs index cf839941123d..926c56332cc1 100644 --- a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs +++ b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs @@ -128,8 +128,8 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports { cx, lint, first_segment.ident.span, - &format!("used import from `{used_mod}` instead of `{replace_with}`"), - &format!("consider importing the item from `{replace_with}`"), + format!("used import from `{used_mod}` instead of `{replace_with}`"), + format!("consider importing the item from `{replace_with}`"), replace_with.to_string(), Applicability::MachineApplicable, ); diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs index 13ae1ff52ddf..b3c729dacdd9 100644 --- a/src/tools/clippy/clippy_lints/src/strings.rs +++ b/src/tools/clippy/clippy_lints/src/strings.rs @@ -495,8 +495,8 @@ impl<'tcx> LateLintPass<'tcx> for TrimSplitWhitespace { cx, TRIM_SPLIT_WHITESPACE, trim_span.with_hi(split_ws_span.lo()), - &format!("found call to `str::{trim_fn_name}` before `str::split_whitespace`"), - &format!("remove `{trim_fn_name}()`"), + format!("found call to `str::{trim_fn_name}` before `str::split_whitespace`"), + format!("remove `{trim_fn_name}()`"), String::new(), Applicability::MachineApplicable, ); diff --git a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs index 8eab3f5874e1..3f030b803318 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs +++ b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs @@ -83,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl { cx, lint, binop.span, - &format!( + format!( "suspicious use of `{}` in `{}` impl", binop.node.as_str(), cx.tcx.item_name(trait_id) diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs index be590aede158..93bad8658097 100644 --- a/src/tools/clippy/clippy_lints/src/swap.rs +++ b/src/tools/clippy/clippy_lints/src/swap.rs @@ -1,10 +1,16 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::snippet_with_context; +use clippy_utils::source::{snippet_indent, snippet_with_context}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; + use clippy_utils::{can_mut_borrow_both, eq_expr_value, in_constant, std_or_core}; +use itertools::Itertools; + +use rustc_hir::intravisit::{walk_expr, Visitor}; + +use crate::FxHashSet; use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind}; +use rustc_hir::{BinOpKind, Block, Expr, ExprKind, LetStmt, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; @@ -80,7 +86,17 @@ impl<'tcx> LateLintPass<'tcx> for Swap { } } -fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, span: Span, is_xor_based: bool) { +#[allow(clippy::too_many_arguments)] +fn generate_swap_warning<'tcx>( + block: &'tcx Block<'tcx>, + cx: &LateContext<'tcx>, + e1: &'tcx Expr<'tcx>, + e2: &'tcx Expr<'tcx>, + rhs1: &'tcx Expr<'tcx>, + rhs2: &'tcx Expr<'tcx>, + span: Span, + is_xor_based: bool, +) { let ctxt = span.ctxt(); let mut applicability = Applicability::MachineApplicable; @@ -99,14 +115,25 @@ fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, spa || is_type_diagnostic_item(cx, ty, sym::VecDeque) { let slice = Sugg::hir_with_applicability(cx, lhs1, "", &mut applicability); + span_lint_and_sugg( cx, MANUAL_SWAP, span, - &format!("this looks like you are swapping elements of `{slice}` manually"), + format!("this looks like you are swapping elements of `{slice}` manually"), "try", format!( - "{}.swap({}, {});", + "{}{}.swap({}, {});", + IndexBinding { + block, + swap1_idx: idx1, + swap2_idx: idx2, + suggest_span: span, + cx, + ctxt, + applicability: &mut applicability, + } + .snippet_index_bindings(&[idx1, idx2, rhs1, rhs2]), slice.maybe_par(), snippet_with_context(cx, idx1.span, ctxt, "..", &mut applicability).0, snippet_with_context(cx, idx2.span, ctxt, "..", &mut applicability).0, @@ -126,7 +153,7 @@ fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, spa cx, MANUAL_SWAP, span, - &format!("this looks like you are swapping `{first}` and `{second}` manually"), + format!("this looks like you are swapping `{first}` and `{second}` manually"), |diag| { diag.span_suggestion( span, @@ -142,7 +169,7 @@ fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, spa } /// Implementation of the `MANUAL_SWAP` lint. -fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) { +fn check_manual_swap<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) { if in_constant(cx, block.hir_id) { return; } @@ -160,10 +187,10 @@ fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) { // bar() = t; && let StmtKind::Semi(second) = s3.kind && let ExprKind::Assign(lhs2, rhs2, _) = second.kind - && let ExprKind::Path(QPath::Resolved(None, rhs2)) = rhs2.kind - && rhs2.segments.len() == 1 + && let ExprKind::Path(QPath::Resolved(None, rhs2_path)) = rhs2.kind + && rhs2_path.segments.len() == 1 - && ident.name == rhs2.segments[0].ident.name + && ident.name == rhs2_path.segments[0].ident.name && eq_expr_value(cx, tmp_init, lhs1) && eq_expr_value(cx, rhs1, lhs2) @@ -174,7 +201,7 @@ fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) { && second.span.ctxt() == ctxt { let span = s1.span.to(s3.span); - generate_swap_warning(cx, lhs1, lhs2, span, false); + generate_swap_warning(block, cx, lhs1, lhs2, rhs1, rhs2, span, false); } } } @@ -201,7 +228,7 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) { cx, ALMOST_SWAPPED, span, - &format!("this looks like you are trying to swap `{lhs_sugg}` and `{rhs_sugg}`"), + format!("this looks like you are trying to swap `{lhs_sugg}` and `{rhs_sugg}`"), |diag| { diag.span_suggestion( span, @@ -254,7 +281,7 @@ fn parse<'a, 'hir>(stmt: &'a Stmt<'hir>) -> Option<(ExprOrIdent<'hir>, &'a Expr< } /// Implementation of the xor case for `MANUAL_SWAP` lint. -fn check_xor_swap(cx: &LateContext<'_>, block: &Block<'_>) { +fn check_xor_swap<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) { for [s1, s2, s3] in block.stmts.array_windows::<3>() { let ctxt = s1.span.ctxt(); if let Some((lhs0, rhs0)) = extract_sides_of_xor_assign(s1, ctxt) @@ -268,7 +295,7 @@ fn check_xor_swap(cx: &LateContext<'_>, block: &Block<'_>) { && s3.span.ctxt() == ctxt { let span = s1.span.to(s3.span); - generate_swap_warning(cx, lhs0, rhs0, span, true); + generate_swap_warning(block, cx, lhs0, rhs0, rhs1, rhs2, span, true); }; } } @@ -294,3 +321,130 @@ fn extract_sides_of_xor_assign<'a, 'hir>( None } } + +struct IndexBinding<'a, 'tcx> { + block: &'a Block<'a>, + swap1_idx: &'a Expr<'a>, + swap2_idx: &'a Expr<'a>, + suggest_span: Span, + cx: &'a LateContext<'tcx>, + ctxt: SyntaxContext, + applicability: &'a mut Applicability, +} + +impl<'a, 'tcx> IndexBinding<'a, 'tcx> { + fn snippet_index_bindings(&mut self, exprs: &[&'tcx Expr<'tcx>]) -> String { + let mut bindings = FxHashSet::default(); + for expr in exprs { + bindings.insert(self.snippet_index_binding(expr)); + } + bindings.into_iter().join("") + } + + fn snippet_index_binding(&mut self, expr: &'tcx Expr<'tcx>) -> String { + match expr.kind { + ExprKind::Binary(_, lhs, rhs) => { + if matches!(lhs.kind, ExprKind::Lit(_)) && matches!(rhs.kind, ExprKind::Lit(_)) { + return String::new(); + } + let lhs_snippet = self.snippet_index_binding(lhs); + let rhs_snippet = self.snippet_index_binding(rhs); + format!("{lhs_snippet}{rhs_snippet}") + }, + ExprKind::Path(QPath::Resolved(_, path)) => { + let init = self.cx.expr_or_init(expr); + + let Some(first_segment) = path.segments.first() else { + return String::new(); + }; + if !self.suggest_span.contains(init.span) || !self.is_used_other_than_swapping(first_segment.ident) { + return String::new(); + } + + let init_str = snippet_with_context(self.cx, init.span, self.ctxt, "", self.applicability) + .0 + .to_string(); + let indent_str = snippet_indent(self.cx, init.span); + let indent_str = indent_str.as_deref().unwrap_or(""); + + format!("let {} = {init_str};\n{indent_str}", first_segment.ident) + }, + _ => String::new(), + } + } + + fn is_used_other_than_swapping(&mut 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) + { + return true; + } + self.is_used_after_swap(idx_ident) + } + + fn is_used_after_swap(&mut self, idx_ident: Ident) -> bool { + let mut v = IndexBindingVisitor { + found_used: false, + suggest_span: self.suggest_span, + idx: idx_ident, + }; + + for stmt in self.block.stmts { + match stmt.kind { + StmtKind::Expr(expr) | StmtKind::Semi(expr) => v.visit_expr(expr), + StmtKind::Let(LetStmt { ref init, .. }) => { + if let Some(init) = init.as_ref() { + v.visit_expr(init); + } + }, + StmtKind::Item(_) => {}, + } + } + + v.found_used + } + + fn is_used_slice_indexed(swap_index: &Expr<'_>, idx_ident: Ident) -> bool { + match swap_index.kind { + ExprKind::Binary(_, lhs, rhs) => { + if matches!(lhs.kind, ExprKind::Lit(_)) && matches!(rhs.kind, ExprKind::Lit(_)) { + return false; + } + Self::is_used_slice_indexed(lhs, idx_ident) || Self::is_used_slice_indexed(rhs, idx_ident) + }, + ExprKind::Path(QPath::Resolved(_, path)) => { + path.segments.first().map_or(false, |idx| idx.ident == idx_ident) + }, + _ => false, + } + } +} + +struct IndexBindingVisitor { + idx: Ident, + suggest_span: Span, + found_used: bool, +} + +impl<'tcx> Visitor<'tcx> for IndexBindingVisitor { + fn visit_path_segment(&mut self, path_segment: &'tcx rustc_hir::PathSegment<'tcx>) -> Self::Result { + if path_segment.ident == self.idx { + self.found_used = true; + } + } + + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> Self::Result { + if expr.span.hi() <= self.suggest_span.hi() { + return; + } + + match expr.kind { + ExprKind::Path(QPath::Resolved(_, path)) => { + for segment in path.segments { + self.visit_path_segment(segment); + } + }, + _ => walk_expr(self, expr), + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs b/src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs index f8bdb866ca39..c1e24674e3e8 100644 --- a/src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs +++ b/src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs @@ -59,7 +59,7 @@ impl_lint_pass!(ThreadLocalInitializerCanBeMadeConst => [THREAD_LOCAL_INITIALIZE #[inline] fn is_thread_local_initializer( cx: &LateContext<'_>, - fn_kind: rustc_hir::intravisit::FnKind<'_>, + fn_kind: intravisit::FnKind<'_>, span: rustc_span::Span, ) -> Option { let macro_def_id = span.source_callee()?.macro_def_id?; @@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for ThreadLocalInitializerCanBeMadeConst { fn check_fn( &mut self, cx: &LateContext<'tcx>, - fn_kind: rustc_hir::intravisit::FnKind<'tcx>, + fn_kind: intravisit::FnKind<'tcx>, _: &'tcx rustc_hir::FnDecl<'tcx>, body: &'tcx rustc_hir::Body<'tcx>, span: rustc_span::Span, diff --git a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs index cbdf31c93364..462084e96a86 100644 --- a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs +++ b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs @@ -44,7 +44,7 @@ impl<'tcx> LateLintPass<'tcx> for TrailingEmptyArray { item.span, "trailing zero-sized array in a struct which is not marked with a `repr` attribute", None, - &format!( + format!( "consider annotating `{}` with `#[repr(C)]` or another `repr` attribute", cx.tcx.def_path_str(item.owner_id) ), diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs index 768623b5d034..9468d367a926 100644 --- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs @@ -293,7 +293,7 @@ impl TraitBounds { p.span, "this type has already been used as a bound predicate", None, - &hint_string, + hint_string, ); } } @@ -420,7 +420,11 @@ fn into_comparable_trait_ref(trait_ref: &TraitRef<'_>) -> ComparableTraitRef { ) } -fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) -> Vec<(ComparableTraitRef, Span)> { +fn rollup_traits( + cx: &LateContext<'_>, + bounds: &[GenericBound<'_>], + msg: &'static str, +) -> Vec<(ComparableTraitRef, Span)> { let mut map = FxHashMap::default(); let mut repeated_res = false; diff --git a/src/tools/clippy/clippy_lints/src/transmute/crosspointer_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/crosspointer_transmute.rs index 102aee1cb959..c8f959a9854b 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/crosspointer_transmute.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/crosspointer_transmute.rs @@ -13,7 +13,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty cx, CROSSPOINTER_TRANSMUTE, e.span, - &format!("transmute from a type (`{from_ty}`) to the type that it points to (`{to_ty}`)"), + format!("transmute from a type (`{from_ty}`) to the type that it points to (`{to_ty}`)"), ); true }, @@ -22,7 +22,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty cx, CROSSPOINTER_TRANSMUTE, e.span, - &format!("transmute from a type (`{from_ty}`) to a pointer to that type (`{to_ty}`)"), + format!("transmute from a type (`{from_ty}`) to a pointer to that type (`{to_ty}`)"), ); true }, diff --git a/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs b/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs new file mode 100644 index 000000000000..cc6ff1cf3b42 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs @@ -0,0 +1,87 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use rustc_errors::Applicability; +use rustc_hir::{GenericArg, HirId, LetStmt, Node, Path, TyKind}; +use rustc_lint::LateContext; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::Ty; + +use crate::transmute::MISSING_TRANSMUTE_ANNOTATIONS; + +fn get_parent_local_binding_ty<'tcx>(cx: &LateContext<'tcx>, expr_hir_id: HirId) -> Option> { + let mut parent_iter = cx.tcx.hir().parent_iter(expr_hir_id); + if let Some((_, node)) = parent_iter.next() { + match node { + Node::LetStmt(local) => Some(*local), + Node::Block(_) => { + if let Some((parent_hir_id, Node::Expr(expr))) = parent_iter.next() + && matches!(expr.kind, rustc_hir::ExprKind::Block(_, _)) + { + get_parent_local_binding_ty(cx, parent_hir_id) + } else { + None + } + }, + _ => None, + } + } else { + None + } +} + +fn is_function_block(cx: &LateContext<'_>, expr_hir_id: HirId) -> bool { + let def_id = cx.tcx.hir().enclosing_body_owner(expr_hir_id); + if let Some(body_id) = cx.tcx.hir().maybe_body_owned_by(def_id) { + let body = cx.tcx.hir().body(body_id); + return body.value.peel_blocks().hir_id == expr_hir_id; + } + false +} + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + path: &Path<'tcx>, + from_ty: Ty<'tcx>, + to_ty: Ty<'tcx>, + expr_hir_id: HirId, +) -> bool { + let last = path.segments.last().unwrap(); + if in_external_macro(cx.tcx.sess, last.ident.span) { + // If it comes from a non-local macro, we ignore it. + return false; + } + let args = last.args; + let missing_generic = match args { + Some(args) if !args.args.is_empty() => args.args.iter().any(|arg| match arg { + GenericArg::Infer(_) => true, + GenericArg::Type(ty) => matches!(ty.kind, TyKind::Infer), + _ => false, + }), + _ => true, + }; + if !missing_generic { + return false; + } + // If it's being set as a local variable value... + if let Some(local) = get_parent_local_binding_ty(cx, expr_hir_id) { + // ... which does have type annotations. + if let Some(ty) = local.ty + // If this is a `let x: _ =`, we should lint. + && !matches!(ty.kind, TyKind::Infer) + { + return false; + } + // We check if this transmute is not the only element in the function + } else if is_function_block(cx, expr_hir_id) { + return false; + } + span_lint_and_sugg( + cx, + MISSING_TRANSMUTE_ANNOTATIONS, + last.ident.span.with_hi(path.span.hi()), + "transmute used without annotations", + "consider adding missing annotations", + format!("{}::<{from_ty}, {to_ty}>", last.ident.as_str()), + Applicability::MaybeIncorrect, + ); + true +} diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs index 3c11b4813105..7fa536a1a29d 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs @@ -1,5 +1,6 @@ mod crosspointer_transmute; mod eager_transmute; +mod missing_transmute_annotations; mod transmute_float_to_int; mod transmute_int_to_bool; mod transmute_int_to_char; @@ -520,6 +521,37 @@ declare_clippy_lint! { "eager evaluation of `transmute`" } +declare_clippy_lint! { + /// ### What it does + /// Checks if transmute calls have all generics specified. + /// + /// ### Why is this bad? + /// If not set, some unexpected output type could be retrieved instead of the expected one, + /// potentially leading to invalid code. + /// + /// This is particularly dangerous in case a seemingly innocent/unrelated change can cause type + /// inference to start inferring a different type. E.g. the transmute is the tail expression of + /// an `if` branch, and a different branches type changes, causing the transmute to silently + /// have a different type, instead of a proper error. + /// + /// ### Example + /// ```no_run + /// # unsafe { + /// let x: i32 = std::mem::transmute([1u16, 2u16]); + /// # } + /// ``` + /// Use instead: + /// ```no_run + /// # unsafe { + /// let x = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]); + /// # } + /// ``` + #[clippy::version = "1.77.0"] + pub MISSING_TRANSMUTE_ANNOTATIONS, + suspicious, + "warns if a transmute call doesn't have all generics specified" +} + pub struct Transmute { msrv: Msrv, } @@ -542,6 +574,7 @@ impl_lint_pass!(Transmute => [ TRANSMUTING_NULL, TRANSMUTE_NULL_TO_FN, EAGER_TRANSMUTE, + MISSING_TRANSMUTE_ANNOTATIONS, ]); impl Transmute { #[must_use] @@ -579,6 +612,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { | transmuting_null::check(cx, e, arg, to_ty) | transmute_null_to_fn::check(cx, e, arg, to_ty) | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, &self.msrv) + | missing_transmute_annotations::check(cx, path, from_ty, to_ty, e.hir_id) | transmute_int_to_char::check(cx, e, from_ty, to_ty, arg, const_context) | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context) | transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg) diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs index aef520923e47..ab3bb5e1062d 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs @@ -23,7 +23,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_FLOAT_TO_INT, e.span, - &format!("transmute from a `{from_ty}` to a `{to_ty}`"), + format!("transmute from a `{from_ty}` to a `{to_ty}`"), |diag| { let mut sugg = sugg::Sugg::hir(cx, arg, ".."); diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_bool.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_bool.rs index 58227c53de2f..a71928090779 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_bool.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_bool.rs @@ -23,7 +23,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_INT_TO_BOOL, e.span, - &format!("transmute from a `{from_ty}` to a `bool`"), + format!("transmute from a `{from_ty}` to a `bool`"), |diag| { let arg = sugg::Sugg::hir(cx, arg, ".."); let zero = sugg::Sugg::NonParen(Cow::from("0")); diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_char.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_char.rs index 2a6c24812545..81d10a7d5bde 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_char.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_char.rs @@ -23,7 +23,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_INT_TO_CHAR, e.span, - &format!("transmute from a `{from_ty}` to a `char`"), + format!("transmute from a `{from_ty}` to a `char`"), |diag| { let Some(top_crate) = std_or_core(cx) else { return }; let arg = sugg::Sugg::hir(cx, arg, ".."); diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_float.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_float.rs index cc3422edbbf1..d51888e30971 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_float.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_float.rs @@ -22,7 +22,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_INT_TO_FLOAT, e.span, - &format!("transmute from a `{from_ty}` to a `{to_ty}`"), + format!("transmute from a `{from_ty}` to a `{to_ty}`"), |diag| { let arg = sugg::Sugg::hir(cx, arg, ".."); let arg = if let ty::Int(int_ty) = from_ty.kind() { diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs index 97068efd43cd..234021f0f479 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs @@ -58,7 +58,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_INT_TO_NON_ZERO, e.span, - &format!("transmute from a `{from_ty}` to a `{nonzero_alias}`"), + format!("transmute from a `{from_ty}` to a `{nonzero_alias}`"), |diag| { let arg = sugg::Sugg::hir(cx, arg, ".."); diag.span_suggestion( diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_num_to_bytes.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_num_to_bytes.rs index 009d5a7c8ae1..88b0ac5a3688 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_num_to_bytes.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_num_to_bytes.rs @@ -31,7 +31,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_NUM_TO_BYTES, e.span, - &format!("transmute from a `{from_ty}` to a `{to_ty}`"), + format!("transmute from a `{from_ty}` to a `{to_ty}`"), |diag| { let arg = sugg::Sugg::hir(cx, arg, ".."); diag.span_suggestion( diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs index cf78709583cf..eaf927c0005f 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs @@ -25,7 +25,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_PTR_TO_REF, e.span, - &format!("transmute from a pointer type (`{from_ty}`) to a reference type (`{to_ty}`)"), + format!("transmute from a pointer type (`{from_ty}`) to a reference type (`{to_ty}`)"), |diag| { let arg = sugg::Sugg::hir(cx, arg, ".."); let (deref, cast) = if *mutbl == Mutability::Mut { diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs index 73321c56f3fe..3842c4eb60e8 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs @@ -35,7 +35,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_BYTES_TO_STR, e.span, - &format!("transmute from a `{from_ty}` to a `{to_ty}`"), + format!("transmute from a `{from_ty}` to a `{to_ty}`"), "consider using", if const_context { format!("{top_crate}::str::from_utf8_unchecked{postfix}({snippet})") diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs index 33c4031fa875..9c8dd37d53dc 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs @@ -71,7 +71,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_UNDEFINED_REPR, e.span, - &format!("transmute from `{from_ty_orig}` which has an undefined layout"), + format!("transmute from `{from_ty_orig}` which has an undefined layout"), |diag| { if from_ty_orig.peel_refs() != from_ty.peel_refs() { diag.note(format!("the contained type `{from_ty}` has an undefined layout")); @@ -85,7 +85,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_UNDEFINED_REPR, e.span, - &format!("transmute to `{to_ty_orig}` which has an undefined layout"), + format!("transmute to `{to_ty_orig}` which has an undefined layout"), |diag| { if to_ty_orig.peel_refs() != to_ty.peel_refs() { diag.note(format!("the contained type `{to_ty}` has an undefined layout")); @@ -111,7 +111,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_UNDEFINED_REPR, e.span, - &format!( + format!( "transmute from `{from_ty_orig}` to `{to_ty_orig}`, both of which have an undefined layout" ), |diag| { @@ -140,7 +140,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_UNDEFINED_REPR, e.span, - &format!("transmute from `{from_ty_orig}` which has an undefined layout"), + format!("transmute from `{from_ty_orig}` which has an undefined layout"), |diag| { if from_ty_orig.peel_refs() != from_ty { diag.note(format!("the contained type `{from_ty}` has an undefined layout")); @@ -157,7 +157,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTE_UNDEFINED_REPR, e.span, - &format!("transmute into `{to_ty_orig}` which has an undefined layout"), + format!("transmute into `{to_ty_orig}` which has an undefined layout"), |diag| { if to_ty_orig.peel_refs() != to_ty { diag.note(format!("the contained type `{to_ty}` has an undefined layout")); diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs index 043c9c886019..6f5ac625e357 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs @@ -53,7 +53,7 @@ pub(super) fn check<'tcx>( cx, TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS, e.span, - &format!("transmute from `{from_ty}` to `{to_ty}` which could be expressed as a pointer cast instead"), + format!("transmute from `{from_ty}` to `{to_ty}` which could be expressed as a pointer cast instead"), "try", sugg, app, diff --git a/src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs index 891fefc17a64..35e938307660 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs @@ -37,7 +37,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty cx, UNSOUND_COLLECTION_TRANSMUTE, e.span, - &format!("transmute from `{from_ty}` to `{to_ty}` with mismatched layout is unsound"), + format!("transmute from `{from_ty}` to `{to_ty}` with mismatched layout is unsound"), ); true } else { 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 70628f3d4f41..ec5fb2793f97 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs @@ -21,7 +21,7 @@ pub(super) fn check<'tcx>( cx, USELESS_TRANSMUTE, e.span, - &format!("transmute from a type (`{from_ty}`) to itself"), + format!("transmute from a type (`{from_ty}`) to itself"), ); true }, diff --git a/src/tools/clippy/clippy_lints/src/transmute/wrong_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/wrong_transmute.rs index ed815884a764..14a5a308a641 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/wrong_transmute.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/wrong_transmute.rs @@ -13,7 +13,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty cx, WRONG_TRANSMUTE, e.span, - &format!("transmute from a `{from_ty}` to a pointer"), + format!("transmute from a `{from_ty}` to a pointer"), ); true }, diff --git a/src/tools/clippy/clippy_lints/src/types/box_collection.rs b/src/tools/clippy/clippy_lints/src/types/box_collection.rs index fc3420af0208..9ac73394548c 100644 --- a/src/tools/clippy/clippy_lints/src/types/box_collection.rs +++ b/src/tools/clippy/clippy_lints/src/types/box_collection.rs @@ -21,9 +21,9 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ cx, BOX_COLLECTION, hir_ty.span, - &format!("you seem to be trying to use `Box<{box_content}>`. Consider using just `{box_content}`"), + format!("you seem to be trying to use `Box<{box_content}>`. Consider using just `{box_content}`"), None, - &format!("`{box_content}` is already on the heap, `Box<{box_content}>` makes an extra allocation"), + format!("`{box_content}` is already on the heap, `Box<{box_content}>` makes an extra allocation"), ); true } else { diff --git a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs index 37437cbfbec4..0801eace4fcf 100644 --- a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs +++ b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs @@ -29,7 +29,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>, qpath: cx, REDUNDANT_ALLOCATION, hir_ty.span, - &format!("usage of `{outer_sym}<{generic_snippet}>`"), + format!("usage of `{outer_sym}<{generic_snippet}>`"), |diag| { diag.span_suggestion(hir_ty.span, "try", format!("{generic_snippet}"), applicability); diag.note(format!( @@ -73,7 +73,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>, qpath: cx, REDUNDANT_ALLOCATION, hir_ty.span, - &format!("usage of `{outer_sym}<{inner_sym}<{generic_snippet}>>`"), + format!("usage of `{outer_sym}<{inner_sym}<{generic_snippet}>>`"), |diag| { diag.span_suggestion( hir_ty.span, @@ -92,7 +92,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>, qpath: cx, REDUNDANT_ALLOCATION, hir_ty.span, - &format!("usage of `{outer_sym}<{inner_sym}<{generic_snippet}>>`"), + format!("usage of `{outer_sym}<{inner_sym}<{generic_snippet}>>`"), |diag| { diag.note(format!( "`{inner_sym}<{generic_snippet}>` is already on the heap, `{outer_sym}<{inner_sym}<{generic_snippet}>>` makes an extra allocation" diff --git a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs index 8764e3006c6b..0c4e2c91aec5 100644 --- a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs +++ b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs @@ -23,7 +23,7 @@ declare_clippy_lint! { /// implementations. /// /// ### Why is this bad? - /// This is a hard to find infinite recursion that will crash any code. + /// This is a hard to find infinite recursion that will crash any code /// using it. /// /// ### Example 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 5fe4b74b3a7a..cbd161800770 100644 --- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -200,7 +200,7 @@ 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 - (hir::ItemKind::Impl(impl_), HasSafetyComment::No) if impl_.unsafety == hir::Unsafety::Unsafe => { + (ItemKind::Impl(impl_), HasSafetyComment::No) if impl_.unsafety == hir::Unsafety::Unsafe => { if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, item.hir_id()) && !is_unsafe_from_proc_macro(cx, item.span) { @@ -222,7 +222,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks { } }, // lint safe impl with unnecessary safety comment - (hir::ItemKind::Impl(impl_), HasSafetyComment::Yes(pos)) if impl_.unsafety == hir::Unsafety::Normal => { + (ItemKind::Impl(impl_), HasSafetyComment::Yes(pos)) if impl_.unsafety == hir::Unsafety::Normal => { if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) { let (span, help_span) = mk_spans(pos); @@ -236,9 +236,9 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks { ); } }, - (hir::ItemKind::Impl(_), _) => {}, + (ItemKind::Impl(_), _) => {}, // const and static items only need a safety comment if their body is an unsafe block, lint otherwise - (&hir::ItemKind::Const(.., body) | &hir::ItemKind::Static(.., body), HasSafetyComment::Yes(pos)) => { + (&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!( @@ -251,7 +251,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks { cx, UNNECESSARY_SAFETY_COMMENT, span, - &format!("{} has unnecessary safety comment", item.kind.descr()), + format!("{} has unnecessary safety comment", item.kind.descr()), Some(help_span), "consider removing the safety comment", ); @@ -268,7 +268,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks { cx, UNNECESSARY_SAFETY_COMMENT, span, - &format!("{} has unnecessary safety comment", item.kind.descr()), + format!("{} has unnecessary safety comment", item.kind.descr()), Some(help_span), "consider removing the safety comment", ); @@ -338,13 +338,13 @@ fn block_parents_have_safety_comment( accept_comment_above_statement: bool, accept_comment_above_attributes: bool, cx: &LateContext<'_>, - id: hir::HirId, + id: HirId, ) -> bool { let (span, hir_id) = match cx.tcx.parent_hir_node(id) { Node::Expr(expr) => match cx.tcx.parent_hir_node(expr.hir_id) { Node::LetStmt(hir::LetStmt { span, hir_id, .. }) => (*span, *hir_id), Node::Item(hir::Item { - kind: hir::ItemKind::Const(..) | ItemKind::Static(..), + kind: ItemKind::Const(..) | ItemKind::Static(..), span, owner_id, .. @@ -365,7 +365,7 @@ fn block_parents_have_safety_comment( }) | Node::LetStmt(hir::LetStmt { span, hir_id, .. }) => (*span, *hir_id), Node::Item(hir::Item { - kind: hir::ItemKind::Const(..) | ItemKind::Static(..), + kind: ItemKind::Const(..) | ItemKind::Static(..), span, owner_id, .. @@ -605,11 +605,11 @@ fn get_body_search_span(cx: &LateContext<'_>) -> Option { Node::Expr(e) => span = e.span, Node::Block(_) | Node::Arm(_) | Node::Stmt(_) | Node::LetStmt(_) => (), Node::Item(hir::Item { - kind: hir::ItemKind::Const(..) | ItemKind::Static(..), + kind: ItemKind::Const(..) | ItemKind::Static(..), .. }) => maybe_global_var = true, Node::Item(hir::Item { - kind: hir::ItemKind::Mod(_), + kind: ItemKind::Mod(_), span: item_span, .. }) => { diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs index 729972de6e6f..214b69dc9250 100644 --- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs +++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs @@ -153,7 +153,7 @@ impl<'tcx> LateLintPass<'tcx> for UnitReturnExpectingOrd { cx, UNIT_RETURN_EXPECTING_ORD, span, - &format!( + format!( "this closure returns \ the unit type which also implements {trait_name}" ), @@ -164,7 +164,7 @@ impl<'tcx> LateLintPass<'tcx> for UnitReturnExpectingOrd { cx, UNIT_RETURN_EXPECTING_ORD, span, - &format!( + format!( "this closure returns \ the unit type which also implements {trait_name}" ), diff --git a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs index ffb909d79073..80b661a757c2 100644 --- a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs +++ b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs @@ -1,9 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_context; -use clippy_utils::visitors::{for_each_local_assignment, for_each_value_source}; +use clippy_utils::visitors::{for_each_local_assignment, for_each_value_source, is_local_used}; use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; +use rustc_hir::intravisit::{walk_body, Visitor}; use rustc_hir::{Expr, ExprKind, HirId, HirIdSet, LetStmt, MatchSource, Node, PatKind, QPath, TyKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::{in_external_macro, is_from_async_await}; @@ -75,12 +76,53 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx LetStmt<'_>) { let snip = snippet_with_context(cx, expr.span, local.span.ctxt(), "()", &mut app).0; diag.span_suggestion(local.span, "omit the `let` binding", format!("{snip};"), app); } + + if let PatKind::Binding(_, binding_hir_id, ident, ..) = local.pat.kind + && let Some(body_id) = cx.enclosing_body.as_ref() + && let body = cx.tcx.hir().body(*body_id) + && is_local_used(cx, body, binding_hir_id) + { + let identifier = ident.as_str(); + let mut visitor = UnitVariableCollector::new(binding_hir_id); + walk_body(&mut visitor, body); + visitor.spans.into_iter().for_each(|span| { + let msg = + format!("variable `{identifier}` of type `()` can be replaced with explicit `()`"); + diag.span_suggestion(span, msg, "()", Applicability::MachineApplicable); + }); + } }, ); } } } +struct UnitVariableCollector { + id: HirId, + spans: Vec, +} + +impl UnitVariableCollector { + fn new(id: HirId) -> Self { + Self { id, spans: vec![] } + } +} + +/** + * Collect all instances where a variable is used based on its `HirId`. + */ +impl<'tcx> Visitor<'tcx> for UnitVariableCollector { + fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) -> Self::Result { + if let ExprKind::Path(QPath::Resolved(None, path)) = ex.kind + && let Res::Local(id) = path.res + && id == self.id + { + self.spans.push(path.span); + } + rustc_hir::intravisit::walk_expr(self, ex); + } +} + /// Checks sub-expressions which create the value returned by the given expression for whether /// return value inference is needed. This checks through locals to see if they also need inference /// at this point. diff --git a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs index eba7fa7b993c..afc53e6f32d9 100644 --- a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs +++ b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; use rustc_errors::Applicability; -use rustc_hir::{self as hir, Block, Expr, ExprKind, MatchSource, Node, StmtKind}; +use rustc_hir::{Block, Expr, ExprKind, MatchSource, Node, StmtKind}; use rustc_lint::LateContext; use super::{utils, UNIT_ARG}; @@ -19,7 +19,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if is_questionmark_desugar_marked_call(expr) { return; } - if let hir::Node::Expr(parent_expr) = cx.tcx.parent_hir_node(expr.hir_id) + if let Node::Expr(parent_expr) = cx.tcx.parent_hir_node(expr.hir_id) && is_questionmark_desugar_marked_call(parent_expr) { return; @@ -69,7 +69,7 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp cx, UNIT_ARG, expr.span, - &format!("passing {singular}unit value{plural} to a function"), + format!("passing {singular}unit value{plural} to a function"), |db| { let mut or = ""; args_to_recover diff --git a/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs b/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs index d4342ec5169a..6dcc1195a705 100644 --- a/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs +++ b/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs @@ -24,7 +24,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { cx, UNIT_CMP, macro_call.span, - &format!("`{macro_name}` of unit values detected. This will always {result}"), + format!("`{macro_name}` of unit values detected. This will always {result}"), ); } return; @@ -41,7 +41,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { cx, UNIT_CMP, expr.span, - &format!( + format!( "{}-comparison of unit values detected. This will always be {result}", op.as_str() ), 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 c332cf076ae7..bfcefb26153f 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs @@ -88,7 +88,7 @@ impl UnnecessaryBoxReturns { cx, UNNECESSARY_BOX_RETURNS, return_ty_hir.span, - format!("boxed return of the sized type `{boxed_ty}`").as_str(), + format!("boxed return of the sized type `{boxed_ty}`"), |diagnostic| { diagnostic.span_suggestion( return_ty_hir.span, diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs b/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs index 2b0d2d61d207..8f1eb5019f0f 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs @@ -65,7 +65,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMapOnConstructor { hir::QPath::LangItem(..) => return, }; match constructor_symbol { - sym::Some | sym::Ok if path.ident.name == rustc_span::sym::map => (), + sym::Some | sym::Ok if path.ident.name == sym::map => (), sym::Err if path.ident.name == sym::map_err => (), _ => return, } @@ -86,7 +86,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMapOnConstructor { cx, UNNECESSARY_MAP_ON_CONSTRUCTOR, expr.span, - &format!( + format!( "unnecessary {} on constructor {constructor_snippet}(_)", path.ident.name ), diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs index 9c8b0ae17276..5c7fbbab988b 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs @@ -156,7 +156,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { ) }; - span_lint_and_then(cx, UNNECESSARY_WRAPS, span, lint_msg.as_str(), |diag| { + span_lint_and_then(cx, UNNECESSARY_WRAPS, span, lint_msg, |diag| { diag.span_suggestion( fn_decl.output.span(), return_type_sugg_msg, 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 d4dd31e11781..0049de931f4f 100644 --- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs @@ -215,7 +215,7 @@ macro_rules! always_pat { /// in `alternatives[focus_idx + 1..]`. fn transform_with_focus_on_idx(alternatives: &mut ThinVec>, focus_idx: usize) -> bool { // Extract the kind; we'll need to make some changes in it. - let mut focus_kind = mem::replace(&mut alternatives[focus_idx].kind, PatKind::Wild); + let mut focus_kind = mem::replace(&mut alternatives[focus_idx].kind, Wild); // We'll focus on `alternatives[focus_idx]`, // so we're draining from `alternatives[focus_idx + 1..]`. let start = focus_idx + 1; @@ -232,7 +232,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec>, focus_idx: us // In the case of only two patterns, replacement adds net characters. | Ref(_, Mutability::Not) // Dealt with elsewhere. - | Or(_) | Paren(_) => false, + | Or(_) | Paren(_) | Deref(_) => false, // Transform `box x | ... | box y` into `box (x | y)`. // // The cases below until `Slice(...)` deal with *singleton* products. @@ -242,8 +242,6 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec>, focus_idx: us |k| matches!(k, Box(_)), |k| always_pat!(k, Box(p) => p), ), - // FIXME(deref_patterns): Should we merge patterns here? - Deref(_) => false, // Transform `&mut x | ... | &mut y` into `&mut (x | y)`. Ref(target, Mutability::Mut) => extend_with_matching( target, start, alternatives, diff --git a/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs b/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs index 3f2f765f7512..51b3ea93b6dc 100644 --- a/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs +++ b/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs @@ -65,7 +65,7 @@ fn unsafe_to_safe_check(old_name: Ident, new_name: Ident, cx: &EarlyContext<'_>, cx, UNSAFE_REMOVED_FROM_NAME, span, - &format!("removed `unsafe` from the name of `{old_str}` in use as `{new_str}`"), + format!("removed `unsafe` from the name of `{old_str}` in use as `{new_str}`"), ); } } diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs index d8c5f1b7382d..448946bd66d5 100644 --- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs +++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs @@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount { if let Some(exp) = block.expr && matches!( exp.kind, - hir::ExprKind::If(_, _, _) | hir::ExprKind::Match(_, _, hir::MatchSource::Normal) + ExprKind::If(_, _, _) | ExprKind::Match(_, _, hir::MatchSource::Normal) ) { check_expr(cx, exp); @@ -130,7 +130,7 @@ fn non_consuming_ok_arm<'a>(cx: &LateContext<'a>, arm: &hir::Arm<'a>) -> bool { fn check_expr<'a>(cx: &LateContext<'a>, expr: &'a hir::Expr<'a>) { match expr.kind { - hir::ExprKind::If(cond, _, _) + ExprKind::If(cond, _, _) if let ExprKind::Let(hir::LetExpr { pat, init, .. }) = cond.kind && is_ok_wild_or_dotdot_pattern(cx, pat) && let Some(op) = should_lint(cx, init) => @@ -140,7 +140,7 @@ fn check_expr<'a>(cx: &LateContext<'a>, expr: &'a hir::Expr<'a>) { // we will capture only the case where the match is Ok( ) or Err( ) // prefer to match the minimum possible, and expand later if needed // to avoid false positives on something as used as this - hir::ExprKind::Match(expr, [arm1, arm2], hir::MatchSource::Normal) if let Some(op) = should_lint(cx, expr) => { + ExprKind::Match(expr, [arm1, arm2], hir::MatchSource::Normal) if let Some(op) = should_lint(cx, expr) => { if non_consuming_ok_arm(cx, arm1) && non_consuming_err_arm(cx, arm2) { emit_lint(cx, expr.span, expr.hir_id, op, &[arm1.pat.span]); } @@ -148,7 +148,7 @@ fn check_expr<'a>(cx: &LateContext<'a>, expr: &'a hir::Expr<'a>) { emit_lint(cx, expr.span, expr.hir_id, op, &[arm2.pat.span]); } }, - hir::ExprKind::Match(_, _, hir::MatchSource::Normal) => {}, + ExprKind::Match(_, _, hir::MatchSource::Normal) => {}, _ if let Some(op) = should_lint(cx, expr) => { emit_lint(cx, expr.span, expr.hir_id, op, &[]); }, @@ -201,7 +201,7 @@ fn is_unreachable_or_panic(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { } fn unpack_call_chain<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { - while let hir::ExprKind::MethodCall(path, receiver, ..) = expr.kind { + while let ExprKind::MethodCall(path, receiver, ..) = expr.kind { if matches!( path.ident.as_str(), "unwrap" | "expect" | "unwrap_or" | "unwrap_or_else" | "ok" | "is_ok" | "is_err" | "or_else" | "or" @@ -215,10 +215,10 @@ fn unpack_call_chain<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { } fn unpack_try<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { - while let hir::ExprKind::Call(func, [ref arg_0, ..]) = expr.kind + while let ExprKind::Call(func, [ref arg_0, ..]) = expr.kind && matches!( func.kind, - hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryTraitBranch, ..)) + ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryTraitBranch, ..)) ) { expr = arg_0; @@ -227,7 +227,7 @@ fn unpack_try<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { } fn unpack_match<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { - while let hir::ExprKind::Match(res, _, _) = expr.kind { + while let ExprKind::Match(res, _, _) = expr.kind { expr = res; } expr @@ -236,11 +236,11 @@ fn unpack_match<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { /// If `expr` is an (e).await, return the inner expression "e" that's being /// waited on. Otherwise return None. fn unpack_await<'a>(expr: &'a hir::Expr<'a>) -> &hir::Expr<'a> { - if let hir::ExprKind::Match(expr, _, hir::MatchSource::AwaitDesugar) = expr.kind { - if let hir::ExprKind::Call(func, [ref arg_0, ..]) = expr.kind { + if let ExprKind::Match(expr, _, hir::MatchSource::AwaitDesugar) = expr.kind { + if let ExprKind::Call(func, [ref arg_0, ..]) = expr.kind { if matches!( func.kind, - hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::IntoFutureIntoFuture, ..)) + ExprKind::Path(hir::QPath::LangItem(hir::LangItem::IntoFutureIntoFuture, ..)) ) { return arg_0; } @@ -251,7 +251,7 @@ fn unpack_await<'a>(expr: &'a hir::Expr<'a>) -> &hir::Expr<'a> { /// Check whether the current expr is a function call for an IO operation fn check_io_mode(cx: &LateContext<'_>, call: &hir::Expr<'_>) -> Option { - let hir::ExprKind::MethodCall(path, ..) = call.kind else { + let ExprKind::MethodCall(path, ..) = call.kind else { return None; }; diff --git a/src/tools/clippy/clippy_lints/src/unused_rounding.rs b/src/tools/clippy/clippy_lints/src/unused_rounding.rs index d5ca844b9e24..3e5afec541c4 100644 --- a/src/tools/clippy/clippy_lints/src/unused_rounding.rs +++ b/src/tools/clippy/clippy_lints/src/unused_rounding.rs @@ -55,8 +55,8 @@ impl EarlyLintPass for UnusedRounding { cx, UNUSED_ROUNDING, expr.span, - &format!("used the `{method_name}` method with a whole number float"), - &format!("remove the `{method_name}` method call"), + format!("used the `{method_name}` method with a whole number float"), + format!("remove the `{method_name}` method call"), float, Applicability::MachineApplicable, ); diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs index f2eb774b5cbf..2622abd59cbd 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap.rs @@ -338,7 +338,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> { UNNECESSARY_UNWRAP, expr.hir_id, expr.span, - &format!( + format!( "called `{}` on `{unwrappable_variable_name}` after checking its variant with `{}`", method_name.ident.name, unwrappable.check_name.ident.as_str(), @@ -373,7 +373,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> { PANICKING_UNWRAP, expr.hir_id, expr.span, - &format!("this call to `{}()` will always panic", method_name.ident.name), + format!("this call to `{}()` will always panic", method_name.ident.name), |diag| { diag.span_label(unwrappable.check.span, "because of this check"); }, diff --git a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs index a615ef116910..aca500590cef 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs @@ -59,7 +59,7 @@ declare_lint_pass!(UnwrapInResult=> [UNWRAP_IN_RESULT]); impl<'tcx> LateLintPass<'tcx> for UnwrapInResult { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) { - if let hir::ImplItemKind::Fn(ref _signature, _) = impl_item.kind + if let ImplItemKind::Fn(ref _signature, _) = impl_item.kind // first check if it's a method or function // checking if its return type is `result` or `option` && (is_type_diagnostic_item(cx, return_ty(cx, impl_item.owner_id), sym::Result) diff --git a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs index d2a1d42f2796..f376d3496461 100644 --- a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs +++ b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs @@ -94,7 +94,7 @@ fn check_ident(cx: &LateContext<'_>, ident: &Ident, hir_id: HirId, be_aggressive UPPER_CASE_ACRONYMS, hir_id, span, - &format!("name `{ident}` contains a capitalized acronym"), + format!("name `{ident}` contains a capitalized acronym"), |diag| { diag.span_suggestion( span, diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs index a6b411d6c0f9..0bab917607da 100644 --- a/src/tools/clippy/clippy_lints/src/use_self.rs +++ b/src/tools/clippy/clippy_lints/src/use_self.rs @@ -207,7 +207,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { } } - fn check_ty(&mut self, cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>) { + fn check_ty(&mut self, cx: &LateContext<'tcx>, hir_ty: &Ty<'tcx>) { if !hir_ty.span.from_expansion() && self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS) && let Some(&StackItem::Check { @@ -286,7 +286,7 @@ impl<'tcx> Visitor<'tcx> for SkipTyCollector { walk_inf(self, inf); } - fn visit_ty(&mut self, hir_ty: &hir::Ty<'_>) { + fn visit_ty(&mut self, hir_ty: &Ty<'_>) { self.types_to_skip.push(hir_ty.hir_id); walk_ty(self, hir_ty); diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs index f7a455977fac..755417661565 100644 --- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs +++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs @@ -184,7 +184,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - &format!("useless conversion to the same type: `{b}`"), + format!("useless conversion to the same type: `{b}`"), "consider removing `.into()`", sugg.into_owned(), app, @@ -301,7 +301,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - &format!("useless conversion to the same type: `{b}`"), + format!("useless conversion to the same type: `{b}`"), "consider removing `.into_iter()`", sugg, Applicability::MachineApplicable, // snippet @@ -321,7 +321,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - &format!("useless conversion to the same type: `{b}`"), + format!("useless conversion to the same type: `{b}`"), None, "consider removing `.try_into()`", ); @@ -346,9 +346,9 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - &format!("useless conversion to the same type: `{b}`"), + format!("useless conversion to the same type: `{b}`"), None, - &hint, + hint, ); } @@ -360,8 +360,8 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - &format!("useless conversion to the same type: `{b}`"), - &sugg_msg, + format!("useless conversion to the same type: `{b}`"), + sugg_msg, sugg.to_string(), app, ); diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index e45beb4910be..7b43abeef671 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -754,7 +754,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { } } -fn has_attr(cx: &LateContext<'_>, hir_id: hir::HirId) -> bool { +fn has_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool { let attrs = cx.tcx.hir().attrs(hir_id); get_attr(cx.sess(), attrs, "author").count() > 0 } @@ -771,7 +771,7 @@ fn path_to_string(path: &QPath<'_>) -> Result { } }, QPath::TypeRelative(ty, segment) => match &ty.kind { - hir::TyKind::Path(inner_path) => { + TyKind::Path(inner_path) => { inner(s, inner_path)?; *s += ", "; write!(s, "{:?}", segment.ident.as_str()).unwrap(); diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs index 4822970e47ef..5483e80f932e 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs @@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for AlmostStandardFormulation { ident.span, "non-standard lint formulation", None, - &format!("consider using `{}`", formulation.correction), + format!("consider using `{}`", formulation.correction), ); } return; diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs index 7c70d3f45dba..f75296826755 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::{is_expr_path_def_path, is_lint_allowed, peel_blocks_with_stmt, SpanlessEq}; use rustc_errors::Applicability; -use rustc_hir as hir; use rustc_hir::{Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -72,7 +71,7 @@ declare_clippy_lint! { declare_lint_pass!(CollapsibleCalls => [COLLAPSIBLE_SPAN_LINT_CALLS]); impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if is_lint_allowed(cx, COLLAPSIBLE_SPAN_LINT_CALLS, expr.hir_id) { return; } diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs index df37619227c8..9b6b68718186 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs @@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for CompilerLintFunctions { path.ident.span, "usage of a compiler lint function", None, - &format!("please use the Clippy variant of this function: `{sugg}`"), + format!("please use the Clippy variant of this function: `{sugg}`"), ); } } diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs index 370ed430bcfb..9be225759df9 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs @@ -181,7 +181,7 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { cx, DEFAULT_LINT, item.span, - &format!("the lint `{}` has the default lint description", item.ident.name), + format!("the lint `{}` has the default lint description", item.ident.name), ); } @@ -191,7 +191,7 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { cx, DEFAULT_DEPRECATION_REASON, item.span, - &format!("the lint `{}` has the default deprecation reason", item.ident.name), + format!("the lint `{}` has the default deprecation reason", item.ident.name), ); } } @@ -247,7 +247,7 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { cx, LINT_WITHOUT_LINT_PASS, lint_span, - &format!("the lint `{lint_name}` is not added to any `LintPass`"), + format!("the lint `{lint_name}` is not added to any `LintPass`"), ); } } diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs index c56c8ddc7a92..5c1ebb922f12 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -153,7 +153,7 @@ impl MetadataCollector { lints: BinaryHeap::::default(), applicability_info: FxHashMap::::default(), config: get_configuration_metadata(), - clippy_project_root: std::env::current_dir() + clippy_project_root: env::current_dir() .expect("failed to get current dir") .ancestors() .nth(1) @@ -243,7 +243,7 @@ Please use that command to update the file and do not edit it by hand. .unwrap(); // Write configuration links to CHANGELOG.md - let changelog = std::fs::read_to_string(CHANGELOG_PATH).unwrap(); + let changelog = fs::read_to_string(CHANGELOG_PATH).unwrap(); let mut changelog_file = File::create(CHANGELOG_PATH).unwrap(); let position = changelog .find("") @@ -822,7 +822,7 @@ fn lint_collection_error_item(cx: &LateContext<'_>, item: &Item<'_>, message: &s cx, METADATA_COLLECTOR, item.ident.span, - &format!("metadata collection error for `{}`: {message}", item.ident.name), + format!("metadata collection error for `{}`: {message}", item.ident.name), ); } @@ -912,7 +912,7 @@ impl<'a, 'hir> LintResolver<'a, 'hir> { } } -impl<'a, 'hir> intravisit::Visitor<'hir> for LintResolver<'a, 'hir> { +impl<'a, 'hir> Visitor<'hir> for LintResolver<'a, 'hir> { type NestedFilter = nested_filter::All; fn nested_visit_map(&mut self) -> Self::Map { @@ -963,7 +963,7 @@ impl<'a, 'hir> ApplicabilityResolver<'a, 'hir> { } } -impl<'a, 'hir> intravisit::Visitor<'hir> for ApplicabilityResolver<'a, 'hir> { +impl<'a, 'hir> Visitor<'hir> for ApplicabilityResolver<'a, 'hir> { type NestedFilter = nested_filter::All; fn nested_visit_map(&mut self) -> Self::Map { @@ -994,7 +994,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for ApplicabilityResolver<'a, 'hir> { } /// This returns the parent local node if the expression is a reference one -fn get_parent_local<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Option<&'hir hir::Local<'hir>> { +fn get_parent_local<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Option<&'hir hir::LetStmt<'hir>> { if let ExprKind::Path(QPath::Resolved(_, path)) = expr.kind { if let hir::def::Res::Local(local_hir) = path.res { return get_parent_local_hir_id(cx, local_hir); @@ -1004,7 +1004,7 @@ fn get_parent_local<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) - None } -fn get_parent_local_hir_id<'hir>(cx: &LateContext<'hir>, hir_id: hir::HirId) -> Option<&'hir hir::Local<'hir>> { +fn get_parent_local_hir_id<'hir>(cx: &LateContext<'hir>, hir_id: hir::HirId) -> Option<&'hir hir::LetStmt<'hir>> { match cx.tcx.parent_hir_node(hir_id) { hir::Node::LetStmt(local) => Some(local), hir::Node::Pat(pattern) => get_parent_local_hir_id(cx, pattern.hir_id), @@ -1042,7 +1042,7 @@ impl<'a, 'hir> IsMultiSpanScanner<'a, 'hir> { } } -impl<'a, 'hir> intravisit::Visitor<'hir> for IsMultiSpanScanner<'a, 'hir> { +impl<'a, 'hir> Visitor<'hir> for IsMultiSpanScanner<'a, 'hir> { type NestedFilter = nested_filter::All; fn nested_visit_map(&mut self) -> Self::Map { diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs index 8d208fbb7e95..63fcbd61528d 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs @@ -51,8 +51,8 @@ impl LateLintPass<'_> for MsrvAttrImpl { cx, MISSING_MSRV_ATTR_IMPL, span, - &format!("`extract_msrv_attr!` macro missing from `{lint_pass}` implementation"), - &format!("add `extract_msrv_attr!({context})` to the `{lint_pass}` implementation"), + format!("`extract_msrv_attr!` macro missing from `{lint_pass}` implementation"), + format!("add `extract_msrv_attr!({context})` to the `{lint_pass}` implementation"), format!("{}\n extract_msrv_attr!({context});", snippet(cx, span, "..")), Applicability::MachineApplicable, ); diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs index 304a13793740..8cf42832761f 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs @@ -4,10 +4,9 @@ use clippy_utils::{def_path_def_ids, is_lint_allowed, match_any_def_paths, peel_ use rustc_ast::ast::LitKind; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_errors::Applicability; -use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::{Expr, ExprKind, Local, Mutability, Node}; +use rustc_hir::{Expr, ExprKind, LetStmt, Mutability, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::interpret::{Allocation, GlobalAlloc}; use rustc_middle::mir::ConstValue; @@ -49,7 +48,7 @@ pub struct UnnecessaryDefPath { } impl<'tcx> LateLintPass<'tcx> for UnnecessaryDefPath { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if is_lint_allowed(cx, UNNECESSARY_DEF_PATH, expr.hir_id) { return; } @@ -79,9 +78,9 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryDefPath { cx, UNNECESSARY_DEF_PATH, span, - &format!("hardcoded path to a {msg}"), + format!("hardcoded path to a {msg}"), None, - &format!("convert all references to use `{sugg}`"), + format!("convert all references to use `{sugg}`"), ); } } @@ -213,11 +212,11 @@ impl UnnecessaryDefPath { } } -fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option> { +fn path_to_matched_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option> { match peel_hir_expr_refs(expr).0.kind { ExprKind::Path(ref qpath) => match cx.qpath_res(qpath, expr.hir_id) { Res::Local(hir_id) => { - if let Node::LetStmt(Local { init: Some(init), .. }) = cx.tcx.parent_hir_node(hir_id) { + if let Node::LetStmt(LetStmt { init: Some(init), .. }) = cx.tcx.parent_hir_node(hir_id) { path_to_matched_type(cx, init) } else { None diff --git a/src/tools/clippy/clippy_lints/src/visibility.rs b/src/tools/clippy/clippy_lints/src/visibility.rs index 83369c66367e..9818b98dd5b4 100644 --- a/src/tools/clippy/clippy_lints/src/visibility.rs +++ b/src/tools/clippy/clippy_lints/src/visibility.rs @@ -89,7 +89,7 @@ impl EarlyLintPass for Visibility { cx, NEEDLESS_PUB_SELF, item.vis.span, - &format!("unnecessary `pub({}self)`", if *shorthand { "" } else { "in " }), + format!("unnecessary `pub({}self)`", if *shorthand { "" } else { "in " }), "remove it", String::new(), Applicability::MachineApplicable, diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs index be16d2e5cc30..26c6859233d5 100644 --- a/src/tools/clippy/clippy_lints/src/write.rs +++ b/src/tools/clippy/clippy_lints/src/write.rs @@ -297,11 +297,11 @@ impl<'tcx> LateLintPass<'tcx> for Write { match diag_name { sym::print_macro | sym::println_macro if !allowed_in_tests => { if !is_build_script { - span_lint(cx, PRINT_STDOUT, macro_call.span, &format!("use of `{name}!`")); + span_lint(cx, PRINT_STDOUT, macro_call.span, format!("use of `{name}!`")); } }, sym::eprint_macro | sym::eprintln_macro if !allowed_in_tests => { - span_lint(cx, PRINT_STDERR, macro_call.span, &format!("use of `{name}!`")); + span_lint(cx, PRINT_STDERR, macro_call.span, format!("use of `{name}!`")); }, sym::write_macro | sym::writeln_macro => {}, _ => return, @@ -390,7 +390,7 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &Ma cx, lint, macro_call.span, - &format!("using `{name}!()` with a format string that ends in a single newline"), + format!("using `{name}!()` with a format string that ends in a single newline"), |diag| { let name_span = cx.sess().source_map().span_until_char(macro_call.span, '!'); let Some(format_snippet) = snippet_opt(cx, format_string_span) else { @@ -440,7 +440,7 @@ fn check_empty_string(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call cx, lint, macro_call.span, - &format!("empty string literal in `{name}!`"), + format!("empty string literal in `{name}!`"), |diag| { diag.span_suggestion( span, diff --git a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs index d3623d6fda44..662242f6196b 100644 --- a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs +++ b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs @@ -53,7 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for ZeroDiv { expr.span, "constant division of `0.0` with `0.0` will always result in NaN", None, - &format!("consider using `{float_type}::NAN` if you would like a constant representing NaN",), + format!("consider using `{float_type}::NAN` if you would like a constant representing NaN",), ); } } diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index f7532121aeb5..f594a40ff59a 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -97,8 +97,8 @@ pub fn eq_path_seg(l: &PathSegment, r: &PathSegment) -> bool { pub fn eq_generic_args(l: &GenericArgs, r: &GenericArgs) -> bool { match (l, r) { - (GenericArgs::AngleBracketed(l), GenericArgs::AngleBracketed(r)) => over(&l.args, &r.args, eq_angle_arg), - (GenericArgs::Parenthesized(l), GenericArgs::Parenthesized(r)) => { + (AngleBracketed(l), AngleBracketed(r)) => over(&l.args, &r.args, eq_angle_arg), + (Parenthesized(l), Parenthesized(r)) => { over(&l.inputs, &r.inputs, |l, r| eq_ty(l, r)) && eq_fn_ret_ty(&l.output, &r.output) }, _ => false, @@ -304,25 +304,25 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { (ExternCrate(l), ExternCrate(r)) => l == r, (Use(l), Use(r)) => eq_use_tree(l, r), ( - Static(box ast::StaticItem { + Static(box StaticItem { ty: lt, mutability: lm, expr: le, }), - Static(box ast::StaticItem { + Static(box StaticItem { ty: rt, mutability: rm, expr: re, }), ) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re), ( - Const(box ast::ConstItem { + Const(box ConstItem { defaultness: ld, generics: lg, ty: lt, expr: le, }), - Const(box ast::ConstItem { + Const(box ConstItem { defaultness: rd, generics: rg, ty: rt, @@ -493,13 +493,13 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { use AssocItemKind::*; match (l, r) { ( - Const(box ast::ConstItem { + Const(box ConstItem { defaultness: ld, generics: lg, ty: lt, expr: le, }), - Const(box ast::ConstItem { + Const(box ConstItem { defaultness: rd, generics: rg, ty: rt, @@ -523,14 +523,14 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r)) }, ( - Type(box ast::TyAlias { + Type(box TyAlias { defaultness: ld, generics: lg, bounds: lb, ty: lt, .. }), - Type(box ast::TyAlias { + Type(box TyAlias { defaultness: rd, generics: rg, bounds: rb, diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs index 2d0c2cf12536..d2200bcf7103 100644 --- a/src/tools/clippy/clippy_utils/src/attrs.rs +++ b/src/tools/clippy/clippy_utils/src/attrs.rs @@ -1,10 +1,15 @@ use rustc_ast::{ast, attr}; use rustc_errors::Applicability; +use rustc_lexer::TokenKind; +use rustc_lint::LateContext; use rustc_middle::ty::{AdtDef, TyCtxt}; use rustc_session::Session; -use rustc_span::sym; +use rustc_span::{sym, Span}; use std::str::FromStr; +use crate::source::snippet_opt; +use crate::tokenize_with_text; + /// Deprecation status of attributes known by Clippy. pub enum DeprecationStatus { /// Attribute is deprecated @@ -171,3 +176,28 @@ pub fn has_non_exhaustive_attr(tcx: TyCtxt<'_>, adt: AdtDef<'_>) -> bool { .all_fields() .any(|field_def| tcx.has_attr(field_def.did, sym::non_exhaustive)) } + +/// Checks if the given span contains a `#[cfg(..)]` attribute +pub fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool { + let Some(snip) = snippet_opt(cx, s) else { + // Assume true. This would require either an invalid span, or one which crosses file boundaries. + return true; + }; + let mut iter = tokenize_with_text(&snip); + + // Search for the token sequence [`#`, `[`, `cfg`] + while iter.any(|(t, _)| matches!(t, TokenKind::Pound)) { + let mut iter = iter.by_ref().skip_while(|(t, _)| { + matches!( + t, + TokenKind::Whitespace | TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } + ) + }); + if matches!(iter.next(), Some((TokenKind::OpenBracket, _))) + && matches!(iter.next(), Some((TokenKind::Ident, "cfg"))) + { + return true; + } + } + false +} 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 d751aeaf9022..422673105136 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -24,7 +24,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; -use rustc_span::symbol::Ident; +use rustc_span::symbol::{kw, Ident}; use rustc_span::{Span, Symbol}; use rustc_target::spec::abi::Abi; @@ -99,9 +99,13 @@ fn qpath_search_pat(path: &QPath<'_>) -> (Pat, Pat) { let start = if ty.is_some() { Pat::Str("<") } else { - path.segments - .first() - .map_or(Pat::Str(""), |seg| Pat::Sym(seg.ident.name)) + path.segments.first().map_or(Pat::Str(""), |seg| { + if seg.ident.name == kw::PathRoot { + Pat::Str("::") + } else { + Pat::Sym(seg.ident.name) + } + }) }; let end = path.segments.last().map_or(Pat::Str(""), |seg| { if seg.args.is_some() { diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 6b86630339fb..253ae3aca689 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -17,14 +17,14 @@ use rustc_span::def_id::DefId; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::SyntaxContext; use rustc_target::abi::Size; -use std::cmp::Ordering::{self, Equal}; +use std::cmp::Ordering; use std::hash::{Hash, Hasher}; use std::iter; /// A `LitKind`-like enum to fold constant `Expr`s into. #[derive(Debug, Clone)] pub enum Constant<'tcx> { - Adt(rustc_middle::mir::Const<'tcx>), + Adt(mir::Const<'tcx>), /// A `String` (e.g., "abc"). Str(String), /// A binary string (e.g., `b"abc"`). @@ -230,7 +230,7 @@ impl<'tcx> Constant<'tcx> { lv, rv, ) { - Some(Equal) => Some(ls.cmp(rs)), + Some(Ordering::Equal) => Some(ls.cmp(rs)), x => x, } }, @@ -579,7 +579,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { /// Lookup a possibly constant expression from an `ExprKind::Path` and apply a function on it. fn fetch_path_and_apply(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>, f: F) -> Option where - F: FnOnce(&mut Self, rustc_middle::mir::Const<'tcx>) -> Option, + F: FnOnce(&mut Self, mir::Const<'tcx>) -> Option, { let res = self.typeck_results.qpath_res(qpath, id); match res { @@ -612,7 +612,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { .tcx .const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, args), qpath.span()) .ok() - .map(|val| rustc_middle::mir::Const::from_value(val, ty))?; + .map(|val| mir::Const::from_value(val, ty))?; f(self, result) }, _ => None, diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs index 0352696f93ec..dc0a139e3c78 100644 --- a/src/tools/clippy/clippy_utils/src/diagnostics.rs +++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs @@ -8,7 +8,7 @@ //! Thank you! //! ~The `INTERNAL_METADATA_COLLECTOR` lint -use rustc_errors::{Applicability, Diag, MultiSpan}; +use rustc_errors::{Applicability, Diag, DiagMessage, MultiSpan, SubdiagMessage}; use rustc_hir::HirId; use rustc_lint::{LateContext, Lint, LintContext}; use rustc_span::Span; @@ -59,9 +59,9 @@ fn docs_link(diag: &mut Diag<'_, ()>, lint: &'static Lint) { /// 17 | std::mem::forget(seven); /// | ^^^^^^^^^^^^^^^^^^^^^^^ /// ``` -pub fn span_lint(cx: &T, lint: &'static Lint, sp: impl Into, msg: &str) { +pub fn span_lint(cx: &T, lint: &'static Lint, sp: impl Into, msg: impl Into) { #[expect(clippy::disallowed_methods)] - cx.span_lint(lint, sp, msg.to_string(), |diag| { + cx.span_lint(lint, sp, msg.into(), |diag| { docs_link(diag, lint); }); } @@ -104,17 +104,16 @@ pub fn span_lint_and_help( cx: &T, lint: &'static Lint, span: impl Into, - msg: &str, + msg: impl Into, help_span: Option, - help: &str, + help: impl Into, ) { #[expect(clippy::disallowed_methods)] - cx.span_lint(lint, span, msg.to_string(), |diag| { - let help = help.to_string(); + cx.span_lint(lint, span, msg.into(), |diag| { if let Some(help_span) = help_span { - diag.span_help(help_span, help); + diag.span_help(help_span, help.into()); } else { - diag.help(help); + diag.help(help.into()); } docs_link(diag, lint); }); @@ -161,17 +160,16 @@ pub fn span_lint_and_note( cx: &T, lint: &'static Lint, span: impl Into, - msg: &str, + msg: impl Into, note_span: Option, - note: &str, + note: impl Into, ) { #[expect(clippy::disallowed_methods)] - cx.span_lint(lint, span, msg.to_string(), |diag| { - let note = note.to_string(); + cx.span_lint(lint, span, msg.into(), |diag| { if let Some(note_span) = note_span { - diag.span_note(note_span, note); + diag.span_note(note_span, note.into()); } else { - diag.note(note); + diag.note(note.into()); } docs_link(diag, lint); }); @@ -195,14 +193,15 @@ pub fn span_lint_and_note( /// If you're unsure which function you should use, you can test if the `#[allow]` attribute works /// where you would expect it to. /// If it doesn't, you likely need to use [`span_lint_hir_and_then`] instead. -pub fn span_lint_and_then(cx: &C, lint: &'static Lint, sp: S, msg: &str, f: F) +pub fn span_lint_and_then(cx: &C, lint: &'static Lint, sp: S, msg: M, f: F) where C: LintContext, S: Into, + M: Into, F: FnOnce(&mut Diag<'_, ()>), { #[expect(clippy::disallowed_methods)] - cx.span_lint(lint, sp, msg.to_string(), |diag| { + cx.span_lint(lint, sp, msg, |diag| { f(diag); docs_link(diag, lint); }); @@ -232,9 +231,9 @@ where /// Instead, use this function and also pass the `HirId` of ``, which will let /// the compiler check lint level attributes at the place of the expression and /// the `#[allow]` will work. -pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: &str) { +pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: impl Into) { #[expect(clippy::disallowed_methods)] - cx.tcx.node_span_lint(lint, hir_id, sp, msg.to_string(), |diag| { + cx.tcx.node_span_lint(lint, hir_id, sp, msg.into(), |diag| { docs_link(diag, lint); }); } @@ -268,11 +267,11 @@ pub fn span_lint_hir_and_then( lint: &'static Lint, hir_id: HirId, sp: impl Into, - msg: &str, + msg: impl Into, f: impl FnOnce(&mut Diag<'_, ()>), ) { #[expect(clippy::disallowed_methods)] - cx.tcx.node_span_lint(lint, hir_id, sp, msg.to_string(), |diag| { + cx.tcx.node_span_lint(lint, hir_id, sp, msg.into(), |diag| { f(diag); docs_link(diag, lint); }); @@ -316,13 +315,13 @@ pub fn span_lint_and_sugg( cx: &T, lint: &'static Lint, sp: Span, - msg: &str, - help: &str, + msg: impl Into, + help: impl Into, sugg: String, applicability: Applicability, ) { - span_lint_and_then(cx, lint, sp, msg, |diag| { - diag.span_suggestion(sp, help.to_string(), sugg, applicability); + span_lint_and_then(cx, lint, sp, msg.into(), |diag| { + diag.span_suggestion(sp, help.into(), sugg, applicability); }); } @@ -332,7 +331,7 @@ pub fn span_lint_and_sugg( /// appear once per /// replacement. In human-readable format though, it only appears once before /// the whole suggestion. -pub fn multispan_sugg(diag: &mut Diag<'_, ()>, help_msg: &str, sugg: I) +pub fn multispan_sugg(diag: &mut Diag<'_, ()>, help_msg: impl Into, sugg: I) where I: IntoIterator, { @@ -346,11 +345,11 @@ where /// Suggestions with multiple spans will be silently ignored. pub fn multispan_sugg_with_applicability( diag: &mut Diag<'_, ()>, - help_msg: &str, + help_msg: impl Into, applicability: Applicability, sugg: I, ) where I: IntoIterator, { - diag.multipart_suggestion(help_msg.to_string(), sugg.into_iter().collect(), applicability); + diag.multipart_suggestion(help_msg.into(), sugg.into_iter().collect(), applicability); } diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs index 8ce19998a082..801a98521590 100644 --- a/src/tools/clippy/clippy_utils/src/higher.rs +++ b/src/tools/clippy/clippy_utils/src/higher.rs @@ -16,11 +16,11 @@ use rustc_span::{sym, symbol, Span}; /// `for pat in arg { body }` becomes `(pat, arg, body)`. Returns `(pat, arg, body, span)`. pub struct ForLoop<'tcx> { /// `for` loop item - pub pat: &'tcx hir::Pat<'tcx>, + pub pat: &'tcx Pat<'tcx>, /// `IntoIterator` argument - pub arg: &'tcx hir::Expr<'tcx>, + pub arg: &'tcx Expr<'tcx>, /// `for` loop body - pub body: &'tcx hir::Expr<'tcx>, + pub body: &'tcx Expr<'tcx>, /// Compare this against `hir::Destination.target` pub loop_id: HirId, /// entire `for` loop span @@ -30,13 +30,13 @@ pub struct ForLoop<'tcx> { impl<'tcx> ForLoop<'tcx> { /// Parses a desugared `for` loop pub fn hir(expr: &Expr<'tcx>) -> Option { - if let hir::ExprKind::DropTemps(e) = expr.kind - && let hir::ExprKind::Match(iterexpr, [arm], hir::MatchSource::ForLoopDesugar) = e.kind - && let hir::ExprKind::Call(_, [arg]) = iterexpr.kind - && let hir::ExprKind::Loop(block, ..) = arm.body.kind + if let ExprKind::DropTemps(e) = expr.kind + && let ExprKind::Match(iterexpr, [arm], MatchSource::ForLoopDesugar) = e.kind + && let ExprKind::Call(_, [arg]) = iterexpr.kind + && let ExprKind::Loop(block, ..) = arm.body.kind && let [stmt] = block.stmts && let hir::StmtKind::Expr(e) = stmt.kind - && let hir::ExprKind::Match(_, [_, some_arm], _) = e.kind + && let ExprKind::Match(_, [_, some_arm], _) = e.kind && let hir::PatKind::Struct(_, [field], _) = some_arm.pat.kind { return Some(Self { @@ -209,28 +209,28 @@ impl<'hir> IfOrIfLet<'hir> { #[derive(Debug, Copy, Clone)] pub struct Range<'a> { /// The lower bound of the range, or `None` for ranges such as `..X`. - pub start: Option<&'a hir::Expr<'a>>, + pub start: Option<&'a Expr<'a>>, /// The upper bound of the range, or `None` for ranges such as `X..`. - pub end: Option<&'a hir::Expr<'a>>, + pub end: Option<&'a Expr<'a>>, /// Whether the interval is open or closed. pub limits: ast::RangeLimits, } impl<'a> Range<'a> { /// Higher a `hir` range to something similar to `ast::ExprKind::Range`. - pub fn hir(expr: &'a hir::Expr<'_>) -> Option> { + pub fn hir(expr: &'a Expr<'_>) -> Option> { /// Finds the field named `name` in the field. Always return `Some` for /// convenience. - fn get_field<'c>(name: &str, fields: &'c [hir::ExprField<'_>]) -> Option<&'c hir::Expr<'c>> { + fn get_field<'c>(name: &str, fields: &'c [hir::ExprField<'_>]) -> Option<&'c Expr<'c>> { let expr = &fields.iter().find(|field| field.ident.name.as_str() == name)?.expr; Some(expr) } match expr.kind { - hir::ExprKind::Call(path, args) + ExprKind::Call(path, args) if matches!( path.kind, - hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, ..)) + ExprKind::Path(QPath::LangItem(hir::LangItem::RangeInclusiveNew, ..)) ) => { Some(Range { @@ -239,28 +239,28 @@ impl<'a> Range<'a> { limits: ast::RangeLimits::Closed, }) }, - hir::ExprKind::Struct(path, fields, None) => match &path { - hir::QPath::LangItem(hir::LangItem::RangeFull, ..) => Some(Range { + ExprKind::Struct(path, fields, None) => match &path { + QPath::LangItem(hir::LangItem::RangeFull, ..) => Some(Range { start: None, end: None, limits: ast::RangeLimits::HalfOpen, }), - hir::QPath::LangItem(hir::LangItem::RangeFrom, ..) => Some(Range { + QPath::LangItem(hir::LangItem::RangeFrom, ..) => Some(Range { start: Some(get_field("start", fields)?), end: None, limits: ast::RangeLimits::HalfOpen, }), - hir::QPath::LangItem(hir::LangItem::Range, ..) => Some(Range { + QPath::LangItem(hir::LangItem::Range, ..) => Some(Range { start: Some(get_field("start", fields)?), end: Some(get_field("end", fields)?), limits: ast::RangeLimits::HalfOpen, }), - hir::QPath::LangItem(hir::LangItem::RangeToInclusive, ..) => Some(Range { + QPath::LangItem(hir::LangItem::RangeToInclusive, ..) => Some(Range { start: None, end: Some(get_field("end", fields)?), limits: ast::RangeLimits::Closed, }), - hir::QPath::LangItem(hir::LangItem::RangeTo, ..) => Some(Range { + QPath::LangItem(hir::LangItem::RangeTo, ..) => Some(Range { start: None, end: Some(get_field("end", fields)?), limits: ast::RangeLimits::HalfOpen, @@ -275,17 +275,17 @@ impl<'a> Range<'a> { /// Represents the pre-expansion arguments of a `vec!` invocation. pub enum VecArgs<'a> { /// `vec![elem; len]` - Repeat(&'a hir::Expr<'a>, &'a hir::Expr<'a>), + Repeat(&'a Expr<'a>, &'a Expr<'a>), /// `vec![a, b, c]` - Vec(&'a [hir::Expr<'a>]), + Vec(&'a [Expr<'a>]), } impl<'a> VecArgs<'a> { /// Returns the arguments of the `vec!` macro if this expression was expanded /// from `vec!`. - pub fn hir(cx: &LateContext<'_>, expr: &'a hir::Expr<'_>) -> Option> { - if let hir::ExprKind::Call(fun, args) = expr.kind - && let hir::ExprKind::Path(ref qpath) = fun.kind + pub fn hir(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> Option> { + if let ExprKind::Call(fun, args) = expr.kind + && let ExprKind::Path(ref qpath) = fun.kind && is_expn_of(fun.span, "vec").is_some() && let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id() { @@ -294,8 +294,8 @@ impl<'a> VecArgs<'a> { Some(VecArgs::Repeat(&args[0], &args[1])) } else if match_def_path(cx, fun_def_id, &paths::SLICE_INTO_VEC) && args.len() == 1 { // `vec![a, b, c]` case - if let hir::ExprKind::Call(_, [arg]) = &args[0].kind - && let hir::ExprKind::Array(args) = arg.kind + if let ExprKind::Call(_, [arg]) = &args[0].kind + && let ExprKind::Array(args) = arg.kind { Some(VecArgs::Vec(args)) } else { diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 7a4eba9790ed..f8bbe9977748 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -954,8 +954,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_pat(pat); } }, - PatKind::Box(pat) => self.hash_pat(pat), - PatKind::Deref(pat) => self.hash_pat(pat), + PatKind::Box(pat) | PatKind::Deref(pat) => self.hash_pat(pat), PatKind::Lit(expr) => self.hash_expr(expr), PatKind::Or(pats) => { for pat in pats { diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 95bab5801d1c..37c12dd850c2 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -16,12 +16,14 @@ rustc::diagnostic_outside_of_impl, rustc::untranslatable_diagnostic )] -// warn on the same lints as `clippy_lints` -#![warn(trivial_casts, trivial_numeric_casts)] -// warn on lints, that are included in `rust-lang/rust`s bootstrap -#![warn(rust_2018_idioms, unused_lifetimes)] -// warn on rustc internal lints -#![warn(rustc::internal)] +#![warn( + trivial_casts, + trivial_numeric_casts, + rust_2018_idioms, + unused_lifetimes, + unused_qualifications, + rustc::internal +)] // FIXME: switch to something more ergonomic here, once available. // (Currently there is no way to opt into sysroot crates without `extern crate`.) @@ -99,8 +101,8 @@ use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::{ self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, ByRef, Closure, Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, Item, - ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy, - QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp, + ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, + PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp, }; use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::{LateContext, Level, Lint, LintContext}; @@ -297,9 +299,10 @@ pub fn is_ty_alias(qpath: &QPath<'_>) -> bool { /// Checks if the method call given in `expr` belongs to the given trait. /// This is a deprecated function, consider using [`is_trait_method`]. pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) -> bool { - let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap(); - let trt_id = cx.tcx.trait_of_item(def_id); - trt_id.map_or(false, |trt_id| match_def_path(cx, trt_id, path)) + cx.typeck_results() + .type_dependent_def_id(expr.hir_id) + .and_then(|defid| cx.tcx.trait_of_item(defid)) + .map_or(false, |trt_id| match_def_path(cx, trt_id, path)) } /// Checks if a method is defined in an impl of a diagnostic item @@ -348,7 +351,7 @@ pub fn is_def_id_trait_method(cx: &LateContext<'_>, def_id: LocalDefId) -> bool /// refers to an item of the trait `Default`, which is associated with the /// `diag_item` of `sym::Default`. pub fn is_trait_item(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool { - if let hir::ExprKind::Path(ref qpath) = expr.kind { + if let ExprKind::Path(ref qpath) = expr.kind { cx.qpath_res(qpath, expr.hir_id) .opt_def_id() .map_or(false, |def_id| is_diag_trait_item(cx, def_id, diag_item)) @@ -722,8 +725,8 @@ pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, def_id: LocalDefId) -> let hir_id = cx.tcx.local_def_id_to_hir_id(def_id); let parent_impl = cx.tcx.hir().get_parent_item(hir_id); if parent_impl != hir::CRATE_OWNER_ID - && let hir::Node::Item(item) = cx.tcx.hir_node_by_def_id(parent_impl.def_id) - && let hir::ItemKind::Impl(impl_) = &item.kind + && let Node::Item(item) = cx.tcx.hir_node_by_def_id(parent_impl.def_id) + && let ItemKind::Impl(impl_) = &item.kind { return impl_.of_trait.as_ref(); } @@ -829,7 +832,7 @@ fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath< /// Returns true if the expr is equal to `Default::default` when evaluated. pub fn is_default_equivalent_call(cx: &LateContext<'_>, repl_func: &Expr<'_>) -> bool { - if let hir::ExprKind::Path(ref repl_func_qpath) = repl_func.kind + if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind && let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id() && (is_diag_trait_item(cx, repl_def_id, sym::Default) || is_default_equivalent_ctor(cx, repl_def_id, repl_func_qpath)) @@ -1295,7 +1298,7 @@ pub fn contains_name<'tcx>(name: Symbol, expr: &'tcx Expr<'_>, cx: &LateContext< /// Returns `true` if `expr` contains a return expression pub fn contains_return<'tcx>(expr: impl Visitable<'tcx>) -> bool { for_each_expr(expr, |e| { - if matches!(e.kind, hir::ExprKind::Ret(..)) { + if matches!(e.kind, ExprKind::Ret(..)) { ControlFlow::Break(()) } else { ControlFlow::Continue(()) @@ -1311,7 +1314,7 @@ pub fn get_parent_expr<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'_>) -> Option<&'t /// This retrieves the parent for the given `HirId` if it's an expression. This is useful for /// constraint lints -pub fn get_parent_expr_for_hir<'tcx>(cx: &LateContext<'tcx>, hir_id: hir::HirId) -> Option<&'tcx Expr<'tcx>> { +pub fn get_parent_expr_for_hir<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'tcx>> { match cx.tcx.parent_hir_node(hir_id) { Node::Expr(parent) => Some(parent), _ => None, @@ -1635,13 +1638,13 @@ pub fn is_direct_expn_of(span: Span, name: &str) -> Option { } /// Convenience function to get the return type of a function. -pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_def_id: hir::OwnerId) -> Ty<'tcx> { +pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_def_id: OwnerId) -> Ty<'tcx> { let ret_ty = cx.tcx.fn_sig(fn_def_id).instantiate_identity().output(); cx.tcx.instantiate_bound_regions_with_erased(ret_ty) } /// Convenience function to get the nth argument type of a function. -pub fn nth_arg<'tcx>(cx: &LateContext<'tcx>, fn_def_id: hir::OwnerId, nth: usize) -> Ty<'tcx> { +pub fn nth_arg<'tcx>(cx: &LateContext<'tcx>, fn_def_id: OwnerId, nth: usize) -> Ty<'tcx> { let arg = cx.tcx.fn_sig(fn_def_id).instantiate_identity().input(nth); cx.tcx.instantiate_bound_regions_with_erased(arg) } @@ -1652,8 +1655,8 @@ pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_ if let ExprKind::Path(ref qp) = fun.kind { let res = cx.qpath_res(qp, fun.hir_id); return match res { - def::Res::Def(DefKind::Variant | DefKind::Ctor(..), ..) => true, - def::Res::Def(_, def_id) => cx.tcx.is_promotable_const_fn(def_id), + Res::Def(DefKind::Variant | DefKind::Ctor(..), ..) => true, + Res::Def(_, def_id) => cx.tcx.is_promotable_const_fn(def_id), _ => false, }; } @@ -1667,7 +1670,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { fn is_enum_variant(cx: &LateContext<'_>, qpath: &QPath<'_>, id: HirId) -> bool { matches!( cx.qpath_res(qpath, id), - def::Res::Def(DefKind::Variant, ..) | Res::Def(DefKind::Ctor(def::CtorOf::Variant, _), _) + Res::Def(DefKind::Variant, ..) | Res::Def(DefKind::Ctor(def::CtorOf::Variant, _), _) ) } @@ -1823,26 +1826,26 @@ pub fn strip_pat_refs<'hir>(mut pat: &'hir Pat<'hir>) -> &'hir Pat<'hir> { pat } -pub fn int_bits(tcx: TyCtxt<'_>, ity: rustc_ty::IntTy) -> u64 { +pub fn int_bits(tcx: TyCtxt<'_>, ity: IntTy) -> u64 { Integer::from_int_ty(&tcx, ity).size().bits() } #[expect(clippy::cast_possible_wrap)] /// Turn a constant int byte representation into an i128 -pub fn sext(tcx: TyCtxt<'_>, u: u128, ity: rustc_ty::IntTy) -> i128 { +pub fn sext(tcx: TyCtxt<'_>, u: u128, ity: IntTy) -> i128 { let amt = 128 - int_bits(tcx, ity); ((u as i128) << amt) >> amt } #[expect(clippy::cast_sign_loss)] /// clip unused bytes -pub fn unsext(tcx: TyCtxt<'_>, u: i128, ity: rustc_ty::IntTy) -> u128 { +pub fn unsext(tcx: TyCtxt<'_>, u: i128, ity: IntTy) -> u128 { let amt = 128 - int_bits(tcx, ity); ((u as u128) << amt) >> amt } /// clip unused bytes -pub fn clip(tcx: TyCtxt<'_>, u: u128, ity: rustc_ty::UintTy) -> u128 { +pub fn clip(tcx: TyCtxt<'_>, u: u128, ity: UintTy) -> u128 { let bits = Integer::from_uint_ty(&tcx, ity).size().bits(); let amt = 128 - bits; (u << amt) >> amt @@ -2007,7 +2010,7 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let did = match expr.kind { ExprKind::Call(path, _) => { if let ExprKind::Path(ref qpath) = path.kind - && let def::Res::Def(_, did) = cx.qpath_res(qpath, path.hir_id) + && let Res::Def(_, did) = cx.qpath_res(qpath, path.hir_id) { Some(did) } else { @@ -2218,7 +2221,7 @@ pub fn is_no_core_crate(cx: &LateContext<'_>) -> bool { /// ``` pub fn is_trait_impl_item(cx: &LateContext<'_>, hir_id: HirId) -> bool { if let Node::Item(item) = cx.tcx.parent_hir_node(hir_id) { - matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. })) + matches!(item.kind, ItemKind::Impl(Impl { of_trait: Some(_), .. })) } else { false } @@ -2254,7 +2257,7 @@ pub fn fn_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { pub fn fn_def_id_with_node_args<'tcx>( cx: &LateContext<'tcx>, expr: &Expr<'_>, -) -> Option<(DefId, rustc_ty::GenericArgsRef<'tcx>)> { +) -> Option<(DefId, GenericArgsRef<'tcx>)> { let typeck = cx.typeck_results(); match &expr.kind { ExprKind::MethodCall(..) => Some(( @@ -2500,7 +2503,7 @@ fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalModDefId, f: impl Fn(&[Sym /// Checks if the function containing the given `HirId` is a `#[test]` function /// /// Note: Add `//@compile-flags: --test` to UI tests with a `#[test]` function -pub fn is_in_test_function(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { +pub fn is_in_test_function(tcx: TyCtxt<'_>, id: HirId) -> bool { with_test_item_names(tcx, tcx.parent_module(id), |names| { tcx.hir() .parent_iter(id) @@ -2523,7 +2526,7 @@ pub fn is_in_test_function(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { /// /// This only checks directly applied attributes, to see if a node is inside a `#[cfg(test)]` parent /// use [`is_in_cfg_test`] -pub fn is_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { +pub fn is_cfg_test(tcx: TyCtxt<'_>, id: HirId) -> bool { tcx.hir().attrs(id).iter().any(|attr| { if attr.has_name(sym::cfg) && let Some(items) = attr.meta_item_list() @@ -2538,7 +2541,7 @@ pub fn is_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { } /// Checks if any parent node of `HirId` has `#[cfg(test)]` attribute applied -pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { +pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: HirId) -> bool { tcx.hir() .parent_id_iter(id) .any(|parent_id| is_cfg_test(tcx, parent_id)) @@ -3333,3 +3336,12 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St repeat(String::from("super")).take(go_up_by).chain(path).join("::") } } + +/// Returns true if the specified `HirId` is the top-level expression of a statement or the only +/// expression in a block. +pub fn is_parent_stmt(cx: &LateContext<'_>, id: HirId) -> bool { + matches!( + cx.tcx.parent_hir_node(id), + Node::Stmt(..) | Node::Block(Block { stmts: &[], .. }) + ) +} diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs index c475e7b7c435..f166087dc3ca 100644 --- a/src/tools/clippy/clippy_utils/src/macros.rs +++ b/src/tools/clippy/clippy_utils/src/macros.rs @@ -429,7 +429,7 @@ pub fn find_format_args(cx: &LateContext<'_>, start: &Expr<'_>, expn_id: ExpnId) pub fn find_format_arg_expr<'hir, 'ast>( start: &'hir Expr<'hir>, target: &'ast FormatArgument, -) -> Result<&'hir rustc_hir::Expr<'hir>, &'ast rustc_ast::Expr> { +) -> Result<&'hir Expr<'hir>, &'ast rustc_ast::Expr> { let SpanData { lo, hi, diff --git a/src/tools/clippy/clippy_utils/src/mir/mod.rs b/src/tools/clippy/clippy_utils/src/mir/mod.rs index 9dbb4c68d13f..e4966690d8c5 100644 --- a/src/tools/clippy/clippy_utils/src/mir/mod.rs +++ b/src/tools/clippy/clippy_utils/src/mir/mod.rs @@ -111,7 +111,7 @@ pub fn block_in_cycle(body: &Body<'_>, block: BasicBlock) -> bool { } /// Convenience wrapper around `visit_local_usage`. -pub fn used_exactly_once(mir: &Body<'_>, local: rustc_middle::mir::Local) -> Option { +pub fn used_exactly_once(mir: &Body<'_>, local: Local) -> Option { visit_local_usage( &[local], mir, diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index 5090d0bd98b1..8d6057272c4e 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -41,7 +41,7 @@ pub const ONE: Sugg<'static> = Sugg::NonParen(Cow::Borrowed("1")); pub const EMPTY: Sugg<'static> = Sugg::NonParen(Cow::Borrowed("")); impl Display for Sugg<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { match *self { Sugg::NonParen(ref s) | Sugg::MaybeParen(ref s) => s.fmt(f), Sugg::BinOp(op, ref lhs, ref rhs) => binop_to_string(op, lhs, rhs).fmt(f), @@ -124,48 +124,48 @@ impl<'a> Sugg<'a> { } match expr.kind { - hir::ExprKind::AddrOf(..) - | hir::ExprKind::If(..) - | hir::ExprKind::Let(..) - | hir::ExprKind::Closure { .. } - | hir::ExprKind::Unary(..) - | hir::ExprKind::Match(..) => Sugg::MaybeParen(get_snippet(expr.span)), - hir::ExprKind::Continue(..) - | hir::ExprKind::Yield(..) - | hir::ExprKind::Array(..) - | hir::ExprKind::Block(..) - | hir::ExprKind::Break(..) - | hir::ExprKind::Call(..) - | hir::ExprKind::Field(..) - | hir::ExprKind::Index(..) - | hir::ExprKind::InlineAsm(..) - | hir::ExprKind::OffsetOf(..) - | hir::ExprKind::ConstBlock(..) - | hir::ExprKind::Lit(..) - | hir::ExprKind::Loop(..) - | hir::ExprKind::MethodCall(..) - | hir::ExprKind::Path(..) - | hir::ExprKind::Repeat(..) - | hir::ExprKind::Ret(..) - | hir::ExprKind::Become(..) - | hir::ExprKind::Struct(..) - | hir::ExprKind::Tup(..) - | hir::ExprKind::Err(_) => Sugg::NonParen(get_snippet(expr.span)), - hir::ExprKind::DropTemps(inner) => Self::hir_from_snippet(inner, get_snippet), - hir::ExprKind::Assign(lhs, rhs, _) => { + ExprKind::AddrOf(..) + | ExprKind::If(..) + | ExprKind::Let(..) + | ExprKind::Closure { .. } + | ExprKind::Unary(..) + | ExprKind::Match(..) => Sugg::MaybeParen(get_snippet(expr.span)), + ExprKind::Continue(..) + | ExprKind::Yield(..) + | ExprKind::Array(..) + | ExprKind::Block(..) + | ExprKind::Break(..) + | ExprKind::Call(..) + | ExprKind::Field(..) + | ExprKind::Index(..) + | ExprKind::InlineAsm(..) + | ExprKind::OffsetOf(..) + | ExprKind::ConstBlock(..) + | ExprKind::Lit(..) + | ExprKind::Loop(..) + | ExprKind::MethodCall(..) + | ExprKind::Path(..) + | ExprKind::Repeat(..) + | ExprKind::Ret(..) + | ExprKind::Become(..) + | ExprKind::Struct(..) + | ExprKind::Tup(..) + | ExprKind::Err(_) => Sugg::NonParen(get_snippet(expr.span)), + ExprKind::DropTemps(inner) => Self::hir_from_snippet(inner, get_snippet), + ExprKind::Assign(lhs, rhs, _) => { Sugg::BinOp(AssocOp::Assign, get_snippet(lhs.span), get_snippet(rhs.span)) }, - hir::ExprKind::AssignOp(op, lhs, rhs) => { + ExprKind::AssignOp(op, lhs, rhs) => { Sugg::BinOp(hirbinop2assignop(op), get_snippet(lhs.span), get_snippet(rhs.span)) }, - hir::ExprKind::Binary(op, lhs, rhs) => Sugg::BinOp( + ExprKind::Binary(op, lhs, rhs) => Sugg::BinOp( AssocOp::from_ast_binop(op.node), get_snippet(lhs.span), get_snippet(rhs.span), ), - hir::ExprKind::Cast(lhs, ty) | + ExprKind::Cast(lhs, ty) | //FIXME(chenyukang), remove this after type ascription is removed from AST - hir::ExprKind::Type(lhs, ty) => Sugg::BinOp(AssocOp::As, get_snippet(lhs.span), get_snippet(ty.span)), + ExprKind::Type(lhs, ty) => Sugg::BinOp(AssocOp::As, get_snippet(lhs.span), get_snippet(ty.span)), } } @@ -358,6 +358,13 @@ impl<'a> Sugg<'a> { }, } } + + pub fn into_string(self) -> String { + match self { + Sugg::NonParen(p) | Sugg::MaybeParen(p) => p.into_owned(), + Sugg::BinOp(b, l, r) => binop_to_string(b, &l, &r), + } + } } /// Generates a string from the operator and both sides. @@ -508,7 +515,7 @@ impl ParenHelper { } impl Display for ParenHelper { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { if self.paren { write!(f, "({})", self.wrapped) } else { @@ -801,7 +808,7 @@ pub struct DerefClosure { /// /// note: this only works on single line immutable closures with exactly one input parameter. pub fn deref_closure_args(cx: &LateContext<'_>, closure: &hir::Expr<'_>) -> Option { - if let hir::ExprKind::Closure(&Closure { + if let ExprKind::Closure(&Closure { fn_decl, def_id, body, .. }) = closure.kind { diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 97ce755adbbe..ab1be66dc787 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -91,12 +91,16 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<' return true; } - if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *inner_ty.kind() { + if let ty::Alias(ty::Opaque, AliasTy { def_id, .. }) = *inner_ty.kind() { if !seen.insert(def_id) { return false; } - for (predicate, _span) in cx.tcx.explicit_item_super_predicates(def_id).instantiate_identity_iter_copied() { + for (predicate, _span) in cx + .tcx + .explicit_item_super_predicates(def_id) + .instantiate_identity_iter_copied() + { match predicate.kind().skip_binder() { // For `impl Trait`, it will register a predicate of `T: Trait`, so we go through // and check substitutions to find `U`. @@ -159,6 +163,16 @@ pub fn get_type_diagnostic_name(cx: &LateContext<'_>, ty: Ty<'_>) -> Option, ty: Ty<'_>) -> bool { + matches!( + get_type_diagnostic_name(cx, ty), + Some(sym::Arc | sym::ArcWeak | sym::Rc | sym::RcWeak) + ) +} + /// Returns true if ty has `iter` or `iter_mut` methods pub fn has_iter_method(cx: &LateContext<'_>, probably_ref_ty: Ty<'_>) -> Option { // FIXME: instead of this hard-coded list, we should check if `::iter` @@ -301,7 +315,7 @@ pub fn implements_trait_with_env_from_iter<'tcx>( cause: ObligationCause::dummy(), param_env, recursion_depth: 0, - predicate: ty::Binder::dummy(trait_ref).to_predicate(tcx), + predicate: Binder::dummy(trait_ref).to_predicate(tcx), }; infcx .evaluate_obligation(&obligation) @@ -327,7 +341,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { is_must_use_ty(cx, *ty) }, ty::Tuple(args) => args.iter().any(|ty| is_must_use_ty(cx, ty)), - ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => { + ty::Alias(ty::Opaque, AliasTy { def_id, .. }) => { for (predicate, _) in cx.tcx.explicit_item_super_predicates(def_id).skip_binder() { if let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() { if cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use) { @@ -356,13 +370,13 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { // not succeed /// Checks if `Ty` is normalizable. This function is useful /// to avoid crashes on `layout_of`. -pub fn is_normalizable<'tcx>(cx: &LateContext<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { +pub fn is_normalizable<'tcx>(cx: &LateContext<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { is_normalizable_helper(cx, param_env, ty, &mut FxHashMap::default()) } fn is_normalizable_helper<'tcx>( cx: &LateContext<'tcx>, - param_env: ty::ParamEnv<'tcx>, + param_env: ParamEnv<'tcx>, ty: Ty<'tcx>, cache: &mut FxHashMap, bool>, ) -> bool { @@ -372,7 +386,7 @@ fn is_normalizable_helper<'tcx>( // prevent recursive loops, false-negative is better than endless loop leading to stack overflow cache.insert(ty, false); let infcx = cx.tcx.infer_ctxt().build(); - let cause = rustc_middle::traits::ObligationCause::dummy(); + let cause = ObligationCause::dummy(); let result = if infcx.at(&cause, param_env).query_normalize(ty).is_ok() { match ty.kind() { ty::Adt(def, args) => def.variants().iter().all(|variant| { @@ -446,7 +460,7 @@ pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symb /// Checks if the type is equal to a lang item. /// /// Returns `false` if the `LangItem` is not defined. -pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangItem) -> bool { +pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: LangItem) -> bool { match ty.kind() { ty::Adt(adt, _) => cx.tcx.lang_items().get(lang_item) == Some(adt.did()), _ => false, @@ -726,7 +740,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option Some(ExprFnSig::Sig(cx.tcx.fn_sig(id).instantiate(cx.tcx, subs), Some(id))), - ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => sig_from_bounds( + ty::Alias(ty::Opaque, AliasTy { def_id, args, .. }) => sig_from_bounds( cx, ty, cx.tcx.item_super_predicates(def_id).iter_instantiated(cx.tcx, args), @@ -807,7 +821,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option for (pred, _) in cx .tcx - .explicit_item_super_predicates(ty.def_id) + .explicit_item_bounds(ty.def_id) .iter_instantiated_copied(cx.tcx, ty.args) { match pred.kind().skip_binder() { @@ -899,7 +913,7 @@ pub fn is_c_void(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { if let ty::Adt(adt, _) = ty.kind() && let &[krate, .., name] = &*cx.get_def_path(adt.did()) && let sym::libc | sym::core | sym::std = krate - && name == rustc_span::sym::c_void + && name == sym::c_void { true } else { @@ -1134,7 +1148,7 @@ pub fn make_projection<'tcx>( #[cfg(debug_assertions)] assert_generic_args_match(tcx, assoc_item.def_id, args); - Some(ty::AliasTy::new(tcx, assoc_item.def_id, args)) + Some(AliasTy::new(tcx, assoc_item.def_id, args)) } helper( tcx, @@ -1251,7 +1265,7 @@ pub fn make_normalized_projection_with_regions<'tcx>( ); return None; } - let cause = rustc_middle::traits::ObligationCause::dummy(); + let cause = ObligationCause::dummy(); match tcx .infer_ctxt() .build() @@ -1269,7 +1283,7 @@ pub fn make_normalized_projection_with_regions<'tcx>( } pub fn normalize_with_regions<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - let cause = rustc_middle::traits::ObligationCause::dummy(); + let cause = ObligationCause::dummy(); match tcx.infer_ctxt().build().at(&cause, param_env).query_normalize(ty) { Ok(ty) => ty.value, Err(_) => ty, diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs index ec131c7f6a31..a145920aa85e 100644 --- a/src/tools/clippy/clippy_utils/src/usage.rs +++ b/src/tools/clippy/clippy_utils/src/usage.rs @@ -83,15 +83,15 @@ impl<'tcx> Delegate<'tcx> for MutVarsDelegate { self.update(cmt); } - fn fake_read(&mut self, _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} + fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} } pub struct ParamBindingIdCollector { - pub binding_hir_ids: Vec, + pub binding_hir_ids: Vec, } impl<'tcx> ParamBindingIdCollector { - fn collect_binding_hir_ids(body: &'tcx hir::Body<'tcx>) -> Vec { - let mut hir_ids: Vec = Vec::new(); + fn collect_binding_hir_ids(body: &'tcx hir::Body<'tcx>) -> Vec { + let mut hir_ids: Vec = Vec::new(); for param in body.params { let mut finder = ParamBindingIdCollector { binding_hir_ids: Vec::new(), @@ -104,7 +104,7 @@ impl<'tcx> ParamBindingIdCollector { hir_ids } } -impl<'tcx> intravisit::Visitor<'tcx> for ParamBindingIdCollector { +impl<'tcx> Visitor<'tcx> for ParamBindingIdCollector { fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) { if let hir::PatKind::Binding(_, hir_id, ..) = pat.kind { self.binding_hir_ids.push(hir_id); @@ -115,7 +115,7 @@ impl<'tcx> intravisit::Visitor<'tcx> for ParamBindingIdCollector { pub struct BindingUsageFinder<'a, 'tcx> { cx: &'a LateContext<'tcx>, - binding_ids: Vec, + binding_ids: Vec, usage_found: bool, } impl<'a, 'tcx> BindingUsageFinder<'a, 'tcx> { @@ -129,16 +129,16 @@ impl<'a, 'tcx> BindingUsageFinder<'a, 'tcx> { finder.usage_found } } -impl<'a, 'tcx> intravisit::Visitor<'tcx> for BindingUsageFinder<'a, 'tcx> { +impl<'a, 'tcx> Visitor<'tcx> for BindingUsageFinder<'a, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { if !self.usage_found { intravisit::walk_expr(self, expr); } } - fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) { + fn visit_path(&mut self, path: &hir::Path<'tcx>, _: HirId) { if let Res::Local(id) = path.res { if self.binding_ids.contains(&id) { self.usage_found = true; diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs index 0a05ac029eae..a3f3b32ed372 100644 --- a/src/tools/clippy/clippy_utils/src/visitors.rs +++ b/src/tools/clippy/clippy_utils/src/visitors.rs @@ -180,9 +180,9 @@ pub fn for_each_expr_with_closures<'tcx, B, C: Continue>( } /// returns `true` if expr contains match expr desugared from try -fn contains_try(expr: &hir::Expr<'_>) -> bool { +fn contains_try(expr: &Expr<'_>) -> bool { for_each_expr(expr, |e| { - if matches!(e.kind, hir::ExprKind::Match(_, _, hir::MatchSource::TryDesugar(_))) { + if matches!(e.kind, ExprKind::Match(_, _, hir::MatchSource::TryDesugar(_))) { ControlFlow::Break(()) } else { ControlFlow::Continue(()) @@ -191,9 +191,9 @@ fn contains_try(expr: &hir::Expr<'_>) -> bool { .is_some() } -pub fn find_all_ret_expressions<'hir, F>(_cx: &LateContext<'_>, expr: &'hir hir::Expr<'hir>, callback: F) -> bool +pub fn find_all_ret_expressions<'hir, F>(_cx: &LateContext<'_>, expr: &'hir Expr<'hir>, callback: F) -> bool where - F: FnMut(&'hir hir::Expr<'hir>) -> bool, + F: FnMut(&'hir Expr<'hir>) -> bool, { struct RetFinder { in_stmt: bool, @@ -236,37 +236,37 @@ where } } - impl<'hir, F: FnMut(&'hir hir::Expr<'hir>) -> bool> intravisit::Visitor<'hir> for RetFinder { - fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'_>) { + impl<'hir, F: FnMut(&'hir Expr<'hir>) -> bool> Visitor<'hir> for RetFinder { + fn visit_stmt(&mut self, stmt: &'hir Stmt<'_>) { intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt); } - fn visit_expr(&mut self, expr: &'hir hir::Expr<'_>) { + fn visit_expr(&mut self, expr: &'hir Expr<'_>) { if self.failed { return; } if self.in_stmt { match expr.kind { - hir::ExprKind::Ret(Some(expr)) => self.inside_stmt(false).visit_expr(expr), - _ => intravisit::walk_expr(self, expr), + ExprKind::Ret(Some(expr)) => self.inside_stmt(false).visit_expr(expr), + _ => walk_expr(self, expr), } } else { match expr.kind { - hir::ExprKind::If(cond, then, else_opt) => { + ExprKind::If(cond, then, else_opt) => { self.inside_stmt(true).visit_expr(cond); self.visit_expr(then); if let Some(el) = else_opt { self.visit_expr(el); } }, - hir::ExprKind::Match(cond, arms, _) => { + ExprKind::Match(cond, arms, _) => { self.inside_stmt(true).visit_expr(cond); for arm in arms { self.visit_expr(arm.body); } }, - hir::ExprKind::Block(..) => intravisit::walk_expr(self, expr), - hir::ExprKind::Ret(Some(expr)) => self.visit_expr(expr), + ExprKind::Block(..) => walk_expr(self, expr), + ExprKind::Ret(Some(expr)) => self.visit_expr(expr), _ => self.failed |= !(self.cb)(expr), } } @@ -316,7 +316,7 @@ pub fn is_const_evaluatable<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> is_const: bool, } impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> { - type NestedFilter = rustc_hir::intravisit::nested_filter::None; + type NestedFilter = intravisit::nested_filter::None; fn visit_expr(&mut self, e: &'tcx Expr<'_>) { if !self.is_const { diff --git a/src/tools/clippy/lintcheck/src/main.rs b/src/tools/clippy/lintcheck/src/main.rs index 664429981619..4251151c4543 100644 --- a/src/tools/clippy/lintcheck/src/main.rs +++ b/src/tools/clippy/lintcheck/src/main.rs @@ -5,6 +5,13 @@ // When a new lint is introduced, we can search the results for new warnings and check for false // positives. +#![warn( + trivial_casts, + trivial_numeric_casts, + rust_2018_idioms, + unused_lifetimes, + unused_qualifications +)] #![allow(clippy::collapsible_else_if)] mod config; @@ -189,13 +196,13 @@ impl CrateSource { // don't download/extract if we already have done so if !krate_file_path.is_file() { // create a file path to download and write the crate data into - let mut krate_dest = std::fs::File::create(&krate_file_path).unwrap(); + let mut krate_dest = fs::File::create(&krate_file_path).unwrap(); let mut krate_req = get(&url).unwrap().into_reader(); // copy the crate into the file - std::io::copy(&mut krate_req, &mut krate_dest).unwrap(); + io::copy(&mut krate_req, &mut krate_dest).unwrap(); // unzip the tarball - let ungz_tar = flate2::read::GzDecoder::new(std::fs::File::open(&krate_file_path).unwrap()); + let ungz_tar = flate2::read::GzDecoder::new(fs::File::open(&krate_file_path).unwrap()); // extract the tar archive let mut archive = tar::Archive::new(ungz_tar); archive.unpack(&extract_dir).expect("Failed to extract!"); @@ -257,7 +264,7 @@ impl CrateSource { }, CrateSource::Path { name, path, options } => { fn is_cache_dir(entry: &DirEntry) -> bool { - std::fs::read(entry.path().join("CACHEDIR.TAG")) + fs::read(entry.path().join("CACHEDIR.TAG")) .map(|x| x.starts_with(b"Signature: 8a477f597d28d172789f06886806bc55")) .unwrap_or(false) } @@ -268,7 +275,7 @@ impl CrateSource { let dest_crate_root = PathBuf::from(LINTCHECK_SOURCES).join(name); if dest_crate_root.exists() { println!("Deleting existing directory at {dest_crate_root:?}"); - std::fs::remove_dir_all(&dest_crate_root).unwrap(); + fs::remove_dir_all(&dest_crate_root).unwrap(); } println!("Copying {path:?} to {dest_crate_root:?}"); @@ -281,9 +288,9 @@ impl CrateSource { let metadata = entry_path.symlink_metadata().unwrap(); if metadata.is_dir() { - std::fs::create_dir(dest_path).unwrap(); + fs::create_dir(dest_path).unwrap(); } else if metadata.is_file() { - std::fs::copy(entry_path, dest_path).unwrap(); + fs::copy(entry_path, dest_path).unwrap(); } } @@ -330,7 +337,7 @@ impl Crate { ); } - let cargo_clippy_path = std::fs::canonicalize(cargo_clippy_path).unwrap(); + let cargo_clippy_path = fs::canonicalize(cargo_clippy_path).unwrap(); let shared_target_dir = clippy_project_root().join("target/lintcheck/shared_target_dir"); @@ -353,7 +360,7 @@ impl Crate { clippy_args.push("--cap-lints=warn"); } else { clippy_args.push("--cap-lints=allow"); - clippy_args.extend(lint_filter.iter().map(std::string::String::as_str)); + clippy_args.extend(lint_filter.iter().map(String::as_str)); } if let Some(server) = server { @@ -454,7 +461,7 @@ fn build_clippy() { /// Read a `lintcheck_crates.toml` file fn read_crates(toml_path: &Path) -> (Vec, RecursiveOptions) { let toml_content: String = - std::fs::read_to_string(toml_path).unwrap_or_else(|_| panic!("Failed to read {}", toml_path.display())); + fs::read_to_string(toml_path).unwrap_or_else(|_| panic!("Failed to read {}", toml_path.display())); let crate_list: SourceList = toml::from_str(&toml_content).unwrap_or_else(|e| panic!("Failed to parse {}: \n{e}", toml_path.display())); // parse the hashmap of the toml file into a list of crates @@ -549,7 +556,7 @@ fn main() { } // assert that we launch lintcheck from the repo root (via cargo lintcheck) - if std::fs::metadata("lintcheck/Cargo.toml").is_err() { + if fs::metadata("lintcheck/Cargo.toml").is_err() { eprintln!("lintcheck needs to be run from clippy's repo root!\nUse `cargo lintcheck` alternatively."); std::process::exit(3); } @@ -570,7 +577,7 @@ fn main() { cargo_clippy_path.display() ); - let clippy_ver = std::process::Command::new(&cargo_clippy_path) + let clippy_ver = Command::new(&cargo_clippy_path) .arg("--version") .output() .map(|o| String::from_utf8_lossy(&o.stdout).into_owned()) @@ -699,7 +706,7 @@ fn main() { /// read the previous stats from the lintcheck-log file fn read_stats_from_file(file_path: &Path) -> HashMap { - let file_content: String = match std::fs::read_to_string(file_path).ok() { + let file_content: String = match fs::read_to_string(file_path).ok() { Some(content) => content, None => { return HashMap::new(); @@ -779,17 +786,17 @@ fn print_stats(old_stats: HashMap, new_stats: HashMap<&String, us /// /// This function panics if creating one of the dirs fails. fn create_dirs(krate_download_dir: &Path, extract_dir: &Path) { - std::fs::create_dir("target/lintcheck/").unwrap_or_else(|err| { + fs::create_dir("target/lintcheck/").unwrap_or_else(|err| { assert_eq!( err.kind(), ErrorKind::AlreadyExists, "cannot create lintcheck target dir" ); }); - std::fs::create_dir(krate_download_dir).unwrap_or_else(|err| { + fs::create_dir(krate_download_dir).unwrap_or_else(|err| { assert_eq!(err.kind(), ErrorKind::AlreadyExists, "cannot create crate download dir"); }); - std::fs::create_dir(extract_dir).unwrap_or_else(|err| { + fs::create_dir(extract_dir).unwrap_or_else(|err| { assert_eq!( err.kind(), ErrorKind::AlreadyExists, @@ -816,7 +823,7 @@ fn lintcheck_test() { "--crates-toml", "lintcheck/test_sources.toml", ]; - let status = std::process::Command::new(env::var("CARGO").unwrap_or("cargo".into())) + let status = Command::new(env::var("CARGO").unwrap_or("cargo".into())) .args(args) .current_dir("..") // repo root .status(); diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain index a63e66f3214c..b2fe5c8bee7a 100644 --- a/src/tools/clippy/rust-toolchain +++ b/src/tools/clippy/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-03-21" +channel = "nightly-2024-04-04" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs index a0c8bf9334c4..32a31f5e0823 100644 --- a/src/tools/clippy/tests/compile-test.rs +++ b/src/tools/clippy/tests/compile-test.rs @@ -146,6 +146,8 @@ fn base_config(test_dir: &str) -> (Config, Args) { ); config.program.args.extend(EXTERN_FLAGS.iter().map(OsString::from)); + // Prevent rustc from creating `rustc-ice-*` files the console output is enough. + config.program.envs.push(("RUSTC_ICE".into(), Some("0".into()))); if let Some(host_libs) = option_env!("HOST_LIBS") { let dep = format!("-Ldependency={}", Path::new(host_libs).join("deps").display()); diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.rs b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.rs index 0e6a54452ee8..a828701bcee9 100644 --- a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.rs +++ b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.rs @@ -3,7 +3,7 @@ //@revisions: allow_crates disallow_crates //@[allow_crates] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/absolute_paths/allow_crates //@[disallow_crates] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/absolute_paths/disallow_crates -#![allow(clippy::no_effect, unused)] +#![allow(clippy::no_effect, clippy::legacy_numeric_constants, unused)] #![warn(clippy::absolute_paths)] #![feature(decl_macro)] diff --git a/src/tools/clippy/tests/ui-toml/large_stack_frames/large_stack_frames.rs b/src/tools/clippy/tests/ui-toml/large_stack_frames/large_stack_frames.rs index 39798ffea494..a612e56570ff 100644 --- a/src/tools/clippy/tests/ui-toml/large_stack_frames/large_stack_frames.rs +++ b/src/tools/clippy/tests/ui-toml/large_stack_frames/large_stack_frames.rs @@ -10,7 +10,7 @@ fn f() { let _x = create_array::<1000>(); } fn f2() { - //~^ ERROR: this function allocates a large amount of stack space + //~^ ERROR: this function may allocate 1001 bytes on the stack let _x = create_array::<1001>(); } diff --git a/src/tools/clippy/tests/ui-toml/large_stack_frames/large_stack_frames.stderr b/src/tools/clippy/tests/ui-toml/large_stack_frames/large_stack_frames.stderr index c23fac145646..19983e2f3e80 100644 --- a/src/tools/clippy/tests/ui-toml/large_stack_frames/large_stack_frames.stderr +++ b/src/tools/clippy/tests/ui-toml/large_stack_frames/large_stack_frames.stderr @@ -1,13 +1,14 @@ -error: this function allocates a large amount of stack space - --> tests/ui-toml/large_stack_frames/large_stack_frames.rs:12:1 +error: this function may allocate 1001 bytes on the stack + --> tests/ui-toml/large_stack_frames/large_stack_frames.rs:12:4 | -LL | / fn f2() { -LL | | -LL | | let _x = create_array::<1001>(); -LL | | } - | |_^ +LL | fn f2() { + | ^^ +LL | +LL | let _x = create_array::<1001>(); + | -- `_x` is the largest part, at 1001 bytes for type `[u8; 1001]` | - = note: allocating large amounts of stack space can overflow the stack + = note: 1001 bytes is larger than Clippy's configured `stack-size-threshold` of 1000 + = note: allocating large amounts of stack space can overflow the stack and cause the program to abort = note: `-D clippy::large-stack-frames` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::large_stack_frames)]` diff --git a/src/tools/clippy/tests/ui/assigning_clones.fixed b/src/tools/clippy/tests/ui/assigning_clones.fixed index 160f3b946631..8387c7d6156b 100644 --- a/src/tools/clippy/tests/ui/assigning_clones.fixed +++ b/src/tools/clippy/tests/ui/assigning_clones.fixed @@ -153,6 +153,19 @@ fn clone_inside_macro() { clone_inside!(a, b); } +// Make sure that we don't suggest the lint when we call clone inside a Clone impl +// https://github.com/rust-lang/rust-clippy/issues/12600 +pub struct AvoidRecursiveCloneFrom; + +impl Clone for AvoidRecursiveCloneFrom { + fn clone(&self) -> Self { + Self + } + fn clone_from(&mut self, source: &Self) { + *self = source.clone(); + } +} + // ToOwned fn owned_method_mut_ref(mut_string: &mut String, ref_str: &str) { ref_str.clone_into(mut_string); diff --git a/src/tools/clippy/tests/ui/assigning_clones.rs b/src/tools/clippy/tests/ui/assigning_clones.rs index 14ba1d4db9a8..6f4da9f652c9 100644 --- a/src/tools/clippy/tests/ui/assigning_clones.rs +++ b/src/tools/clippy/tests/ui/assigning_clones.rs @@ -153,6 +153,19 @@ fn clone_inside_macro() { clone_inside!(a, b); } +// Make sure that we don't suggest the lint when we call clone inside a Clone impl +// https://github.com/rust-lang/rust-clippy/issues/12600 +pub struct AvoidRecursiveCloneFrom; + +impl Clone for AvoidRecursiveCloneFrom { + fn clone(&self) -> Self { + Self + } + fn clone_from(&mut self, source: &Self) { + *self = source.clone(); + } +} + // ToOwned fn owned_method_mut_ref(mut_string: &mut String, ref_str: &str) { *mut_string = ref_str.to_owned(); diff --git a/src/tools/clippy/tests/ui/assigning_clones.stderr b/src/tools/clippy/tests/ui/assigning_clones.stderr index ba59f067431a..793927bd1cb1 100644 --- a/src/tools/clippy/tests/ui/assigning_clones.stderr +++ b/src/tools/clippy/tests/ui/assigning_clones.stderr @@ -86,37 +86,37 @@ LL | a = c.to_owned(); | ^^^^^^^^^^^^^^^^ help: use `clone_into()`: `c.clone_into(&mut a)` error: assigning the result of `ToOwned::to_owned()` may be inefficient - --> tests/ui/assigning_clones.rs:158:5 + --> tests/ui/assigning_clones.rs:171:5 | LL | *mut_string = ref_str.to_owned(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(mut_string)` error: assigning the result of `ToOwned::to_owned()` may be inefficient - --> tests/ui/assigning_clones.rs:162:5 + --> tests/ui/assigning_clones.rs:175:5 | LL | mut_string = ref_str.to_owned(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut mut_string)` error: assigning the result of `ToOwned::to_owned()` may be inefficient - --> tests/ui/assigning_clones.rs:183:5 + --> tests/ui/assigning_clones.rs:196:5 | LL | **mut_box_string = ref_str.to_owned(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut (*mut_box_string))` error: assigning the result of `ToOwned::to_owned()` may be inefficient - --> tests/ui/assigning_clones.rs:187:5 + --> tests/ui/assigning_clones.rs:200:5 | LL | **mut_box_string = ref_str.to_owned(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut (*mut_box_string))` error: assigning the result of `ToOwned::to_owned()` may be inefficient - --> tests/ui/assigning_clones.rs:191:5 + --> tests/ui/assigning_clones.rs:204:5 | LL | *mut_thing = ToOwned::to_owned(ref_str); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ToOwned::clone_into(ref_str, mut_thing)` error: assigning the result of `ToOwned::to_owned()` may be inefficient - --> tests/ui/assigning_clones.rs:195:5 + --> tests/ui/assigning_clones.rs:208:5 | LL | mut_thing = ToOwned::to_owned(ref_str); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ToOwned::clone_into(ref_str, &mut mut_thing)` diff --git a/src/tools/clippy/tests/ui/author/issue_3849.rs b/src/tools/clippy/tests/ui/author/issue_3849.rs index bae4570e539a..5f65746d71f2 100644 --- a/src/tools/clippy/tests/ui/author/issue_3849.rs +++ b/src/tools/clippy/tests/ui/author/issue_3849.rs @@ -1,7 +1,7 @@ #![allow(dead_code)] #![allow(clippy::zero_ptr)] #![allow(clippy::transmute_ptr_to_ref)] -#![allow(clippy::transmuting_null)] +#![allow(clippy::transmuting_null, clippy::missing_transmute_annotations)] pub const ZPTR: *const usize = 0 as *const _; diff --git a/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs b/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs index 6b164967a28e..9efbb3908497 100644 --- a/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs +++ b/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs @@ -50,3 +50,10 @@ macro_rules! macro_with_panic { panic!() }; } + +#[macro_export] +macro_rules! bad_transmute { + ($e:expr) => { + std::mem::transmute($e) + }; +} diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.fixed b/src/tools/clippy/tests/ui/blocks_in_conditions.fixed index caf29e23d545..a2da5f9c5fb9 100644 --- a/src/tools/clippy/tests/ui/blocks_in_conditions.fixed +++ b/src/tools/clippy/tests/ui/blocks_in_conditions.fixed @@ -1,7 +1,12 @@ //@aux-build:proc_macro_attr.rs #![warn(clippy::blocks_in_conditions)] -#![allow(unused, clippy::let_and_return, clippy::needless_if)] +#![allow( + unused, + clippy::let_and_return, + clippy::needless_if, + clippy::missing_transmute_annotations +)] #![warn(clippy::nonminimal_bool)] macro_rules! blocky { diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.rs b/src/tools/clippy/tests/ui/blocks_in_conditions.rs index e72daaa910d4..608ca4cf267f 100644 --- a/src/tools/clippy/tests/ui/blocks_in_conditions.rs +++ b/src/tools/clippy/tests/ui/blocks_in_conditions.rs @@ -1,7 +1,12 @@ //@aux-build:proc_macro_attr.rs #![warn(clippy::blocks_in_conditions)] -#![allow(unused, clippy::let_and_return, clippy::needless_if)] +#![allow( + unused, + clippy::let_and_return, + clippy::needless_if, + clippy::missing_transmute_annotations +)] #![warn(clippy::nonminimal_bool)] macro_rules! blocky { diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.stderr b/src/tools/clippy/tests/ui/blocks_in_conditions.stderr index 3641e71aae83..a55e1efb575e 100644 --- a/src/tools/clippy/tests/ui/blocks_in_conditions.stderr +++ b/src/tools/clippy/tests/ui/blocks_in_conditions.stderr @@ -1,5 +1,5 @@ error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` - --> tests/ui/blocks_in_conditions.rs:25:5 + --> tests/ui/blocks_in_conditions.rs:30:5 | LL | / if { LL | | @@ -20,13 +20,13 @@ LL ~ }; if res { | error: omit braces around single expression condition - --> tests/ui/blocks_in_conditions.rs:37:8 + --> tests/ui/blocks_in_conditions.rs:42:8 | LL | if { true } { 6 } else { 10 } | ^^^^^^^^ help: try: `true` error: this boolean expression can be simplified - --> tests/ui/blocks_in_conditions.rs:43:8 + --> tests/ui/blocks_in_conditions.rs:48:8 | LL | if true && x == 3 { 6 } else { 10 } | ^^^^^^^^^^^^^^ help: try: `x == 3` @@ -35,7 +35,7 @@ LL | if true && x == 3 { 6 } else { 10 } = help: to override `-D warnings` add `#[allow(clippy::nonminimal_bool)]` error: in a `match` scrutinee, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` - --> tests/ui/blocks_in_conditions.rs:70:5 + --> tests/ui/blocks_in_conditions.rs:75:5 | LL | / match { LL | | diff --git a/src/tools/clippy/tests/ui/box_default.fixed b/src/tools/clippy/tests/ui/box_default.fixed index fea7405c6858..6c2896b3aa0f 100644 --- a/src/tools/clippy/tests/ui/box_default.fixed +++ b/src/tools/clippy/tests/ui/box_default.fixed @@ -1,5 +1,5 @@ #![warn(clippy::box_default)] -#![allow(clippy::default_constructed_unit_structs)] +#![allow(clippy::boxed_local, clippy::default_constructed_unit_structs)] #[derive(Default)] struct ImplementsDefault; @@ -12,26 +12,50 @@ impl OwnDefault { } } -macro_rules! outer { - ($e: expr) => { - $e +macro_rules! default { + () => { + Default::default() + }; +} + +macro_rules! string_new { + () => { + String::new() + }; +} + +macro_rules! box_new { + ($e:expr) => { + Box::new($e) }; } fn main() { - let _string: Box = Box::default(); - let _byte = Box::::default(); - let _vec = Box::>::default(); - let _impl = Box::::default(); - let _impl2 = Box::::default(); - let _impl3: Box = Box::default(); - let _own = Box::new(OwnDefault::default()); // should not lint - let _in_macro = outer!(Box::::default()); - let _string_default = outer!(Box::::default()); - let _vec2: Box> = Box::default(); - let _vec3: Box> = Box::default(); - let _vec4: Box<_> = Box::>::default(); - let _more = ret_ty_fn(); + let string1: Box = Box::default(); + let string2: Box = Box::default(); + let impl1: Box = Box::default(); + let vec: Box> = Box::default(); + let byte: Box = Box::default(); + let vec2: Box> = Box::default(); + let vec3: Box> = Box::default(); + + let plain_default = Box::default(); + let _: Box = plain_default; + + let _: Box = Box::new(default!()); + let _: Box = Box::new(string_new!()); + let _: Box = box_new!(Default::default()); + let _: Box = box_new!(String::new()); + let _: Box = box_new!(default!()); + let _: Box = box_new!(string_new!()); + + let own: Box = Box::new(OwnDefault::default()); // should not lint + + // Do not suggest where a turbofish would be required + let impl2 = Box::new(ImplementsDefault::default()); + let impl3 = Box::new(::default()); + let vec4: Box<_> = Box::new(Vec::from([false; 0])); + let more = ret_ty_fn(); call_ty_fn(Box::default()); issue_10381(); @@ -44,10 +68,9 @@ fn main() { } fn ret_ty_fn() -> Box { - Box::::default() + Box::new(bool::default()) // Could lint, currently doesn't } -#[allow(clippy::boxed_local)] fn call_ty_fn(_b: Box) { issue_9621_dyn_trait(); } @@ -61,7 +84,7 @@ impl Read for ImplementsDefault { } fn issue_9621_dyn_trait() { - let _: Box = Box::::default(); + let _: Box = Box::new(ImplementsDefault::default()); issue_10089(); } @@ -70,7 +93,7 @@ fn issue_10089() { #[derive(Default)] struct WeirdPathed; - let _ = Box::::default(); + let _ = Box::new(WeirdPathed::default()); }; } @@ -82,7 +105,7 @@ fn issue_10381() { fn maybe_get_bar(i: u32) -> Option> { if i % 2 == 0 { - Some(Box::::default()) + Some(Box::new(Foo::default())) } else { None } @@ -91,20 +114,6 @@ fn issue_10381() { assert!(maybe_get_bar(2).is_some()); } -#[allow(unused)] -fn issue_11868() { - fn foo(_: &mut Vec) {} - - macro_rules! bar { - ($baz:expr) => { - Box::leak(Box::new($baz)) - }; - } - - foo(bar!(vec![])); - foo(bar!(vec![1])); -} - // Issue #11927: The quickfix for the `Box::new` suggests replacing with `Box::::default()`, // removing the `outer::` segment. fn issue_11927() { @@ -116,7 +125,7 @@ fn issue_11927() { } fn foo() { - let _b = Box::::default(); - let _b = Box::>::default(); + let _b = Box::new(outer::Inner::default()); + let _b = Box::new(std::collections::HashSet::::new()); } } diff --git a/src/tools/clippy/tests/ui/box_default.rs b/src/tools/clippy/tests/ui/box_default.rs index eecba7464ec2..e19a62a90221 100644 --- a/src/tools/clippy/tests/ui/box_default.rs +++ b/src/tools/clippy/tests/ui/box_default.rs @@ -1,5 +1,5 @@ #![warn(clippy::box_default)] -#![allow(clippy::default_constructed_unit_structs)] +#![allow(clippy::boxed_local, clippy::default_constructed_unit_structs)] #[derive(Default)] struct ImplementsDefault; @@ -12,26 +12,50 @@ impl OwnDefault { } } -macro_rules! outer { - ($e: expr) => { - $e +macro_rules! default { + () => { + Default::default() + }; +} + +macro_rules! string_new { + () => { + String::new() + }; +} + +macro_rules! box_new { + ($e:expr) => { + Box::new($e) }; } fn main() { - let _string: Box = Box::new(Default::default()); - let _byte = Box::new(u8::default()); - let _vec = Box::new(Vec::::new()); - let _impl = Box::new(ImplementsDefault::default()); - let _impl2 = Box::new(::default()); - let _impl3: Box = Box::new(Default::default()); - let _own = Box::new(OwnDefault::default()); // should not lint - let _in_macro = outer!(Box::new(String::new())); - let _string_default = outer!(Box::new(String::from(""))); - let _vec2: Box> = Box::new(vec![]); - let _vec3: Box> = Box::new(Vec::from([])); - let _vec4: Box<_> = Box::new(Vec::from([false; 0])); - let _more = ret_ty_fn(); + let string1: Box = Box::new(Default::default()); + let string2: Box = Box::new(String::new()); + let impl1: Box = Box::new(Default::default()); + let vec: Box> = Box::new(Vec::new()); + let byte: Box = Box::new(u8::default()); + let vec2: Box> = Box::new(vec![]); + let vec3: Box> = Box::new(Vec::from([])); + + let plain_default = Box::new(Default::default()); + let _: Box = plain_default; + + let _: Box = Box::new(default!()); + let _: Box = Box::new(string_new!()); + let _: Box = box_new!(Default::default()); + let _: Box = box_new!(String::new()); + let _: Box = box_new!(default!()); + let _: Box = box_new!(string_new!()); + + let own: Box = Box::new(OwnDefault::default()); // should not lint + + // Do not suggest where a turbofish would be required + let impl2 = Box::new(ImplementsDefault::default()); + let impl3 = Box::new(::default()); + let vec4: Box<_> = Box::new(Vec::from([false; 0])); + let more = ret_ty_fn(); call_ty_fn(Box::new(u8::default())); issue_10381(); @@ -44,10 +68,9 @@ fn main() { } fn ret_ty_fn() -> Box { - Box::new(bool::default()) + Box::new(bool::default()) // Could lint, currently doesn't } -#[allow(clippy::boxed_local)] fn call_ty_fn(_b: Box) { issue_9621_dyn_trait(); } @@ -91,20 +114,6 @@ fn issue_10381() { assert!(maybe_get_bar(2).is_some()); } -#[allow(unused)] -fn issue_11868() { - fn foo(_: &mut Vec) {} - - macro_rules! bar { - ($baz:expr) => { - Box::leak(Box::new($baz)) - }; - } - - foo(bar!(vec![])); - foo(bar!(vec![1])); -} - // Issue #11927: The quickfix for the `Box::new` suggests replacing with `Box::::default()`, // removing the `outer::` segment. fn issue_11927() { diff --git a/src/tools/clippy/tests/ui/box_default.stderr b/src/tools/clippy/tests/ui/box_default.stderr index 8bb5917a627b..f172a875dce4 100644 --- a/src/tools/clippy/tests/ui/box_default.stderr +++ b/src/tools/clippy/tests/ui/box_default.stderr @@ -1,113 +1,59 @@ error: `Box::new(_)` of default value - --> tests/ui/box_default.rs:22:32 + --> tests/ui/box_default.rs:34:32 | -LL | let _string: Box = Box::new(Default::default()); +LL | let string1: Box = Box::new(Default::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` | = note: `-D clippy::box-default` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::box_default)]` error: `Box::new(_)` of default value - --> tests/ui/box_default.rs:23:17 + --> tests/ui/box_default.rs:35:32 | -LL | let _byte = Box::new(u8::default()); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::::default()` +LL | let string2: Box = Box::new(String::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` error: `Box::new(_)` of default value - --> tests/ui/box_default.rs:24:16 + --> tests/ui/box_default.rs:36:41 | -LL | let _vec = Box::new(Vec::::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::>::default()` +LL | let impl1: Box = Box::new(Default::default()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` error: `Box::new(_)` of default value - --> tests/ui/box_default.rs:25:17 + --> tests/ui/box_default.rs:37:29 | -LL | let _impl = Box::new(ImplementsDefault::default()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::::default()` +LL | let vec: Box> = Box::new(Vec::new()); + | ^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` error: `Box::new(_)` of default value - --> tests/ui/box_default.rs:26:18 + --> tests/ui/box_default.rs:38:25 | -LL | let _impl2 = Box::new(::default()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::::default()` +LL | let byte: Box = Box::new(u8::default()); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` error: `Box::new(_)` of default value - --> tests/ui/box_default.rs:27:42 + --> tests/ui/box_default.rs:39:45 | -LL | let _impl3: Box = Box::new(Default::default()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` +LL | let vec2: Box> = Box::new(vec![]); + | ^^^^^^^^^^^^^^^^ help: try: `Box::default()` error: `Box::new(_)` of default value - --> tests/ui/box_default.rs:29:28 + --> tests/ui/box_default.rs:40:32 | -LL | let _in_macro = outer!(Box::new(String::new())); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::::default()` +LL | let vec3: Box> = Box::new(Vec::from([])); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` error: `Box::new(_)` of default value - --> tests/ui/box_default.rs:30:34 + --> tests/ui/box_default.rs:42:25 | -LL | let _string_default = outer!(Box::new(String::from(""))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::::default()` +LL | let plain_default = Box::new(Default::default()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` error: `Box::new(_)` of default value - --> tests/ui/box_default.rs:31:46 - | -LL | let _vec2: Box> = Box::new(vec![]); - | ^^^^^^^^^^^^^^^^ help: try: `Box::default()` - -error: `Box::new(_)` of default value - --> tests/ui/box_default.rs:32:33 - | -LL | let _vec3: Box> = Box::new(Vec::from([])); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` - -error: `Box::new(_)` of default value - --> tests/ui/box_default.rs:33:25 - | -LL | let _vec4: Box<_> = Box::new(Vec::from([false; 0])); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::>::default()` - -error: `Box::new(_)` of default value - --> tests/ui/box_default.rs:35:16 + --> tests/ui/box_default.rs:59:16 | LL | call_ty_fn(Box::new(u8::default())); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` -error: `Box::new(_)` of default value - --> tests/ui/box_default.rs:47:5 - | -LL | Box::new(bool::default()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::::default()` - -error: `Box::new(_)` of default value - --> tests/ui/box_default.rs:64:28 - | -LL | let _: Box = Box::new(ImplementsDefault::default()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::::default()` - -error: `Box::new(_)` of default value - --> tests/ui/box_default.rs:73:17 - | -LL | let _ = Box::new(WeirdPathed::default()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::::default()` - -error: `Box::new(_)` of default value - --> tests/ui/box_default.rs:85:18 - | -LL | Some(Box::new(Foo::default())) - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::::default()` - -error: `Box::new(_)` of default value - --> tests/ui/box_default.rs:119:18 - | -LL | let _b = Box::new(outer::Inner::default()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::::default()` - -error: `Box::new(_)` of default value - --> tests/ui/box_default.rs:120:18 - | -LL | let _b = Box::new(std::collections::HashSet::::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::>::default()` - -error: aborting due to 18 previous errors +error: aborting due to 9 previous errors diff --git a/src/tools/clippy/tests/ui/cast.rs b/src/tools/clippy/tests/ui/cast.rs index a7331ddc7d0e..ce76ad3d3ad1 100644 --- a/src/tools/clippy/tests/ui/cast.rs +++ b/src/tools/clippy/tests/ui/cast.rs @@ -9,7 +9,12 @@ clippy::cast_sign_loss, clippy::cast_possible_wrap )] -#![allow(clippy::cast_abs_to_unsigned, clippy::no_effect, clippy::unnecessary_operation)] +#![allow( + clippy::cast_abs_to_unsigned, + clippy::no_effect, + clippy::unnecessary_operation, + clippy::unnecessary_literal_unwrap +)] fn main() { // Test clippy::cast_precision_loss @@ -457,3 +462,8 @@ fn issue11642() { //~^ ERROR: casting `i32` to `u32` may lose the sign of the value } } + +fn issue12506() -> usize { + let bar: Result, u32> = Ok(Some(10)); + bar.unwrap().unwrap() as usize +} diff --git a/src/tools/clippy/tests/ui/cast.stderr b/src/tools/clippy/tests/ui/cast.stderr index dd5d339b81b2..3736e8aee0af 100644 --- a/src/tools/clippy/tests/ui/cast.stderr +++ b/src/tools/clippy/tests/ui/cast.stderr @@ -1,5 +1,5 @@ error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:17:5 + --> tests/ui/cast.rs:22:5 | LL | x0 as f32; | ^^^^^^^^^ @@ -8,37 +8,37 @@ LL | x0 as f32; = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]` error: casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:21:5 + --> tests/ui/cast.rs:26:5 | LL | x1 as f32; | ^^^^^^^^^ error: casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast.rs:23:5 + --> tests/ui/cast.rs:28:5 | LL | x1 as f64; | ^^^^^^^^^ error: casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:26:5 + --> tests/ui/cast.rs:31:5 | LL | x2 as f32; | ^^^^^^^^^ error: casting `u64` to `f32` causes a loss of precision (`u64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:29:5 + --> tests/ui/cast.rs:34:5 | LL | x3 as f32; | ^^^^^^^^^ error: casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast.rs:31:5 + --> tests/ui/cast.rs:36:5 | LL | x3 as f64; | ^^^^^^^^^ error: casting `f32` to `i32` may truncate the value - --> tests/ui/cast.rs:34:5 + --> tests/ui/cast.rs:39:5 | LL | 1f32 as i32; | ^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | 1f32 as i32; = help: to override `-D warnings` add `#[allow(clippy::cast_possible_truncation)]` error: casting `f32` to `u32` may truncate the value - --> tests/ui/cast.rs:36:5 + --> tests/ui/cast.rs:41:5 | LL | 1f32 as u32; | ^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | 1f32 as u32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:36:5 + --> tests/ui/cast.rs:41:5 | LL | 1f32 as u32; | ^^^^^^^^^^^ @@ -65,7 +65,7 @@ LL | 1f32 as u32; = help: to override `-D warnings` add `#[allow(clippy::cast_sign_loss)]` error: casting `f64` to `f32` may truncate the value - --> tests/ui/cast.rs:40:5 + --> tests/ui/cast.rs:45:5 | LL | 1f64 as f32; | ^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | 1f64 as f32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `i32` to `i8` may truncate the value - --> tests/ui/cast.rs:42:5 + --> tests/ui/cast.rs:47:5 | LL | 1i32 as i8; | ^^^^^^^^^^ @@ -85,7 +85,7 @@ LL | i8::try_from(1i32); | ~~~~~~~~~~~~~~~~~~ error: casting `i32` to `u8` may truncate the value - --> tests/ui/cast.rs:44:5 + --> tests/ui/cast.rs:49:5 | LL | 1i32 as u8; | ^^^^^^^^^^ @@ -97,7 +97,7 @@ LL | u8::try_from(1i32); | ~~~~~~~~~~~~~~~~~~ error: casting `f64` to `isize` may truncate the value - --> tests/ui/cast.rs:46:5 + --> tests/ui/cast.rs:51:5 | LL | 1f64 as isize; | ^^^^^^^^^^^^^ @@ -105,7 +105,7 @@ LL | 1f64 as isize; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `usize` may truncate the value - --> tests/ui/cast.rs:48:5 + --> tests/ui/cast.rs:53:5 | LL | 1f64 as usize; | ^^^^^^^^^^^^^ @@ -113,13 +113,13 @@ LL | 1f64 as usize; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:48:5 + --> tests/ui/cast.rs:53:5 | LL | 1f64 as usize; | ^^^^^^^^^^^^^ error: casting `u32` to `u16` may truncate the value - --> tests/ui/cast.rs:51:5 + --> tests/ui/cast.rs:56:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^^^^^^^^ @@ -131,7 +131,7 @@ LL | u16::try_from(1f32 as u32); | ~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `f32` to `u32` may truncate the value - --> tests/ui/cast.rs:51:5 + --> tests/ui/cast.rs:56:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^ @@ -139,13 +139,13 @@ LL | 1f32 as u32 as u16; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:51:5 + --> tests/ui/cast.rs:56:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^ error: casting `i32` to `i8` may truncate the value - --> tests/ui/cast.rs:56:22 + --> tests/ui/cast.rs:61:22 | LL | let _x: i8 = 1i32 as _; | ^^^^^^^^^ @@ -157,7 +157,7 @@ LL | let _x: i8 = 1i32.try_into(); | ~~~~~~~~~~~~~~~ error: casting `f32` to `i32` may truncate the value - --> tests/ui/cast.rs:58:9 + --> tests/ui/cast.rs:63:9 | LL | 1f32 as i32; | ^^^^^^^^^^^ @@ -165,7 +165,7 @@ LL | 1f32 as i32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `i32` may truncate the value - --> tests/ui/cast.rs:60:9 + --> tests/ui/cast.rs:65:9 | LL | 1f64 as i32; | ^^^^^^^^^^^ @@ -173,7 +173,7 @@ LL | 1f64 as i32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u8` may truncate the value - --> tests/ui/cast.rs:62:9 + --> tests/ui/cast.rs:67:9 | LL | 1f32 as u8; | ^^^^^^^^^^ @@ -181,13 +181,13 @@ LL | 1f32 as u8; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u8` may lose the sign of the value - --> tests/ui/cast.rs:62:9 + --> tests/ui/cast.rs:67:9 | LL | 1f32 as u8; | ^^^^^^^^^^ error: casting `u8` to `i8` may wrap around the value - --> tests/ui/cast.rs:67:5 + --> tests/ui/cast.rs:72:5 | LL | 1u8 as i8; | ^^^^^^^^^ @@ -196,31 +196,31 @@ LL | 1u8 as i8; = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]` error: casting `u16` to `i16` may wrap around the value - --> tests/ui/cast.rs:70:5 + --> tests/ui/cast.rs:75:5 | LL | 1u16 as i16; | ^^^^^^^^^^^ error: casting `u32` to `i32` may wrap around the value - --> tests/ui/cast.rs:72:5 + --> tests/ui/cast.rs:77:5 | LL | 1u32 as i32; | ^^^^^^^^^^^ error: casting `u64` to `i64` may wrap around the value - --> tests/ui/cast.rs:74:5 + --> tests/ui/cast.rs:79:5 | LL | 1u64 as i64; | ^^^^^^^^^^^ error: casting `usize` to `isize` may wrap around the value - --> tests/ui/cast.rs:76:5 + --> tests/ui/cast.rs:81:5 | LL | 1usize as isize; | ^^^^^^^^^^^^^^^ error: casting `usize` to `i8` may truncate the value - --> tests/ui/cast.rs:79:5 + --> tests/ui/cast.rs:84:5 | LL | 1usize as i8; | ^^^^^^^^^^^^ @@ -232,7 +232,7 @@ LL | i8::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i16` may truncate the value - --> tests/ui/cast.rs:82:5 + --> tests/ui/cast.rs:87:5 | LL | 1usize as i16; | ^^^^^^^^^^^^^ @@ -244,7 +244,7 @@ LL | i16::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i16` may wrap around the value on targets with 16-bit wide pointers - --> tests/ui/cast.rs:82:5 + --> tests/ui/cast.rs:87:5 | LL | 1usize as i16; | ^^^^^^^^^^^^^ @@ -253,7 +253,7 @@ LL | 1usize as i16; = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers - --> tests/ui/cast.rs:87:5 + --> tests/ui/cast.rs:92:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ @@ -265,19 +265,19 @@ LL | i32::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:87:5 + --> tests/ui/cast.rs:92:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ error: casting `usize` to `i64` may wrap around the value on targets with 64-bit wide pointers - --> tests/ui/cast.rs:91:5 + --> tests/ui/cast.rs:96:5 | LL | 1usize as i64; | ^^^^^^^^^^^^^ error: casting `u16` to `isize` may wrap around the value on targets with 16-bit wide pointers - --> tests/ui/cast.rs:96:5 + --> tests/ui/cast.rs:101:5 | LL | 1u16 as isize; | ^^^^^^^^^^^^^ @@ -286,13 +286,13 @@ LL | 1u16 as isize; = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:100:5 + --> tests/ui/cast.rs:105:5 | LL | 1u32 as isize; | ^^^^^^^^^^^^^ error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:103:5 + --> tests/ui/cast.rs:108:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ @@ -304,55 +304,55 @@ LL | isize::try_from(1u64); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers - --> tests/ui/cast.rs:103:5 + --> tests/ui/cast.rs:108:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:108:5 + --> tests/ui/cast.rs:113:5 | LL | -1i32 as u32; | ^^^^^^^^^^^^ error: casting `isize` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:111:5 + --> tests/ui/cast.rs:116:5 | LL | -1isize as usize; | ^^^^^^^^^^^^^^^^ error: casting `i8` to `u8` may lose the sign of the value - --> tests/ui/cast.rs:122:5 + --> tests/ui/cast.rs:127:5 | LL | (i8::MIN).abs() as u8; | ^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:126:5 + --> tests/ui/cast.rs:131:5 | LL | (-1i64).abs() as u64; | ^^^^^^^^^^^^^^^^^^^^ error: casting `isize` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:127:5 + --> tests/ui/cast.rs:132:5 | LL | (-1isize).abs() as usize; | ^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:134:5 + --> tests/ui/cast.rs:139:5 | LL | (unsafe { (-1i64).checked_abs().unwrap_unchecked() }) as u64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:149:5 + --> tests/ui/cast.rs:154:5 | LL | (unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }) as u64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `i8` may truncate the value - --> tests/ui/cast.rs:200:5 + --> tests/ui/cast.rs:205:5 | LL | (-99999999999i64).min(1) as i8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -364,7 +364,7 @@ LL | i8::try_from((-99999999999i64).min(1)); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `u8` may truncate the value - --> tests/ui/cast.rs:214:5 + --> tests/ui/cast.rs:219:5 | LL | 999999u64.clamp(0, 256) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -376,7 +376,7 @@ LL | u8::try_from(999999u64.clamp(0, 256)); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `main::E2` to `u8` may truncate the value - --> tests/ui/cast.rs:237:21 + --> tests/ui/cast.rs:242:21 | LL | let _ = self as u8; | ^^^^^^^^^^ @@ -388,7 +388,7 @@ LL | let _ = u8::try_from(self); | ~~~~~~~~~~~~~~~~~~ error: casting `main::E2::B` to `u8` will truncate the value - --> tests/ui/cast.rs:239:21 + --> tests/ui/cast.rs:244:21 | LL | let _ = Self::B as u8; | ^^^^^^^^^^^^^ @@ -397,7 +397,7 @@ LL | let _ = Self::B as u8; = help: to override `-D warnings` add `#[allow(clippy::cast_enum_truncation)]` error: casting `main::E5` to `i8` may truncate the value - --> tests/ui/cast.rs:281:21 + --> tests/ui/cast.rs:286:21 | LL | let _ = self as i8; | ^^^^^^^^^^ @@ -409,13 +409,13 @@ LL | let _ = i8::try_from(self); | ~~~~~~~~~~~~~~~~~~ error: casting `main::E5::A` to `i8` will truncate the value - --> tests/ui/cast.rs:283:21 + --> tests/ui/cast.rs:288:21 | LL | let _ = Self::A as i8; | ^^^^^^^^^^^^^ error: casting `main::E6` to `i16` may truncate the value - --> tests/ui/cast.rs:300:21 + --> tests/ui/cast.rs:305:21 | LL | let _ = self as i16; | ^^^^^^^^^^^ @@ -427,7 +427,7 @@ LL | let _ = i16::try_from(self); | ~~~~~~~~~~~~~~~~~~~ error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:319:21 + --> tests/ui/cast.rs:324:21 | LL | let _ = self as usize; | ^^^^^^^^^^^^^ @@ -439,7 +439,7 @@ LL | let _ = usize::try_from(self); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `main::E10` to `u16` may truncate the value - --> tests/ui/cast.rs:366:21 + --> tests/ui/cast.rs:371:21 | LL | let _ = self as u16; | ^^^^^^^^^^^ @@ -451,7 +451,7 @@ LL | let _ = u16::try_from(self); | ~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:377:13 + --> tests/ui/cast.rs:382:13 | LL | let c = (q >> 16) as u8; | ^^^^^^^^^^^^^^^ @@ -463,7 +463,7 @@ LL | let c = u8::try_from(q >> 16); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:381:13 + --> tests/ui/cast.rs:386:13 | LL | let c = (q / 1000) as u8; | ^^^^^^^^^^^^^^^^ @@ -475,85 +475,85 @@ LL | let c = u8::try_from(q / 1000); | ~~~~~~~~~~~~~~~~~~~~~~ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:393:9 + --> tests/ui/cast.rs:398:9 | LL | (x * x) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:398:32 + --> tests/ui/cast.rs:403:32 | LL | let _a = |x: i32| -> u32 { (x * x * x * x) as u32 }; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:400:5 + --> tests/ui/cast.rs:405:5 | LL | (2_i32).checked_pow(3).unwrap() as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:401:5 + --> tests/ui/cast.rs:406:5 | LL | (-2_i32).pow(3) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:406:5 + --> tests/ui/cast.rs:411:5 | LL | (-5_i32 % 2) as u32; | ^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:408:5 + --> tests/ui/cast.rs:413:5 | LL | (-5_i32 % -2) as u32; | ^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:411:5 + --> tests/ui/cast.rs:416:5 | LL | (-2_i32 >> 1) as u32; | ^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:415:5 + --> tests/ui/cast.rs:420:5 | LL | (x * x) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:416:5 + --> tests/ui/cast.rs:421:5 | LL | (x * x * x) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:420:5 + --> tests/ui/cast.rs:425:5 | LL | (y * y * y * y * -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:422:5 + --> tests/ui/cast.rs:427:5 | LL | (y * y * y / y * 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:423:5 + --> tests/ui/cast.rs:428:5 | LL | (y * y / y * 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:425:5 + --> tests/ui/cast.rs:430:5 | LL | (y / y * y * -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^ error: equal expressions as operands to `/` - --> tests/ui/cast.rs:425:6 + --> tests/ui/cast.rs:430:6 | LL | (y / y * y * -2) as u16; | ^^^^^ @@ -561,94 +561,112 @@ LL | (y / y * y * -2) as u16; = note: `#[deny(clippy::eq_op)]` on by default error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:428:5 + --> tests/ui/cast.rs:433:5 | LL | (y + y + y + -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:430:5 + --> tests/ui/cast.rs:435:5 | LL | (y + y + y + 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:434:5 + --> tests/ui/cast.rs:439:5 | LL | (z + -2) as u16; | ^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:436:5 + --> tests/ui/cast.rs:441:5 | LL | (z + z + 2) as u16; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:439:9 + --> tests/ui/cast.rs:444:9 | LL | (a * a * b * b * c * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:440:9 + --> tests/ui/cast.rs:445:9 | LL | (a * b * c) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:442:9 + --> tests/ui/cast.rs:447:9 | LL | (a * -b * c) as u32; | ^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:444:9 + --> tests/ui/cast.rs:449:9 | LL | (a * b * c * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:445:9 + --> tests/ui/cast.rs:450:9 | LL | (a * -2) as u32; | ^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:447:9 + --> tests/ui/cast.rs:452:9 | LL | (a * b * c * -2) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:449:9 + --> tests/ui/cast.rs:454:9 | LL | (a / b) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:450:9 + --> tests/ui/cast.rs:455:9 | LL | (a / b * c) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:452:9 + --> tests/ui/cast.rs:457:9 | LL | (a / b + b * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:454:9 + --> tests/ui/cast.rs:459:9 | LL | a.saturating_pow(3) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:456:9 + --> tests/ui/cast.rs:461:9 | LL | (a.abs() * b.pow(2) / c.abs()) as u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 85 previous errors +error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers + --> tests/ui/cast.rs:468:5 + | +LL | bar.unwrap().unwrap() as usize + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | usize::try_from(bar.unwrap().unwrap()) + | + +error: casting `i64` to `usize` may lose the sign of the value + --> tests/ui/cast.rs:468:5 + | +LL | bar.unwrap().unwrap() as usize + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 87 previous errors diff --git a/src/tools/clippy/tests/ui/checked_conversions.fixed b/src/tools/clippy/tests/ui/checked_conversions.fixed index 0e05a27429b0..1e8da3316141 100644 --- a/src/tools/clippy/tests/ui/checked_conversions.fixed +++ b/src/tools/clippy/tests/ui/checked_conversions.fixed @@ -1,5 +1,6 @@ #![allow( clippy::cast_lossless, + clippy::legacy_numeric_constants, unused, // Int::max_value will be deprecated in the future deprecated, diff --git a/src/tools/clippy/tests/ui/checked_conversions.rs b/src/tools/clippy/tests/ui/checked_conversions.rs index ac7826992653..67a9adc049ea 100644 --- a/src/tools/clippy/tests/ui/checked_conversions.rs +++ b/src/tools/clippy/tests/ui/checked_conversions.rs @@ -1,5 +1,6 @@ #![allow( clippy::cast_lossless, + clippy::legacy_numeric_constants, unused, // Int::max_value will be deprecated in the future deprecated, diff --git a/src/tools/clippy/tests/ui/checked_conversions.stderr b/src/tools/clippy/tests/ui/checked_conversions.stderr index 223e379cce96..453cd7fcf016 100644 --- a/src/tools/clippy/tests/ui/checked_conversions.stderr +++ b/src/tools/clippy/tests/ui/checked_conversions.stderr @@ -1,5 +1,5 @@ error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:14:13 + --> tests/ui/checked_conversions.rs:15:13 | LL | let _ = value <= (u32::max_value() as i64) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()` @@ -8,97 +8,97 @@ LL | let _ = value <= (u32::max_value() as i64) && value >= 0; = help: to override `-D warnings` add `#[allow(clippy::checked_conversions)]` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:15:13 + --> tests/ui/checked_conversions.rs:16:13 | LL | let _ = value <= (u32::MAX as i64) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:19:13 + --> tests/ui/checked_conversions.rs:20:13 | LL | let _ = value <= i64::from(u16::max_value()) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:20:13 + --> tests/ui/checked_conversions.rs:21:13 | LL | let _ = value <= i64::from(u16::MAX) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:24:13 + --> tests/ui/checked_conversions.rs:25:13 | LL | let _ = value <= (u8::max_value() as isize) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:25:13 + --> tests/ui/checked_conversions.rs:26:13 | LL | let _ = value <= (u8::MAX as isize) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:31:13 + --> tests/ui/checked_conversions.rs:32:13 | LL | let _ = value <= (i32::max_value() as i64) && value >= (i32::min_value() as i64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:32:13 + --> tests/ui/checked_conversions.rs:33:13 | LL | let _ = value <= (i32::MAX as i64) && value >= (i32::MIN as i64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:36:13 + --> tests/ui/checked_conversions.rs:37:13 | LL | let _ = value <= i64::from(i16::max_value()) && value >= i64::from(i16::min_value()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:37:13 + --> tests/ui/checked_conversions.rs:38:13 | LL | let _ = value <= i64::from(i16::MAX) && value >= i64::from(i16::MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:43:13 + --> tests/ui/checked_conversions.rs:44:13 | LL | let _ = value <= i32::max_value() as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:44:13 + --> tests/ui/checked_conversions.rs:45:13 | LL | let _ = value <= i32::MAX as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:48:13 + --> tests/ui/checked_conversions.rs:49:13 | LL | let _ = value <= isize::max_value() as usize && value as i32 == 5; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:49:13 + --> tests/ui/checked_conversions.rs:50:13 | LL | let _ = value <= isize::MAX as usize && value as i32 == 5; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:53:13 + --> tests/ui/checked_conversions.rs:54:13 | LL | let _ = value <= u16::max_value() as u32 && value as i32 == 5; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:54:13 + --> tests/ui/checked_conversions.rs:55:13 | LL | let _ = value <= u16::MAX as u32 && value as i32 == 5; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:87:13 + --> tests/ui/checked_conversions.rs:88:13 | LL | let _ = value <= (u32::MAX as i64) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()` diff --git a/src/tools/clippy/tests/ui/crashes/ice-12616.fixed b/src/tools/clippy/tests/ui/crashes/ice-12616.fixed new file mode 100644 index 000000000000..a5a5b3d1e78e --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-12616.fixed @@ -0,0 +1,7 @@ +#![warn(clippy::ptr_as_ptr)] +#![allow(clippy::unnecessary_operation, clippy::unnecessary_cast)] + +fn main() { + let s = std::ptr::null::<()>; + s().cast::<()>(); +} diff --git a/src/tools/clippy/tests/ui/crashes/ice-12616.rs b/src/tools/clippy/tests/ui/crashes/ice-12616.rs new file mode 100644 index 000000000000..6ee9a5ec08fe --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-12616.rs @@ -0,0 +1,7 @@ +#![warn(clippy::ptr_as_ptr)] +#![allow(clippy::unnecessary_operation, clippy::unnecessary_cast)] + +fn main() { + let s = std::ptr::null::<()>; + s() as *const (); +} diff --git a/src/tools/clippy/tests/ui/crashes/ice-12616.stderr b/src/tools/clippy/tests/ui/crashes/ice-12616.stderr new file mode 100644 index 000000000000..ef573f55cf36 --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-12616.stderr @@ -0,0 +1,19 @@ +error: `as` casting between raw pointers without changing its mutability + --> tests/ui/crashes/ice-12616.rs:6:5 + | +LL | s() as *const (); + | ^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `s().cast::<()>()` + | + = note: `-D clippy::ptr-as-ptr` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::ptr_as_ptr)]` + +error: `as` casting between raw pointers without changing its mutability + --> tests/ui/crashes/ice-12616.rs:6:5 + | +LL | s() as *const (); + | ^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `s().cast::<()>()` + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/crashes/ice-1782.rs b/src/tools/clippy/tests/ui/crashes/ice-1782.rs index 19ab03418eed..73de5721cbc1 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-1782.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-1782.rs @@ -1,5 +1,5 @@ #![allow(dead_code, unused_variables)] -#![allow(clippy::unnecessary_cast)] +#![allow(clippy::unnecessary_cast, clippy::missing_transmute_annotations)] /// Should not trigger an ICE in `SpanlessEq` / `consts::constant` /// diff --git a/src/tools/clippy/tests/ui/duplicated_attributes.rs b/src/tools/clippy/tests/ui/duplicated_attributes.rs index 0f036c684c1c..d051c881f15b 100644 --- a/src/tools/clippy/tests/ui/duplicated_attributes.rs +++ b/src/tools/clippy/tests/ui/duplicated_attributes.rs @@ -2,16 +2,17 @@ #![cfg(any(unix, windows))] #![allow(dead_code)] #![allow(dead_code)] //~ ERROR: duplicated attribute -#![cfg(any(unix, windows))] -//~^ ERROR: duplicated attribute -//~| ERROR: duplicated attribute +#![cfg(any(unix, windows))] // Should not warn! #[cfg(any(unix, windows, target_os = "linux"))] #[allow(dead_code)] #[allow(dead_code)] //~ ERROR: duplicated attribute -#[cfg(any(unix, windows, target_os = "linux"))] -//~^ ERROR: duplicated attribute -//~| ERROR: duplicated attribute +#[cfg(any(unix, windows, target_os = "linux"))] // Should not warn! fn foo() {} +#[cfg(unix)] +#[cfg(windows)] +#[cfg(unix)] //~ ERROR: duplicated attribute +fn bar() {} + fn main() {} diff --git a/src/tools/clippy/tests/ui/duplicated_attributes.stderr b/src/tools/clippy/tests/ui/duplicated_attributes.stderr index 1c6578dbb43a..9e26ba990ac1 100644 --- a/src/tools/clippy/tests/ui/duplicated_attributes.stderr +++ b/src/tools/clippy/tests/ui/duplicated_attributes.stderr @@ -18,106 +18,38 @@ LL | #![allow(dead_code)] = help: to override `-D warnings` add `#[allow(clippy::duplicated_attributes)]` error: duplicated attribute - --> tests/ui/duplicated_attributes.rs:5:12 - | -LL | #![cfg(any(unix, windows))] - | ^^^^ - | -note: first defined here - --> tests/ui/duplicated_attributes.rs:2:12 - | -LL | #![cfg(any(unix, windows))] - | ^^^^ -help: remove this attribute - --> tests/ui/duplicated_attributes.rs:5:12 - | -LL | #![cfg(any(unix, windows))] - | ^^^^ - -error: duplicated attribute - --> tests/ui/duplicated_attributes.rs:5:18 - | -LL | #![cfg(any(unix, windows))] - | ^^^^^^^ - | -note: first defined here - --> tests/ui/duplicated_attributes.rs:2:18 - | -LL | #![cfg(any(unix, windows))] - | ^^^^^^^ -help: remove this attribute - --> tests/ui/duplicated_attributes.rs:5:18 - | -LL | #![cfg(any(unix, windows))] - | ^^^^^^^ - -error: duplicated attribute - --> tests/ui/duplicated_attributes.rs:11:9 + --> tests/ui/duplicated_attributes.rs:9:9 | LL | #[allow(dead_code)] | ^^^^^^^^^ | note: first defined here - --> tests/ui/duplicated_attributes.rs:10:9 + --> tests/ui/duplicated_attributes.rs:8:9 | LL | #[allow(dead_code)] | ^^^^^^^^^ help: remove this attribute - --> tests/ui/duplicated_attributes.rs:11:9 + --> tests/ui/duplicated_attributes.rs:9:9 | LL | #[allow(dead_code)] | ^^^^^^^^^ error: duplicated attribute - --> tests/ui/duplicated_attributes.rs:12:11 + --> tests/ui/duplicated_attributes.rs:15:7 | -LL | #[cfg(any(unix, windows, target_os = "linux"))] - | ^^^^ +LL | #[cfg(unix)] + | ^^^^ | note: first defined here - --> tests/ui/duplicated_attributes.rs:9:11 + --> tests/ui/duplicated_attributes.rs:13:7 | -LL | #[cfg(any(unix, windows, target_os = "linux"))] - | ^^^^ +LL | #[cfg(unix)] + | ^^^^ help: remove this attribute - --> tests/ui/duplicated_attributes.rs:12:11 + --> tests/ui/duplicated_attributes.rs:15:7 | -LL | #[cfg(any(unix, windows, target_os = "linux"))] - | ^^^^ +LL | #[cfg(unix)] + | ^^^^ -error: duplicated attribute - --> tests/ui/duplicated_attributes.rs:12:17 - | -LL | #[cfg(any(unix, windows, target_os = "linux"))] - | ^^^^^^^ - | -note: first defined here - --> tests/ui/duplicated_attributes.rs:9:17 - | -LL | #[cfg(any(unix, windows, target_os = "linux"))] - | ^^^^^^^ -help: remove this attribute - --> tests/ui/duplicated_attributes.rs:12:17 - | -LL | #[cfg(any(unix, windows, target_os = "linux"))] - | ^^^^^^^ - -error: duplicated attribute - --> tests/ui/duplicated_attributes.rs:12:26 - | -LL | #[cfg(any(unix, windows, target_os = "linux"))] - | ^^^^^^^^^^^^^^^^^^^ - | -note: first defined here - --> tests/ui/duplicated_attributes.rs:9:26 - | -LL | #[cfg(any(unix, windows, target_os = "linux"))] - | ^^^^^^^^^^^^^^^^^^^ -help: remove this attribute - --> tests/ui/duplicated_attributes.rs:12:26 - | -LL | #[cfg(any(unix, windows, target_os = "linux"))] - | ^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 7 previous errors +error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/eager_transmute.fixed b/src/tools/clippy/tests/ui/eager_transmute.fixed index bece09bba1ab..c29e7dd9ab3e 100644 --- a/src/tools/clippy/tests/ui/eager_transmute.fixed +++ b/src/tools/clippy/tests/ui/eager_transmute.fixed @@ -1,6 +1,6 @@ #![feature(rustc_attrs)] #![warn(clippy::eager_transmute)] -#![allow(clippy::transmute_int_to_non_zero)] +#![allow(clippy::transmute_int_to_non_zero, clippy::missing_transmute_annotations)] use std::num::NonZeroU8; diff --git a/src/tools/clippy/tests/ui/eager_transmute.rs b/src/tools/clippy/tests/ui/eager_transmute.rs index a82bd578f76c..491a9485c932 100644 --- a/src/tools/clippy/tests/ui/eager_transmute.rs +++ b/src/tools/clippy/tests/ui/eager_transmute.rs @@ -1,6 +1,6 @@ #![feature(rustc_attrs)] #![warn(clippy::eager_transmute)] -#![allow(clippy::transmute_int_to_non_zero)] +#![allow(clippy::transmute_int_to_non_zero, clippy::missing_transmute_annotations)] use std::num::NonZeroU8; diff --git a/src/tools/clippy/tests/ui/filter_map_identity.fixed b/src/tools/clippy/tests/ui/filter_map_identity.fixed index ad438afaca77..f3f6848e5f92 100644 --- a/src/tools/clippy/tests/ui/filter_map_identity.fixed +++ b/src/tools/clippy/tests/ui/filter_map_identity.fixed @@ -1,17 +1,83 @@ -#![allow(unused_imports, clippy::needless_return)] +#![allow(unused_imports, clippy::needless_return, clippy::useless_vec)] #![warn(clippy::filter_map_identity)] +#![feature(stmt_expr_attributes)] + +use std::option::Option; +struct NonCopy; +use std::convert::identity; + +fn non_copy_vec() -> Vec> { + todo!() +} + +fn copy_vec() -> Vec> { + todo!() +} + +fn copy_vec_non_inferred() -> Vec> { + todo!() +} + +fn opaque() -> impl IntoIterator> { + vec![Some(T::default())] +} fn main() { - let iterator = vec![Some(1), None, Some(2)].into_iter(); - let _ = iterator.flatten(); + { + // into_iter + copy_vec_non_inferred().into_iter().flatten(); + //~^ ERROR: use of + copy_vec_non_inferred().into_iter().flatten(); + //~^ ERROR: use of + copy_vec_non_inferred().into_iter().flatten(); + //~^ ERROR: use of + copy_vec_non_inferred().into_iter().flatten(); + //~^ ERROR: use of + copy_vec_non_inferred().into_iter().flatten(); + //~^ ERROR: use of - let iterator = vec![Some(1), None, Some(2)].into_iter(); - let _ = iterator.flatten(); + non_copy_vec().into_iter().flatten(); + //~^ ERROR: use of + non_copy_vec().into_iter().flatten(); + //~^ ERROR: use of - use std::convert::identity; - let iterator = vec![Some(1), None, Some(2)].into_iter(); - let _ = iterator.flatten(); + non_copy_vec().into_iter().flatten(); + //~^ ERROR: use of + non_copy_vec().into_iter().flatten(); + //~^ ERROR: use of + non_copy_vec().into_iter().flatten(); + //~^ ERROR: use of + non_copy_vec().into_iter().flatten(); + //~^ ERROR: use of - let iterator = vec![Some(1), None, Some(2)].into_iter(); - let _ = iterator.flatten(); + copy_vec::().into_iter().flatten(); + //~^ ERROR: use of + copy_vec::().into_iter().flatten(); + //~^ ERROR: use of + copy_vec::().into_iter().flatten(); + //~^ ERROR: use of + copy_vec::().into_iter().flatten(); + //~^ ERROR: use of + + // we are forced to pass the type in the call. + copy_vec::().into_iter().flatten(); + //~^ ERROR: use of + copy_vec::().into_iter().flatten(); + //~^ ERROR: use of + copy_vec::().into_iter().flatten(); + //~^ ERROR: use of + copy_vec::().into_iter().flatten(); + //~^ ERROR: use of + #[rustfmt::skip] + copy_vec::().into_iter().flatten(); + //~^ ERROR: use of + #[rustfmt::skip] + copy_vec::().into_iter().flatten(); + //~^ ERROR: use of + + // note, the compiler requires that we pass the type to `opaque`. This is mostly for reference, + // it behaves the same as copy_vec. + opaque::().into_iter().flatten(); + //~^ ERROR: use of + } } diff --git a/src/tools/clippy/tests/ui/filter_map_identity.rs b/src/tools/clippy/tests/ui/filter_map_identity.rs index d7423276872a..b9aa9c05be89 100644 --- a/src/tools/clippy/tests/ui/filter_map_identity.rs +++ b/src/tools/clippy/tests/ui/filter_map_identity.rs @@ -1,17 +1,83 @@ -#![allow(unused_imports, clippy::needless_return)] +#![allow(unused_imports, clippy::needless_return, clippy::useless_vec)] #![warn(clippy::filter_map_identity)] +#![feature(stmt_expr_attributes)] + +use std::option::Option; +struct NonCopy; +use std::convert::identity; + +fn non_copy_vec() -> Vec> { + todo!() +} + +fn copy_vec() -> Vec> { + todo!() +} + +fn copy_vec_non_inferred() -> Vec> { + todo!() +} + +fn opaque() -> impl IntoIterator> { + vec![Some(T::default())] +} fn main() { - let iterator = vec![Some(1), None, Some(2)].into_iter(); - let _ = iterator.filter_map(|x| x); + { + // into_iter + copy_vec_non_inferred().into_iter().filter_map(|x| x); + //~^ ERROR: use of + copy_vec_non_inferred().into_iter().filter_map(std::convert::identity); + //~^ ERROR: use of + copy_vec_non_inferred().into_iter().filter_map(identity); + //~^ ERROR: use of + copy_vec_non_inferred().into_iter().filter_map(|x| return x); + //~^ ERROR: use of + copy_vec_non_inferred().into_iter().filter_map(|x| return x); + //~^ ERROR: use of - let iterator = vec![Some(1), None, Some(2)].into_iter(); - let _ = iterator.filter_map(std::convert::identity); + non_copy_vec().into_iter().filter_map(|x| x); + //~^ ERROR: use of + non_copy_vec().into_iter().filter_map(|x| x); + //~^ ERROR: use of - use std::convert::identity; - let iterator = vec![Some(1), None, Some(2)].into_iter(); - let _ = iterator.filter_map(identity); + non_copy_vec().into_iter().filter_map(std::convert::identity); + //~^ ERROR: use of + non_copy_vec().into_iter().filter_map(identity); + //~^ ERROR: use of + non_copy_vec().into_iter().filter_map(|x| return x); + //~^ ERROR: use of + non_copy_vec().into_iter().filter_map(|x| return x); + //~^ ERROR: use of - let iterator = vec![Some(1), None, Some(2)].into_iter(); - let _ = iterator.filter_map(|x| return x); + copy_vec::().into_iter().filter_map(|x: Option<_>| x); + //~^ ERROR: use of + copy_vec::().into_iter().filter_map(|x: Option<_>| x); + //~^ ERROR: use of + copy_vec::().into_iter().filter_map(|x: Option<_>| return x); + //~^ ERROR: use of + copy_vec::().into_iter().filter_map(|x: Option<_>| return x); + //~^ ERROR: use of + + // we are forced to pass the type in the call. + copy_vec::().into_iter().filter_map(|x: Option| x); + //~^ ERROR: use of + copy_vec::().into_iter().filter_map(|x: Option| x); + //~^ ERROR: use of + copy_vec::().into_iter().filter_map(|x: Option| return x); + //~^ ERROR: use of + copy_vec::().into_iter().filter_map(|x: Option| return x); + //~^ ERROR: use of + #[rustfmt::skip] + copy_vec::().into_iter().filter_map(|x: Option| -> Option {{ x }}); + //~^ ERROR: use of + #[rustfmt::skip] + copy_vec::().into_iter().filter_map(|x: Option| -> Option {{ return x }}); + //~^ ERROR: use of + + // note, the compiler requires that we pass the type to `opaque`. This is mostly for reference, + // it behaves the same as copy_vec. + opaque::().into_iter().filter_map(|x| x); + //~^ ERROR: use of + } } diff --git a/src/tools/clippy/tests/ui/filter_map_identity.stderr b/src/tools/clippy/tests/ui/filter_map_identity.stderr index 5aa46ad6d237..55068db4e9d0 100644 --- a/src/tools/clippy/tests/ui/filter_map_identity.stderr +++ b/src/tools/clippy/tests/ui/filter_map_identity.stderr @@ -1,29 +1,137 @@ error: use of `filter_map` with an identity function - --> tests/ui/filter_map_identity.rs:6:22 + --> tests/ui/filter_map_identity.rs:28:45 | -LL | let _ = iterator.filter_map(|x| x); - | ^^^^^^^^^^^^^^^^^ help: try: `flatten()` +LL | copy_vec_non_inferred().into_iter().filter_map(|x| x); + | ^^^^^^^^^^^^^^^^^ help: try: `flatten()` | = note: `-D clippy::filter-map-identity` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::filter_map_identity)]` error: use of `filter_map` with an identity function - --> tests/ui/filter_map_identity.rs:9:22 + --> tests/ui/filter_map_identity.rs:30:45 | -LL | let _ = iterator.filter_map(std::convert::identity); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` +LL | copy_vec_non_inferred().into_iter().filter_map(std::convert::identity); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` error: use of `filter_map` with an identity function - --> tests/ui/filter_map_identity.rs:13:22 + --> tests/ui/filter_map_identity.rs:32:45 | -LL | let _ = iterator.filter_map(identity); - | ^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` +LL | copy_vec_non_inferred().into_iter().filter_map(identity); + | ^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` error: use of `filter_map` with an identity function - --> tests/ui/filter_map_identity.rs:16:22 + --> tests/ui/filter_map_identity.rs:34:45 | -LL | let _ = iterator.filter_map(|x| return x); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` +LL | copy_vec_non_inferred().into_iter().filter_map(|x| return x); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` -error: aborting due to 4 previous errors +error: use of `filter_map` with an identity function + --> tests/ui/filter_map_identity.rs:36:45 + | +LL | copy_vec_non_inferred().into_iter().filter_map(|x| return x); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` + +error: use of `filter_map` with an identity function + --> tests/ui/filter_map_identity.rs:39:36 + | +LL | non_copy_vec().into_iter().filter_map(|x| x); + | ^^^^^^^^^^^^^^^^^ help: try: `flatten()` + +error: use of `filter_map` with an identity function + --> tests/ui/filter_map_identity.rs:41:36 + | +LL | non_copy_vec().into_iter().filter_map(|x| x); + | ^^^^^^^^^^^^^^^^^ help: try: `flatten()` + +error: use of `filter_map` with an identity function + --> tests/ui/filter_map_identity.rs:44:36 + | +LL | non_copy_vec().into_iter().filter_map(std::convert::identity); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` + +error: use of `filter_map` with an identity function + --> tests/ui/filter_map_identity.rs:46:36 + | +LL | non_copy_vec().into_iter().filter_map(identity); + | ^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` + +error: use of `filter_map` with an identity function + --> tests/ui/filter_map_identity.rs:48:36 + | +LL | non_copy_vec().into_iter().filter_map(|x| return x); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` + +error: use of `filter_map` with an identity function + --> tests/ui/filter_map_identity.rs:50:36 + | +LL | non_copy_vec().into_iter().filter_map(|x| return x); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` + +error: use of `filter_map` with an identity function + --> tests/ui/filter_map_identity.rs:53:39 + | +LL | copy_vec::().into_iter().filter_map(|x: Option<_>| x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` + +error: use of `filter_map` with an identity function + --> tests/ui/filter_map_identity.rs:55:39 + | +LL | copy_vec::().into_iter().filter_map(|x: Option<_>| x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` + +error: use of `filter_map` with an identity function + --> tests/ui/filter_map_identity.rs:57:39 + | +LL | copy_vec::().into_iter().filter_map(|x: Option<_>| return x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` + +error: use of `filter_map` with an identity function + --> tests/ui/filter_map_identity.rs:59:39 + | +LL | copy_vec::().into_iter().filter_map(|x: Option<_>| return x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` + +error: use of `filter_map` with an identity function + --> tests/ui/filter_map_identity.rs:63:39 + | +LL | copy_vec::().into_iter().filter_map(|x: Option| x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` + +error: use of `filter_map` with an identity function + --> tests/ui/filter_map_identity.rs:65:39 + | +LL | copy_vec::().into_iter().filter_map(|x: Option| x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` + +error: use of `filter_map` with an identity function + --> tests/ui/filter_map_identity.rs:67:39 + | +LL | copy_vec::().into_iter().filter_map(|x: Option| return x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` + +error: use of `filter_map` with an identity function + --> tests/ui/filter_map_identity.rs:69:39 + | +LL | copy_vec::().into_iter().filter_map(|x: Option| return x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` + +error: use of `filter_map` with an identity function + --> tests/ui/filter_map_identity.rs:72:43 + | +LL | copy_vec::().into_iter().filter_map(|x: Option| -> Option {{ x }}); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` + +error: use of `filter_map` with an identity function + --> tests/ui/filter_map_identity.rs:75:43 + | +LL | copy_vec::().into_iter().filter_map(|x: Option| -> Option {{ return x }}); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` + +error: use of `filter_map` with an identity function + --> tests/ui/filter_map_identity.rs:80:37 + | +LL | opaque::().into_iter().filter_map(|x| x); + | ^^^^^^^^^^^^^^^^^ help: try: `flatten()` + +error: aborting due to 22 previous errors diff --git a/src/tools/clippy/tests/ui/large_stack_frames.rs b/src/tools/clippy/tests/ui/large_stack_frames.rs index f32368f93975..e6c030b8a9e8 100644 --- a/src/tools/clippy/tests/ui/large_stack_frames.rs +++ b/src/tools/clippy/tests/ui/large_stack_frames.rs @@ -1,3 +1,5 @@ +//@ normalize-stderr-test: "\b10000(08|16|32)\b" -> "100$$PTR" +//@ normalize-stderr-test: "\b2500(060|120)\b" -> "250$$PTR" #![allow(unused, incomplete_features)] #![warn(clippy::large_stack_frames)] #![feature(unsized_locals)] @@ -23,8 +25,7 @@ impl Default for ArrayDefault { } fn many_small_arrays() { - //~^ ERROR: this function allocates a large amount of stack space - //~| NOTE: allocating large amounts of stack space can overflow the stack + //~^ ERROR: this function may allocate let x = [0u8; 500_000]; let x2 = [0u8; 500_000]; let x3 = [0u8; 500_000]; @@ -34,17 +35,21 @@ fn many_small_arrays() { } fn large_return_value() -> ArrayDefault<1_000_000> { - //~^ ERROR: this function allocates a large amount of stack space - //~| NOTE: allocating large amounts of stack space can overflow the stack + //~^ ERROR: this function may allocate 1000000 bytes on the stack Default::default() } fn large_fn_arg(x: ArrayDefault<1_000_000>) { - //~^ ERROR: this function allocates a large amount of stack space - //~| NOTE: allocating large amounts of stack space can overflow the stack + //~^ ERROR: this function may allocate black_box(&x); } +fn has_large_closure() { + let f = || black_box(&[0u8; 1_000_000]); + //~^ ERROR: this function may allocate + f(); +} + fn main() { generic::>(); } diff --git a/src/tools/clippy/tests/ui/large_stack_frames.stderr b/src/tools/clippy/tests/ui/large_stack_frames.stderr index b99500fd9c34..f2e0a127f5f5 100644 --- a/src/tools/clippy/tests/ui/large_stack_frames.stderr +++ b/src/tools/clippy/tests/ui/large_stack_frames.stderr @@ -1,42 +1,42 @@ -error: this function allocates a large amount of stack space - --> tests/ui/large_stack_frames.rs:25:1 +error: this function may allocate 250$PTR bytes on the stack + --> tests/ui/large_stack_frames.rs:27:4 | -LL | / fn many_small_arrays() { -LL | | -LL | | -LL | | let x = [0u8; 500_000]; -... | -LL | | black_box((&x, &x2, &x3, &x4, &x5)); -LL | | } - | |_^ +LL | fn many_small_arrays() { + | ^^^^^^^^^^^^^^^^^ +... +LL | let x5 = [0u8; 500_000]; + | -- `x5` is the largest part, at 500000 bytes for type `[u8; 500000]` | - = note: allocating large amounts of stack space can overflow the stack + = note: 250$PTR bytes is larger than Clippy's configured `stack-size-threshold` of 512000 + = note: allocating large amounts of stack space can overflow the stack and cause the program to abort = note: `-D clippy::large-stack-frames` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::large_stack_frames)]` -error: this function allocates a large amount of stack space - --> tests/ui/large_stack_frames.rs:36:1 +error: this function may allocate 1000000 bytes on the stack + --> tests/ui/large_stack_frames.rs:37:4 | -LL | / fn large_return_value() -> ArrayDefault<1_000_000> { -LL | | -LL | | -LL | | Default::default() -LL | | } - | |_^ +LL | fn large_return_value() -> ArrayDefault<1_000_000> { + | ^^^^^^^^^^^^^^^^^^ ----------------------- this is the largest part, at 1000000 bytes for type `ArrayDefault<1000000>` | - = note: allocating large amounts of stack space can overflow the stack + = note: 1000000 bytes is larger than Clippy's configured `stack-size-threshold` of 512000 -error: this function allocates a large amount of stack space - --> tests/ui/large_stack_frames.rs:42:1 +error: this function may allocate 100$PTR bytes on the stack + --> tests/ui/large_stack_frames.rs:42:4 | -LL | / fn large_fn_arg(x: ArrayDefault<1_000_000>) { -LL | | -LL | | -LL | | black_box(&x); -LL | | } - | |_^ +LL | fn large_fn_arg(x: ArrayDefault<1_000_000>) { + | ^^^^^^^^^^^^ - `x` is the largest part, at 1000000 bytes for type `ArrayDefault<1000000>` | - = note: allocating large amounts of stack space can overflow the stack + = note: 100$PTR bytes is larger than Clippy's configured `stack-size-threshold` of 512000 -error: aborting due to 3 previous errors +error: this function may allocate 100$PTR bytes on the stack + --> tests/ui/large_stack_frames.rs:48:13 + | +LL | let f = || black_box(&[0u8; 1_000_000]); + | ^^^^^^^^^^^^^^----------------^ + | | + | this is the largest part, at 1000000 bytes for type `[u8; 1000000]` + | + = note: 100$PTR bytes is larger than Clippy's configured `stack-size-threshold` of 512000 + +error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/legacy_numeric_constants.fixed b/src/tools/clippy/tests/ui/legacy_numeric_constants.fixed new file mode 100644 index 000000000000..a6ef8f8c119a --- /dev/null +++ b/src/tools/clippy/tests/ui/legacy_numeric_constants.fixed @@ -0,0 +1,117 @@ +//@aux-build:proc_macros.rs +#![allow(clippy::no_effect, deprecated, unused)] +#![allow(clippy::legacy_numeric_constants)] // For imports. + +#[macro_use] +extern crate proc_macros; + +pub mod a { + pub use std::u128; +} + +macro_rules! b { + () => { + mod b { + #[warn(clippy::legacy_numeric_constants)] + fn b() { + let x = u64::MAX; + //~^ ERROR: usage of a legacy numeric constant + //~| HELP: use the associated constant instead + } + } + }; +} + +use std::u32::MAX; +use std::u8::MIN; +use std::{f64, u32}; + +#[warn(clippy::legacy_numeric_constants)] +fn main() { + f32::EPSILON; + //~^ ERROR: usage of a legacy numeric constant + //~| HELP: use the associated constant instead + u8::MIN; + //~^ ERROR: usage of a legacy numeric constant + //~| HELP: use the associated constant instead + usize::MIN; + //~^ ERROR: usage of a legacy numeric constant + //~| HELP: use the associated constant instead + u32::MAX; + //~^ ERROR: usage of a legacy numeric constant + //~| HELP: use the associated constant instead + u32::MAX; + //~^ ERROR: usage of a legacy numeric constant + //~| HELP: use the associated constant instead + u32::MAX; + //~^ ERROR: usage of a legacy numeric constant + //~| HELP: use the associated constant instead + i32::MAX; + //~^ ERROR: usage of a legacy numeric method + //~| HELP: use the associated constant instead + u8::MAX; + //~^ ERROR: usage of a legacy numeric method + //~| HELP: use the associated constant instead + u8::MIN; + //~^ ERROR: usage of a legacy numeric method + //~| HELP: use the associated constant instead + u8::MIN; + //~^ ERROR: usage of a legacy numeric constant + //~| HELP: use the associated constant instead + ::std::primitive::u8::MIN; + //~^ ERROR: usage of a legacy numeric method + //~| HELP: use the associated constant instead + std::primitive::i32::MAX; + //~^ ERROR: usage of a legacy numeric method + //~| HELP: use the associated constant instead + u128::MAX; + //~^ ERROR: usage of a legacy numeric constant + //~| HELP: use the associated constant instead + u32::MAX; + u128::MAX; + f32::EPSILON; + ::std::primitive::u8::MIN; + std::f32::consts::E; + f64::consts::E; + u8::MIN; + std::f32::consts::E; + f64::consts::E; + b!(); + + [(0, "", i128::MAX)]; + //~^ ERROR: usage of a legacy numeric constant + //~| HELP: use the associated constant instead +} + +#[warn(clippy::legacy_numeric_constants)] +fn ext() { + external! { + ::std::primitive::u8::MIN; + ::std::u8::MIN; + ::std::primitive::u8::min_value(); + use std::u64; + use std::u8::MIN; + } +} + +#[allow(clippy::legacy_numeric_constants)] +fn allow() { + ::std::primitive::u8::MIN; + ::std::u8::MIN; + ::std::primitive::u8::min_value(); + use std::u64; + use std::u8::MIN; +} + +#[warn(clippy::legacy_numeric_constants)] +#[clippy::msrv = "1.42.0"] +fn msrv_too_low() { + std::u32::MAX; +} + +#[warn(clippy::legacy_numeric_constants)] +#[clippy::msrv = "1.43.0"] +fn msrv_juust_right() { + u32::MAX; + //~^ ERROR: usage of a legacy numeric constant +} diff --git a/src/tools/clippy/tests/ui/legacy_numeric_constants.rs b/src/tools/clippy/tests/ui/legacy_numeric_constants.rs new file mode 100644 index 000000000000..cd633545372c --- /dev/null +++ b/src/tools/clippy/tests/ui/legacy_numeric_constants.rs @@ -0,0 +1,117 @@ +//@aux-build:proc_macros.rs +#![allow(clippy::no_effect, deprecated, unused)] +#![allow(clippy::legacy_numeric_constants)] // For imports. + +#[macro_use] +extern crate proc_macros; + +pub mod a { + pub use std::u128; +} + +macro_rules! b { + () => { + mod b { + #[warn(clippy::legacy_numeric_constants)] + fn b() { + let x = std::u64::MAX; + //~^ ERROR: usage of a legacy numeric constant + //~| HELP: use the associated constant instead + } + } + }; +} + +use std::u32::MAX; +use std::u8::MIN; +use std::{f64, u32}; + +#[warn(clippy::legacy_numeric_constants)] +fn main() { + std::f32::EPSILON; + //~^ ERROR: usage of a legacy numeric constant + //~| HELP: use the associated constant instead + std::u8::MIN; + //~^ ERROR: usage of a legacy numeric constant + //~| HELP: use the associated constant instead + std::usize::MIN; + //~^ ERROR: usage of a legacy numeric constant + //~| HELP: use the associated constant instead + std::u32::MAX; + //~^ ERROR: usage of a legacy numeric constant + //~| HELP: use the associated constant instead + core::u32::MAX; + //~^ ERROR: usage of a legacy numeric constant + //~| HELP: use the associated constant instead + MAX; + //~^ ERROR: usage of a legacy numeric constant + //~| HELP: use the associated constant instead + i32::max_value(); + //~^ ERROR: usage of a legacy numeric method + //~| HELP: use the associated constant instead + u8::max_value(); + //~^ ERROR: usage of a legacy numeric method + //~| HELP: use the associated constant instead + u8::min_value(); + //~^ ERROR: usage of a legacy numeric method + //~| HELP: use the associated constant instead + ::std::u8::MIN; + //~^ ERROR: usage of a legacy numeric constant + //~| HELP: use the associated constant instead + ::std::primitive::u8::min_value(); + //~^ ERROR: usage of a legacy numeric method + //~| HELP: use the associated constant instead + std::primitive::i32::max_value(); + //~^ ERROR: usage of a legacy numeric method + //~| HELP: use the associated constant instead + self::a::u128::MAX; + //~^ ERROR: usage of a legacy numeric constant + //~| HELP: use the associated constant instead + u32::MAX; + u128::MAX; + f32::EPSILON; + ::std::primitive::u8::MIN; + std::f32::consts::E; + f64::consts::E; + u8::MIN; + std::f32::consts::E; + f64::consts::E; + b!(); + + [(0, "", std::i128::MAX)]; + //~^ ERROR: usage of a legacy numeric constant + //~| HELP: use the associated constant instead +} + +#[warn(clippy::legacy_numeric_constants)] +fn ext() { + external! { + ::std::primitive::u8::MIN; + ::std::u8::MIN; + ::std::primitive::u8::min_value(); + use std::u64; + use std::u8::MIN; + } +} + +#[allow(clippy::legacy_numeric_constants)] +fn allow() { + ::std::primitive::u8::MIN; + ::std::u8::MIN; + ::std::primitive::u8::min_value(); + use std::u64; + use std::u8::MIN; +} + +#[warn(clippy::legacy_numeric_constants)] +#[clippy::msrv = "1.42.0"] +fn msrv_too_low() { + std::u32::MAX; +} + +#[warn(clippy::legacy_numeric_constants)] +#[clippy::msrv = "1.43.0"] +fn msrv_juust_right() { + std::u32::MAX; + //~^ ERROR: usage of a legacy numeric constant +} diff --git a/src/tools/clippy/tests/ui/legacy_numeric_constants.stderr b/src/tools/clippy/tests/ui/legacy_numeric_constants.stderr new file mode 100644 index 000000000000..267b9ac8e4d1 --- /dev/null +++ b/src/tools/clippy/tests/ui/legacy_numeric_constants.stderr @@ -0,0 +1,184 @@ +error: usage of a legacy numeric constant + --> tests/ui/legacy_numeric_constants.rs:31:5 + | +LL | std::f32::EPSILON; + | ^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::legacy-numeric-constants` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::legacy_numeric_constants)]` +help: use the associated constant instead + | +LL | f32::EPSILON; + | ~~~~~~~~~~~~ + +error: usage of a legacy numeric constant + --> tests/ui/legacy_numeric_constants.rs:34:5 + | +LL | std::u8::MIN; + | ^^^^^^^^^^^^ + | +help: use the associated constant instead + | +LL | u8::MIN; + | ~~~~~~~ + +error: usage of a legacy numeric constant + --> tests/ui/legacy_numeric_constants.rs:37:5 + | +LL | std::usize::MIN; + | ^^^^^^^^^^^^^^^ + | +help: use the associated constant instead + | +LL | usize::MIN; + | ~~~~~~~~~~ + +error: usage of a legacy numeric constant + --> tests/ui/legacy_numeric_constants.rs:40:5 + | +LL | std::u32::MAX; + | ^^^^^^^^^^^^^ + | +help: use the associated constant instead + | +LL | u32::MAX; + | ~~~~~~~~ + +error: usage of a legacy numeric constant + --> tests/ui/legacy_numeric_constants.rs:43:5 + | +LL | core::u32::MAX; + | ^^^^^^^^^^^^^^ + | +help: use the associated constant instead + | +LL | u32::MAX; + | ~~~~~~~~ + +error: usage of a legacy numeric constant + --> tests/ui/legacy_numeric_constants.rs:46:5 + | +LL | MAX; + | ^^^ + | +help: use the associated constant instead + | +LL | u32::MAX; + | ~~~~~~~~ + +error: usage of a legacy numeric method + --> tests/ui/legacy_numeric_constants.rs:49:10 + | +LL | i32::max_value(); + | ^^^^^^^^^^^ + | +help: use the associated constant instead + | +LL | i32::MAX; + | ~~~ + +error: usage of a legacy numeric method + --> tests/ui/legacy_numeric_constants.rs:52:9 + | +LL | u8::max_value(); + | ^^^^^^^^^^^ + | +help: use the associated constant instead + | +LL | u8::MAX; + | ~~~ + +error: usage of a legacy numeric method + --> tests/ui/legacy_numeric_constants.rs:55:9 + | +LL | u8::min_value(); + | ^^^^^^^^^^^ + | +help: use the associated constant instead + | +LL | u8::MIN; + | ~~~ + +error: usage of a legacy numeric constant + --> tests/ui/legacy_numeric_constants.rs:58:5 + | +LL | ::std::u8::MIN; + | ^^^^^^^^^^^^^^ + | +help: use the associated constant instead + | +LL | u8::MIN; + | ~~~~~~~ + +error: usage of a legacy numeric method + --> tests/ui/legacy_numeric_constants.rs:61:27 + | +LL | ::std::primitive::u8::min_value(); + | ^^^^^^^^^^^ + | +help: use the associated constant instead + | +LL | ::std::primitive::u8::MIN; + | ~~~ + +error: usage of a legacy numeric method + --> tests/ui/legacy_numeric_constants.rs:64:26 + | +LL | std::primitive::i32::max_value(); + | ^^^^^^^^^^^ + | +help: use the associated constant instead + | +LL | std::primitive::i32::MAX; + | ~~~ + +error: usage of a legacy numeric constant + --> tests/ui/legacy_numeric_constants.rs:67:5 + | +LL | self::a::u128::MAX; + | ^^^^^^^^^^^^^^^^^^ + | +help: use the associated constant instead + | +LL | u128::MAX; + | ~~~~~~~~~ + +error: usage of a legacy numeric constant + --> tests/ui/legacy_numeric_constants.rs:17:25 + | +LL | let x = std::u64::MAX; + | ^^^^^^^^^^^^^ +... +LL | b!(); + | ---- in this macro invocation + | + = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use the associated constant instead + | +LL | let x = u64::MAX; + | ~~~~~~~~ + +error: usage of a legacy numeric constant + --> tests/ui/legacy_numeric_constants.rs:81:14 + | +LL | [(0, "", std::i128::MAX)]; + | ^^^^^^^^^^^^^^ + | +help: use the associated constant instead + | +LL | [(0, "", i128::MAX)]; + | ~~~~~~~~~ + +error: usage of a legacy numeric constant + --> tests/ui/legacy_numeric_constants.rs:115:5 + | +LL | std::u32::MAX; + | ^^^^^^^^^^^^^ + | +help: use the associated constant instead + | +LL | u32::MAX; + | ~~~~~~~~ + +error: aborting due to 16 previous errors + diff --git a/src/tools/clippy/tests/ui/legacy_numeric_constants_unfixable.rs b/src/tools/clippy/tests/ui/legacy_numeric_constants_unfixable.rs new file mode 100644 index 000000000000..86738ede210c --- /dev/null +++ b/src/tools/clippy/tests/ui/legacy_numeric_constants_unfixable.rs @@ -0,0 +1,78 @@ +//@no-rustfix +//@aux-build:proc_macros.rs +#![allow(clippy::no_effect, deprecated, unused)] +#![warn(clippy::legacy_numeric_constants)] + +#[macro_use] +extern crate proc_macros; + +use std::u128 as _; +//~^ ERROR: importing legacy numeric constants +//~| HELP: remove this import +pub mod a { + pub use std::{mem, u128}; + //~^ ERROR: importing legacy numeric constants + //~| HELP: remove this import +} + +macro_rules! b { + () => { + mod b { + use std::u32; + //~^ ERROR: importing legacy numeric constants + //~| HELP: remove this import + } + }; +} + +fn main() { + use std::u32::MAX; + //~^ ERROR: importing a legacy numeric constant + //~| HELP: remove this import and use the associated constant `u32::MAX` + use std::u8::MIN; + //~^ ERROR: importing a legacy numeric constant + //~| HELP: remove this import and use the associated constant `u8::MIN` + f64::MAX; + use std::u32; + //~^ ERROR: importing legacy numeric constants + //~| HELP: remove this import + u32::MAX; + use std::f32::MIN_POSITIVE; + //~^ ERROR: importing a legacy numeric constant + //~| HELP: remove this import and use the associated constant `f32::MIN_POSITIVE` + use std::f64; + use std::i16::*; + //~^ ERROR: importing legacy numeric constants + //~| HELP: remove this import and use associated constants `i16::` + u128::MAX; + f32::EPSILON; + f64::EPSILON; + ::std::primitive::u8::MIN; + std::f32::consts::E; + f64::consts::E; + u8::MIN; + std::f32::consts::E; + f64::consts::E; + b!(); +} + +fn ext() { + external! { + ::std::primitive::u8::MIN; + ::std::u8::MIN; + ::std::primitive::u8::min_value(); + use std::u64; + use std::u8::MIN; + } +} + +#[clippy::msrv = "1.42.0"] +fn msrv_too_low() { + use std::u32::MAX; +} + +#[clippy::msrv = "1.43.0"] +fn msrv_juust_right() { + use std::u32::MAX; + //~^ ERROR: importing a legacy numeric constant +} diff --git a/src/tools/clippy/tests/ui/legacy_numeric_constants_unfixable.stderr b/src/tools/clippy/tests/ui/legacy_numeric_constants_unfixable.stderr new file mode 100644 index 000000000000..2edcf7188362 --- /dev/null +++ b/src/tools/clippy/tests/ui/legacy_numeric_constants_unfixable.stderr @@ -0,0 +1,83 @@ +error: importing legacy numeric constants + --> tests/ui/legacy_numeric_constants_unfixable.rs:9:5 + | +LL | use std::u128 as _; + | ^^^^^^^^^ + | + = help: remove this import + = note: `-D clippy::legacy-numeric-constants` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::legacy_numeric_constants)]` + +error: importing legacy numeric constants + --> tests/ui/legacy_numeric_constants_unfixable.rs:13:24 + | +LL | pub use std::{mem, u128}; + | ^^^^ + | + = help: remove this import + = note: then `u128::` will resolve to the respective associated constant + +error: importing a legacy numeric constant + --> tests/ui/legacy_numeric_constants_unfixable.rs:29:9 + | +LL | use std::u32::MAX; + | ^^^^^^^^^^^^^ + | + = help: remove this import and use the associated constant `u32::MAX` from the primitive type instead + +error: importing a legacy numeric constant + --> tests/ui/legacy_numeric_constants_unfixable.rs:32:9 + | +LL | use std::u8::MIN; + | ^^^^^^^^^^^^ + | + = help: remove this import and use the associated constant `u8::MIN` from the primitive type instead + +error: importing legacy numeric constants + --> tests/ui/legacy_numeric_constants_unfixable.rs:36:9 + | +LL | use std::u32; + | ^^^^^^^^ + | + = help: remove this import + = note: then `u32::` will resolve to the respective associated constant + +error: importing a legacy numeric constant + --> tests/ui/legacy_numeric_constants_unfixable.rs:40:9 + | +LL | use std::f32::MIN_POSITIVE; + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: remove this import and use the associated constant `f32::MIN_POSITIVE` from the primitive type instead + +error: importing legacy numeric constants + --> tests/ui/legacy_numeric_constants_unfixable.rs:44:9 + | +LL | use std::i16::*; + | ^^^^^^^^ + | + = help: remove this import and use associated constants `i16::` from the primitive type instead + +error: importing legacy numeric constants + --> tests/ui/legacy_numeric_constants_unfixable.rs:21:17 + | +LL | use std::u32; + | ^^^^^^^^ +... +LL | b!(); + | ---- in this macro invocation + | + = help: remove this import + = note: then `u32::` will resolve to the respective associated constant + = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: importing a legacy numeric constant + --> tests/ui/legacy_numeric_constants_unfixable.rs:76:9 + | +LL | use std::u32::MAX; + | ^^^^^^^^^^^^^ + | + = help: remove this import and use the associated constant `u32::MAX` from the primitive type instead + +error: aborting due to 9 previous errors + diff --git a/src/tools/clippy/tests/ui/len_zero.fixed b/src/tools/clippy/tests/ui/len_zero.fixed index c16d7a266161..27319d9c20e8 100644 --- a/src/tools/clippy/tests/ui/len_zero.fixed +++ b/src/tools/clippy/tests/ui/len_zero.fixed @@ -189,3 +189,40 @@ fn main() { fn test_slice(b: &[u8]) { if !b.is_empty() {} } + +// issue #11992 +fn binop_with_macros() { + macro_rules! len { + ($seq:ident) => { + $seq.len() + }; + } + + macro_rules! compare_to { + ($val:literal) => { + $val + }; + ($val:expr) => {{ $val }}; + } + + macro_rules! zero { + () => { + 0 + }; + } + + let has_is_empty = HasIsEmpty; + // Don't lint, suggesting changes might break macro compatibility. + (len!(has_is_empty) > 0).then(|| println!("This can happen.")); + // Don't lint, suggesting changes might break macro compatibility. + if len!(has_is_empty) == 0 {} + // Don't lint + if has_is_empty.len() == compare_to!(if true { 0 } else { 1 }) {} + // This is fine + if has_is_empty.len() == compare_to!(1) {} + + if has_is_empty.is_empty() {} + if has_is_empty.is_empty() {} + + (!has_is_empty.is_empty()).then(|| println!("This can happen.")); +} diff --git a/src/tools/clippy/tests/ui/len_zero.rs b/src/tools/clippy/tests/ui/len_zero.rs index 5c49a5abf812..03c05bc6ed7b 100644 --- a/src/tools/clippy/tests/ui/len_zero.rs +++ b/src/tools/clippy/tests/ui/len_zero.rs @@ -189,3 +189,40 @@ fn main() { fn test_slice(b: &[u8]) { if b.len() != 0 {} } + +// issue #11992 +fn binop_with_macros() { + macro_rules! len { + ($seq:ident) => { + $seq.len() + }; + } + + macro_rules! compare_to { + ($val:literal) => { + $val + }; + ($val:expr) => {{ $val }}; + } + + macro_rules! zero { + () => { + 0 + }; + } + + let has_is_empty = HasIsEmpty; + // Don't lint, suggesting changes might break macro compatibility. + (len!(has_is_empty) > 0).then(|| println!("This can happen.")); + // Don't lint, suggesting changes might break macro compatibility. + if len!(has_is_empty) == 0 {} + // Don't lint + if has_is_empty.len() == compare_to!(if true { 0 } else { 1 }) {} + // This is fine + if has_is_empty.len() == compare_to!(1) {} + + if has_is_empty.len() == compare_to!(0) {} + if has_is_empty.len() == zero!() {} + + (compare_to!(0) < has_is_empty.len()).then(|| println!("This can happen.")); +} diff --git a/src/tools/clippy/tests/ui/len_zero.stderr b/src/tools/clippy/tests/ui/len_zero.stderr index dd07a85d62ca..5c849a2aca64 100644 --- a/src/tools/clippy/tests/ui/len_zero.stderr +++ b/src/tools/clippy/tests/ui/len_zero.stderr @@ -142,5 +142,23 @@ error: length comparison to zero LL | if b.len() != 0 {} | ^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!b.is_empty()` -error: aborting due to 23 previous errors +error: length comparison to zero + --> tests/ui/len_zero.rs:224:8 + | +LL | if has_is_empty.len() == compare_to!(0) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()` + +error: length comparison to zero + --> tests/ui/len_zero.rs:225:8 + | +LL | if has_is_empty.len() == zero!() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()` + +error: length comparison to zero + --> tests/ui/len_zero.rs:227:6 + | +LL | (compare_to!(0) < has_is_empty.len()).then(|| println!("This can happen.")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()` + +error: aborting due to 26 previous errors diff --git a/src/tools/clippy/tests/ui/let_and_return.fixed b/src/tools/clippy/tests/ui/let_and_return.fixed index b5584fcde8c9..4187019e5894 100644 --- a/src/tools/clippy/tests/ui/let_and_return.fixed +++ b/src/tools/clippy/tests/ui/let_and_return.fixed @@ -203,4 +203,11 @@ fn_in_macro!({ return 1; }); +fn issue9150() -> usize { + let x = 1; + #[cfg(any())] + panic!("can't see me"); + x +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/let_and_return.rs b/src/tools/clippy/tests/ui/let_and_return.rs index f13c7c4e2034..54444957b7d5 100644 --- a/src/tools/clippy/tests/ui/let_and_return.rs +++ b/src/tools/clippy/tests/ui/let_and_return.rs @@ -203,4 +203,11 @@ fn_in_macro!({ return 1; }); +fn issue9150() -> usize { + let x = 1; + #[cfg(any())] + panic!("can't see me"); + x +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/let_unit.fixed b/src/tools/clippy/tests/ui/let_unit.fixed index 4d41b5e5e503..20940daffa7a 100644 --- a/src/tools/clippy/tests/ui/let_unit.fixed +++ b/src/tools/clippy/tests/ui/let_unit.fixed @@ -177,3 +177,21 @@ async fn issue10433() { } pub async fn issue11502(a: ()) {} + +pub fn issue12594() { + fn returns_unit() {} + + fn returns_result(res: T) -> Result { + Ok(res) + } + + fn actual_test() { + // create first a unit value'd value + returns_unit(); + returns_result(()).unwrap(); + returns_result(()).unwrap(); + // make sure we replace only the first variable + let res = 1; + returns_result(res).unwrap(); + } +} diff --git a/src/tools/clippy/tests/ui/let_unit.rs b/src/tools/clippy/tests/ui/let_unit.rs index daa660be25e6..dca66f2e3edb 100644 --- a/src/tools/clippy/tests/ui/let_unit.rs +++ b/src/tools/clippy/tests/ui/let_unit.rs @@ -177,3 +177,21 @@ async fn issue10433() { } pub async fn issue11502(a: ()) {} + +pub fn issue12594() { + fn returns_unit() {} + + fn returns_result(res: T) -> Result { + Ok(res) + } + + fn actual_test() { + // create first a unit value'd value + let res = returns_unit(); + returns_result(res).unwrap(); + returns_result(res).unwrap(); + // make sure we replace only the first variable + let res = 1; + returns_result(res).unwrap(); + } +} diff --git a/src/tools/clippy/tests/ui/let_unit.stderr b/src/tools/clippy/tests/ui/let_unit.stderr index 0f1f3d782234..aafb77bcd0d6 100644 --- a/src/tools/clippy/tests/ui/let_unit.stderr +++ b/src/tools/clippy/tests/ui/let_unit.stderr @@ -51,5 +51,24 @@ LL + Some(_) => (), LL + }; | -error: aborting due to 3 previous errors +error: this let-binding has unit value + --> tests/ui/let_unit.rs:190:9 + | +LL | let res = returns_unit(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: omit the `let` binding + | +LL | returns_unit(); + | +help: variable `res` of type `()` can be replaced with explicit `()` + | +LL | returns_result(()).unwrap(); + | ~~ +help: variable `res` of type `()` can be replaced with explicit `()` + | +LL | returns_result(()).unwrap(); + | ~~ + +error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed b/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed index 75beedfa4508..758357808010 100644 --- a/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed +++ b/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed @@ -66,3 +66,11 @@ fn issue7730(a: u8) { // comment after `panic!` assert!(!(a > 2), "panic with comment"); } + +fn issue12505() { + struct Foo(T); + + impl Foo { + const BAR: () = assert!(!(N == 0), ); + } +} diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr b/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr index 57015933d40a..1eebe1bfe177 100644 --- a/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr +++ b/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr @@ -82,5 +82,14 @@ help: try instead LL | assert!(!(a > 2), "panic with comment"); | -error: aborting due to 9 previous errors +error: only a `panic!` in `if`-then statement + --> tests/ui/manual_assert.rs:91:25 + | +LL | const BAR: () = if N == 0 { + | _________________________^ +LL | | panic!() +LL | | }; + | |_________^ help: try instead: `assert!(!(N == 0), )` + +error: aborting due to 10 previous errors diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed b/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed index 75beedfa4508..758357808010 100644 --- a/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed +++ b/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed @@ -66,3 +66,11 @@ fn issue7730(a: u8) { // comment after `panic!` assert!(!(a > 2), "panic with comment"); } + +fn issue12505() { + struct Foo(T); + + impl Foo { + const BAR: () = assert!(!(N == 0), ); + } +} diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr b/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr index 57015933d40a..1eebe1bfe177 100644 --- a/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr +++ b/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr @@ -82,5 +82,14 @@ help: try instead LL | assert!(!(a > 2), "panic with comment"); | -error: aborting due to 9 previous errors +error: only a `panic!` in `if`-then statement + --> tests/ui/manual_assert.rs:91:25 + | +LL | const BAR: () = if N == 0 { + | _________________________^ +LL | | panic!() +LL | | }; + | |_________^ help: try instead: `assert!(!(N == 0), )` + +error: aborting due to 10 previous errors diff --git a/src/tools/clippy/tests/ui/manual_assert.rs b/src/tools/clippy/tests/ui/manual_assert.rs index 5979496ca836..363bafdf05d0 100644 --- a/src/tools/clippy/tests/ui/manual_assert.rs +++ b/src/tools/clippy/tests/ui/manual_assert.rs @@ -83,3 +83,13 @@ fn issue7730(a: u8) { panic!("panic with comment") // comment after `panic!` } } + +fn issue12505() { + struct Foo(T); + + impl Foo { + const BAR: () = if N == 0 { + panic!() + }; + } +} diff --git a/src/tools/clippy/tests/ui/manual_clamp.fixed b/src/tools/clippy/tests/ui/manual_clamp.fixed index c5355cce8e21..8d57cbbf51bf 100644 --- a/src/tools/clippy/tests/ui/manual_clamp.fixed +++ b/src/tools/clippy/tests/ui/manual_clamp.fixed @@ -17,48 +17,171 @@ const CONST_F64_MIN: f64 = 4.0; fn main() { let (input, min, max) = (0, -2, 3); - // Lint - let x0 = input.clamp(min, max); + // Min and max are not const, so this shouldn't trigger the lint. + let x0 = if max < input { + max + } else if min > input { + min + } else { + input + }; - let x1 = input.clamp(min, max); + let x1 = if input > max { + max + } else if input < min { + min + } else { + input + }; - let x2 = input.clamp(min, max); + let x2 = if input < min { + min + } else if input > max { + max + } else { + input + }; - let x3 = input.clamp(min, max); + let x3 = if min > input { + min + } else if max < input { + max + } else { + input + }; - let x4 = input.clamp(min, max); - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min + let x4 = input.max(min).min(max); - let x5 = input.clamp(min, max); - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min + let x5 = input.min(max).max(min); - let x6 = input.clamp(min, max); + let x6 = match input { + x if x > max => max, + x if x < min => min, + x => x, + }; - let x7 = input.clamp(min, max); + let x7 = match input { + x if x < min => min, + x if x > max => max, + x => x, + }; - let x8 = input.clamp(min, max); + let x8 = match input { + x if max < x => max, + x if min > x => min, + x => x, + }; let mut x9 = input; - x9 = x9.clamp(min, max); + if x9 < min { + x9 = min; + } + if x9 > max { + x9 = max; + } - let x10 = input.clamp(min, max); + let x10 = match input { + x if min > x => min, + x if max < x => max, + x => x, + }; let mut x11 = input; let _ = 1; - x11 = x11.clamp(min, max); + if x11 > max { + x11 = max; + } + if x11 < min { + x11 = min; + } let mut x12 = input; - x12 = x12.clamp(min, max); + if min > x12 { + x12 = min; + } + if max < x12 { + x12 = max; + } let mut x13 = input; - x13 = x13.clamp(min, max); + if max < x13 { + x13 = max; + } + if min > x13 { + x13 = min; + } + + { + let (input, min, max) = (0.0f64, -2.0, 3.0); + let x14 = if input > max { + max + } else if input < min { + min + } else { + input + }; + } + let mut x15 = input; + if x15 < min { + x15 = min; + } else if x15 > max { + x15 = max; + } + + // It's important this be the last set of statements + let mut x16 = input; + if max < x16 { + x16 = max; + } + if min > x16 { + x16 = min; + } +} + +fn const_main() { + let input = 0; + // Min and max are const, so this should trigger the lint. + let x0 = input.clamp(CONST_MIN, CONST_MAX); + + let x1 = input.clamp(CONST_MIN, CONST_MAX); + + let x2 = input.clamp(CONST_MIN, CONST_MAX); + + let x3 = input.clamp(CONST_MIN, CONST_MAX); + + let x4 = input.clamp(CONST_MIN, CONST_MAX); + //~^ ERROR: clamp-like pattern without using clamp function + //~| NOTE: clamp will panic if max < min + + let x5 = input.clamp(CONST_MIN, CONST_MAX); + //~^ ERROR: clamp-like pattern without using clamp function + //~| NOTE: clamp will panic if max < min + + let x6 = input.clamp(CONST_MIN, CONST_MAX); + + let x7 = input.clamp(CONST_MIN, CONST_MAX); + + let x8 = input.clamp(CONST_MIN, CONST_MAX); + + let mut x9 = input; + x9 = x9.clamp(CONST_MIN, CONST_MAX); + + let x10 = input.clamp(CONST_MIN, CONST_MAX); + + let mut x11 = input; + let _ = 1; + x11 = x11.clamp(CONST_MIN, CONST_MAX); + + let mut x12 = input; + x12 = x12.clamp(CONST_MIN, CONST_MAX); + + let mut x13 = input; + x13 = x13.clamp(CONST_MIN, CONST_MAX); let x14 = input.clamp(CONST_MIN, CONST_MAX); { - let (input, min, max) = (0.0f64, -2.0, 3.0); - let x15 = input.clamp(min, max); + let input = 0.0f64; + let x15 = input.clamp(CONST_F64_MIN, CONST_F64_MAX); } { let input: i32 = cmp_min_max(1); @@ -114,108 +237,128 @@ fn main() { //~| NOTE: clamp will panic if max < min, min.is_nan(), or max.is_nan() } let mut x32 = input; - x32 = x32.clamp(min, max); + x32 = x32.clamp(CONST_MIN, CONST_MAX); + + // Flip the script, swap the places of min and max. Make sure this doesn't + // trigger when clamp would be guaranteed to panic. + let mut x33 = input; + if x33 < CONST_MAX { + x33 = CONST_MAX; + } else if x33 > CONST_MIN { + x33 = CONST_MIN; + } + + // Do it again for NaN + #[allow(invalid_nan_comparisons)] + { + let mut x34 = input as f64; + if x34 < f64::NAN { + x34 = f64::NAN; + } else if x34 > CONST_F64_MAX { + x34 = CONST_F64_MAX; + } + } // It's important this be the last set of statements - let mut x33 = input; - x33 = x33.clamp(min, max); + let mut x35 = input; + x35 = x35.clamp(CONST_MIN, CONST_MAX); } // This code intentionally nonsense. fn no_lint() { - let (input, min, max) = (0, -2, 3); - let x0 = if max < input { - max - } else if min > input { - max + let input = 0; + let x0 = if CONST_MAX < input { + CONST_MAX + } else if CONST_MIN > input { + CONST_MAX } else { - min + CONST_MIN }; - let x1 = if input > max { - max - } else if input > min { - min + let x1 = if input > CONST_MAX { + CONST_MAX + } else if input > CONST_MIN { + CONST_MIN } else { - max + CONST_MAX }; - let x2 = if max < min { - min - } else if input > max { + let x2 = if CONST_MAX < CONST_MIN { + CONST_MIN + } else if input > CONST_MAX { input } else { input }; - let x3 = if min > input { + let x3 = if CONST_MIN > input { input - } else if max < input { - max + } else if CONST_MAX < input { + CONST_MAX } else { - max + CONST_MAX }; let x6 = match input { - x if x < max => x, - x if x < min => x, + x if x < CONST_MAX => x, + x if x < CONST_MIN => x, x => x, }; let x7 = match input { - x if x < min => max, - x if x > max => min, + x if x < CONST_MIN => CONST_MAX, + x if x > CONST_MAX => CONST_MIN, x => x, }; let x8 = match input { - x if max > x => max, - x if min > x => min, + x if CONST_MAX > x => CONST_MAX, + x if CONST_MIN > x => CONST_MIN, x => x, }; let mut x9 = input; - if x9 > min { - x9 = min; + if x9 > CONST_MIN { + x9 = CONST_MIN; } - if x9 > max { - x9 = max; + if x9 > CONST_MAX { + x9 = CONST_MAX; } let x10 = match input { - x if min > x => min, - x if max < x => max, - x => min, + x if CONST_MIN > x => CONST_MIN, + x if CONST_MAX < x => CONST_MAX, + x => CONST_MIN, }; let mut x11 = input; - if x11 > max { - x11 = min; + if x11 > CONST_MAX { + x11 = CONST_MIN; } - if x11 < min { - x11 = max; + if x11 < CONST_MIN { + x11 = CONST_MAX; } let mut x12 = input; - if min > x12 { - x12 = max * 3; + if CONST_MIN > x12 { + x12 = CONST_MAX * 3; } - if max < x12 { - x12 = min; + if CONST_MAX < x12 { + x12 = CONST_MIN; } let mut x13 = input; - if max < x13 { - let x13 = max; + if CONST_MAX < x13 { + let x13 = CONST_MAX; } - if min > x13 { - x13 = min; + if CONST_MIN > x13 { + x13 = CONST_MIN; } let mut x14 = input; - if x14 < min { + if x14 < CONST_MIN { x14 = 3; - } else if x14 > max { - x14 = max; + } else if x14 > CONST_MAX { + x14 = CONST_MAX; } { let input: i32 = cmp_min_max(1); @@ -272,8 +415,8 @@ fn msrv_1_49() { #[clippy::msrv = "1.50"] fn msrv_1_50() { - let (input, min, max) = (0, -1, 2); - let _ = input.clamp(min, max); + let input = 0; + let _ = input.clamp(CONST_MIN, CONST_MAX); } const fn _const() { diff --git a/src/tools/clippy/tests/ui/manual_clamp.rs b/src/tools/clippy/tests/ui/manual_clamp.rs index cacb40ae027f..4d2a0c47bbd7 100644 --- a/src/tools/clippy/tests/ui/manual_clamp.rs +++ b/src/tools/clippy/tests/ui/manual_clamp.rs @@ -17,10 +17,8 @@ const CONST_F64_MIN: f64 = 4.0; fn main() { let (input, min, max) = (0, -2, 3); - // Lint + // Min and max are not const, so this shouldn't trigger the lint. let x0 = if max < input { - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min max } else if min > input { min @@ -29,8 +27,6 @@ fn main() { }; let x1 = if input > max { - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min max } else if input < min { min @@ -39,8 +35,6 @@ fn main() { }; let x2 = if input < min { - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min min } else if input > max { max @@ -49,8 +43,6 @@ fn main() { }; let x3 = if min > input { - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min min } else if max < input { max @@ -59,32 +51,22 @@ fn main() { }; let x4 = input.max(min).min(max); - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min let x5 = input.min(max).max(min); - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min let x6 = match input { - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min x if x > max => max, x if x < min => min, x => x, }; let x7 = match input { - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min x if x < min => min, x if x > max => max, x => x, }; let x8 = match input { - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min x if max < x => max, x if min > x => min, x => x, @@ -92,8 +74,6 @@ fn main() { let mut x9 = input; if x9 < min { - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min x9 = min; } if x9 > max { @@ -101,8 +81,6 @@ fn main() { } let x10 = match input { - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min x if min > x => min, x if max < x => max, x => x, @@ -111,8 +89,6 @@ fn main() { let mut x11 = input; let _ = 1; if x11 > max { - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min x11 = max; } if x11 < min { @@ -121,8 +97,6 @@ fn main() { let mut x12 = input; if min > x12 { - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min x12 = min; } if max < x12 { @@ -131,14 +105,163 @@ fn main() { let mut x13 = input; if max < x13 { - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min x13 = max; } if min > x13 { x13 = min; } + { + let (input, min, max) = (0.0f64, -2.0, 3.0); + let x14 = if input > max { + max + } else if input < min { + min + } else { + input + }; + } + let mut x15 = input; + if x15 < min { + x15 = min; + } else if x15 > max { + x15 = max; + } + + // It's important this be the last set of statements + let mut x16 = input; + if max < x16 { + x16 = max; + } + if min > x16 { + x16 = min; + } +} + +fn const_main() { + let input = 0; + // Min and max are const, so this should trigger the lint. + let x0 = if CONST_MAX < input { + //~^ ERROR: clamp-like pattern without using clamp function + //~| NOTE: clamp will panic if max < min + CONST_MAX + } else if CONST_MIN > input { + CONST_MIN + } else { + input + }; + + let x1 = if input > CONST_MAX { + //~^ ERROR: clamp-like pattern without using clamp function + //~| NOTE: clamp will panic if max < min + CONST_MAX + } else if input < CONST_MIN { + CONST_MIN + } else { + input + }; + + let x2 = if input < CONST_MIN { + //~^ ERROR: clamp-like pattern without using clamp function + //~| NOTE: clamp will panic if max < min + CONST_MIN + } else if input > CONST_MAX { + CONST_MAX + } else { + input + }; + + let x3 = if CONST_MIN > input { + //~^ ERROR: clamp-like pattern without using clamp function + //~| NOTE: clamp will panic if max < min + CONST_MIN + } else if CONST_MAX < input { + CONST_MAX + } else { + input + }; + + let x4 = input.max(CONST_MIN).min(CONST_MAX); + //~^ ERROR: clamp-like pattern without using clamp function + //~| NOTE: clamp will panic if max < min + + let x5 = input.min(CONST_MAX).max(CONST_MIN); + //~^ ERROR: clamp-like pattern without using clamp function + //~| NOTE: clamp will panic if max < min + + let x6 = match input { + //~^ ERROR: clamp-like pattern without using clamp function + //~| NOTE: clamp will panic if max < min + x if x > CONST_MAX => CONST_MAX, + x if x < CONST_MIN => CONST_MIN, + x => x, + }; + + let x7 = match input { + //~^ ERROR: clamp-like pattern without using clamp function + //~| NOTE: clamp will panic if max < min + x if x < CONST_MIN => CONST_MIN, + x if x > CONST_MAX => CONST_MAX, + x => x, + }; + + let x8 = match input { + //~^ ERROR: clamp-like pattern without using clamp function + //~| NOTE: clamp will panic if max < min + x if CONST_MAX < x => CONST_MAX, + x if CONST_MIN > x => CONST_MIN, + x => x, + }; + + let mut x9 = input; + if x9 < CONST_MIN { + //~^ ERROR: clamp-like pattern without using clamp function + //~| NOTE: clamp will panic if max < min + x9 = CONST_MIN; + } + if x9 > CONST_MAX { + x9 = CONST_MAX; + } + + let x10 = match input { + //~^ ERROR: clamp-like pattern without using clamp function + //~| NOTE: clamp will panic if max < min + x if CONST_MIN > x => CONST_MIN, + x if CONST_MAX < x => CONST_MAX, + x => x, + }; + + let mut x11 = input; + let _ = 1; + if x11 > CONST_MAX { + //~^ ERROR: clamp-like pattern without using clamp function + //~| NOTE: clamp will panic if max < min + x11 = CONST_MAX; + } + if x11 < CONST_MIN { + x11 = CONST_MIN; + } + + let mut x12 = input; + if CONST_MIN > x12 { + //~^ ERROR: clamp-like pattern without using clamp function + //~| NOTE: clamp will panic if max < min + x12 = CONST_MIN; + } + if CONST_MAX < x12 { + x12 = CONST_MAX; + } + + let mut x13 = input; + if CONST_MAX < x13 { + //~^ ERROR: clamp-like pattern without using clamp function + //~| NOTE: clamp will panic if max < min + x13 = CONST_MAX; + } + if CONST_MIN > x13 { + x13 = CONST_MIN; + } + let x14 = if input > CONST_MAX { //~^ ERROR: clamp-like pattern without using clamp function //~| NOTE: clamp will panic if max < min @@ -149,13 +272,13 @@ fn main() { input }; { - let (input, min, max) = (0.0f64, -2.0, 3.0); - let x15 = if input > max { + let input = 0.0f64; + let x15 = if input > CONST_F64_MAX { //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min, min.is_nan(), or max.is_nan() - max - } else if input < min { - min + //~| NOTE: clamp will panic if max < min + CONST_F64_MAX + } else if input < CONST_F64_MIN { + CONST_F64_MIN } else { input }; @@ -214,121 +337,141 @@ fn main() { //~| NOTE: clamp will panic if max < min, min.is_nan(), or max.is_nan() } let mut x32 = input; - if x32 < min { + if x32 < CONST_MIN { //~^ ERROR: clamp-like pattern without using clamp function //~| NOTE: clamp will panic if max < min - x32 = min; - } else if x32 > max { - x32 = max; + x32 = CONST_MIN; + } else if x32 > CONST_MAX { + x32 = CONST_MAX; + } + + // Flip the script, swap the places of min and max. Make sure this doesn't + // trigger when clamp would be guaranteed to panic. + let mut x33 = input; + if x33 < CONST_MAX { + x33 = CONST_MAX; + } else if x33 > CONST_MIN { + x33 = CONST_MIN; + } + + // Do it again for NaN + #[allow(invalid_nan_comparisons)] + { + let mut x34 = input as f64; + if x34 < f64::NAN { + x34 = f64::NAN; + } else if x34 > CONST_F64_MAX { + x34 = CONST_F64_MAX; + } } // It's important this be the last set of statements - let mut x33 = input; - if max < x33 { + let mut x35 = input; + if CONST_MAX < x35 { //~^ ERROR: clamp-like pattern without using clamp function //~| NOTE: clamp will panic if max < min - x33 = max; + x35 = CONST_MAX; } - if min > x33 { - x33 = min; + if CONST_MIN > x35 { + x35 = CONST_MIN; } } // This code intentionally nonsense. fn no_lint() { - let (input, min, max) = (0, -2, 3); - let x0 = if max < input { - max - } else if min > input { - max + let input = 0; + let x0 = if CONST_MAX < input { + CONST_MAX + } else if CONST_MIN > input { + CONST_MAX } else { - min + CONST_MIN }; - let x1 = if input > max { - max - } else if input > min { - min + let x1 = if input > CONST_MAX { + CONST_MAX + } else if input > CONST_MIN { + CONST_MIN } else { - max + CONST_MAX }; - let x2 = if max < min { - min - } else if input > max { + let x2 = if CONST_MAX < CONST_MIN { + CONST_MIN + } else if input > CONST_MAX { input } else { input }; - let x3 = if min > input { + let x3 = if CONST_MIN > input { input - } else if max < input { - max + } else if CONST_MAX < input { + CONST_MAX } else { - max + CONST_MAX }; let x6 = match input { - x if x < max => x, - x if x < min => x, + x if x < CONST_MAX => x, + x if x < CONST_MIN => x, x => x, }; let x7 = match input { - x if x < min => max, - x if x > max => min, + x if x < CONST_MIN => CONST_MAX, + x if x > CONST_MAX => CONST_MIN, x => x, }; let x8 = match input { - x if max > x => max, - x if min > x => min, + x if CONST_MAX > x => CONST_MAX, + x if CONST_MIN > x => CONST_MIN, x => x, }; let mut x9 = input; - if x9 > min { - x9 = min; + if x9 > CONST_MIN { + x9 = CONST_MIN; } - if x9 > max { - x9 = max; + if x9 > CONST_MAX { + x9 = CONST_MAX; } let x10 = match input { - x if min > x => min, - x if max < x => max, - x => min, + x if CONST_MIN > x => CONST_MIN, + x if CONST_MAX < x => CONST_MAX, + x => CONST_MIN, }; let mut x11 = input; - if x11 > max { - x11 = min; + if x11 > CONST_MAX { + x11 = CONST_MIN; } - if x11 < min { - x11 = max; + if x11 < CONST_MIN { + x11 = CONST_MAX; } let mut x12 = input; - if min > x12 { - x12 = max * 3; + if CONST_MIN > x12 { + x12 = CONST_MAX * 3; } - if max < x12 { - x12 = min; + if CONST_MAX < x12 { + x12 = CONST_MIN; } let mut x13 = input; - if max < x13 { - let x13 = max; + if CONST_MAX < x13 { + let x13 = CONST_MAX; } - if min > x13 { - x13 = min; + if CONST_MIN > x13 { + x13 = CONST_MIN; } let mut x14 = input; - if x14 < min { + if x14 < CONST_MIN { x14 = 3; - } else if x14 > max { - x14 = max; + } else if x14 > CONST_MAX { + x14 = CONST_MAX; } { let input: i32 = cmp_min_max(1); @@ -385,13 +528,13 @@ fn msrv_1_49() { #[clippy::msrv = "1.50"] fn msrv_1_50() { - let (input, min, max) = (0, -1, 2); - let _ = if input < min { + let input = 0; + let _ = if input > CONST_MAX { //~^ ERROR: clamp-like pattern without using clamp function //~| NOTE: clamp will panic if max < min - min - } else if input > max { - max + CONST_MAX + } else if input < CONST_MIN { + CONST_MIN } else { input }; diff --git a/src/tools/clippy/tests/ui/manual_clamp.stderr b/src/tools/clippy/tests/ui/manual_clamp.stderr index 52c816f2b347..459d46796d87 100644 --- a/src/tools/clippy/tests/ui/manual_clamp.stderr +++ b/src/tools/clippy/tests/ui/manual_clamp.stderr @@ -1,213 +1,213 @@ error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:94:5 + --> tests/ui/manual_clamp.rs:217:5 | -LL | / if x9 < min { +LL | / if x9 < CONST_MIN { LL | | LL | | -LL | | x9 = min; +LL | | x9 = CONST_MIN; ... | -LL | | x9 = max; +LL | | x9 = CONST_MAX; LL | | } - | |_____^ help: replace with clamp: `x9 = x9.clamp(min, max);` + | |_____^ help: replace with clamp: `x9 = x9.clamp(CONST_MIN, CONST_MAX);` | = note: clamp will panic if max < min = note: `-D clippy::manual-clamp` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::manual_clamp)]` error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:113:5 + --> tests/ui/manual_clamp.rs:236:5 | -LL | / if x11 > max { +LL | / if x11 > CONST_MAX { LL | | LL | | -LL | | x11 = max; +LL | | x11 = CONST_MAX; ... | -LL | | x11 = min; +LL | | x11 = CONST_MIN; LL | | } - | |_____^ help: replace with clamp: `x11 = x11.clamp(min, max);` + | |_____^ help: replace with clamp: `x11 = x11.clamp(CONST_MIN, CONST_MAX);` | = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:123:5 + --> tests/ui/manual_clamp.rs:246:5 | -LL | / if min > x12 { +LL | / if CONST_MIN > x12 { LL | | LL | | -LL | | x12 = min; +LL | | x12 = CONST_MIN; ... | -LL | | x12 = max; +LL | | x12 = CONST_MAX; LL | | } - | |_____^ help: replace with clamp: `x12 = x12.clamp(min, max);` + | |_____^ help: replace with clamp: `x12 = x12.clamp(CONST_MIN, CONST_MAX);` | = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:133:5 + --> tests/ui/manual_clamp.rs:256:5 | -LL | / if max < x13 { +LL | / if CONST_MAX < x13 { LL | | LL | | -LL | | x13 = max; +LL | | x13 = CONST_MAX; ... | -LL | | x13 = min; +LL | | x13 = CONST_MIN; LL | | } - | |_____^ help: replace with clamp: `x13 = x13.clamp(min, max);` + | |_____^ help: replace with clamp: `x13 = x13.clamp(CONST_MIN, CONST_MAX);` | = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:227:5 + --> tests/ui/manual_clamp.rs:370:5 | -LL | / if max < x33 { +LL | / if CONST_MAX < x35 { LL | | LL | | -LL | | x33 = max; +LL | | x35 = CONST_MAX; ... | -LL | | x33 = min; +LL | | x35 = CONST_MIN; LL | | } - | |_____^ help: replace with clamp: `x33 = x33.clamp(min, max);` + | |_____^ help: replace with clamp: `x35 = x35.clamp(CONST_MIN, CONST_MAX);` | = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:21:14 + --> tests/ui/manual_clamp.rs:144:14 | -LL | let x0 = if max < input { +LL | let x0 = if CONST_MAX < input { | ______________^ LL | | LL | | -LL | | max +LL | | CONST_MAX ... | LL | | input LL | | }; - | |_____^ help: replace with clamp: `input.clamp(min, max)` + | |_____^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` | = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:31:14 + --> tests/ui/manual_clamp.rs:154:14 | -LL | let x1 = if input > max { +LL | let x1 = if input > CONST_MAX { | ______________^ LL | | LL | | -LL | | max +LL | | CONST_MAX ... | LL | | input LL | | }; - | |_____^ help: replace with clamp: `input.clamp(min, max)` + | |_____^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` | = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:41:14 + --> tests/ui/manual_clamp.rs:164:14 | -LL | let x2 = if input < min { +LL | let x2 = if input < CONST_MIN { | ______________^ LL | | LL | | -LL | | min +LL | | CONST_MIN ... | LL | | input LL | | }; - | |_____^ help: replace with clamp: `input.clamp(min, max)` + | |_____^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` | = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:51:14 + --> tests/ui/manual_clamp.rs:174:14 | -LL | let x3 = if min > input { +LL | let x3 = if CONST_MIN > input { | ______________^ LL | | LL | | -LL | | min +LL | | CONST_MIN ... | LL | | input LL | | }; - | |_____^ help: replace with clamp: `input.clamp(min, max)` + | |_____^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` | = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:61:14 + --> tests/ui/manual_clamp.rs:184:14 | -LL | let x4 = input.max(min).min(max); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(min, max)` +LL | let x4 = input.max(CONST_MIN).min(CONST_MAX); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` | = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:65:14 + --> tests/ui/manual_clamp.rs:188:14 | -LL | let x5 = input.min(max).max(min); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(min, max)` +LL | let x5 = input.min(CONST_MAX).max(CONST_MIN); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` | = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:69:14 + --> tests/ui/manual_clamp.rs:192:14 | LL | let x6 = match input { | ______________^ LL | | LL | | -LL | | x if x > max => max, -LL | | x if x < min => min, +LL | | x if x > CONST_MAX => CONST_MAX, +LL | | x if x < CONST_MIN => CONST_MIN, LL | | x => x, LL | | }; - | |_____^ help: replace with clamp: `input.clamp(min, max)` + | |_____^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` | = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:77:14 + --> tests/ui/manual_clamp.rs:200:14 | LL | let x7 = match input { | ______________^ LL | | LL | | -LL | | x if x < min => min, -LL | | x if x > max => max, +LL | | x if x < CONST_MIN => CONST_MIN, +LL | | x if x > CONST_MAX => CONST_MAX, LL | | x => x, LL | | }; - | |_____^ help: replace with clamp: `input.clamp(min, max)` + | |_____^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` | = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:85:14 + --> tests/ui/manual_clamp.rs:208:14 | LL | let x8 = match input { | ______________^ LL | | LL | | -LL | | x if max < x => max, -LL | | x if min > x => min, +LL | | x if CONST_MAX < x => CONST_MAX, +LL | | x if CONST_MIN > x => CONST_MIN, LL | | x => x, LL | | }; - | |_____^ help: replace with clamp: `input.clamp(min, max)` + | |_____^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` | = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:103:15 + --> tests/ui/manual_clamp.rs:226:15 | LL | let x10 = match input { | _______________^ LL | | LL | | -LL | | x if min > x => min, -LL | | x if max < x => max, +LL | | x if CONST_MIN > x => CONST_MIN, +LL | | x if CONST_MAX < x => CONST_MAX, LL | | x => x, LL | | }; - | |_____^ help: replace with clamp: `input.clamp(min, max)` + | |_____^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` | = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:142:15 + --> tests/ui/manual_clamp.rs:265:15 | LL | let x14 = if input > CONST_MAX { | _______________^ @@ -222,23 +222,23 @@ LL | | }; = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:153:19 + --> tests/ui/manual_clamp.rs:276:19 | -LL | let x15 = if input > max { +LL | let x15 = if input > CONST_F64_MAX { | ___________________^ LL | | LL | | -LL | | max +LL | | CONST_F64_MAX ... | LL | | input LL | | }; - | |_________^ help: replace with clamp: `input.clamp(min, max)` + | |_________^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` | = note: clamp will panic if max < min, min.is_nan(), or max.is_nan() = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:166:19 + --> tests/ui/manual_clamp.rs:289:19 | LL | let x16 = cmp_max(cmp_min(input, CONST_MAX), CONST_MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -246,7 +246,7 @@ LL | let x16 = cmp_max(cmp_min(input, CONST_MAX), CONST_MIN); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:169:19 + --> tests/ui/manual_clamp.rs:292:19 | LL | let x17 = cmp_min(cmp_max(input, CONST_MIN), CONST_MAX); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -254,7 +254,7 @@ LL | let x17 = cmp_min(cmp_max(input, CONST_MIN), CONST_MAX); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:172:19 + --> tests/ui/manual_clamp.rs:295:19 | LL | let x18 = cmp_max(CONST_MIN, cmp_min(input, CONST_MAX)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -262,7 +262,7 @@ LL | let x18 = cmp_max(CONST_MIN, cmp_min(input, CONST_MAX)); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:175:19 + --> tests/ui/manual_clamp.rs:298:19 | LL | let x19 = cmp_min(CONST_MAX, cmp_max(input, CONST_MIN)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -270,7 +270,7 @@ LL | let x19 = cmp_min(CONST_MAX, cmp_max(input, CONST_MIN)); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:178:19 + --> tests/ui/manual_clamp.rs:301:19 | LL | let x20 = cmp_max(cmp_min(CONST_MAX, input), CONST_MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -278,7 +278,7 @@ LL | let x20 = cmp_max(cmp_min(CONST_MAX, input), CONST_MIN); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:181:19 + --> tests/ui/manual_clamp.rs:304:19 | LL | let x21 = cmp_min(cmp_max(CONST_MIN, input), CONST_MAX); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -286,7 +286,7 @@ LL | let x21 = cmp_min(cmp_max(CONST_MIN, input), CONST_MAX); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:184:19 + --> tests/ui/manual_clamp.rs:307:19 | LL | let x22 = cmp_max(CONST_MIN, cmp_min(CONST_MAX, input)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -294,7 +294,7 @@ LL | let x22 = cmp_max(CONST_MIN, cmp_min(CONST_MAX, input)); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:187:19 + --> tests/ui/manual_clamp.rs:310:19 | LL | let x23 = cmp_min(CONST_MAX, cmp_max(CONST_MIN, input)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -302,7 +302,7 @@ LL | let x23 = cmp_min(CONST_MAX, cmp_max(CONST_MIN, input)); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:191:19 + --> tests/ui/manual_clamp.rs:314:19 | LL | let x24 = f64::max(f64::min(input, CONST_F64_MAX), CONST_F64_MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` @@ -311,7 +311,7 @@ LL | let x24 = f64::max(f64::min(input, CONST_F64_MAX), CONST_F64_MIN); = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:194:19 + --> tests/ui/manual_clamp.rs:317:19 | LL | let x25 = f64::min(f64::max(input, CONST_F64_MIN), CONST_F64_MAX); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` @@ -320,7 +320,7 @@ LL | let x25 = f64::min(f64::max(input, CONST_F64_MIN), CONST_F64_MAX); = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:197:19 + --> tests/ui/manual_clamp.rs:320:19 | LL | let x26 = f64::max(CONST_F64_MIN, f64::min(input, CONST_F64_MAX)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` @@ -329,7 +329,7 @@ LL | let x26 = f64::max(CONST_F64_MIN, f64::min(input, CONST_F64_MAX)); = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:200:19 + --> tests/ui/manual_clamp.rs:323:19 | LL | let x27 = f64::min(CONST_F64_MAX, f64::max(input, CONST_F64_MIN)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` @@ -338,7 +338,7 @@ LL | let x27 = f64::min(CONST_F64_MAX, f64::max(input, CONST_F64_MIN)); = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:203:19 + --> tests/ui/manual_clamp.rs:326:19 | LL | let x28 = f64::max(f64::min(CONST_F64_MAX, input), CONST_F64_MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` @@ -347,7 +347,7 @@ LL | let x28 = f64::max(f64::min(CONST_F64_MAX, input), CONST_F64_MIN); = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:206:19 + --> tests/ui/manual_clamp.rs:329:19 | LL | let x29 = f64::min(f64::max(CONST_F64_MIN, input), CONST_F64_MAX); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` @@ -356,7 +356,7 @@ LL | let x29 = f64::min(f64::max(CONST_F64_MIN, input), CONST_F64_MAX); = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:209:19 + --> tests/ui/manual_clamp.rs:332:19 | LL | let x30 = f64::max(CONST_F64_MIN, f64::min(CONST_F64_MAX, input)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` @@ -365,7 +365,7 @@ LL | let x30 = f64::max(CONST_F64_MIN, f64::min(CONST_F64_MAX, input)); = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:212:19 + --> tests/ui/manual_clamp.rs:335:19 | LL | let x31 = f64::min(CONST_F64_MAX, f64::max(CONST_F64_MIN, input)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` @@ -374,31 +374,31 @@ LL | let x31 = f64::min(CONST_F64_MAX, f64::max(CONST_F64_MIN, input)); = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:217:5 + --> tests/ui/manual_clamp.rs:340:5 | -LL | / if x32 < min { +LL | / if x32 < CONST_MIN { LL | | LL | | -LL | | x32 = min; -LL | | } else if x32 > max { -LL | | x32 = max; +LL | | x32 = CONST_MIN; +LL | | } else if x32 > CONST_MAX { +LL | | x32 = CONST_MAX; LL | | } - | |_____^ help: replace with clamp: `x32 = x32.clamp(min, max);` + | |_____^ help: replace with clamp: `x32 = x32.clamp(CONST_MIN, CONST_MAX);` | = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:389:13 + --> tests/ui/manual_clamp.rs:532:13 | -LL | let _ = if input < min { +LL | let _ = if input > CONST_MAX { | _____________^ LL | | LL | | -LL | | min +LL | | CONST_MAX ... | LL | | input LL | | }; - | |_____^ help: replace with clamp: `input.clamp(min, max)` + | |_____^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` | = note: clamp will panic if max < min diff --git a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.fixed b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.fixed index 8218f10881a7..41a32df32ee4 100644 --- a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.fixed +++ b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.fixed @@ -1,4 +1,4 @@ -#![allow(unused_imports)] +#![allow(clippy::legacy_numeric_constants, unused_imports)] use std::{i128, i32, u128, u32}; diff --git a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.rs b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.rs index 60022b54b02d..3a6b32d80690 100644 --- a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.rs +++ b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.rs @@ -1,4 +1,4 @@ -#![allow(unused_imports)] +#![allow(clippy::legacy_numeric_constants, unused_imports)] use std::{i128, i32, u128, u32}; diff --git a/src/tools/clippy/tests/ui/manual_swap_auto_fix.fixed b/src/tools/clippy/tests/ui/manual_swap_auto_fix.fixed new file mode 100644 index 000000000000..28466ff3f9b4 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_swap_auto_fix.fixed @@ -0,0 +1,57 @@ +#![warn(clippy::manual_swap)] +#![no_main] + +fn swap1() { + let mut v = [3, 2, 1, 0]; + let index = v[0]; + v.swap(0, index); +} + +fn swap2() { + let mut v = [3, 2, 1, 0]; + let tmp = v[0]; + v.swap(0, 1); + // check not found in this scope. + let _ = tmp; +} + +fn swap3() { + let mut v = [3, 2]; + let i1 = 0; + let i2 = 1; + v.swap(i1, i2); +} + +fn swap4() { + let mut v = [3, 2, 1]; + let i1 = 0; + let i2 = 1; + v.swap(i1, i2 + 1); +} + +fn swap5() { + let mut v = [0, 1, 2, 3]; + let i1 = 0; + let i2 = 1; + v.swap(i1, i2 + 1); +} + +fn swap6() { + let mut v = [0, 1, 2, 3]; + let index = v[0]; + v.swap(0, index + 1); +} + +fn swap7() { + let mut v = [0, 1, 2, 3]; + let i1 = 0; + let i2 = 6; + v.swap(i1 * 3, i2 / 2); +} + +fn swap8() { + let mut v = [1, 2, 3, 4]; + let i1 = 1; + let i2 = 1; + v.swap(i1 + i2, i2); +} diff --git a/src/tools/clippy/tests/ui/manual_swap_auto_fix.rs b/src/tools/clippy/tests/ui/manual_swap_auto_fix.rs new file mode 100644 index 000000000000..702a9e67d3d5 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_swap_auto_fix.rs @@ -0,0 +1,72 @@ +#![warn(clippy::manual_swap)] +#![no_main] + +fn swap1() { + let mut v = [3, 2, 1, 0]; + let index = v[0]; + //~^ ERROR: this looks like you are swapping elements of `v` manually + v[0] = v[index]; + v[index] = index; +} + +fn swap2() { + let mut v = [3, 2, 1, 0]; + let tmp = v[0]; + v[0] = v[1]; + v[1] = tmp; + // check not found in this scope. + let _ = tmp; +} + +fn swap3() { + let mut v = [3, 2]; + let i1 = 0; + let i2 = 1; + let temp = v[i1]; + v[i1] = v[i2]; + v[i2] = temp; +} + +fn swap4() { + let mut v = [3, 2, 1]; + let i1 = 0; + let i2 = 1; + let temp = v[i1]; + v[i1] = v[i2 + 1]; + v[i2 + 1] = temp; +} + +fn swap5() { + let mut v = [0, 1, 2, 3]; + let i1 = 0; + let i2 = 1; + let temp = v[i1]; + v[i1] = v[i2 + 1]; + v[i2 + 1] = temp; +} + +fn swap6() { + let mut v = [0, 1, 2, 3]; + let index = v[0]; + //~^ ERROR: this looks like you are swapping elements of `v` manually + v[0] = v[index + 1]; + v[index + 1] = index; +} + +fn swap7() { + let mut v = [0, 1, 2, 3]; + let i1 = 0; + let i2 = 6; + let tmp = v[i1 * 3]; + v[i1 * 3] = v[i2 / 2]; + v[i2 / 2] = tmp; +} + +fn swap8() { + let mut v = [1, 2, 3, 4]; + let i1 = 1; + let i2 = 1; + let tmp = v[i1 + i2]; + v[i1 + i2] = v[i2]; + v[i2] = tmp; +} diff --git a/src/tools/clippy/tests/ui/manual_swap_auto_fix.stderr b/src/tools/clippy/tests/ui/manual_swap_auto_fix.stderr new file mode 100644 index 000000000000..eecfcd3977be --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_swap_auto_fix.stderr @@ -0,0 +1,88 @@ +error: this looks like you are swapping elements of `v` manually + --> tests/ui/manual_swap_auto_fix.rs:6:5 + | +LL | / let index = v[0]; +LL | | +LL | | v[0] = v[index]; +LL | | v[index] = index; + | |_____________________^ + | + = note: `-D clippy::manual-swap` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_swap)]` +help: try + | +LL ~ let index = v[0]; +LL + v.swap(0, index); + | + +error: this looks like you are swapping elements of `v` manually + --> tests/ui/manual_swap_auto_fix.rs:14:5 + | +LL | / let tmp = v[0]; +LL | | v[0] = v[1]; +LL | | v[1] = tmp; + | |_______________^ + | +help: try + | +LL ~ let tmp = v[0]; +LL + v.swap(0, 1); + | + +error: this looks like you are swapping elements of `v` manually + --> tests/ui/manual_swap_auto_fix.rs:25:5 + | +LL | / let temp = v[i1]; +LL | | v[i1] = v[i2]; +LL | | v[i2] = temp; + | |_________________^ help: try: `v.swap(i1, i2);` + +error: this looks like you are swapping elements of `v` manually + --> tests/ui/manual_swap_auto_fix.rs:34:5 + | +LL | / let temp = v[i1]; +LL | | v[i1] = v[i2 + 1]; +LL | | v[i2 + 1] = temp; + | |_____________________^ help: try: `v.swap(i1, i2 + 1);` + +error: this looks like you are swapping elements of `v` manually + --> tests/ui/manual_swap_auto_fix.rs:43:5 + | +LL | / let temp = v[i1]; +LL | | v[i1] = v[i2 + 1]; +LL | | v[i2 + 1] = temp; + | |_____________________^ help: try: `v.swap(i1, i2 + 1);` + +error: this looks like you are swapping elements of `v` manually + --> tests/ui/manual_swap_auto_fix.rs:50:5 + | +LL | / let index = v[0]; +LL | | +LL | | v[0] = v[index + 1]; +LL | | v[index + 1] = index; + | |_________________________^ + | +help: try + | +LL ~ let index = v[0]; +LL + v.swap(0, index + 1); + | + +error: this looks like you are swapping elements of `v` manually + --> tests/ui/manual_swap_auto_fix.rs:60:5 + | +LL | / let tmp = v[i1 * 3]; +LL | | v[i1 * 3] = v[i2 / 2]; +LL | | v[i2 / 2] = tmp; + | |____________________^ help: try: `v.swap(i1 * 3, i2 / 2);` + +error: this looks like you are swapping elements of `v` manually + --> tests/ui/manual_swap_auto_fix.rs:69:5 + | +LL | / let tmp = v[i1 + i2]; +LL | | v[i1 + i2] = v[i2]; +LL | | v[i2] = tmp; + | |________________^ help: try: `v.swap(i1 + i2, i2);` + +error: aborting due to 8 previous errors + diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed b/src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed index c8456805ee6e..a0b707628a88 100644 --- a/src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed +++ b/src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed @@ -17,3 +17,48 @@ fn main() { let x: Option> = None; x.unwrap_or_default(); } + +// Issue #12531 +unsafe fn no_deref_ptr(a: Option, b: *const Option) -> i32 { + match a { + // `*b` being correct depends on `a == Some(_)` + Some(_) => (*b).unwrap_or_default(), + _ => 0, + } +} + +const fn issue_12568(opt: Option) -> bool { + match opt { + Some(s) => s, + None => false, + } +} + +fn issue_12569() { + let match_none_se = match 1u32.checked_div(0) { + Some(v) => v, + None => { + println!("important"); + 0 + }, + }; + let match_some_se = match 1u32.checked_div(0) { + Some(v) => { + println!("important"); + v + }, + None => 0, + }; + let iflet_else_se = if let Some(v) = 1u32.checked_div(0) { + v + } else { + println!("important"); + 0 + }; + let iflet_then_se = if let Some(v) = 1u32.checked_div(0) { + println!("important"); + v + } else { + 0 + }; +} diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs b/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs index 820717be53a8..1d4cca12f6c7 100644 --- a/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs +++ b/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs @@ -38,3 +38,51 @@ fn main() { Vec::default() }; } + +// Issue #12531 +unsafe fn no_deref_ptr(a: Option, b: *const Option) -> i32 { + match a { + // `*b` being correct depends on `a == Some(_)` + Some(_) => match *b { + Some(v) => v, + _ => 0, + }, + _ => 0, + } +} + +const fn issue_12568(opt: Option) -> bool { + match opt { + Some(s) => s, + None => false, + } +} + +fn issue_12569() { + let match_none_se = match 1u32.checked_div(0) { + Some(v) => v, + None => { + println!("important"); + 0 + }, + }; + let match_some_se = match 1u32.checked_div(0) { + Some(v) => { + println!("important"); + v + }, + None => 0, + }; + let iflet_else_se = if let Some(v) = 1u32.checked_div(0) { + v + } else { + println!("important"); + 0 + }; + let iflet_then_se = if let Some(v) = 1u32.checked_div(0) { + println!("important"); + v + } else { + 0 + }; +} diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or_default.stderr b/src/tools/clippy/tests/ui/manual_unwrap_or_default.stderr index f4eb65835884..d89212e60459 100644 --- a/src/tools/clippy/tests/ui/manual_unwrap_or_default.stderr +++ b/src/tools/clippy/tests/ui/manual_unwrap_or_default.stderr @@ -52,5 +52,15 @@ LL | | Vec::default() LL | | }; | |_____^ help: replace it with: `x.unwrap_or_default()` -error: aborting due to 5 previous errors +error: match can be simplified with `.unwrap_or_default()` + --> tests/ui/manual_unwrap_or_default.rs:46:20 + | +LL | Some(_) => match *b { + | ____________________^ +LL | | Some(v) => v, +LL | | _ => 0, +LL | | }, + | |_________^ help: replace it with: `(*b).unwrap_or_default()` + +error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui/map_clone.fixed b/src/tools/clippy/tests/ui/map_clone.fixed index e58b6b2f19ea..f9f8dc1a5123 100644 --- a/src/tools/clippy/tests/ui/map_clone.fixed +++ b/src/tools/clippy/tests/ui/map_clone.fixed @@ -131,4 +131,28 @@ fn main() { let x: Vec<&u8> = vec![]; let y = x.into_iter().map(|x| u8::clone(loop {})); } + + // Issue #12528 + { + // Don't lint these + use std::rc::{Rc, Weak as RcWeak}; + use std::sync::{Arc, Weak as ArcWeak}; + struct Foo; + + let x = Arc::new(Foo); + let y = Some(&x); + let _z = y.map(Arc::clone); + + let x = Rc::new(Foo); + let y = Some(&x); + let _z = y.map(Rc::clone); + + let x = Arc::downgrade(&Arc::new(Foo)); + let y = Some(&x); + let _z = y.map(ArcWeak::clone); + + let x = Rc::downgrade(&Rc::new(Foo)); + let y = Some(&x); + let _z = y.map(RcWeak::clone); + } } diff --git a/src/tools/clippy/tests/ui/map_clone.rs b/src/tools/clippy/tests/ui/map_clone.rs index e642e4046f8b..a5c19ce06319 100644 --- a/src/tools/clippy/tests/ui/map_clone.rs +++ b/src/tools/clippy/tests/ui/map_clone.rs @@ -131,4 +131,28 @@ fn main() { let x: Vec<&u8> = vec![]; let y = x.into_iter().map(|x| u8::clone(loop {})); } + + // Issue #12528 + { + // Don't lint these + use std::rc::{Rc, Weak as RcWeak}; + use std::sync::{Arc, Weak as ArcWeak}; + struct Foo; + + let x = Arc::new(Foo); + let y = Some(&x); + let _z = y.map(Arc::clone); + + let x = Rc::new(Foo); + let y = Some(&x); + let _z = y.map(Rc::clone); + + let x = Arc::downgrade(&Arc::new(Foo)); + let y = Some(&x); + let _z = y.map(ArcWeak::clone); + + let x = Rc::downgrade(&Rc::new(Foo)); + let y = Some(&x); + let _z = y.map(RcWeak::clone); + } } diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs index 6985c2d0c195..12a8320c8f32 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs @@ -1,5 +1,5 @@ #![warn(clippy::missing_const_for_fn)] -#![allow(incomplete_features, clippy::let_and_return)] +#![allow(incomplete_features, clippy::let_and_return, clippy::missing_transmute_annotations)] #![feature(const_mut_refs)] #![feature(const_trait_impl)] diff --git a/src/tools/clippy/tests/ui/missing_transmute_annotations.fixed b/src/tools/clippy/tests/ui/missing_transmute_annotations.fixed new file mode 100644 index 000000000000..a3c94ab139ec --- /dev/null +++ b/src/tools/clippy/tests/ui/missing_transmute_annotations.fixed @@ -0,0 +1,78 @@ +//@aux-build:macro_rules.rs + +#![warn(clippy::missing_transmute_annotations)] +#![allow(clippy::let_with_type_underscore)] + +#[macro_use] +extern crate macro_rules; + +macro_rules! local_bad_transmute { + ($e:expr) => { + std::mem::transmute::<[u16; 2], i32>($e) + //~^ ERROR: transmute used without annotations + }; +} + +fn bar(x: i32) -> i32 { + x +} + +unsafe fn foo1() -> i32 { + // Should not warn! + std::mem::transmute([1u16, 2u16]) +} + +// Should not warn! +const _: i32 = unsafe { std::mem::transmute([1u16, 2u16]) }; + +#[repr(i32)] +enum Foo { + A = 0, +} + +unsafe fn foo2() -> i32 { + let mut i: i32 = 0; + i = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]); + //~^ ERROR: transmute used without annotations + i = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]); + //~^ ERROR: transmute used without annotations + i = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]); + //~^ ERROR: transmute used without annotations + i = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]); + //~^ ERROR: transmute used without annotations + + let x: i32 = bar(std::mem::transmute::<[u16; 2], i32>([1u16, 2u16])); + //~^ ERROR: transmute used without annotations + bar(std::mem::transmute::<[u16; 2], i32>([1u16, 2u16])); + //~^ ERROR: transmute used without annotations + + i = local_bad_transmute!([1u16, 2u16]); + + // Should not warn. + i = bad_transmute!([1u16, 2u16]); + + i = std::mem::transmute::<[i16; 2], i32>([0i16, 0i16]); + //~^ ERROR: transmute used without annotations + + i = std::mem::transmute::(Foo::A); + //~^ ERROR: transmute used without annotations + + i +} + +fn main() { + let x: _ = unsafe { std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]) }; + //~^ ERROR: transmute used without annotations + unsafe { + let x: _ = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]); + //~^ ERROR: transmute used without annotations + + // Should not warn. + std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]); + let x = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]); + let x: i32 = std::mem::transmute::<[u16; 2], _>([1u16, 2u16]); + let x: i32 = std::mem::transmute::<_, i32>([1u16, 2u16]); + let x: i32 = std::mem::transmute([1u16, 2u16]); + } + let x: i32 = unsafe { std::mem::transmute([1u16, 2u16]) }; +} diff --git a/src/tools/clippy/tests/ui/missing_transmute_annotations.rs b/src/tools/clippy/tests/ui/missing_transmute_annotations.rs new file mode 100644 index 000000000000..c12e1b0f8d22 --- /dev/null +++ b/src/tools/clippy/tests/ui/missing_transmute_annotations.rs @@ -0,0 +1,78 @@ +//@aux-build:macro_rules.rs + +#![warn(clippy::missing_transmute_annotations)] +#![allow(clippy::let_with_type_underscore)] + +#[macro_use] +extern crate macro_rules; + +macro_rules! local_bad_transmute { + ($e:expr) => { + std::mem::transmute($e) + //~^ ERROR: transmute used without annotations + }; +} + +fn bar(x: i32) -> i32 { + x +} + +unsafe fn foo1() -> i32 { + // Should not warn! + std::mem::transmute([1u16, 2u16]) +} + +// Should not warn! +const _: i32 = unsafe { std::mem::transmute([1u16, 2u16]) }; + +#[repr(i32)] +enum Foo { + A = 0, +} + +unsafe fn foo2() -> i32 { + let mut i: i32 = 0; + i = std::mem::transmute([1u16, 2u16]); + //~^ ERROR: transmute used without annotations + i = std::mem::transmute::<_, _>([1u16, 2u16]); + //~^ ERROR: transmute used without annotations + i = std::mem::transmute::<_, i32>([1u16, 2u16]); + //~^ ERROR: transmute used without annotations + i = std::mem::transmute::<[u16; 2], _>([1u16, 2u16]); + //~^ ERROR: transmute used without annotations + + let x: i32 = bar(std::mem::transmute::<[u16; 2], _>([1u16, 2u16])); + //~^ ERROR: transmute used without annotations + bar(std::mem::transmute::<[u16; 2], _>([1u16, 2u16])); + //~^ ERROR: transmute used without annotations + + i = local_bad_transmute!([1u16, 2u16]); + + // Should not warn. + i = bad_transmute!([1u16, 2u16]); + + i = std::mem::transmute([0i16, 0i16]); + //~^ ERROR: transmute used without annotations + + i = std::mem::transmute(Foo::A); + //~^ ERROR: transmute used without annotations + + i +} + +fn main() { + let x: _ = unsafe { std::mem::transmute::<_, i32>([1u16, 2u16]) }; + //~^ ERROR: transmute used without annotations + unsafe { + let x: _ = std::mem::transmute::<_, i32>([1u16, 2u16]); + //~^ ERROR: transmute used without annotations + + // Should not warn. + std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]); + let x = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]); + let x: i32 = std::mem::transmute::<[u16; 2], _>([1u16, 2u16]); + let x: i32 = std::mem::transmute::<_, i32>([1u16, 2u16]); + let x: i32 = std::mem::transmute([1u16, 2u16]); + } + let x: i32 = unsafe { std::mem::transmute([1u16, 2u16]) }; +} diff --git a/src/tools/clippy/tests/ui/missing_transmute_annotations.stderr b/src/tools/clippy/tests/ui/missing_transmute_annotations.stderr new file mode 100644 index 000000000000..5903ed488ef1 --- /dev/null +++ b/src/tools/clippy/tests/ui/missing_transmute_annotations.stderr @@ -0,0 +1,76 @@ +error: transmute used without annotations + --> tests/ui/missing_transmute_annotations.rs:35:19 + | +LL | i = std::mem::transmute([1u16, 2u16]); + | ^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>` + | + = note: `-D clippy::missing-transmute-annotations` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_transmute_annotations)]` + +error: transmute used without annotations + --> tests/ui/missing_transmute_annotations.rs:37:19 + | +LL | i = std::mem::transmute::<_, _>([1u16, 2u16]); + | ^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>` + +error: transmute used without annotations + --> tests/ui/missing_transmute_annotations.rs:39:19 + | +LL | i = std::mem::transmute::<_, i32>([1u16, 2u16]); + | ^^^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>` + +error: transmute used without annotations + --> tests/ui/missing_transmute_annotations.rs:41:19 + | +LL | i = std::mem::transmute::<[u16; 2], _>([1u16, 2u16]); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>` + +error: transmute used without annotations + --> tests/ui/missing_transmute_annotations.rs:44:32 + | +LL | let x: i32 = bar(std::mem::transmute::<[u16; 2], _>([1u16, 2u16])); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>` + +error: transmute used without annotations + --> tests/ui/missing_transmute_annotations.rs:46:19 + | +LL | bar(std::mem::transmute::<[u16; 2], _>([1u16, 2u16])); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>` + +error: transmute used without annotations + --> tests/ui/missing_transmute_annotations.rs:11:19 + | +LL | std::mem::transmute($e) + | ^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>` +... +LL | i = local_bad_transmute!([1u16, 2u16]); + | ---------------------------------- in this macro invocation + | + = note: this error originates in the macro `local_bad_transmute` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: transmute used without annotations + --> tests/ui/missing_transmute_annotations.rs:54:19 + | +LL | i = std::mem::transmute([0i16, 0i16]); + | ^^^^^^^^^ help: consider adding missing annotations: `transmute::<[i16; 2], i32>` + +error: transmute used without annotations + --> tests/ui/missing_transmute_annotations.rs:57:19 + | +LL | i = std::mem::transmute(Foo::A); + | ^^^^^^^^^ help: consider adding missing annotations: `transmute::` + +error: transmute used without annotations + --> tests/ui/missing_transmute_annotations.rs:64:35 + | +LL | let x: _ = unsafe { std::mem::transmute::<_, i32>([1u16, 2u16]) }; + | ^^^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>` + +error: transmute used without annotations + --> tests/ui/missing_transmute_annotations.rs:67:30 + | +LL | let x: _ = std::mem::transmute::<_, i32>([1u16, 2u16]); + | ^^^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>` + +error: aborting due to 11 previous errors + diff --git a/src/tools/clippy/tests/ui/mixed_attributes_style.rs b/src/tools/clippy/tests/ui/mixed_attributes_style.rs index 4f89aa8a5e55..1a646c265223 100644 --- a/src/tools/clippy/tests/ui/mixed_attributes_style.rs +++ b/src/tools/clippy/tests/ui/mixed_attributes_style.rs @@ -1,6 +1,12 @@ +//@aux-build:proc_macro_attr.rs +//@compile-flags: --test --cfg dummy_cfg +#![feature(custom_inner_attributes)] #![warn(clippy::mixed_attributes_style)] #![allow(clippy::duplicated_attributes)] +#[macro_use] +extern crate proc_macro_attr; + #[allow(unused)] //~ ERROR: item has both inner and outer attributes fn foo1() { #![allow(unused)] @@ -38,3 +44,57 @@ mod bar { fn main() { // test code goes here } + +// issue #12435 +#[cfg(test)] +mod tests { + //! Module doc, don't lint +} +#[allow(unused)] +mod baz { + //! Module doc, don't lint + const FOO: u8 = 0; +} +/// Module doc, don't lint +mod quz { + #![allow(unused)] +} + +mod issue_12530 { + // don't lint different attributes entirely + #[cfg(test)] + mod tests { + #![allow(clippy::unreadable_literal)] + + #[allow(dead_code)] //~ ERROR: item has both inner and outer attributes + mod inner_mod { + #![allow(dead_code)] + } + } + #[cfg(dummy_cfg)] + mod another_mod { + #![allow(clippy::question_mark)] + } + /// Nested mod + mod nested_mod { + #[allow(dead_code)] //~ ERROR: item has both inner and outer attributes + mod inner_mod { + #![allow(dead_code)] + } + } + /// Nested mod //~ ERROR: item has both inner and outer attributes + #[allow(unused)] + mod nest_mod_2 { + #![allow(unused)] + + #[allow(dead_code)] //~ ERROR: item has both inner and outer attributes + mod inner_mod { + #![allow(dead_code)] + } + } + // Different path symbols - Known FN + #[dummy] + fn use_dummy() { + #![proc_macro_attr::dummy] + } +} diff --git a/src/tools/clippy/tests/ui/mixed_attributes_style.stderr b/src/tools/clippy/tests/ui/mixed_attributes_style.stderr index ed798073cb7c..a1d3fc430f6c 100644 --- a/src/tools/clippy/tests/ui/mixed_attributes_style.stderr +++ b/src/tools/clippy/tests/ui/mixed_attributes_style.stderr @@ -1,5 +1,5 @@ error: item has both inner and outer attributes - --> tests/ui/mixed_attributes_style.rs:4:1 + --> tests/ui/mixed_attributes_style.rs:10:1 | LL | / #[allow(unused)] LL | | fn foo1() { @@ -10,7 +10,7 @@ LL | | #![allow(unused)] = help: to override `-D warnings` add `#[allow(clippy::mixed_attributes_style)]` error: item has both inner and outer attributes - --> tests/ui/mixed_attributes_style.rs:18:1 + --> tests/ui/mixed_attributes_style.rs:24:1 | LL | / /// linux LL | | @@ -19,12 +19,45 @@ LL | | //! windows | |_______________^ error: item has both inner and outer attributes - --> tests/ui/mixed_attributes_style.rs:33:1 + --> tests/ui/mixed_attributes_style.rs:39:1 | LL | / #[allow(unused)] LL | | mod bar { LL | | #![allow(unused)] | |_____________________^ -error: aborting due to 3 previous errors +error: item has both inner and outer attributes + --> tests/ui/mixed_attributes_style.rs:69:9 + | +LL | / #[allow(dead_code)] +LL | | mod inner_mod { +LL | | #![allow(dead_code)] + | |________________________________^ + +error: item has both inner and outer attributes + --> tests/ui/mixed_attributes_style.rs:80:9 + | +LL | / #[allow(dead_code)] +LL | | mod inner_mod { +LL | | #![allow(dead_code)] + | |________________________________^ + +error: item has both inner and outer attributes + --> tests/ui/mixed_attributes_style.rs:85:5 + | +LL | / /// Nested mod +LL | | #[allow(unused)] +LL | | mod nest_mod_2 { +LL | | #![allow(unused)] + | |_________________________^ + +error: item has both inner and outer attributes + --> tests/ui/mixed_attributes_style.rs:90:9 + | +LL | / #[allow(dead_code)] +LL | | mod inner_mod { +LL | | #![allow(dead_code)] + | |________________________________^ + +error: aborting due to 7 previous errors diff --git a/src/tools/clippy/tests/ui/mixed_attributes_style/auxiliary/submodule.rs b/src/tools/clippy/tests/ui/mixed_attributes_style/auxiliary/submodule.rs new file mode 100644 index 000000000000..df44b07a6941 --- /dev/null +++ b/src/tools/clippy/tests/ui/mixed_attributes_style/auxiliary/submodule.rs @@ -0,0 +1,9 @@ +//! Module level doc + +#![allow(dead_code)] + +#[allow(unused)] +//~^ ERROR: item has both inner and outer attributes +mod foo { + #![allow(dead_code)] +} diff --git a/src/tools/clippy/tests/ui/mixed_attributes_style/global_allow.rs b/src/tools/clippy/tests/ui/mixed_attributes_style/global_allow.rs new file mode 100644 index 000000000000..153262e65570 --- /dev/null +++ b/src/tools/clippy/tests/ui/mixed_attributes_style/global_allow.rs @@ -0,0 +1,7 @@ +// issue 12436 +#![allow(clippy::mixed_attributes_style)] + +#[path = "auxiliary/submodule.rs"] +mod submodule; + +fn main() {} diff --git a/src/tools/clippy/tests/ui/mixed_attributes_style/mod_declaration.rs b/src/tools/clippy/tests/ui/mixed_attributes_style/mod_declaration.rs new file mode 100644 index 000000000000..b0f1f0bda9e6 --- /dev/null +++ b/src/tools/clippy/tests/ui/mixed_attributes_style/mod_declaration.rs @@ -0,0 +1,3 @@ +#[path = "auxiliary/submodule.rs"] // don't lint. +/// This doc comment should not lint, it could be used to add context to the original module doc +mod submodule; diff --git a/src/tools/clippy/tests/ui/mixed_attributes_style/mod_declaration.stderr b/src/tools/clippy/tests/ui/mixed_attributes_style/mod_declaration.stderr new file mode 100644 index 000000000000..968c537c7e44 --- /dev/null +++ b/src/tools/clippy/tests/ui/mixed_attributes_style/mod_declaration.stderr @@ -0,0 +1,14 @@ +error: item has both inner and outer attributes + --> tests/ui/mixed_attributes_style/auxiliary/submodule.rs:5:1 + | +LL | / #[allow(unused)] +LL | | +LL | | mod foo { +LL | | #![allow(dead_code)] + | |________________________^ + | + = note: `-D clippy::mixed-attributes-style` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mixed_attributes_style)]` + +error: aborting due to 1 previous error + diff --git a/src/tools/clippy/tests/ui/ptr_cast_constness.fixed b/src/tools/clippy/tests/ui/ptr_cast_constness.fixed index c410a660dc42..33c0725faad0 100644 --- a/src/tools/clippy/tests/ui/ptr_cast_constness.fixed +++ b/src/tools/clippy/tests/ui/ptr_cast_constness.fixed @@ -1,7 +1,12 @@ //@aux-build:proc_macros.rs #![warn(clippy::ptr_cast_constness)] -#![allow(clippy::transmute_ptr_to_ref, clippy::unnecessary_cast, unused)] +#![allow( + clippy::transmute_ptr_to_ref, + clippy::unnecessary_cast, + unused, + clippy::missing_transmute_annotations +)] extern crate proc_macros; use proc_macros::{external, inline_macros}; diff --git a/src/tools/clippy/tests/ui/ptr_cast_constness.rs b/src/tools/clippy/tests/ui/ptr_cast_constness.rs index 6025b857b8f4..24d959856dbd 100644 --- a/src/tools/clippy/tests/ui/ptr_cast_constness.rs +++ b/src/tools/clippy/tests/ui/ptr_cast_constness.rs @@ -1,7 +1,12 @@ //@aux-build:proc_macros.rs #![warn(clippy::ptr_cast_constness)] -#![allow(clippy::transmute_ptr_to_ref, clippy::unnecessary_cast, unused)] +#![allow( + clippy::transmute_ptr_to_ref, + clippy::unnecessary_cast, + unused, + clippy::missing_transmute_annotations +)] extern crate proc_macros; use proc_macros::{external, inline_macros}; diff --git a/src/tools/clippy/tests/ui/ptr_cast_constness.stderr b/src/tools/clippy/tests/ui/ptr_cast_constness.stderr index 8e2bec527ffb..322c3585e62f 100644 --- a/src/tools/clippy/tests/ui/ptr_cast_constness.stderr +++ b/src/tools/clippy/tests/ui/ptr_cast_constness.stderr @@ -1,5 +1,5 @@ error: `as` casting between raw pointers while changing only its constness - --> tests/ui/ptr_cast_constness.rs:10:41 + --> tests/ui/ptr_cast_constness.rs:15:41 | LL | let _: &mut T = std::mem::transmute(p as *mut T); | ^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `p.cast_mut()` @@ -8,37 +8,37 @@ LL | let _: &mut T = std::mem::transmute(p as *mut T); = help: to override `-D warnings` add `#[allow(clippy::ptr_cast_constness)]` error: `as` casting between raw pointers while changing only its constness - --> tests/ui/ptr_cast_constness.rs:11:19 + --> tests/ui/ptr_cast_constness.rs:16:19 | LL | let _ = &mut *(p as *mut T); | ^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `p.cast_mut()` error: `as` casting between raw pointers while changing only its constness - --> tests/ui/ptr_cast_constness.rs:26:17 + --> tests/ui/ptr_cast_constness.rs:31:17 | LL | let _ = *ptr_ptr as *mut u32; | ^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `(*ptr_ptr).cast_mut()` error: `as` casting between raw pointers while changing only its constness - --> tests/ui/ptr_cast_constness.rs:29:13 + --> tests/ui/ptr_cast_constness.rs:34:13 | LL | let _ = ptr as *mut u32; | ^^^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `ptr.cast_mut()` error: `as` casting between raw pointers while changing only its constness - --> tests/ui/ptr_cast_constness.rs:30:13 + --> tests/ui/ptr_cast_constness.rs:35:13 | LL | let _ = mut_ptr as *const u32; | ^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_const`, a safer alternative: `mut_ptr.cast_const()` error: `as` casting between raw pointers while changing only its constness - --> tests/ui/ptr_cast_constness.rs:59:13 + --> tests/ui/ptr_cast_constness.rs:64:13 | LL | let _ = ptr as *mut u32; | ^^^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `ptr.cast_mut()` error: `as` casting between raw pointers while changing only its constness - --> tests/ui/ptr_cast_constness.rs:60:13 + --> tests/ui/ptr_cast_constness.rs:65:13 | LL | let _ = mut_ptr as *const u32; | ^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_const`, a safer alternative: `mut_ptr.cast_const()` diff --git a/src/tools/clippy/tests/ui/question_mark.fixed b/src/tools/clippy/tests/ui/question_mark.fixed index 567472a8af22..679388372e61 100644 --- a/src/tools/clippy/tests/ui/question_mark.fixed +++ b/src/tools/clippy/tests/ui/question_mark.fixed @@ -283,3 +283,37 @@ fn issue12337() -> Option { }; Some(42) } + +fn issue11983(option: &Option) -> Option<()> { + // Don't lint, `&Option` dose not impl `Try`. + let Some(v) = option else { return None }; + + let opt = Some(String::new()); + // Don't lint, `branch` method in `Try` takes ownership of `opt`, + // and `(&opt)?` also doesn't work since it's `&Option`. + let Some(v) = &opt else { return None }; + let mov = opt; + + Some(()) +} + +struct Foo { + owned: Option, +} +struct Bar { + foo: Foo, +} +#[allow(clippy::disallowed_names)] +fn issue12412(foo: &Foo, bar: &Bar) -> Option<()> { + // Don't lint, `owned` is behind a shared reference. + let Some(v) = &foo.owned else { + return None; + }; + // Don't lint, `owned` is behind a shared reference. + let Some(v) = &bar.foo.owned else { + return None; + }; + // lint + let v = bar.foo.owned.clone()?; + Some(()) +} diff --git a/src/tools/clippy/tests/ui/question_mark.rs b/src/tools/clippy/tests/ui/question_mark.rs index abf8c270de83..601ab78bf5aa 100644 --- a/src/tools/clippy/tests/ui/question_mark.rs +++ b/src/tools/clippy/tests/ui/question_mark.rs @@ -323,3 +323,39 @@ fn issue12337() -> Option { }; Some(42) } + +fn issue11983(option: &Option) -> Option<()> { + // Don't lint, `&Option` dose not impl `Try`. + let Some(v) = option else { return None }; + + let opt = Some(String::new()); + // Don't lint, `branch` method in `Try` takes ownership of `opt`, + // and `(&opt)?` also doesn't work since it's `&Option`. + let Some(v) = &opt else { return None }; + let mov = opt; + + Some(()) +} + +struct Foo { + owned: Option, +} +struct Bar { + foo: Foo, +} +#[allow(clippy::disallowed_names)] +fn issue12412(foo: &Foo, bar: &Bar) -> Option<()> { + // Don't lint, `owned` is behind a shared reference. + let Some(v) = &foo.owned else { + return None; + }; + // Don't lint, `owned` is behind a shared reference. + let Some(v) = &bar.foo.owned else { + return None; + }; + // lint + let Some(v) = bar.foo.owned.clone() else { + return None; + }; + Some(()) +} diff --git a/src/tools/clippy/tests/ui/question_mark.stderr b/src/tools/clippy/tests/ui/question_mark.stderr index 4fcccdf5512f..5f26a7ea2c3e 100644 --- a/src/tools/clippy/tests/ui/question_mark.stderr +++ b/src/tools/clippy/tests/ui/question_mark.stderr @@ -141,5 +141,13 @@ LL | | // https://github.com/rust-lang/rust-clippy/pull/11001#is LL | | } | |_____________^ help: replace it with: `a?;` -error: aborting due to 16 previous errors +error: this `let...else` may be rewritten with the `?` operator + --> tests/ui/question_mark.rs:357:5 + | +LL | / let Some(v) = bar.foo.owned.clone() else { +LL | | return None; +LL | | }; + | |______^ help: replace it with: `let v = bar.foo.owned.clone()?;` + +error: aborting due to 17 previous errors diff --git a/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.rs b/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.rs index 1bd4cd5fb50d..07280351e76c 100644 --- a/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.rs +++ b/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.rs @@ -1,3 +1,4 @@ +#![allow(clippy::legacy_numeric_constants)] #![warn(clippy::suspicious_arithmetic_impl)] use std::ops::{ Add, AddAssign, BitAnd, BitOr, BitOrAssign, BitXor, Div, DivAssign, Mul, MulAssign, Rem, Shl, Shr, Sub, diff --git a/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.stderr b/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.stderr index 193cd64149b1..1bfca49a635d 100644 --- a/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.stderr +++ b/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.stderr @@ -1,5 +1,5 @@ error: suspicious use of `-` in `Add` impl - --> tests/ui/suspicious_arithmetic_impl.rs:13:20 + --> tests/ui/suspicious_arithmetic_impl.rs:14:20 | LL | Foo(self.0 - other.0) | ^ @@ -8,7 +8,7 @@ LL | Foo(self.0 - other.0) = help: to override `-D warnings` add `#[allow(clippy::suspicious_arithmetic_impl)]` error: suspicious use of `-` in `AddAssign` impl - --> tests/ui/suspicious_arithmetic_impl.rs:21:23 + --> tests/ui/suspicious_arithmetic_impl.rs:22:23 | LL | *self = *self - other; | ^ @@ -17,43 +17,43 @@ LL | *self = *self - other; = help: to override `-D warnings` add `#[allow(clippy::suspicious_op_assign_impl)]` error: suspicious use of `/` in `MulAssign` impl - --> tests/ui/suspicious_arithmetic_impl.rs:36:16 + --> tests/ui/suspicious_arithmetic_impl.rs:37:16 | LL | self.0 /= other.0; | ^^ error: suspicious use of `/` in `Rem` impl - --> tests/ui/suspicious_arithmetic_impl.rs:75:20 + --> tests/ui/suspicious_arithmetic_impl.rs:76:20 | LL | Foo(self.0 / other.0) | ^ error: suspicious use of `|` in `BitAnd` impl - --> tests/ui/suspicious_arithmetic_impl.rs:84:20 + --> tests/ui/suspicious_arithmetic_impl.rs:85:20 | LL | Foo(self.0 | other.0) | ^ error: suspicious use of `^` in `BitOr` impl - --> tests/ui/suspicious_arithmetic_impl.rs:93:20 + --> tests/ui/suspicious_arithmetic_impl.rs:94:20 | LL | Foo(self.0 ^ other.0) | ^ error: suspicious use of `&` in `BitXor` impl - --> tests/ui/suspicious_arithmetic_impl.rs:102:20 + --> tests/ui/suspicious_arithmetic_impl.rs:103:20 | LL | Foo(self.0 & other.0) | ^ error: suspicious use of `>>` in `Shl` impl - --> tests/ui/suspicious_arithmetic_impl.rs:111:20 + --> tests/ui/suspicious_arithmetic_impl.rs:112:20 | LL | Foo(self.0 >> other.0) | ^^ error: suspicious use of `<<` in `Shr` impl - --> tests/ui/suspicious_arithmetic_impl.rs:120:20 + --> tests/ui/suspicious_arithmetic_impl.rs:121:20 | LL | Foo(self.0 << other.0) | ^^ diff --git a/src/tools/clippy/tests/ui/suspicious_else_formatting.rs b/src/tools/clippy/tests/ui/suspicious_else_formatting.rs index c0856427eaef..3d5c892eb606 100644 --- a/src/tools/clippy/tests/ui/suspicious_else_formatting.rs +++ b/src/tools/clippy/tests/ui/suspicious_else_formatting.rs @@ -120,6 +120,34 @@ fn main() { /* whelp */ { } + + // #12497 Don't trigger lint as rustfmt wants it + if true { + println!("true"); + } + /*else if false { +}*/ + else { + println!("false"); + } + + if true { + println!("true"); + } // else if false {} + else { + println!("false"); + } + + if true { + println!("true"); + } /* if true { + println!("true"); +} + */ + else { + println!("false"); + } + } // #7650 - Don't lint. Proc-macro using bad spans for `if` expressions. diff --git a/src/tools/clippy/tests/ui/transmute.rs b/src/tools/clippy/tests/ui/transmute.rs index 1796ccaf28e1..be6e071767d9 100644 --- a/src/tools/clippy/tests/ui/transmute.rs +++ b/src/tools/clippy/tests/ui/transmute.rs @@ -1,4 +1,9 @@ -#![allow(dead_code, clippy::borrow_as_ptr, clippy::needless_lifetimes)] +#![allow( + dead_code, + clippy::borrow_as_ptr, + clippy::needless_lifetimes, + clippy::missing_transmute_annotations +)] //@no-rustfix extern crate core; diff --git a/src/tools/clippy/tests/ui/transmute.stderr b/src/tools/clippy/tests/ui/transmute.stderr index 3ed6cb2b3f97..375e8f19dd6b 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:24:23 + --> tests/ui/transmute.rs:29:23 | LL | let _: *const T = core::intrinsics::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T` @@ -8,61 +8,61 @@ LL | let _: *const T = core::intrinsics::transmute(t); = help: to override `-D warnings` add `#[allow(clippy::useless_transmute)]` error: transmute from a reference to a pointer - --> tests/ui/transmute.rs:28:21 + --> tests/ui/transmute.rs:33:21 | LL | let _: *mut T = core::intrinsics::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *mut T` error: transmute from a reference to a pointer - --> tests/ui/transmute.rs:31:23 + --> tests/ui/transmute.rs:36:23 | LL | let _: *const U = core::intrinsics::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *const U` error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:38:27 + --> tests/ui/transmute.rs:43:27 | LL | let _: Vec = core::intrinsics::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:41:27 + --> tests/ui/transmute.rs:46:27 | LL | let _: Vec = core::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:44:27 + --> tests/ui/transmute.rs:49:27 | LL | let _: Vec = std::intrinsics::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:47:27 + --> tests/ui/transmute.rs:52:27 | LL | let _: Vec = std::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:50:27 + --> tests/ui/transmute.rs:55:27 | LL | let _: Vec = my_transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^ error: transmute from an integer to a pointer - --> tests/ui/transmute.rs:53:31 + --> tests/ui/transmute.rs:58: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:58:31 + --> tests/ui/transmute.rs:63: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:90:24 + --> tests/ui/transmute.rs:95:24 | LL | let _: Usize = core::intrinsics::transmute(int_const_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,25 +71,25 @@ LL | let _: Usize = core::intrinsics::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:94:24 + --> tests/ui/transmute.rs:99:24 | LL | let _: Usize = core::intrinsics::transmute(int_mut_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`Usize`) to a pointer to that type (`*const Usize`) - --> tests/ui/transmute.rs:97:31 + --> tests/ui/transmute.rs:102:31 | LL | let _: *const Usize = core::intrinsics::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`) - --> tests/ui/transmute.rs:100:29 + --> tests/ui/transmute.rs:105:29 | LL | let _: *mut Usize = core::intrinsics::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a `u8` to a `bool` - --> tests/ui/transmute.rs:107:28 + --> tests/ui/transmute.rs:112:28 | LL | let _: bool = unsafe { std::mem::transmute(0_u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `0_u8 != 0` @@ -98,7 +98,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 `u32` to a `f32` - --> tests/ui/transmute.rs:115:31 + --> tests/ui/transmute.rs:120:31 | LL | let _: f32 = unsafe { std::mem::transmute(0_u32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)` @@ -107,25 +107,25 @@ LL | let _: f32 = unsafe { std::mem::transmute(0_u32) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_float)]` error: transmute from a `i32` to a `f32` - --> tests/ui/transmute.rs:118:31 + --> tests/ui/transmute.rs:123:31 | LL | let _: f32 = unsafe { std::mem::transmute(0_i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_i32 as u32)` error: transmute from a `u64` to a `f64` - --> tests/ui/transmute.rs:120:31 + --> tests/ui/transmute.rs:125:31 | LL | let _: f64 = unsafe { std::mem::transmute(0_u64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_u64)` error: transmute from a `i64` to a `f64` - --> tests/ui/transmute.rs:122:31 + --> tests/ui/transmute.rs:127:31 | LL | let _: f64 = unsafe { std::mem::transmute(0_i64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)` error: transmute from a `u8` to a `[u8; 1]` - --> tests/ui/transmute.rs:143:30 + --> tests/ui/transmute.rs:148:30 | LL | let _: [u8; 1] = std::mem::transmute(0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()` @@ -134,85 +134,85 @@ LL | let _: [u8; 1] = std::mem::transmute(0u8); = help: to override `-D warnings` add `#[allow(clippy::transmute_num_to_bytes)]` error: transmute from a `u32` to a `[u8; 4]` - --> tests/ui/transmute.rs:146:30 + --> tests/ui/transmute.rs:151:30 | LL | let _: [u8; 4] = std::mem::transmute(0u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()` error: transmute from a `u128` to a `[u8; 16]` - --> tests/ui/transmute.rs:148:31 + --> tests/ui/transmute.rs:153:31 | LL | let _: [u8; 16] = std::mem::transmute(0u128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()` error: transmute from a `i8` to a `[u8; 1]` - --> tests/ui/transmute.rs:150:30 + --> tests/ui/transmute.rs:155:30 | LL | let _: [u8; 1] = std::mem::transmute(0i8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()` error: transmute from a `i32` to a `[u8; 4]` - --> tests/ui/transmute.rs:152:30 + --> tests/ui/transmute.rs:157:30 | LL | let _: [u8; 4] = std::mem::transmute(0i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()` error: transmute from a `i128` to a `[u8; 16]` - --> tests/ui/transmute.rs:154:31 + --> tests/ui/transmute.rs:159:31 | LL | let _: [u8; 16] = std::mem::transmute(0i128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()` error: transmute from a `f32` to a `[u8; 4]` - --> tests/ui/transmute.rs:156:30 + --> tests/ui/transmute.rs:161:30 | LL | let _: [u8; 4] = std::mem::transmute(0.0f32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()` error: transmute from a `f64` to a `[u8; 8]` - --> tests/ui/transmute.rs:158:30 + --> tests/ui/transmute.rs:163:30 | LL | let _: [u8; 8] = std::mem::transmute(0.0f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()` error: transmute from a `u8` to a `[u8; 1]` - --> tests/ui/transmute.rs:164:30 + --> tests/ui/transmute.rs:169:30 | LL | let _: [u8; 1] = std::mem::transmute(0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()` error: transmute from a `u32` to a `[u8; 4]` - --> tests/ui/transmute.rs:166:30 + --> tests/ui/transmute.rs:171:30 | LL | let _: [u8; 4] = std::mem::transmute(0u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()` error: transmute from a `u128` to a `[u8; 16]` - --> tests/ui/transmute.rs:168:31 + --> tests/ui/transmute.rs:173:31 | LL | let _: [u8; 16] = std::mem::transmute(0u128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()` error: transmute from a `i8` to a `[u8; 1]` - --> tests/ui/transmute.rs:170:30 + --> tests/ui/transmute.rs:175:30 | LL | let _: [u8; 1] = std::mem::transmute(0i8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()` error: transmute from a `i32` to a `[u8; 4]` - --> tests/ui/transmute.rs:172:30 + --> tests/ui/transmute.rs:177:30 | LL | let _: [u8; 4] = std::mem::transmute(0i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()` error: transmute from a `i128` to a `[u8; 16]` - --> tests/ui/transmute.rs:174:31 + --> tests/ui/transmute.rs:179:31 | LL | let _: [u8; 16] = std::mem::transmute(0i128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()` error: transmute from a `&[u8]` to a `&str` - --> tests/ui/transmute.rs:185:28 + --> tests/ui/transmute.rs:190:28 | LL | let _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(B).unwrap()` @@ -221,13 +221,13 @@ 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:188:32 + --> tests/ui/transmute.rs:193: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:190:30 + --> tests/ui/transmute.rs:195:30 | LL | const _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_unchecked(B)` diff --git a/src/tools/clippy/tests/ui/transmute_collection.rs b/src/tools/clippy/tests/ui/transmute_collection.rs index 8bf454573355..e30b34a5d7d6 100644 --- a/src/tools/clippy/tests/ui/transmute_collection.rs +++ b/src/tools/clippy/tests/ui/transmute_collection.rs @@ -1,4 +1,5 @@ #![warn(clippy::unsound_collection_transmute)] +#![allow(clippy::missing_transmute_annotations)] use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque}; use std::mem::{transmute, MaybeUninit}; diff --git a/src/tools/clippy/tests/ui/transmute_collection.stderr b/src/tools/clippy/tests/ui/transmute_collection.stderr index f71fba6315ca..06db9321064b 100644 --- a/src/tools/clippy/tests/ui/transmute_collection.stderr +++ b/src/tools/clippy/tests/ui/transmute_collection.stderr @@ -1,5 +1,5 @@ error: transmute from `std::vec::Vec` to `std::vec::Vec` with mismatched layout is unsound - --> tests/ui/transmute_collection.rs:9:17 + --> tests/ui/transmute_collection.rs:10:17 | LL | let _ = transmute::<_, Vec>(vec![0u8]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,103 +8,103 @@ LL | let _ = transmute::<_, Vec>(vec![0u8]); = help: to override `-D warnings` add `#[allow(clippy::unsound_collection_transmute)]` error: transmute from `std::vec::Vec` to `std::vec::Vec<[u8; 4]>` with mismatched layout is unsound - --> tests/ui/transmute_collection.rs:13:17 + --> tests/ui/transmute_collection.rs:14:17 | LL | let _ = transmute::<_, Vec<[u8; 4]>>(vec![1234u32]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from `std::collections::VecDeque` to `std::collections::VecDeque` with mismatched layout is unsound - --> tests/ui/transmute_collection.rs:17:17 + --> tests/ui/transmute_collection.rs:18:17 | LL | let _ = transmute::<_, VecDeque>(VecDeque::::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from `std::collections::VecDeque<[u8; 4]>` to `std::collections::VecDeque` with mismatched layout is unsound - --> tests/ui/transmute_collection.rs:20:17 + --> tests/ui/transmute_collection.rs:21:17 | LL | let _ = transmute::<_, VecDeque>(VecDeque::<[u8; 4]>::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from `std::collections::BinaryHeap` to `std::collections::BinaryHeap` with mismatched layout is unsound - --> tests/ui/transmute_collection.rs:24:17 + --> tests/ui/transmute_collection.rs:25:17 | LL | let _ = transmute::<_, BinaryHeap>(BinaryHeap::::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from `std::collections::BinaryHeap<[u8; 4]>` to `std::collections::BinaryHeap` with mismatched layout is unsound - --> tests/ui/transmute_collection.rs:27:17 + --> tests/ui/transmute_collection.rs:28:17 | LL | let _ = transmute::<_, BinaryHeap>(BinaryHeap::<[u8; 4]>::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from `std::collections::BTreeSet` to `std::collections::BTreeSet` with mismatched layout is unsound - --> tests/ui/transmute_collection.rs:31:17 + --> tests/ui/transmute_collection.rs:32:17 | LL | let _ = transmute::<_, BTreeSet>(BTreeSet::::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from `std::collections::BTreeSet<[u8; 4]>` to `std::collections::BTreeSet` with mismatched layout is unsound - --> tests/ui/transmute_collection.rs:34:17 + --> tests/ui/transmute_collection.rs:35:17 | LL | let _ = transmute::<_, BTreeSet>(BTreeSet::<[u8; 4]>::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from `std::collections::HashSet` to `std::collections::HashSet` with mismatched layout is unsound - --> tests/ui/transmute_collection.rs:38:17 + --> tests/ui/transmute_collection.rs:39:17 | LL | let _ = transmute::<_, HashSet>(HashSet::::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from `std::collections::HashSet<[u8; 4]>` to `std::collections::HashSet` with mismatched layout is unsound - --> tests/ui/transmute_collection.rs:41:17 + --> tests/ui/transmute_collection.rs:42:17 | LL | let _ = transmute::<_, HashSet>(HashSet::<[u8; 4]>::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from `std::collections::BTreeMap` to `std::collections::BTreeMap` with mismatched layout is unsound - --> tests/ui/transmute_collection.rs:45:17 + --> tests/ui/transmute_collection.rs:46:17 | LL | let _ = transmute::<_, BTreeMap>(BTreeMap::::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from `std::collections::BTreeMap` to `std::collections::BTreeMap` with mismatched layout is unsound - --> tests/ui/transmute_collection.rs:47:17 + --> tests/ui/transmute_collection.rs:48:17 | LL | let _ = transmute::<_, BTreeMap>(BTreeMap::::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from `std::collections::BTreeMap` to `std::collections::BTreeMap` with mismatched layout is unsound - --> tests/ui/transmute_collection.rs:50:17 + --> tests/ui/transmute_collection.rs:51:17 | LL | let _ = transmute::<_, BTreeMap>(BTreeMap::::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from `std::collections::BTreeMap<[u8; 4], u32>` to `std::collections::BTreeMap` with mismatched layout is unsound - --> tests/ui/transmute_collection.rs:52:17 + --> tests/ui/transmute_collection.rs:53:17 | LL | let _ = transmute::<_, BTreeMap>(BTreeMap::<[u8; 4], u32>::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from `std::collections::HashMap` to `std::collections::HashMap` with mismatched layout is unsound - --> tests/ui/transmute_collection.rs:56:17 + --> tests/ui/transmute_collection.rs:57:17 | LL | let _ = transmute::<_, HashMap>(HashMap::::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from `std::collections::HashMap` to `std::collections::HashMap` with mismatched layout is unsound - --> tests/ui/transmute_collection.rs:58:17 + --> tests/ui/transmute_collection.rs:59:17 | LL | let _ = transmute::<_, HashMap>(HashMap::::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from `std::collections::HashMap` to `std::collections::HashMap` with mismatched layout is unsound - --> tests/ui/transmute_collection.rs:61:17 + --> tests/ui/transmute_collection.rs:62:17 | LL | let _ = transmute::<_, HashMap>(HashMap::::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from `std::collections::HashMap<[u8; 4], u32>` to `std::collections::HashMap` with mismatched layout is unsound - --> tests/ui/transmute_collection.rs:63:17 + --> tests/ui/transmute_collection.rs:64:17 | LL | let _ = transmute::<_, HashMap>(HashMap::<[u8; 4], u32>::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/transmute_float_to_int.fixed b/src/tools/clippy/tests/ui/transmute_float_to_int.fixed index cef0bcfa623a..82d5f7fdca10 100644 --- a/src/tools/clippy/tests/ui/transmute_float_to_int.fixed +++ b/src/tools/clippy/tests/ui/transmute_float_to_int.fixed @@ -1,4 +1,5 @@ #![warn(clippy::transmute_float_to_int)] +#![allow(clippy::missing_transmute_annotations)] fn float_to_int() { let _: u32 = unsafe { 1f32.to_bits() }; diff --git a/src/tools/clippy/tests/ui/transmute_float_to_int.rs b/src/tools/clippy/tests/ui/transmute_float_to_int.rs index 3d95bec2a20a..9f056330adf9 100644 --- a/src/tools/clippy/tests/ui/transmute_float_to_int.rs +++ b/src/tools/clippy/tests/ui/transmute_float_to_int.rs @@ -1,4 +1,5 @@ #![warn(clippy::transmute_float_to_int)] +#![allow(clippy::missing_transmute_annotations)] fn float_to_int() { let _: u32 = unsafe { std::mem::transmute(1f32) }; diff --git a/src/tools/clippy/tests/ui/transmute_float_to_int.stderr b/src/tools/clippy/tests/ui/transmute_float_to_int.stderr index e89258d9102a..ac3aae5f8b78 100644 --- a/src/tools/clippy/tests/ui/transmute_float_to_int.stderr +++ b/src/tools/clippy/tests/ui/transmute_float_to_int.stderr @@ -1,5 +1,5 @@ error: transmute from a `f32` to a `u32` - --> tests/ui/transmute_float_to_int.rs:4:27 + --> tests/ui/transmute_float_to_int.rs:5:27 | LL | let _: u32 = unsafe { std::mem::transmute(1f32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f32.to_bits()` @@ -8,31 +8,31 @@ LL | let _: u32 = unsafe { std::mem::transmute(1f32) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_float_to_int)]` error: transmute from a `f32` to a `i32` - --> tests/ui/transmute_float_to_int.rs:7:27 + --> tests/ui/transmute_float_to_int.rs:8:27 | LL | let _: i32 = unsafe { std::mem::transmute(1f32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f32.to_bits() as i32` error: transmute from a `f64` to a `u64` - --> tests/ui/transmute_float_to_int.rs:9:27 + --> tests/ui/transmute_float_to_int.rs:10:27 | LL | let _: u64 = unsafe { std::mem::transmute(1f64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f64.to_bits()` error: transmute from a `f64` to a `i64` - --> tests/ui/transmute_float_to_int.rs:11:27 + --> tests/ui/transmute_float_to_int.rs:12:27 | LL | let _: i64 = unsafe { std::mem::transmute(1f64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f64.to_bits() as i64` error: transmute from a `f64` to a `u64` - --> tests/ui/transmute_float_to_int.rs:13:27 + --> tests/ui/transmute_float_to_int.rs:14:27 | LL | let _: u64 = unsafe { std::mem::transmute(1.0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1.0f64.to_bits()` error: transmute from a `f64` to a `u64` - --> tests/ui/transmute_float_to_int.rs:15:27 + --> tests/ui/transmute_float_to_int.rs:16:27 | LL | let _: u64 = unsafe { std::mem::transmute(-1.0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-1.0f64).to_bits()` diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char.fixed b/src/tools/clippy/tests/ui/transmute_int_to_char.fixed index 170801181754..d3277d1b8c73 100644 --- a/src/tools/clippy/tests/ui/transmute_int_to_char.fixed +++ b/src/tools/clippy/tests/ui/transmute_int_to_char.fixed @@ -1,4 +1,5 @@ #![warn(clippy::transmute_int_to_char)] +#![allow(clippy::missing_transmute_annotations)] fn int_to_char() { let _: char = unsafe { std::char::from_u32(0_u32).unwrap() }; diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char.rs b/src/tools/clippy/tests/ui/transmute_int_to_char.rs index 5846a97e88ab..d21c4fd6fea3 100644 --- a/src/tools/clippy/tests/ui/transmute_int_to_char.rs +++ b/src/tools/clippy/tests/ui/transmute_int_to_char.rs @@ -1,4 +1,5 @@ #![warn(clippy::transmute_int_to_char)] +#![allow(clippy::missing_transmute_annotations)] fn int_to_char() { let _: char = unsafe { std::mem::transmute(0_u32) }; diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char.stderr b/src/tools/clippy/tests/ui/transmute_int_to_char.stderr index 8444afbd21ef..e3a3620f28b7 100644 --- a/src/tools/clippy/tests/ui/transmute_int_to_char.stderr +++ b/src/tools/clippy/tests/ui/transmute_int_to_char.stderr @@ -1,5 +1,5 @@ error: transmute from a `u32` to a `char` - --> tests/ui/transmute_int_to_char.rs:4:28 + --> tests/ui/transmute_int_to_char.rs:5:28 | LL | let _: char = unsafe { std::mem::transmute(0_u32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_u32).unwrap()` @@ -8,7 +8,7 @@ LL | let _: char = unsafe { std::mem::transmute(0_u32) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_char)]` error: transmute from a `i32` to a `char` - --> tests/ui/transmute_int_to_char.rs:7:28 + --> tests/ui/transmute_int_to_char.rs:8:28 | LL | let _: char = unsafe { std::mem::transmute(0_i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_i32 as u32).unwrap()` diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.fixed b/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.fixed index 9ae4e11fb56e..32a57645b46f 100644 --- a/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.fixed +++ b/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.fixed @@ -1,6 +1,7 @@ #![no_std] #![feature(lang_items)] #![warn(clippy::transmute_int_to_char)] +#![allow(clippy::missing_transmute_annotations)] use core::panic::PanicInfo; diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.rs b/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.rs index 9a2afd5bd2fd..942794c32f81 100644 --- a/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.rs +++ b/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.rs @@ -1,6 +1,7 @@ #![no_std] #![feature(lang_items)] #![warn(clippy::transmute_int_to_char)] +#![allow(clippy::missing_transmute_annotations)] use core::panic::PanicInfo; diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.stderr b/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.stderr index d2c3842b684e..d94580a84d7a 100644 --- a/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.stderr +++ b/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.stderr @@ -1,5 +1,5 @@ error: transmute from a `u32` to a `char` - --> tests/ui/transmute_int_to_char_no_std.rs:16:28 + --> tests/ui/transmute_int_to_char_no_std.rs:17:28 | LL | let _: char = unsafe { core::mem::transmute(0_u32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `core::char::from_u32(0_u32).unwrap()` @@ -8,7 +8,7 @@ LL | let _: char = unsafe { core::mem::transmute(0_u32) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_char)]` error: transmute from a `i32` to a `char` - --> tests/ui/transmute_int_to_char_no_std.rs:19:28 + --> tests/ui/transmute_int_to_char_no_std.rs:20:28 | LL | let _: char = unsafe { core::mem::transmute(0_i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `core::char::from_u32(0_i32 as u32).unwrap()` diff --git a/src/tools/clippy/tests/ui/transmute_int_to_non_zero.fixed b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.fixed index 866c0bbf1271..fe8db3dcb0cf 100644 --- a/src/tools/clippy/tests/ui/transmute_int_to_non_zero.fixed +++ b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.fixed @@ -1,4 +1,5 @@ #![warn(clippy::transmute_int_to_non_zero)] +#![allow(clippy::missing_transmute_annotations)] use core::num::*; diff --git a/src/tools/clippy/tests/ui/transmute_int_to_non_zero.rs b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.rs index 803c4945c755..a79ed5279b1f 100644 --- a/src/tools/clippy/tests/ui/transmute_int_to_non_zero.rs +++ b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.rs @@ -1,4 +1,5 @@ #![warn(clippy::transmute_int_to_non_zero)] +#![allow(clippy::missing_transmute_annotations)] use core::num::*; diff --git a/src/tools/clippy/tests/ui/transmute_int_to_non_zero.stderr b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.stderr index dd37bd210558..bb0b0d0ff4f0 100644 --- a/src/tools/clippy/tests/ui/transmute_int_to_non_zero.stderr +++ b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.stderr @@ -1,5 +1,5 @@ error: transmute from a `u8` to a `NonZeroU8` - --> tests/ui/transmute_int_to_non_zero.rs:18:33 + --> tests/ui/transmute_int_to_non_zero.rs:19:33 | LL | let _: NonZeroU8 = unsafe { std::mem::transmute(int_u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU8::new_unchecked(int_u8)` @@ -8,55 +8,55 @@ LL | let _: NonZeroU8 = unsafe { std::mem::transmute(int_u8) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_non_zero)]` error: transmute from a `u16` to a `NonZeroU16` - --> tests/ui/transmute_int_to_non_zero.rs:21:34 + --> tests/ui/transmute_int_to_non_zero.rs:22:34 | LL | let _: NonZeroU16 = unsafe { std::mem::transmute(int_u16) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU16::new_unchecked(int_u16)` error: transmute from a `u32` to a `NonZeroU32` - --> tests/ui/transmute_int_to_non_zero.rs:23:34 + --> tests/ui/transmute_int_to_non_zero.rs:24:34 | LL | let _: NonZeroU32 = unsafe { std::mem::transmute(int_u32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU32::new_unchecked(int_u32)` error: transmute from a `u64` to a `NonZeroU64` - --> tests/ui/transmute_int_to_non_zero.rs:25:34 + --> tests/ui/transmute_int_to_non_zero.rs:26:34 | LL | let _: NonZeroU64 = unsafe { std::mem::transmute(int_u64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU64::new_unchecked(int_u64)` error: transmute from a `u128` to a `NonZeroU128` - --> tests/ui/transmute_int_to_non_zero.rs:27:35 + --> tests/ui/transmute_int_to_non_zero.rs:28:35 | LL | let _: NonZeroU128 = unsafe { std::mem::transmute(int_u128) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU128::new_unchecked(int_u128)` error: transmute from a `i8` to a `NonZeroI8` - --> tests/ui/transmute_int_to_non_zero.rs:30:33 + --> tests/ui/transmute_int_to_non_zero.rs:31:33 | LL | let _: NonZeroI8 = unsafe { std::mem::transmute(int_i8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI8::new_unchecked(int_i8)` error: transmute from a `i16` to a `NonZeroI16` - --> tests/ui/transmute_int_to_non_zero.rs:32:34 + --> tests/ui/transmute_int_to_non_zero.rs:33:34 | LL | let _: NonZeroI16 = unsafe { std::mem::transmute(int_i16) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI16::new_unchecked(int_i16)` error: transmute from a `i32` to a `NonZeroI32` - --> tests/ui/transmute_int_to_non_zero.rs:34:34 + --> tests/ui/transmute_int_to_non_zero.rs:35:34 | LL | let _: NonZeroI32 = unsafe { std::mem::transmute(int_i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI32::new_unchecked(int_i32)` error: transmute from a `i64` to a `NonZeroI64` - --> tests/ui/transmute_int_to_non_zero.rs:36:34 + --> tests/ui/transmute_int_to_non_zero.rs:37:34 | LL | let _: NonZeroI64 = unsafe { std::mem::transmute(int_i64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI64::new_unchecked(int_i64)` error: transmute from a `i128` to a `NonZeroI128` - --> tests/ui/transmute_int_to_non_zero.rs:38:35 + --> tests/ui/transmute_int_to_non_zero.rs:39:35 | LL | let _: NonZeroI128 = unsafe { std::mem::transmute(int_i128) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI128::new_unchecked(int_i128)` diff --git a/src/tools/clippy/tests/ui/transmute_null_to_fn.rs b/src/tools/clippy/tests/ui/transmute_null_to_fn.rs index b07851e864f6..c0196ad52d43 100644 --- a/src/tools/clippy/tests/ui/transmute_null_to_fn.rs +++ b/src/tools/clippy/tests/ui/transmute_null_to_fn.rs @@ -1,6 +1,6 @@ #![allow(dead_code)] #![warn(clippy::transmute_null_to_fn)] -#![allow(clippy::zero_ptr)] +#![allow(clippy::zero_ptr, clippy::missing_transmute_annotations)] // Easy to lint because these only span one line. fn one_liners() { diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.fixed b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.fixed index 696def08f142..b696a574ae39 100644 --- a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.fixed +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.fixed @@ -1,5 +1,5 @@ #![warn(clippy::transmute_ptr_to_ptr)] -#![allow(clippy::borrow_as_ptr)] +#![allow(clippy::borrow_as_ptr, clippy::missing_transmute_annotations)] // Make sure we can modify lifetimes, which is one of the recommended uses // of transmute diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs index 0700d8c19576..85cc1d7802c2 100644 --- a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs @@ -1,5 +1,5 @@ #![warn(clippy::transmute_ptr_to_ptr)] -#![allow(clippy::borrow_as_ptr)] +#![allow(clippy::borrow_as_ptr, clippy::missing_transmute_annotations)] // Make sure we can modify lifetimes, which is one of the recommended uses // of transmute diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed index acec14ccb6b8..56330d719389 100644 --- a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed @@ -1,5 +1,9 @@ #![warn(clippy::transmute_ptr_to_ref)] -#![allow(clippy::match_single_binding, clippy::unnecessary_cast)] +#![allow( + clippy::match_single_binding, + clippy::unnecessary_cast, + clippy::missing_transmute_annotations +)] unsafe fn _ptr_to_ref(p: *const T, m: *mut T, o: *const U, om: *mut U) { let _: &T = &*p; diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs index 3376401e284b..ce1ee8bfbfae 100644 --- a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs @@ -1,5 +1,9 @@ #![warn(clippy::transmute_ptr_to_ref)] -#![allow(clippy::match_single_binding, clippy::unnecessary_cast)] +#![allow( + clippy::match_single_binding, + clippy::unnecessary_cast, + clippy::missing_transmute_annotations +)] unsafe fn _ptr_to_ref(p: *const T, m: *mut T, o: *const U, om: *mut U) { let _: &T = std::mem::transmute(p); diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr index d7d180398e1c..44cda254c3f7 100644 --- a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr @@ -1,5 +1,5 @@ error: transmute from a pointer type (`*const T`) to a reference type (`&T`) - --> tests/ui/transmute_ptr_to_ref.rs:5:17 + --> tests/ui/transmute_ptr_to_ref.rs:9:17 | LL | let _: &T = std::mem::transmute(p); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*p` @@ -8,127 +8,127 @@ LL | let _: &T = std::mem::transmute(p); = help: to override `-D warnings` add `#[allow(clippy::transmute_ptr_to_ref)]` error: transmute from a pointer type (`*mut T`) to a reference type (`&mut T`) - --> tests/ui/transmute_ptr_to_ref.rs:8:21 + --> tests/ui/transmute_ptr_to_ref.rs:12:21 | LL | let _: &mut T = std::mem::transmute(m); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *m` error: transmute from a pointer type (`*mut T`) to a reference type (`&T`) - --> tests/ui/transmute_ptr_to_ref.rs:11:17 + --> tests/ui/transmute_ptr_to_ref.rs:15:17 | LL | let _: &T = std::mem::transmute(m); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*m` error: transmute from a pointer type (`*mut T`) to a reference type (`&mut T`) - --> tests/ui/transmute_ptr_to_ref.rs:14:21 + --> tests/ui/transmute_ptr_to_ref.rs:18:21 | LL | let _: &mut T = std::mem::transmute(p as *mut T); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(p as *mut T)` error: transmute from a pointer type (`*const U`) to a reference type (`&T`) - --> tests/ui/transmute_ptr_to_ref.rs:17:17 + --> tests/ui/transmute_ptr_to_ref.rs:21:17 | LL | let _: &T = std::mem::transmute(o); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(o as *const T)` error: transmute from a pointer type (`*mut U`) to a reference type (`&mut T`) - --> tests/ui/transmute_ptr_to_ref.rs:20:21 + --> tests/ui/transmute_ptr_to_ref.rs:24:21 | LL | let _: &mut T = std::mem::transmute(om); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(om as *mut T)` error: transmute from a pointer type (`*mut U`) to a reference type (`&T`) - --> tests/ui/transmute_ptr_to_ref.rs:23:17 + --> tests/ui/transmute_ptr_to_ref.rs:27:17 | LL | let _: &T = std::mem::transmute(om); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(om as *const T)` error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<'_, u8>`) - --> tests/ui/transmute_ptr_to_ref.rs:33:32 + --> tests/ui/transmute_ptr_to_ref.rs:37:32 | LL | let _: &Foo = unsafe { std::mem::transmute::<_, &Foo<_>>(raw) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*raw.cast::>()` error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<'_, &u8>`) - --> tests/ui/transmute_ptr_to_ref.rs:35:33 + --> tests/ui/transmute_ptr_to_ref.rs:39:33 | LL | let _: &Foo<&u8> = unsafe { std::mem::transmute::<_, &Foo<&_>>(raw) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*raw.cast::>()` error: transmute from a pointer type (`*const i32`) to a reference type (`&u8`) - --> tests/ui/transmute_ptr_to_ref.rs:39:14 + --> tests/ui/transmute_ptr_to_ref.rs:43:14 | LL | unsafe { std::mem::transmute::<_, Bar>(raw) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(raw as *const u8)` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:44:14 + --> tests/ui/transmute_ptr_to_ref.rs:48:14 | LL | 0 => std::mem::transmute(x), | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&u32>()` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:45:14 + --> tests/ui/transmute_ptr_to_ref.rs:49:14 | LL | 1 => std::mem::transmute(y), | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*y.cast::<&u32>()` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:46:14 + --> tests/ui/transmute_ptr_to_ref.rs:50:14 | LL | 2 => std::mem::transmute::<_, &&'b u32>(x), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&'b u32>()` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:47:14 + --> tests/ui/transmute_ptr_to_ref.rs:51:14 | LL | _ => std::mem::transmute::<_, &&'b u32>(y), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*y.cast::<&'b u32>()` error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:55:19 + --> tests/ui/transmute_ptr_to_ref.rs:59:19 | LL | let _: &u32 = std::mem::transmute(a); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a` error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:56:19 + --> tests/ui/transmute_ptr_to_ref.rs:60:19 | LL | let _: &u32 = std::mem::transmute::<_, &u32>(a); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a.cast::()` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:58:14 + --> tests/ui/transmute_ptr_to_ref.rs:62:14 | LL | 0 => std::mem::transmute(x), | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&u32>()` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:59:14 + --> tests/ui/transmute_ptr_to_ref.rs:63:14 | LL | _ => std::mem::transmute::<_, &&'b u32>(x), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&'b u32>()` error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:67:19 + --> tests/ui/transmute_ptr_to_ref.rs:71:19 | LL | let _: &u32 = std::mem::transmute(a); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a` error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:68:19 + --> tests/ui/transmute_ptr_to_ref.rs:72:19 | LL | let _: &u32 = std::mem::transmute::<_, &u32>(a); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a as *const u32)` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:70:14 + --> tests/ui/transmute_ptr_to_ref.rs:74:14 | LL | 0 => std::mem::transmute(x), | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(x as *const () as *const &u32)` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> tests/ui/transmute_ptr_to_ref.rs:71:14 + --> tests/ui/transmute_ptr_to_ref.rs:75:14 | LL | _ => std::mem::transmute::<_, &&'b u32>(x), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(x as *const () as *const &'b u32)` diff --git a/src/tools/clippy/tests/ui/transmute_ref_to_ref.rs b/src/tools/clippy/tests/ui/transmute_ref_to_ref.rs index bdc7b9f64787..44d7af44a805 100644 --- a/src/tools/clippy/tests/ui/transmute_ref_to_ref.rs +++ b/src/tools/clippy/tests/ui/transmute_ref_to_ref.rs @@ -1,7 +1,7 @@ //@no-rustfix #![deny(clippy::transmute_ptr_to_ptr)] -#![allow(dead_code)] +#![allow(dead_code, clippy::missing_transmute_annotations)] fn main() { unsafe { diff --git a/src/tools/clippy/tests/ui/transmute_ref_to_ref_no_std.rs b/src/tools/clippy/tests/ui/transmute_ref_to_ref_no_std.rs index b67386f85885..591770587549 100644 --- a/src/tools/clippy/tests/ui/transmute_ref_to_ref_no_std.rs +++ b/src/tools/clippy/tests/ui/transmute_ref_to_ref_no_std.rs @@ -1,7 +1,7 @@ //@no-rustfix #![deny(clippy::transmute_ptr_to_ptr)] -#![allow(dead_code)] +#![allow(dead_code, clippy::missing_transmute_annotations)] #![feature(lang_items)] #![no_std] diff --git a/src/tools/clippy/tests/ui/transmute_undefined_repr.rs b/src/tools/clippy/tests/ui/transmute_undefined_repr.rs index a087d09c1202..dd4bac7f1ed7 100644 --- a/src/tools/clippy/tests/ui/transmute_undefined_repr.rs +++ b/src/tools/clippy/tests/ui/transmute_undefined_repr.rs @@ -1,5 +1,10 @@ #![warn(clippy::transmute_undefined_repr)] -#![allow(clippy::unit_arg, clippy::transmute_ptr_to_ref, clippy::useless_transmute)] +#![allow( + clippy::unit_arg, + clippy::transmute_ptr_to_ref, + clippy::useless_transmute, + clippy::missing_transmute_annotations +)] use core::any::TypeId; use core::ffi::c_void; diff --git a/src/tools/clippy/tests/ui/transmute_undefined_repr.stderr b/src/tools/clippy/tests/ui/transmute_undefined_repr.stderr index 5504fbe16e41..b41d37a5cd13 100644 --- a/src/tools/clippy/tests/ui/transmute_undefined_repr.stderr +++ b/src/tools/clippy/tests/ui/transmute_undefined_repr.stderr @@ -1,5 +1,5 @@ error: transmute from `Ty2` which has an undefined layout - --> tests/ui/transmute_undefined_repr.rs:29:33 + --> tests/ui/transmute_undefined_repr.rs:34:33 | LL | let _: Ty2C = transmute(value::>()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,13 +8,13 @@ LL | let _: Ty2C = transmute(value::>()); = help: to override `-D warnings` add `#[allow(clippy::transmute_undefined_repr)]` error: transmute into `Ty2` which has an undefined layout - --> tests/ui/transmute_undefined_repr.rs:33:32 + --> tests/ui/transmute_undefined_repr.rs:38:32 | LL | let _: Ty2 = transmute(value::>()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from `Ty>` to `Ty2`, both of which have an undefined layout - --> tests/ui/transmute_undefined_repr.rs:42:32 + --> tests/ui/transmute_undefined_repr.rs:47:32 | LL | let _: Ty2 = transmute(value::>>()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -22,7 +22,7 @@ LL | let _: Ty2 = transmute(value::>>()); = note: two instances of the same generic type (`Ty2`) may have different layouts error: transmute from `Ty2` to `Ty>`, both of which have an undefined layout - --> tests/ui/transmute_undefined_repr.rs:46:36 + --> tests/ui/transmute_undefined_repr.rs:51:36 | LL | let _: Ty> = transmute(value::>()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -30,7 +30,7 @@ LL | let _: Ty> = transmute(value::>()); = note: two instances of the same generic type (`Ty2`) may have different layouts error: transmute from `Ty<&Ty2>` to `&Ty2`, both of which have an undefined layout - --> tests/ui/transmute_undefined_repr.rs:54:33 + --> tests/ui/transmute_undefined_repr.rs:59:33 | LL | let _: &Ty2 = transmute(value::>>()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -38,7 +38,7 @@ LL | let _: &Ty2 = transmute(value::>>()); = note: two instances of the same generic type (`Ty2`) may have different layouts error: transmute from `&Ty2` to `Ty<&Ty2>`, both of which have an undefined layout - --> tests/ui/transmute_undefined_repr.rs:58:37 + --> tests/ui/transmute_undefined_repr.rs:63:37 | LL | let _: Ty<&Ty2> = transmute(value::<&Ty2>()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -46,7 +46,7 @@ LL | let _: Ty<&Ty2> = transmute(value::<&Ty2>()); = note: two instances of the same generic type (`Ty2`) may have different layouts error: transmute from `std::boxed::Box>` to `&mut Ty2`, both of which have an undefined layout - --> tests/ui/transmute_undefined_repr.rs:88:45 + --> tests/ui/transmute_undefined_repr.rs:93:45 | LL | let _: &'static mut Ty2 = transmute(value::>>()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -54,7 +54,7 @@ LL | let _: &'static mut Ty2 = transmute(value::` to `std::boxed::Box>`, both of which have an undefined layout - --> tests/ui/transmute_undefined_repr.rs:92:37 + --> tests/ui/transmute_undefined_repr.rs:97:37 | LL | let _: Box> = transmute(value::<&'static mut Ty2>()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -62,7 +62,7 @@ LL | let _: Box> = transmute(value::<&'static mut Ty2` which has an undefined layout - --> tests/ui/transmute_undefined_repr.rs:189:39 + --> tests/ui/transmute_undefined_repr.rs:194:39 | LL | let _: *const Ty2 = transmute(value::<*const Ty2C>>()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -70,7 +70,7 @@ LL | let _: *const Ty2 = transmute(value::<*const Ty2C` has an undefined layout error: transmute from `*const Ty2` which has an undefined layout - --> tests/ui/transmute_undefined_repr.rs:193:50 + --> tests/ui/transmute_undefined_repr.rs:198:50 | LL | let _: *const Ty2C> = transmute(value::<*const Ty2>()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -78,7 +78,7 @@ LL | let _: *const Ty2C> = transmute(value::<*const T = note: the contained type `Ty2` has an undefined layout error: transmute from `std::vec::Vec>` to `std::vec::Vec>`, both of which have an undefined layout - --> tests/ui/transmute_undefined_repr.rs:240:35 + --> tests/ui/transmute_undefined_repr.rs:245:35 | LL | let _: Vec> = transmute(value::>>()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -86,7 +86,7 @@ LL | let _: Vec> = transmute(value::>>()); = note: two instances of the same generic type (`Vec`) may have different layouts error: transmute from `std::vec::Vec>` to `std::vec::Vec>`, both of which have an undefined layout - --> tests/ui/transmute_undefined_repr.rs:244:35 + --> tests/ui/transmute_undefined_repr.rs:249:35 | LL | let _: Vec> = transmute(value::>>()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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 2365695d6914..51682da4a988 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 @@ -3,7 +3,7 @@ // would otherwise be responsible for #![warn(clippy::useless_transmute)] #![warn(clippy::transmute_ptr_to_ptr)] -#![allow(unused, clippy::borrow_as_ptr)] +#![allow(unused, clippy::borrow_as_ptr, clippy::missing_transmute_annotations)] use std::mem::{size_of, transmute}; 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 cd1607b4c199..e5fcdef7a1c3 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 @@ -3,7 +3,7 @@ // would otherwise be responsible for #![warn(clippy::useless_transmute)] #![warn(clippy::transmute_ptr_to_ptr)] -#![allow(unused, clippy::borrow_as_ptr)] +#![allow(unused, clippy::borrow_as_ptr, clippy::missing_transmute_annotations)] use std::mem::{size_of, transmute}; diff --git a/src/tools/clippy/tests/ui/transmuting_null.rs b/src/tools/clippy/tests/ui/transmuting_null.rs index 88b8c9965237..c2deb6b6c460 100644 --- a/src/tools/clippy/tests/ui/transmuting_null.rs +++ b/src/tools/clippy/tests/ui/transmuting_null.rs @@ -2,7 +2,7 @@ #![warn(clippy::transmuting_null)] #![allow(clippy::zero_ptr)] #![allow(clippy::transmute_ptr_to_ref)] -#![allow(clippy::eq_op)] +#![allow(clippy::eq_op, clippy::missing_transmute_annotations)] // Easy to lint because these only span one line. fn one_liners() { diff --git a/src/tools/clippy/tests/ui/type_id_on_box.fixed b/src/tools/clippy/tests/ui/type_id_on_box.fixed index 538c38b70e6b..3656043700fa 100644 --- a/src/tools/clippy/tests/ui/type_id_on_box.fixed +++ b/src/tools/clippy/tests/ui/type_id_on_box.fixed @@ -19,19 +19,37 @@ fn existential() -> impl Any { Box::new(1) as Box } +trait AnySubTrait: Any {} +impl AnySubTrait for T {} + fn main() { + // Don't lint, calling `.type_id()` on a `&dyn Any` does the expected thing + let ref_dyn: &dyn Any = &42; + let _ = ref_dyn.type_id(); + let any_box: Box = Box::new(0usize); let _ = (*any_box).type_id(); - let _ = TypeId::of::>(); // Don't lint. We explicitly say "do this instead" if this is intentional + //~^ ERROR: calling `.type_id()` on + + // Don't lint. We explicitly say "do this instead" if this is intentional + let _ = TypeId::of::>(); let _ = (*any_box).type_id(); + + // 2 derefs are needed here to get to the `dyn Any` let any_box: &Box = &(Box::new(0usize) as Box); - let _ = (**any_box).type_id(); // 2 derefs are needed here to get to the `dyn Any` + let _ = (**any_box).type_id(); + //~^ ERROR: calling `.type_id()` on let b = existential(); - let _ = b.type_id(); // Don't lint. + let _ = b.type_id(); // Don't + + let b: Box = Box::new(1); + let _ = (*b).type_id(); + //~^ ERROR: calling `.type_id()` on let b: SomeBox = Box::new(0usize); let _ = (*b).type_id(); + //~^ ERROR: calling `.type_id()` on let b = BadBox(Box::new(0usize)); let _ = b.type_id(); // Don't lint. This is a call to `::type_id`. Not `std::boxed::Box`! diff --git a/src/tools/clippy/tests/ui/type_id_on_box.rs b/src/tools/clippy/tests/ui/type_id_on_box.rs index f224d273bc23..4bd9e73f2da0 100644 --- a/src/tools/clippy/tests/ui/type_id_on_box.rs +++ b/src/tools/clippy/tests/ui/type_id_on_box.rs @@ -19,19 +19,37 @@ fn existential() -> impl Any { Box::new(1) as Box } +trait AnySubTrait: Any {} +impl AnySubTrait for T {} + fn main() { + // Don't lint, calling `.type_id()` on a `&dyn Any` does the expected thing + let ref_dyn: &dyn Any = &42; + let _ = ref_dyn.type_id(); + let any_box: Box = Box::new(0usize); let _ = any_box.type_id(); - let _ = TypeId::of::>(); // Don't lint. We explicitly say "do this instead" if this is intentional + //~^ ERROR: calling `.type_id()` on + + // Don't lint. We explicitly say "do this instead" if this is intentional + let _ = TypeId::of::>(); let _ = (*any_box).type_id(); + + // 2 derefs are needed here to get to the `dyn Any` let any_box: &Box = &(Box::new(0usize) as Box); - let _ = any_box.type_id(); // 2 derefs are needed here to get to the `dyn Any` + let _ = any_box.type_id(); + //~^ ERROR: calling `.type_id()` on let b = existential(); - let _ = b.type_id(); // Don't lint. + let _ = b.type_id(); // Don't + + let b: Box = Box::new(1); + let _ = b.type_id(); + //~^ ERROR: calling `.type_id()` on let b: SomeBox = Box::new(0usize); let _ = b.type_id(); + //~^ ERROR: calling `.type_id()` on let b = BadBox(Box::new(0usize)); let _ = b.type_id(); // Don't lint. This is a call to `::type_id`. Not `std::boxed::Box`! diff --git a/src/tools/clippy/tests/ui/type_id_on_box.stderr b/src/tools/clippy/tests/ui/type_id_on_box.stderr index 0fce6a37c004..4528195607da 100644 --- a/src/tools/clippy/tests/ui/type_id_on_box.stderr +++ b/src/tools/clippy/tests/ui/type_id_on_box.stderr @@ -1,37 +1,48 @@ -error: calling `.type_id()` on a `Box` - --> tests/ui/type_id_on_box.rs:24:13 +error: calling `.type_id()` on `Box` + --> tests/ui/type_id_on_box.rs:31:13 | LL | let _ = any_box.type_id(); | -------^^^^^^^^^^ | | | help: consider dereferencing first: `(*any_box)` | - = note: this returns the type id of the literal type `Box` instead of the type id of the boxed value, which is most likely not what you want + = note: this returns the type id of the literal type `Box<_>` instead of the type id of the boxed value, which is most likely not what you want = note: if this is intentional, use `TypeId::of::>()` instead, which makes it more clear = note: `-D clippy::type-id-on-box` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::type_id_on_box)]` -error: calling `.type_id()` on a `Box` - --> tests/ui/type_id_on_box.rs:28:13 +error: calling `.type_id()` on `Box` + --> tests/ui/type_id_on_box.rs:40:13 | -LL | let _ = any_box.type_id(); // 2 derefs are needed here to get to the `dyn Any` +LL | let _ = any_box.type_id(); | -------^^^^^^^^^^ | | | help: consider dereferencing first: `(**any_box)` | - = note: this returns the type id of the literal type `Box` instead of the type id of the boxed value, which is most likely not what you want + = note: this returns the type id of the literal type `Box<_>` instead of the type id of the boxed value, which is most likely not what you want = note: if this is intentional, use `TypeId::of::>()` instead, which makes it more clear -error: calling `.type_id()` on a `Box` - --> tests/ui/type_id_on_box.rs:34:13 +error: calling `.type_id()` on `Box` + --> tests/ui/type_id_on_box.rs:47:13 | LL | let _ = b.type_id(); | -^^^^^^^^^^ | | | help: consider dereferencing first: `(*b)` | - = note: this returns the type id of the literal type `Box` instead of the type id of the boxed value, which is most likely not what you want + = note: this returns the type id of the literal type `Box<_>` instead of the type id of the boxed value, which is most likely not what you want + = note: if this is intentional, use `TypeId::of::>()` instead, which makes it more clear + +error: calling `.type_id()` on `Box` + --> tests/ui/type_id_on_box.rs:51:13 + | +LL | let _ = b.type_id(); + | -^^^^^^^^^^ + | | + | help: consider dereferencing first: `(*b)` + | + = note: this returns the type id of the literal type `Box<_>` instead of the type id of the boxed value, which is most likely not what you want = note: if this is intentional, use `TypeId::of::>()` instead, which makes it more clear -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/type_id_on_box_unfixable.rs b/src/tools/clippy/tests/ui/type_id_on_box_unfixable.rs new file mode 100644 index 000000000000..f6d09834adb1 --- /dev/null +++ b/src/tools/clippy/tests/ui/type_id_on_box_unfixable.rs @@ -0,0 +1,31 @@ +#![warn(clippy::type_id_on_box)] + +use std::any::{Any, TypeId}; +use std::ops::Deref; + +trait AnySubTrait: Any {} +impl AnySubTrait for T {} + +// `Any` is an indirect supertrait +trait AnySubSubTrait: AnySubTrait {} +impl AnySubSubTrait for T {} + +// This trait mentions `Any` in its predicates, but it is not a subtrait of `Any`. +trait NormalTrait +where + i32: Any, +{ +} +impl NormalTrait for T {} + +fn main() { + // (currently we don't look deeper than one level into the supertrait hierachy, but we probably + // could) + let b: Box = Box::new(1); + let _ = b.type_id(); + //~^ ERROR: calling `.type_id()` on + + let b: Box = Box::new(1); + let _ = b.type_id(); + //~^ ERROR: calling `.type_id()` on +} diff --git a/src/tools/clippy/tests/ui/type_id_on_box_unfixable.stderr b/src/tools/clippy/tests/ui/type_id_on_box_unfixable.stderr new file mode 100644 index 000000000000..539ed481ec10 --- /dev/null +++ b/src/tools/clippy/tests/ui/type_id_on_box_unfixable.stderr @@ -0,0 +1,22 @@ +error: calling `.type_id()` on `Box` + --> tests/ui/type_id_on_box_unfixable.rs:25:13 + | +LL | let _ = b.type_id(); + | ^^^^^^^^^^^ + | + = note: this returns the type id of the literal type `Box<_>` instead of the type id of the boxed value, which is most likely not what you want + = note: if this is intentional, use `TypeId::of::>()` instead, which makes it more clear + = note: `-D clippy::type-id-on-box` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::type_id_on_box)]` + +error: calling `.type_id()` on `Box` + --> tests/ui/type_id_on_box_unfixable.rs:29:13 + | +LL | let _ = b.type_id(); + | ^^^^^^^^^^^ + | + = note: this returns the type id of the literal type `Box<_>` instead of the type id of the boxed value, which is most likely not what you want + = note: if this is intentional, use `TypeId::of::>()` instead, which makes it more clear + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/uninhabited_references.rs b/src/tools/clippy/tests/ui/uninhabited_references.rs index cd07b590a616..3569366ed056 100644 --- a/src/tools/clippy/tests/ui/uninhabited_references.rs +++ b/src/tools/clippy/tests/ui/uninhabited_references.rs @@ -1,4 +1,5 @@ #![warn(clippy::uninhabited_references)] +#![allow(clippy::missing_transmute_annotations)] #![feature(never_type)] fn ret_uninh_ref() -> &'static std::convert::Infallible { diff --git a/src/tools/clippy/tests/ui/uninhabited_references.stderr b/src/tools/clippy/tests/ui/uninhabited_references.stderr index 446d4e755570..8c9b206f4296 100644 --- a/src/tools/clippy/tests/ui/uninhabited_references.stderr +++ b/src/tools/clippy/tests/ui/uninhabited_references.stderr @@ -1,5 +1,5 @@ error: dereferencing a reference to an uninhabited type would be undefined behavior - --> tests/ui/uninhabited_references.rs:4:23 + --> tests/ui/uninhabited_references.rs:5:23 | LL | fn ret_uninh_ref() -> &'static std::convert::Infallible { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | fn ret_uninh_ref() -> &'static std::convert::Infallible { = help: to override `-D warnings` add `#[allow(clippy::uninhabited_references)]` error: dereferencing a reference to an uninhabited type would be undefined behavior - --> tests/ui/uninhabited_references.rs:10:30 + --> tests/ui/uninhabited_references.rs:11:30 | LL | fn $name(x: &$ty) -> &$ty { | ^^^^ @@ -19,7 +19,7 @@ LL | ret_something!(id_never, !); = note: this error originates in the macro `ret_something` (in Nightly builds, run with -Z macro-backtrace for more info) error: dereferencing a reference to an uninhabited type is undefined behavior - --> tests/ui/uninhabited_references.rs:11:14 + --> tests/ui/uninhabited_references.rs:12:14 | LL | &*x | ^^ @@ -30,7 +30,7 @@ LL | ret_something!(id_never, !); = note: this error originates in the macro `ret_something` (in Nightly builds, run with -Z macro-backtrace for more info) error: dereferencing a reference to an uninhabited type is undefined behavior - --> tests/ui/uninhabited_references.rs:21:13 + --> tests/ui/uninhabited_references.rs:22:13 | LL | let _ = *x; | ^^ diff --git a/src/tools/clippy/tests/ui/use_self.fixed b/src/tools/clippy/tests/ui/use_self.fixed index 6ea7857a238d..ffc5b74d7bd6 100644 --- a/src/tools/clippy/tests/ui/use_self.fixed +++ b/src/tools/clippy/tests/ui/use_self.fixed @@ -7,7 +7,8 @@ clippy::upper_case_acronyms, clippy::from_over_into, clippy::self_named_constructors, - clippy::needless_lifetimes + clippy::needless_lifetimes, + clippy::missing_transmute_annotations )] #[macro_use] diff --git a/src/tools/clippy/tests/ui/use_self.rs b/src/tools/clippy/tests/ui/use_self.rs index 338cc00e45a8..eb9d96168bcd 100644 --- a/src/tools/clippy/tests/ui/use_self.rs +++ b/src/tools/clippy/tests/ui/use_self.rs @@ -7,7 +7,8 @@ clippy::upper_case_acronyms, clippy::from_over_into, clippy::self_named_constructors, - clippy::needless_lifetimes + clippy::needless_lifetimes, + clippy::missing_transmute_annotations )] #[macro_use] diff --git a/src/tools/clippy/tests/ui/use_self.stderr b/src/tools/clippy/tests/ui/use_self.stderr index d7aa8410a47b..bd5b685b45d5 100644 --- a/src/tools/clippy/tests/ui/use_self.stderr +++ b/src/tools/clippy/tests/ui/use_self.stderr @@ -1,5 +1,5 @@ error: unnecessary structure name repetition - --> tests/ui/use_self.rs:22:21 + --> tests/ui/use_self.rs:23:21 | LL | fn new() -> Foo { | ^^^ help: use the applicable keyword: `Self` @@ -8,253 +8,253 @@ LL | fn new() -> Foo { = help: to override `-D warnings` add `#[allow(clippy::use_self)]` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:23:13 + --> tests/ui/use_self.rs:24:13 | LL | Foo {} | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:25:22 + --> tests/ui/use_self.rs:26:22 | LL | fn test() -> Foo { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:26:13 + --> tests/ui/use_self.rs:27:13 | LL | Foo::new() | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:31:25 + --> tests/ui/use_self.rs:32:25 | LL | fn default() -> Foo { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:32:13 + --> tests/ui/use_self.rs:33:13 | LL | Foo::new() | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:73:28 + --> tests/ui/use_self.rs:74:28 | LL | fn clone(&self) -> Foo<'a> { | ^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:106:24 + --> tests/ui/use_self.rs:107:24 | LL | fn bad(foos: &[Foo]) -> impl Iterator { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:106:55 + --> tests/ui/use_self.rs:107:55 | LL | fn bad(foos: &[Foo]) -> impl Iterator { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:121:13 + --> tests/ui/use_self.rs:122:13 | LL | TS(0) | ^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:156:29 + --> tests/ui/use_self.rs:157:29 | LL | fn bar() -> Bar { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:157:21 + --> tests/ui/use_self.rs:158:21 | LL | Bar { foo: Foo {} } | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:168:21 + --> tests/ui/use_self.rs:169:21 | LL | fn baz() -> Foo { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:169:13 + --> tests/ui/use_self.rs:170:13 | LL | Foo {} | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:186:21 + --> tests/ui/use_self.rs:187:21 | LL | let _ = Enum::B(42); | ^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:187:21 + --> tests/ui/use_self.rs:188:21 | LL | let _ = Enum::C { field: true }; | ^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:188:21 + --> tests/ui/use_self.rs:189:21 | LL | let _ = Enum::A; | ^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:230:13 + --> tests/ui/use_self.rs:231:13 | LL | nested::A::fun_1(); | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:231:13 + --> tests/ui/use_self.rs:232:13 | LL | nested::A::A; | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:233:13 + --> tests/ui/use_self.rs:234:13 | LL | nested::A {}; | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:252:13 + --> tests/ui/use_self.rs:253:13 | LL | TestStruct::from_something() | ^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:266:25 + --> tests/ui/use_self.rs:267:25 | LL | async fn g() -> S { | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:267:13 + --> tests/ui/use_self.rs:268:13 | LL | S {} | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:271:16 + --> tests/ui/use_self.rs:272:16 | LL | &p[S::A..S::B] | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:271:22 + --> tests/ui/use_self.rs:272:22 | LL | &p[S::A..S::B] | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:294:29 + --> tests/ui/use_self.rs:295:29 | LL | fn foo(value: T) -> Foo { | ^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:295:13 + --> tests/ui/use_self.rs:296:13 | LL | Foo:: { value } | ^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:467:13 + --> tests/ui/use_self.rs:468:13 | LL | A::new::(submod::B {}) | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:504:13 + --> tests/ui/use_self.rs:505:13 | LL | S2::new() | ^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:541:17 + --> tests/ui/use_self.rs:542:17 | LL | Foo::Bar => unimplemented!(), | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:542:17 + --> tests/ui/use_self.rs:543:17 | LL | Foo::Baz => unimplemented!(), | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:548:20 + --> tests/ui/use_self.rs:549:20 | LL | if let Foo::Bar = self { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:572:17 + --> tests/ui/use_self.rs:573:17 | LL | Something::Num(n) => *n, | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:573:17 + --> tests/ui/use_self.rs:574:17 | LL | Something::TupleNums(n, _m) => *n, | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:574:17 + --> tests/ui/use_self.rs:575:17 | LL | Something::StructNums { one, two: _ } => *one, | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:580:17 + --> tests/ui/use_self.rs:581:17 | LL | crate::issue8845::Something::Num(n) => *n, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:581:17 + --> tests/ui/use_self.rs:582:17 | LL | crate::issue8845::Something::TupleNums(n, _m) => *n, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:582:17 + --> tests/ui/use_self.rs:583:17 | LL | crate::issue8845::Something::StructNums { one, two: _ } => *one, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:598:17 + --> tests/ui/use_self.rs:599:17 | LL | let Foo(x) = self; | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:603:17 + --> tests/ui/use_self.rs:604:17 | LL | let crate::issue8845::Foo(x) = self; | ^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:610:17 + --> tests/ui/use_self.rs:611:17 | LL | let Bar { x, .. } = self; | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:615:17 + --> tests/ui/use_self.rs:616:17 | LL | let crate::issue8845::Bar { x, .. } = self; | ^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:654:17 + --> tests/ui/use_self.rs:655:17 | LL | E::A => {}, | ^ help: use the applicable keyword: `Self` diff --git a/src/tools/clippy/tests/ui/useless_asref.fixed b/src/tools/clippy/tests/ui/useless_asref.fixed index c98f2928e03c..ddbb9255b466 100644 --- a/src/tools/clippy/tests/ui/useless_asref.fixed +++ b/src/tools/clippy/tests/ui/useless_asref.fixed @@ -8,6 +8,8 @@ )] use std::fmt::Debug; +use std::rc::{Rc, Weak as RcWeak}; +use std::sync::{Arc, Weak as ArcWeak}; struct FakeAsRef; @@ -180,6 +182,22 @@ mod issue12135 { } } +fn issue_12528() { + struct Foo; + + let opt = Some(Arc::new(Foo)); + let _ = opt.as_ref().map(Arc::clone); + + let opt = Some(Rc::new(Foo)); + let _ = opt.as_ref().map(Rc::clone); + + let opt = Some(Arc::downgrade(&Arc::new(Foo))); + let _ = opt.as_ref().map(ArcWeak::clone); + + let opt = Some(Rc::downgrade(&Rc::new(Foo))); + let _ = opt.as_ref().map(RcWeak::clone); +} + fn main() { not_ok(); ok(); diff --git a/src/tools/clippy/tests/ui/useless_asref.rs b/src/tools/clippy/tests/ui/useless_asref.rs index f9d603f116de..b0405e930a25 100644 --- a/src/tools/clippy/tests/ui/useless_asref.rs +++ b/src/tools/clippy/tests/ui/useless_asref.rs @@ -8,6 +8,8 @@ )] use std::fmt::Debug; +use std::rc::{Rc, Weak as RcWeak}; +use std::sync::{Arc, Weak as ArcWeak}; struct FakeAsRef; @@ -180,6 +182,22 @@ mod issue12135 { } } +fn issue_12528() { + struct Foo; + + let opt = Some(Arc::new(Foo)); + let _ = opt.as_ref().map(Arc::clone); + + let opt = Some(Rc::new(Foo)); + let _ = opt.as_ref().map(Rc::clone); + + let opt = Some(Arc::downgrade(&Arc::new(Foo))); + let _ = opt.as_ref().map(ArcWeak::clone); + + let opt = Some(Rc::downgrade(&Rc::new(Foo))); + let _ = opt.as_ref().map(RcWeak::clone); +} + fn main() { not_ok(); ok(); diff --git a/src/tools/clippy/tests/ui/useless_asref.stderr b/src/tools/clippy/tests/ui/useless_asref.stderr index c7d622ec2dca..5f495c396705 100644 --- a/src/tools/clippy/tests/ui/useless_asref.stderr +++ b/src/tools/clippy/tests/ui/useless_asref.stderr @@ -1,5 +1,5 @@ error: this call to `as_ref` does nothing - --> tests/ui/useless_asref.rs:48:18 + --> tests/ui/useless_asref.rs:50:18 | LL | foo_rstr(rstr.as_ref()); | ^^^^^^^^^^^^^ help: try: `rstr` @@ -11,103 +11,103 @@ LL | #![deny(clippy::useless_asref)] | ^^^^^^^^^^^^^^^^^^^^^ error: this call to `as_ref` does nothing - --> tests/ui/useless_asref.rs:50:20 + --> tests/ui/useless_asref.rs:52:20 | LL | foo_rslice(rslice.as_ref()); | ^^^^^^^^^^^^^^^ help: try: `rslice` error: this call to `as_mut` does nothing - --> tests/ui/useless_asref.rs:54:21 + --> tests/ui/useless_asref.rs:56:21 | LL | foo_mrslice(mrslice.as_mut()); | ^^^^^^^^^^^^^^^^ help: try: `mrslice` error: this call to `as_ref` does nothing - --> tests/ui/useless_asref.rs:56:20 + --> tests/ui/useless_asref.rs:58:20 | LL | foo_rslice(mrslice.as_ref()); | ^^^^^^^^^^^^^^^^ help: try: `mrslice` error: this call to `as_ref` does nothing - --> tests/ui/useless_asref.rs:63:20 + --> tests/ui/useless_asref.rs:65:20 | LL | foo_rslice(rrrrrslice.as_ref()); | ^^^^^^^^^^^^^^^^^^^ help: try: `rrrrrslice` error: this call to `as_ref` does nothing - --> tests/ui/useless_asref.rs:65:18 + --> tests/ui/useless_asref.rs:67:18 | LL | foo_rstr(rrrrrstr.as_ref()); | ^^^^^^^^^^^^^^^^^ help: try: `rrrrrstr` error: this call to `as_mut` does nothing - --> tests/ui/useless_asref.rs:70:21 + --> tests/ui/useless_asref.rs:72:21 | LL | foo_mrslice(mrrrrrslice.as_mut()); | ^^^^^^^^^^^^^^^^^^^^ help: try: `mrrrrrslice` error: this call to `as_ref` does nothing - --> tests/ui/useless_asref.rs:72:20 + --> tests/ui/useless_asref.rs:74:20 | LL | foo_rslice(mrrrrrslice.as_ref()); | ^^^^^^^^^^^^^^^^^^^^ help: try: `mrrrrrslice` error: this call to `as_ref` does nothing - --> tests/ui/useless_asref.rs:76:16 + --> tests/ui/useless_asref.rs:78:16 | LL | foo_rrrrmr((&&&&MoreRef).as_ref()); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `(&&&&MoreRef)` error: this call to `as_mut` does nothing - --> tests/ui/useless_asref.rs:126:13 + --> tests/ui/useless_asref.rs:128:13 | LL | foo_mrt(mrt.as_mut()); | ^^^^^^^^^^^^ help: try: `mrt` error: this call to `as_ref` does nothing - --> tests/ui/useless_asref.rs:128:12 + --> tests/ui/useless_asref.rs:130:12 | LL | foo_rt(mrt.as_ref()); | ^^^^^^^^^^^^ help: try: `mrt` error: this call to `as_ref.map(...)` does nothing - --> tests/ui/useless_asref.rs:139:13 + --> tests/ui/useless_asref.rs:141:13 | LL | let z = x.as_ref().map(String::clone); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.clone()` error: this call to `as_ref.map(...)` does nothing - --> tests/ui/useless_asref.rs:141:13 + --> tests/ui/useless_asref.rs:143:13 | LL | let z = x.as_ref().map(|z| z.clone()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.clone()` error: this call to `as_ref.map(...)` does nothing - --> tests/ui/useless_asref.rs:143:13 + --> tests/ui/useless_asref.rs:145:13 | LL | let z = x.as_ref().map(|z| String::clone(z)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.clone()` error: this call to `as_ref.map(...)` does nothing - --> tests/ui/useless_asref.rs:167:9 + --> tests/ui/useless_asref.rs:169:9 | LL | x.field.as_ref().map(|v| v.clone()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.field.clone()` error: this call to `as_ref.map(...)` does nothing - --> tests/ui/useless_asref.rs:169:9 + --> tests/ui/useless_asref.rs:171:9 | LL | x.field.as_ref().map(Clone::clone); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.field.clone()` error: this call to `as_ref.map(...)` does nothing - --> tests/ui/useless_asref.rs:171:9 + --> tests/ui/useless_asref.rs:173:9 | LL | x.field.as_ref().map(|v| Clone::clone(v)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.field.clone()` error: this call to `as_ref.map(...)` does nothing - --> tests/ui/useless_asref.rs:176:9 + --> tests/ui/useless_asref.rs:178:9 | LL | Some(1).as_ref().map(|&x| x.clone()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(1).clone()` diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml index d455d967e30c..d8131044ff2e 100644 --- a/src/tools/clippy/triagebot.toml +++ b/src/tools/clippy/triagebot.toml @@ -19,7 +19,7 @@ new_pr = true [assign] contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md" -users_on_vacation = [] +users_on_vacation = ["y21"] [assign.owners] "/.github" = ["@flip1995"] diff --git a/src/tools/compiletest/src/raise_fd_limit.rs b/src/tools/compiletest/src/raise_fd_limit.rs index bc2946e2c135..a4235381beb6 100644 --- a/src/tools/compiletest/src/raise_fd_limit.rs +++ b/src/tools/compiletest/src/raise_fd_limit.rs @@ -4,7 +4,7 @@ /// on the number of cores available. /// /// This fixes issue #7772. -#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] +#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos", target_os = "visionos"))] #[allow(non_camel_case_types)] pub unsafe fn raise_fd_limit() { use std::cmp; diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index bd2f65925bb9..689fdc5dfebc 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -3926,11 +3926,17 @@ impl<'test> TestCx<'test> { cmd.env("IS_MSVC", "1") .env("IS_WINDOWS", "1") .env("MSVC_LIB", format!("'{}' -nologo", lib.display())) - .env("CC", format!("'{}' {}", self.config.cc, cflags)) - .env("CXX", format!("'{}' {}", &self.config.cxx, cxxflags)); + // Note: we diverge from legacy run_make and don't lump `CC` the compiler and + // default flags together. + .env("CC_DEFAULT_FLAGS", &cflags) + .env("CC", &self.config.cc) + .env("CXX_DEFAULT_FLAGS", &cxxflags) + .env("CXX", &self.config.cxx); } else { - cmd.env("CC", format!("{} {}", self.config.cc, self.config.cflags)) - .env("CXX", format!("{} {}", self.config.cxx, self.config.cxxflags)) + cmd.env("CC_DEFAULT_FLAGS", &self.config.cflags) + .env("CC", &self.config.cc) + .env("CXX_DEFAULT_FLAGS", &self.config.cxxflags) + .env("CXX", &self.config.cxx) .env("AR", &self.config.ar); if self.config.target.contains("windows") { diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index 11b777808330..60a1c1fa1dd2 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -507,6 +507,8 @@ binaries, and as such worth documenting: crate currently being compiled. * `MIRI_ORIG_RUSTDOC` is set and read by different phases of `cargo-miri` to remember the value of `RUSTDOC` from before it was overwritten. +* `MIRI_REPLACE_LIBRS_IF_NOT_TEST` when set to any value enables a hack that helps bootstrap + run the standard library tests in Miri. * `MIRI_VERBOSE` when set to any value tells the various `cargo-miri` phases to perform verbose logging. * `MIRI_HOST_SYSROOT` is set by bootstrap to tell `cargo-miri` which sysroot to use for *host* diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs index 694720ab21f2..3f6c484a057d 100644 --- a/src/tools/miri/cargo-miri/src/phases.rs +++ b/src/tools/miri/cargo-miri/src/phases.rs @@ -3,7 +3,7 @@ use std::env; use std::fs::{self, File}; use std::io::BufReader; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::process::Command; use rustc_version::VersionMeta; @@ -412,9 +412,25 @@ pub fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { // Arguments are treated very differently depending on whether this crate is // for interpretation by Miri, or for use by a build script / proc macro. if target_crate { - // Forward arguments, but remove "link" from "--emit" to make this a check-only build. + // Forward arguments, but patched. let emit_flag = "--emit"; + // This hack helps bootstrap run standard library tests in Miri. The issue is as follows: + // when running `cargo miri test` on libcore, cargo builds a local copy of core and makes it + // a dependency of the integration test crate. This copy duplicates all the lang items, so + // the build fails. (Regular testing avoids this because the sysroot is a literal copy of + // what `cargo build` produces, but since Miri builds its own sysroot this does not work for + // us.) So we need to make it so that the locally built libcore contains all the items from + // `core`, but does not re-define them -- we want to replace the entire crate but a + // re-export of the sysroot crate. We do this by swapping out the source file: if + // `MIRI_REPLACE_LIBRS_IF_NOT_TEST` is set and we are building a `lib.rs` file, and a + // `lib.miri.rs` file exists in the same folder, we build that instead. But crucially we + // only do that for the library, not the unit test crate (which would be runnable) or + // rustdoc (which would have a different `phase`). + let replace_librs = env::var_os("MIRI_REPLACE_LIBRS_IF_NOT_TEST").is_some() + && !runnable_crate + && phase == RustcPhase::Build; while let Some(arg) = args.next() { + // Patch `--emit`: remove "link" from "--emit" to make this a check-only build. if let Some(val) = arg.strip_prefix(emit_flag) { // Patch this argument. First, extract its value. let val = @@ -429,13 +445,36 @@ pub fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { } } cmd.arg(format!("{emit_flag}={}", val.join(","))); - } else if arg == "--extern" { - // Patch `--extern` filenames, since Cargo sometimes passes stub `.rlib` files: - // https://github.com/rust-lang/miri/issues/1705 - forward_patched_extern_arg(&mut args, &mut cmd); - } else { - cmd.arg(arg); + continue; } + // Patch `--extern` filenames, since Cargo sometimes passes stub `.rlib` files: + // https://github.com/rust-lang/miri/issues/1705 + if arg == "--extern" { + forward_patched_extern_arg(&mut args, &mut cmd); + continue; + } + // If the REPLACE_LIBRS hack is enabled and we are building a `lib.rs` file, and a + // `lib.miri.rs` file exists, then build that instead. We only consider relative paths + // as cargo uses those for files in the workspace; dependencies from crates.io get + // absolute paths. + if replace_librs { + let path = Path::new(&arg); + if path.is_relative() + && path.file_name().is_some_and(|f| f == "lib.rs") + && path.is_file() + { + let miri_rs = Path::new(&arg).with_extension("miri.rs"); + if miri_rs.is_file() { + if verbose > 0 { + eprintln!("Performing REPLACE_LIBRS hack: {arg:?} -> {miri_rs:?}"); + } + cmd.arg(miri_rs); + continue; + } + } + } + // Fallback: just propagate the argument. + cmd.arg(arg); } // During setup, patch the panic runtime for `libpanic_abort` (mirroring what bootstrap usually does). diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 02e2e6459fbf..6ad8fba723c8 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -0accf4ec4c07d23aa86f6a97aeb8797941abc30e +23d47dba319331d4418827cfbb8c1af283497d3c diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index c12fe0e086d8..6e320b60eecb 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -105,24 +105,41 @@ fn try_resolve_did(tcx: TyCtxt<'_>, path: &[&str], namespace: Option) (path, None) }; - // First find the crate. - let krate = - tcx.crates(()).iter().find(|&&krate| tcx.crate_name(krate).as_str() == crate_name)?; - let mut cur_item = DefId { krate: *krate, index: CRATE_DEF_INDEX }; - // Then go over the modules. - for &segment in modules { - cur_item = find_children(tcx, cur_item, segment) - .find(|item| tcx.def_kind(item) == DefKind::Mod)?; - } - // Finally, look up the desired item in this module, if any. - match item { - Some((item_name, namespace)) => - Some( - find_children(tcx, cur_item, item_name) - .find(|item| tcx.def_kind(item).ns() == Some(namespace))?, - ), - None => Some(cur_item), + // There may be more than one crate with this name. We try them all. + // (This is particularly relevant when running `std` tests as then there are two `std` crates: + // the one in the sysroot and the one locally built by `cargo test`.) + // FIXME: can we prefer the one from the sysroot? + 'crates: for krate in + tcx.crates(()).iter().filter(|&&krate| tcx.crate_name(krate).as_str() == crate_name) + { + let mut cur_item = DefId { krate: *krate, index: CRATE_DEF_INDEX }; + // Go over the modules. + for &segment in modules { + let Some(next_item) = find_children(tcx, cur_item, segment) + .find(|item| tcx.def_kind(item) == DefKind::Mod) + else { + continue 'crates; + }; + cur_item = next_item; + } + // Finally, look up the desired item in this module, if any. + match item { + Some((item_name, namespace)) => { + let Some(item) = find_children(tcx, cur_item, item_name) + .find(|item| tcx.def_kind(item).ns() == Some(namespace)) + else { + continue 'crates; + }; + return Some(item); + } + None => { + // Just return the module. + return Some(cur_item); + } + } } + // Item not found in any of the crates with the right name. + None } /// Convert a softfloat type to its corresponding hostfloat type. @@ -968,10 +985,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { fn frame_in_std(&self) -> bool { let this = self.eval_context_ref(); - let Some(start_fn) = this.tcx.lang_items().start_fn() else { - // no_std situations - return false; - }; let frame = this.frame(); // Make an attempt to get at the instance of the function this is inlined from. let instance: Option<_> = try { @@ -982,13 +995,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { }; // Fall back to the instance of the function itself. let instance = instance.unwrap_or(frame.instance); - // Now check if this is in the same crate as start_fn. - // As a special exception we also allow unit tests from - // to call these - // shims. + // Now check the crate it is in. We could try to be clever here and e.g. check if this is + // the same crate as `start_fn`, but that would not work for running std tests in Miri, so + // we'd need some more hacks anyway. So we just check the name of the crate. If someone + // calls their crate `std` then we'll just let them keep the pieces. let frame_crate = this.tcx.def_path(instance.def_id()).krate; - frame_crate == this.tcx.def_path(start_fn).krate - || this.tcx.crate_name(frame_crate).as_str() == "std_miri_test" + let crate_name = this.tcx.crate_name(frame_crate); + let crate_name = crate_name.as_str(); + // On miri-test-libstd, the name of the crate is different. + crate_name == "std" || crate_name == "std_miri_test" } /// Handler that should be called when unsupported functionality is encountered. diff --git a/src/tools/miri/tests/pass/async-closure-captures.rs b/src/tools/miri/tests/pass/async-closure-captures.rs index 3e33de32efb0..cac26bfe1462 100644 --- a/src/tools/miri/tests/pass/async-closure-captures.rs +++ b/src/tools/miri/tests/pass/async-closure-captures.rs @@ -88,4 +88,38 @@ async fn async_main() { }; call_once(c).await; } + + fn force_fnonce(f: impl async FnOnce() -> T) -> impl async FnOnce() -> T { + f + } + + // Capture something with `move`, but infer to `AsyncFnOnce` + { + let x = Hello(6); + let c = force_fnonce(async move || { + println!("{x:?}"); + }); + call_once(c).await; + + let x = &Hello(7); + let c = force_fnonce(async move || { + println!("{x:?}"); + }); + call_once(c).await; + } + + // Capture something by-ref, but infer to `AsyncFnOnce` + { + let x = Hello(8); + let c = force_fnonce(async || { + println!("{x:?}"); + }); + call_once(c).await; + + let x = &Hello(9); + let c = force_fnonce(async || { + println!("{x:?}"); + }); + call_once(c).await; + } } diff --git a/src/tools/miri/tests/pass/async-closure-captures.stdout b/src/tools/miri/tests/pass/async-closure-captures.stdout index a0db6d236fef..42a7999b2dcd 100644 --- a/src/tools/miri/tests/pass/async-closure-captures.stdout +++ b/src/tools/miri/tests/pass/async-closure-captures.stdout @@ -8,3 +8,7 @@ Hello(3) Hello(4) Hello(4) Hello(5) +Hello(6) +Hello(7) +Hello(8) +Hello(9) diff --git a/src/tools/run-make-support/src/cc.rs b/src/tools/run-make-support/src/cc.rs new file mode 100644 index 000000000000..2c9ad4f17006 --- /dev/null +++ b/src/tools/run-make-support/src/cc.rs @@ -0,0 +1,202 @@ +use std::env; +use std::path::Path; +use std::process::{Command, Output}; + +use crate::{bin_name, cygpath_windows, handle_failed_output, is_msvc, is_windows, tmp_dir, uname}; + +/// Construct a new platform-specific C compiler invocation. +/// +/// WARNING: This means that what flags are accepted by the underlying C compiler is +/// platform- AND compiler-specific. Consult the relevant docs for `gcc`, `clang` and `mvsc`. +pub fn cc() -> Cc { + Cc::new() +} + +/// A platform-specific C compiler invocation builder. The specific C compiler used is +/// passed down from compiletest. +#[derive(Debug)] +pub struct Cc { + cmd: Command, +} + +impl Cc { + /// Construct a new platform-specific C compiler invocation. + /// + /// WARNING: This means that what flags are accepted by the underlying C compile is + /// platform- AND compiler-specific. Consult the relevant docs for `gcc`, `clang` and `mvsc`. + pub fn new() -> Self { + let compiler = env::var("CC").unwrap(); + + let mut cmd = Command::new(compiler); + + let default_cflags = env::var("CC_DEFAULT_FLAGS").unwrap(); + for flag in default_cflags.split(char::is_whitespace) { + cmd.arg(flag); + } + + Self { cmd } + } + + /// Specify path of the input file. + pub fn input>(&mut self, path: P) -> &mut Self { + self.cmd.arg(path.as_ref()); + self + } + + /// Add a *platform-and-compiler-specific* argument. Please consult the docs for the various + /// possible C compilers on the various platforms to check which arguments are legal for + /// which compiler. + pub fn arg(&mut self, flag: &str) -> &mut Self { + self.cmd.arg(flag); + self + } + + /// Add multiple *platform-and-compiler-specific* arguments. Please consult the docs for the + /// various possible C compilers on the various platforms to check which arguments are legal + /// for which compiler. + pub fn args(&mut self, args: &[&str]) -> &mut Self { + self.cmd.args(args); + self + } + + /// Specify `-o` or `-Fe`/`-Fo` depending on platform/compiler. This assumes that the executable + /// is under `$TMPDIR`. + pub fn out_exe(&mut self, name: &str) -> &mut Self { + // Ref: tools.mk (irrelevant lines omitted): + // + // ```makefile + // ifdef IS_MSVC + // OUT_EXE=-Fe:`cygpath -w $(TMPDIR)/$(call BIN,$(1))` \ + // -Fo:`cygpath -w $(TMPDIR)/$(1).obj` + // else + // OUT_EXE=-o $(TMPDIR)/$(1) + // endif + // ``` + + if is_msvc() { + let fe_path = cygpath_windows(tmp_dir().join(bin_name(name))); + let fo_path = cygpath_windows(tmp_dir().join(format!("{name}.obj"))); + self.cmd.arg(format!("-Fe:{fe_path}")); + self.cmd.arg(format!("-Fo:{fo_path}")); + } else { + self.cmd.arg("-o"); + self.cmd.arg(tmp_dir().join(name)); + } + + self + } + + /// Run the constructed C invocation command and assert that it is successfully run. + #[track_caller] + pub fn run(&mut self) -> Output { + let caller_location = std::panic::Location::caller(); + let caller_line_number = caller_location.line(); + + let output = self.cmd.output().unwrap(); + if !output.status.success() { + handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number); + } + output + } + + /// Inspect what the underlying [`Command`] is up to the current construction. + pub fn inspect(&mut self, f: impl FnOnce(&Command)) -> &mut Self { + f(&self.cmd); + self + } +} + +/// `EXTRACFLAGS` +pub fn extra_c_flags() -> Vec<&'static str> { + // Adapted from tools.mk (trimmed): + // + // ```makefile + // ifdef IS_WINDOWS + // ifdef IS_MSVC + // EXTRACFLAGS := ws2_32.lib userenv.lib advapi32.lib bcrypt.lib ntdll.lib synchronization.lib + // else + // EXTRACFLAGS := -lws2_32 -luserenv -lbcrypt -lntdll -lsynchronization + // endif + // else + // ifeq ($(UNAME),Darwin) + // EXTRACFLAGS := -lresolv + // else + // ifeq ($(UNAME),FreeBSD) + // EXTRACFLAGS := -lm -lpthread -lgcc_s + // else + // ifeq ($(UNAME),SunOS) + // EXTRACFLAGS := -lm -lpthread -lposix4 -lsocket -lresolv + // else + // ifeq ($(UNAME),OpenBSD) + // EXTRACFLAGS := -lm -lpthread -lc++abi + // else + // EXTRACFLAGS := -lm -lrt -ldl -lpthread + // endif + // endif + // endif + // endif + // endif + // ``` + + if is_windows() { + if is_msvc() { + vec![ + "ws2_32.lib", + "userenv.lib", + "advapi32.lib", + "bcrypt.lib", + "ntdll.lib", + "synchronization.lib", + ] + } else { + vec!["-lws2_32", "-luserenv", "-lbcrypt", "-lntdll", "-lsynchronization"] + } + } else { + match uname() { + n if n.contains("Darwin") => vec!["-lresolv"], + n if n.contains("FreeBSD") => vec!["-lm", "-lpthread", "-lgcc_s"], + n if n.contains("SunOS") => { + vec!["-lm", "-lpthread", "-lposix4", "-lsocket", "-lresolv"] + } + n if n.contains("OpenBSD") => vec!["-lm", "-lpthread", "-lc++abi"], + _ => vec!["-lm", "-lrt", "-ldl", "-lpthread"], + } + } +} + +/// `EXTRACXXFLAGS` +pub fn extra_cxx_flags() -> Vec<&'static str> { + // Adapted from tools.mk (trimmed): + // + // ```makefile + // ifdef IS_WINDOWS + // ifdef IS_MSVC + // else + // EXTRACXXFLAGS := -lstdc++ + // endif + // else + // ifeq ($(UNAME),Darwin) + // EXTRACXXFLAGS := -lc++ + // else + // ifeq ($(UNAME),FreeBSD) + // else + // ifeq ($(UNAME),SunOS) + // else + // ifeq ($(UNAME),OpenBSD) + // else + // EXTRACXXFLAGS := -lstdc++ + // endif + // endif + // endif + // endif + // endif + // ``` + if is_windows() { + if is_msvc() { vec![] } else { vec!["-lstdc++"] } + } else { + match uname() { + n if n.contains("Darwin") => vec!["-lc++"], + _ => vec!["-lstdc++"], + } + } +} diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 48fa2bbf1ac4..e70acf585716 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -1,14 +1,16 @@ +pub mod cc; pub mod run; pub mod rustc; pub mod rustdoc; use std::env; -use std::path::PathBuf; -use std::process::Output; +use std::path::{Path, PathBuf}; +use std::process::{Command, Output}; pub use object; pub use wasmparser; +pub use cc::{cc, extra_c_flags, extra_cxx_flags, Cc}; pub use run::{run, run_fail}; pub use rustc::{aux_build, rustc, Rustc}; pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc}; @@ -18,6 +20,89 @@ pub fn tmp_dir() -> PathBuf { env::var_os("TMPDIR").unwrap().into() } +/// `TARGET` +pub fn target() -> String { + env::var("TARGET").unwrap() +} + +/// Check if target is windows-like. +pub fn is_windows() -> bool { + env::var_os("IS_WINDOWS").is_some() +} + +/// Check if target uses msvc. +pub fn is_msvc() -> bool { + env::var_os("IS_MSVC").is_some() +} + +/// Construct a path to a static library under `$TMPDIR` given the library name. This will return a +/// path with `$TMPDIR` joined with platform-and-compiler-specific library name. +pub fn static_lib(name: &str) -> PathBuf { + tmp_dir().join(static_lib_name(name)) +} + +/// Construct the static library name based on the platform. +pub fn static_lib_name(name: &str) -> String { + // See tools.mk (irrelevant lines omitted): + // + // ```makefile + // ifeq ($(UNAME),Darwin) + // STATICLIB = $(TMPDIR)/lib$(1).a + // else + // ifdef IS_WINDOWS + // ifdef IS_MSVC + // STATICLIB = $(TMPDIR)/$(1).lib + // else + // STATICLIB = $(TMPDIR)/lib$(1).a + // endif + // else + // STATICLIB = $(TMPDIR)/lib$(1).a + // endif + // endif + // ``` + assert!(!name.contains(char::is_whitespace), "name cannot contain whitespace"); + + if target().contains("msvc") { format!("{name}.lib") } else { format!("lib{name}.a") } +} + +/// Construct the binary name based on platform. +pub fn bin_name(name: &str) -> String { + if is_windows() { format!("{name}.exe") } else { name.to_string() } +} + +/// Use `cygpath -w` on a path to get a Windows path string back. This assumes that `cygpath` is +/// available on the platform! +#[track_caller] +pub fn cygpath_windows>(path: P) -> String { + let caller_location = std::panic::Location::caller(); + let caller_line_number = caller_location.line(); + + let mut cygpath = Command::new("cygpath"); + cygpath.arg("-w"); + cygpath.arg(path.as_ref()); + let output = cygpath.output().unwrap(); + if !output.status.success() { + handle_failed_output(&format!("{:#?}", cygpath), output, caller_line_number); + } + let s = String::from_utf8(output.stdout).unwrap(); + // cygpath -w can attach a newline + s.trim().to_string() +} + +/// Run `uname`. This assumes that `uname` is available on the platform! +#[track_caller] +pub fn uname() -> String { + let caller_location = std::panic::Location::caller(); + let caller_line_number = caller_location.line(); + + let mut uname = Command::new("uname"); + let output = uname.output().unwrap(); + if !output.status.success() { + handle_failed_output(&format!("{:#?}", uname), output, caller_line_number); + } + String::from_utf8(output.stdout).unwrap() +} + fn handle_failed_output(cmd: &str, output: Output, caller_line_number: u32) -> ! { if output.status.success() { eprintln!("command incorrectly succeeded at line {caller_line_number}"); diff --git a/src/tools/run-make-support/src/run.rs b/src/tools/run-make-support/src/run.rs index 42dcf54da22e..e33ea9d6e40a 100644 --- a/src/tools/run-make-support/src/run.rs +++ b/src/tools/run-make-support/src/run.rs @@ -2,17 +2,14 @@ use std::env; use std::path::{Path, PathBuf}; use std::process::{Command, Output}; -use super::handle_failed_output; +use crate::is_windows; -fn run_common(bin_name: &str) -> (Command, Output) { - let target = env::var("TARGET").unwrap(); - - let bin_name = - if target.contains("windows") { format!("{}.exe", bin_name) } else { bin_name.to_owned() }; +use super::{bin_name, handle_failed_output}; +fn run_common(name: &str) -> (Command, Output) { let mut bin_path = PathBuf::new(); bin_path.push(env::var("TMPDIR").unwrap()); - bin_path.push(&bin_name); + bin_path.push(&bin_name(name)); let ld_lib_path_envvar = env::var("LD_LIB_PATH_ENVVAR").unwrap(); let mut cmd = Command::new(bin_path); cmd.env(&ld_lib_path_envvar, { @@ -27,7 +24,7 @@ fn run_common(bin_name: &str) -> (Command, Output) { env::join_paths(paths.iter()).unwrap() }); - if target.contains("windows") { + if is_windows() { let mut paths = vec![]; for p in env::split_paths(&std::env::var("PATH").unwrap_or(String::new())) { paths.push(p.to_path_buf()); @@ -42,11 +39,11 @@ fn run_common(bin_name: &str) -> (Command, Output) { /// Run a built binary and make sure it succeeds. #[track_caller] -pub fn run(bin_name: &str) -> Output { +pub fn run(name: &str) -> Output { let caller_location = std::panic::Location::caller(); let caller_line_number = caller_location.line(); - let (cmd, output) = run_common(bin_name); + let (cmd, output) = run_common(name); if !output.status.success() { handle_failed_output(&format!("{:#?}", cmd), output, caller_line_number); } @@ -55,11 +52,11 @@ pub fn run(bin_name: &str) -> Output { /// Run a built binary and make sure it fails. #[track_caller] -pub fn run_fail(bin_name: &str) -> Output { +pub fn run_fail(name: &str) -> Output { let caller_location = std::panic::Location::caller(); let caller_line_number = caller_location.line(); - let (cmd, output) = run_common(bin_name); + let (cmd, output) = run_common(name); if output.status.success() { handle_failed_output(&format!("{:#?}", cmd), output, caller_line_number); } diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 40950e6ba443..c3ed1ff68914 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -5,7 +5,6 @@ run-make/allocator-shim-circular-deps/Makefile run-make/allow-non-lint-warnings-cmdline/Makefile run-make/allow-warnings-cmdline-stability/Makefile run-make/archive-duplicate-names/Makefile -run-make/arguments-non-c-like-enum/Makefile run-make/atomic-lock-free/Makefile run-make/bare-outfile/Makefile run-make/branch-protection-check-IBT/Makefile @@ -86,7 +85,6 @@ run-make/foreign-exceptions/Makefile run-make/foreign-rust-exceptions/Makefile run-make/fpic/Makefile run-make/glibc-staticlib-args/Makefile -run-make/hir-tree/Makefile run-make/inaccessible-temp-dir/Makefile run-make/include_bytes_deps/Makefile run-make/incr-add-rust-src-component/Makefile @@ -132,7 +130,6 @@ run-make/issue-53964/Makefile run-make/issue-64153/Makefile run-make/issue-68794-textrel-on-minimal-lib/Makefile run-make/issue-69368/Makefile -run-make/issue-7349/Makefile run-make/issue-83045/Makefile run-make/issue-83112-incr-test-moved-file/Makefile run-make/issue-84395-lto-embed-bitcode/Makefile diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index b74afa0d3e86..aec2856dbbc8 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -56,7 +56,7 @@ pub(crate) const WORKSPACES: &[(&str, ExceptionList, Option<(&[&str], &[&str])>) Some((&["rustc_codegen_cranelift"], PERMITTED_CRANELIFT_DEPENDENCIES)), ), // tidy-alphabetical-start - //("compiler/rustc_codegen_gcc", EXCEPTIONS_GCC, None), // FIXME uncomment once all deps are vendored + ("compiler/rustc_codegen_gcc", EXCEPTIONS_GCC, None), //("library/backtrace", &[], None), // FIXME uncomment once rust-lang/backtrace#562 has been synced back to the rust repo //("library/portable-simd", &[], None), // FIXME uncomment once rust-lang/portable-simd#363 has been synced back to the rust repo //("library/stdarch", EXCEPTIONS_STDARCH, None), // FIXME uncomment once rust-lang/stdarch#1462 has been synced back to the rust repo @@ -164,15 +164,12 @@ const EXCEPTIONS_CRANELIFT: ExceptionList = &[ // tidy-alphabetical-end ]; -// FIXME uncomment once all deps are vendored -/* const EXCEPTIONS_GCC: ExceptionList = &[ // tidy-alphabetical-start ("gccjit", "GPL-3.0"), ("gccjit_sys", "GPL-3.0"), // tidy-alphabetical-end ]; -*/ const EXCEPTIONS_BOOTSTRAP: ExceptionList = &[ ("ryu", "Apache-2.0 OR BSL-1.0"), // through serde. BSL is not acceptble, but we use it under Apache-2.0 diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 6e8452493421..874c15ce41da 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -1132,7 +1132,6 @@ "ui/generics/issue-98432.rs", "ui/higher-ranked/trait-bounds/issue-100689.rs", "ui/higher-ranked/trait-bounds/issue-102899.rs", -"ui/higher-ranked/trait-bounds/issue-30786.rs", "ui/higher-ranked/trait-bounds/issue-36139-normalize-closure-sig.rs", "ui/higher-ranked/trait-bounds/issue-39292.rs", "ui/higher-ranked/trait-bounds/issue-42114.rs", diff --git a/src/tools/tidy/src/rustdoc_css_themes.rs b/src/tools/tidy/src/rustdoc_css_themes.rs index 852d6e14e91d..af36f9ba58e0 100644 --- a/src/tools/tidy/src/rustdoc_css_themes.rs +++ b/src/tools/tidy/src/rustdoc_css_themes.rs @@ -74,8 +74,11 @@ fn compare_themes<'a>( (noscript_css_line_number, noscript_css_line), ) in rustdoc_css_lines.zip(noscript_css_lines) { - if noscript_css_line.starts_with(":root {") - && rustdoc_css_line.starts_with(&format!(r#":root[data-theme="{name}"] {{"#)) + if noscript_css_line.starts_with(":root, :root:not([data-theme]) {") + && (rustdoc_css_line.starts_with(&format!(r#":root[data-theme="{name}"] {{"#)) + || rustdoc_css_line.starts_with(&format!( + r#":root[data-theme="{name}"], :root:not([data-theme]) {{"# + ))) { // selectors are different between rustdoc.css and noscript.css // that's why they both exist: one uses JS, the other uses media queries diff --git a/tests/assembly/targets/targets-macho.rs b/tests/assembly/targets/targets-macho.rs index bbdafb76e5a9..713129b692cd 100644 --- a/tests/assembly/targets/targets-macho.rs +++ b/tests/assembly/targets/targets-macho.rs @@ -27,6 +27,14 @@ //@ revisions: arm64_32_apple_watchos //@ [arm64_32_apple_watchos] compile-flags: --target arm64_32-apple-watchos //@ [arm64_32_apple_watchos] needs-llvm-components: aarch64 +//@ revisions: aarch64_apple_visionos +//@ [aarch64_apple_visionos] min-llvm-version: 18 +//@ [aarch64_apple_visionos] compile-flags: --target aarch64-apple-visionos +//@ [aarch64_apple_visionos] needs-llvm-components: aarch64 +//@ revisions: aarch64_apple_visionos_sim +//@ [aarch64_apple_visionos_sim] min-llvm-version: 18 +//@ [aarch64_apple_visionos_sim] compile-flags: --target aarch64-apple-visionos-sim +//@ [aarch64_apple_visionos_sim] needs-llvm-components: aarch64 //@ revisions: arm64e_apple_darwin //@ [arm64e_apple_darwin] compile-flags: --target arm64e-apple-darwin //@ [arm64e_apple_darwin] needs-llvm-components: aarch64 diff --git a/tests/codegen/no-redundant-item-monomorphization.rs b/tests/codegen/no-redundant-item-monomorphization.rs new file mode 100644 index 000000000000..466037c37700 --- /dev/null +++ b/tests/codegen/no-redundant-item-monomorphization.rs @@ -0,0 +1,33 @@ +// Test to make sure that inner functions within a polymorphic outer function +// don't get re-codegened when the outer function is monomorphized. The test +// code monomorphizes the outer functions several times, but the magic constants +// used in the inner functions should each appear only once in the generated IR. + +// issue: rust-lang/rust#7349 +//@ compile-flags: -Cno-prepopulate-passes -Copt-level=0 + +// CHECK-COUNT-1: ret i32 8675309 +// CHECK-COUNT-1: ret i32 11235813 + +fn outer() { + #[allow(dead_code)] + fn inner() -> u32 { + 8675309 + } + inner(); +} + +extern "C" fn outer_foreign() { + #[allow(dead_code)] + fn inner() -> u32 { + 11235813 + } + inner(); +} + +fn main() { + outer::(); + outer::(); + outer_foreign::(); + outer_foreign::(); +} diff --git a/tests/mir-opt/building/match/match_false_edges.main.built.after.mir b/tests/mir-opt/building/match/match_false_edges.main.built.after.mir index b71b2412cdf4..dfa31cfff6b2 100644 --- a/tests/mir-opt/building/match/match_false_edges.main.built.after.mir +++ b/tests/mir-opt/building/match/match_false_edges.main.built.after.mir @@ -48,7 +48,7 @@ fn main() -> () { } bb2: { - falseEdge -> [real: bb15, imaginary: bb6]; + falseEdge -> [real: bb15, imaginary: bb3]; } bb3: { diff --git a/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir index e95a97b5b87f..c3497c6989d7 100644 --- a/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/building/match/sort_candidates.constant_eq.SimplifyCfg-initial.after.mir @@ -40,7 +40,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 { } bb4: { - falseEdge -> [real: bb12, imaginary: bb9]; + falseEdge -> [real: bb12, imaginary: bb7]; } bb5: { @@ -48,7 +48,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 { } bb6: { - falseEdge -> [real: bb16, imaginary: bb3]; + falseEdge -> [real: bb16, imaginary: bb1]; } bb7: { @@ -60,7 +60,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 { } bb9: { - falseEdge -> [real: bb15, imaginary: bb6]; + falseEdge -> [real: bb15, imaginary: bb5]; } bb10: { @@ -89,7 +89,7 @@ fn constant_eq(_1: &str, _2: bool) -> u32 { bb14: { StorageDead(_10); - falseEdge -> [real: bb5, imaginary: bb9]; + falseEdge -> [real: bb5, imaginary: bb7]; } bb15: { diff --git a/tests/mir-opt/building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir index 80d3c2e5c23e..4a1e4fb9ec56 100644 --- a/tests/mir-opt/building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/building/match/sort_candidates.disjoint_ranges.SimplifyCfg-initial.after.mir @@ -23,7 +23,7 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 { } bb2: { - falseEdge -> [real: bb9, imaginary: bb4]; + falseEdge -> [real: bb9, imaginary: bb3]; } bb3: { @@ -32,7 +32,7 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 { } bb4: { - falseEdge -> [real: bb12, imaginary: bb6]; + falseEdge -> [real: bb12, imaginary: bb5]; } bb5: { @@ -69,7 +69,7 @@ fn disjoint_ranges(_1: i32, _2: bool) -> u32 { bb11: { StorageDead(_8); - falseEdge -> [real: bb1, imaginary: bb4]; + falseEdge -> [real: bb1, imaginary: bb3]; } bb12: { diff --git a/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff b/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff index 307f7105dd2f..ba333ba1a586 100644 --- a/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff +++ b/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff @@ -60,11 +60,11 @@ } - bb5: { -- falseEdge -> [real: bb13, imaginary: bb3]; +- falseEdge -> [real: bb13, imaginary: bb2]; - } - - bb6: { -- falseEdge -> [real: bb8, imaginary: bb5]; +- falseEdge -> [real: bb8, imaginary: bb1]; - } - - bb7: { @@ -127,7 +127,7 @@ StorageDead(_9); StorageDead(_8); StorageDead(_6); -- falseEdge -> [real: bb1, imaginary: bb5]; +- falseEdge -> [real: bb1, imaginary: bb1]; + goto -> bb1; } @@ -184,7 +184,7 @@ StorageDead(_12); StorageDead(_8); StorageDead(_6); -- falseEdge -> [real: bb2, imaginary: bb3]; +- falseEdge -> [real: bb2, imaginary: bb2]; + goto -> bb2; } diff --git a/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff b/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff index 307f7105dd2f..ba333ba1a586 100644 --- a/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff +++ b/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff @@ -60,11 +60,11 @@ } - bb5: { -- falseEdge -> [real: bb13, imaginary: bb3]; +- falseEdge -> [real: bb13, imaginary: bb2]; - } - - bb6: { -- falseEdge -> [real: bb8, imaginary: bb5]; +- falseEdge -> [real: bb8, imaginary: bb1]; - } - - bb7: { @@ -127,7 +127,7 @@ StorageDead(_9); StorageDead(_8); StorageDead(_6); -- falseEdge -> [real: bb1, imaginary: bb5]; +- falseEdge -> [real: bb1, imaginary: bb1]; + goto -> bb1; } @@ -184,7 +184,7 @@ StorageDead(_12); StorageDead(_8); StorageDead(_6); -- falseEdge -> [real: bb2, imaginary: bb3]; +- falseEdge -> [real: bb2, imaginary: bb2]; + goto -> bb2; } diff --git a/tests/run-make/arguments-non-c-like-enum/Makefile b/tests/run-make/arguments-non-c-like-enum/Makefile deleted file mode 100644 index 0c8d8bf3acc6..000000000000 --- a/tests/run-make/arguments-non-c-like-enum/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - $(RUSTC) --crate-type=staticlib nonclike.rs - $(CC) test.c $(call STATICLIB,nonclike) $(call OUT_EXE,test) \ - $(EXTRACFLAGS) $(EXTRACXXFLAGS) - $(call RUN,test) diff --git a/tests/run-make/arguments-non-c-like-enum/rmake.rs b/tests/run-make/arguments-non-c-like-enum/rmake.rs new file mode 100644 index 000000000000..624a7fb22518 --- /dev/null +++ b/tests/run-make/arguments-non-c-like-enum/rmake.rs @@ -0,0 +1,20 @@ +//! Check that non-trivial `repr(C)` enum in Rust has valid C layout. +//@ ignore-cross-compile + +extern crate run_make_support; + +use run_make_support::{cc, extra_c_flags, extra_cxx_flags, run, rustc, static_lib}; + +pub fn main() { + use std::path::Path; + + rustc().input("nonclike.rs").crate_type("staticlib").run(); + cc().input("test.c") + .input(static_lib("nonclike")) + .out_exe("test") + .args(&extra_c_flags()) + .args(&extra_cxx_flags()) + .inspect(|cmd| eprintln!("{cmd:?}")) + .run(); + run("test"); +} diff --git a/tests/run-make/hir-tree/Makefile b/tests/run-make/hir-tree/Makefile deleted file mode 100644 index b0450ea4bc5f..000000000000 --- a/tests/run-make/hir-tree/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -include ../tools.mk - -# Test that hir-tree output doesn't crash and includes -# the string constant we would expect to see. - -all: - $(RUSTC) -o $(TMPDIR)/input.hir -Z unpretty=hir-tree input.rs - $(CGREP) '"Hello, Rustaceans!\n"' < $(TMPDIR)/input.hir diff --git a/tests/run-make/hir-tree/input.rs b/tests/run-make/hir-tree/input.rs deleted file mode 100644 index 9d1a4e9e47d7..000000000000 --- a/tests/run-make/hir-tree/input.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, Rustaceans!"); -} diff --git a/tests/run-make/issue-7349/Makefile b/tests/run-make/issue-7349/Makefile deleted file mode 100644 index dc073b77fe12..000000000000 --- a/tests/run-make/issue-7349/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -include ../tools.mk - -# Test to make sure that inner functions within a polymorphic outer function -# don't get re-codegened when the outer function is monomorphized. The test -# code monomorphizes the outer functions several times, but the magic constants -# used in the inner functions should each appear only once in the generated IR. - -all: - $(RUSTC) foo.rs --emit=llvm-ir - [ "$$(grep -c 'ret i32 8675309' "$(TMPDIR)/foo.ll")" -eq "1" ] - [ "$$(grep -c 'ret i32 11235813' "$(TMPDIR)/foo.ll")" -eq "1" ] diff --git a/tests/run-make/issue-7349/foo.rs b/tests/run-make/issue-7349/foo.rs deleted file mode 100644 index 246a12595808..000000000000 --- a/tests/run-make/issue-7349/foo.rs +++ /dev/null @@ -1,22 +0,0 @@ -fn outer() { - #[allow(dead_code)] - fn inner() -> u32 { - 8675309 - } - inner(); -} - -extern "C" fn outer_foreign() { - #[allow(dead_code)] - fn inner() -> u32 { - 11235813 - } - inner(); -} - -fn main() { - outer::(); - outer::(); - outer_foreign::(); - outer_foreign::(); -} diff --git a/tests/rustdoc-gui/anchors.goml b/tests/rustdoc-gui/anchors.goml index 3239e54a866b..61b2e8880c60 100644 --- a/tests/rustdoc-gui/anchors.goml +++ b/tests/rustdoc-gui/anchors.goml @@ -1,4 +1,5 @@ // This test is to ensure that the anchors (`§`) have the expected color and position. +include: "utils.goml" define-function: ( "check-colors", @@ -8,10 +9,7 @@ define-function: ( // This is needed to ensure that the text color is computed. show-text: true - // Setting the theme. - set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} - // We reload the page so the local storage settings are being used. - reload: + call-function: ("switch-theme", {"theme": |theme|}) assert-css: ("#toggle-all-docs", {"color": |main_color|}) assert-css: (".main-heading h1 a:nth-of-type(1)", {"color": |main_heading_color|}) diff --git a/tests/rustdoc-gui/code-color.goml b/tests/rustdoc-gui/code-color.goml index e17af5e7f1fa..661709aa1cea 100644 --- a/tests/rustdoc-gui/code-color.goml +++ b/tests/rustdoc-gui/code-color.goml @@ -2,6 +2,7 @@ // check that the rule isn't applied on other "" elements. // // While we're at it, we also check it for the other themes. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html" // If the text isn't displayed, the browser doesn't compute color style correctly... show-text: true @@ -10,10 +11,7 @@ define-function: ( "check-colors", [theme, doc_code_color, doc_inline_code_color], block { - // Set the theme. - set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} - // We reload the page so the local storage settings are being used. - reload: + call-function: ("switch-theme", {"theme": |theme|}) assert-css: (".docblock pre > code", {"color": |doc_code_color|}, ALL) assert-css: (".docblock > p > code", {"color": |doc_inline_code_color|}, ALL) }, diff --git a/tests/rustdoc-gui/codeblock-tooltip.goml b/tests/rustdoc-gui/codeblock-tooltip.goml index 19e3927f6429..654589c3ebaa 100644 --- a/tests/rustdoc-gui/codeblock-tooltip.goml +++ b/tests/rustdoc-gui/codeblock-tooltip.goml @@ -1,4 +1,5 @@ // Checking the colors of the codeblocks tooltips. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html" show-text: true @@ -6,9 +7,7 @@ define-function: ( "check-colors", [theme, background, color, border], block { - // Setting the theme. - set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} - reload: + call-function: ("switch-theme", {"theme": |theme|}) // compile_fail block assert-css: ( diff --git a/tests/rustdoc-gui/docblock-code-block-line-number.goml b/tests/rustdoc-gui/docblock-code-block-line-number.goml index cb7bdaab4c8d..fc80932cabaa 100644 --- a/tests/rustdoc-gui/docblock-code-block-line-number.goml +++ b/tests/rustdoc-gui/docblock-code-block-line-number.goml @@ -1,4 +1,5 @@ // Checks that the setting "line numbers" is working as expected. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html" // Otherwise, we can't check text color @@ -13,14 +14,10 @@ define-function: ( [theme, color], block { // We now set the setting to show the line numbers on code examples. - set-local-storage: { - "rustdoc-theme": |theme|, - "rustdoc-use-system-theme": "false", - "rustdoc-line-numbers": "true" - } - // We reload to make the line numbers appear and change theme. - reload: - // We wait for them to be added into the DOM by the JS... + set-local-storage: {"rustdoc-line-numbers": "true"} + // Page will be reloaded in "switch-theme". + call-function: ("switch-theme", {"theme": |theme|}) + // We wait for the line numbers to be added into the DOM by the JS... wait-for: "pre.example-line-numbers" // If the test didn't fail, it means that it was found! assert-css: ( diff --git a/tests/rustdoc-gui/docblock-details.goml b/tests/rustdoc-gui/docblock-details.goml index 4b8f5b54fac5..b8fc58ef1e49 100644 --- a/tests/rustdoc-gui/docblock-details.goml +++ b/tests/rustdoc-gui/docblock-details.goml @@ -1,8 +1,8 @@ // This ensures that the `
`/`` elements are displayed as expected. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/details/struct.Details.html" show-text: true -set-local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false"} -reload: +call-function: ("switch-theme", {"theme": "dark"}) // We first check that the headers in the `.top-doc` doc block still have their // bottom border. diff --git a/tests/rustdoc-gui/docblock-table.goml b/tests/rustdoc-gui/docblock-table.goml index db6d065a4b33..a73f4aaa7677 100644 --- a/tests/rustdoc-gui/docblock-table.goml +++ b/tests/rustdoc-gui/docblock-table.goml @@ -1,4 +1,5 @@ // This test checks the appearance of the tables in the doc comments. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/doc_block_table/struct.DocBlockTable.html#method.func" compare-elements-css: (".impl-items .docblock table th", ".top-doc .docblock table th", ["border"]) @@ -8,8 +9,7 @@ define-function: ( "check-colors", [theme, border_color, zebra_stripe_color], block { - set-local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": |theme|} - reload: + call-function: ("switch-theme", {"theme": |theme|}) assert-css: (".top-doc .docblock table tbody tr:nth-child(1)", { "background-color": "rgba(0, 0, 0, 0)", }) diff --git a/tests/rustdoc-gui/headers-color.goml b/tests/rustdoc-gui/headers-color.goml index 2a181c0669fe..81346fc12d06 100644 --- a/tests/rustdoc-gui/headers-color.goml +++ b/tests/rustdoc-gui/headers-color.goml @@ -1,5 +1,7 @@ // This test check for headings text and background colors for the different themes. +include: "utils.goml" + define-function: ( "check-colors", [theme, color, code_header_color, focus_background_color, headings_color], @@ -7,8 +9,7 @@ define-function: ( go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" // This is needed so that the text color is computed. show-text: true - set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} - reload: + call-function: ("switch-theme", {"theme": |theme|}) assert-css: ( ".impl", {"color": |color|, "background-color": "rgba(0, 0, 0, 0)"}, diff --git a/tests/rustdoc-gui/headings.goml b/tests/rustdoc-gui/headings.goml index cdc61e36be20..94d80a3e3df5 100644 --- a/tests/rustdoc-gui/headings.goml +++ b/tests/rustdoc-gui/headings.goml @@ -11,6 +11,7 @@ // 18px 1.125em // 16px 1rem // 14px 0.875rem +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html" assert-css: (".main-heading h1", {"font-size": "24px"}) @@ -158,8 +159,8 @@ define-function: ( "check-colors", [theme, heading_color, small_heading_color, heading_border_color], block { - set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} - reload: + call-function: ("switch-theme", {"theme": |theme|}) + assert-css: ( ".top-doc .docblock h2", {"color": |heading_color|, "border-bottom": "1px solid " + |heading_border_color|}, @@ -222,8 +223,7 @@ define-function: ( "check-since-color", [theme], block { - set-local-storage: {"rustdoc-theme": |theme|} - reload: + call-function: ("switch-theme", {"theme": |theme|}) assert-css: (".since", {"color": "#808080"}, ALL) }, ) diff --git a/tests/rustdoc-gui/help-page.goml b/tests/rustdoc-gui/help-page.goml index 9a7247a737ba..09d33af139cd 100644 --- a/tests/rustdoc-gui/help-page.goml +++ b/tests/rustdoc-gui/help-page.goml @@ -1,4 +1,5 @@ // This test ensures that opening the help page in its own tab works. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/help.html" set-window-size: (1000, 1000) // Try desktop size first. wait-for: "#help" @@ -19,10 +20,7 @@ define-function: ( "check-colors", [theme, color, background, box_shadow], block { - // Setting the theme. - set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} - // We reload the page so the local storage settings are being used. - reload: + call-function: ("switch-theme", {"theme": |theme|}) assert-css: ("#help kbd", { "color": |color|, "background-color": |background|, diff --git a/tests/rustdoc-gui/highlight-colors.goml b/tests/rustdoc-gui/highlight-colors.goml index 48bef319d42f..65fb3e1285eb 100644 --- a/tests/rustdoc-gui/highlight-colors.goml +++ b/tests/rustdoc-gui/highlight-colors.goml @@ -1,4 +1,5 @@ // This test checks the highlight colors in the source code pages. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html" show-text: true @@ -22,8 +23,7 @@ define-function: ( doc_comment, ], block { - set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} - reload: + call-function: ("switch-theme", {"theme": |theme|}) assert-css: ("pre.rust .kw", {"color": |kw|}, ALL) assert-css: ("pre.rust .kw-2", {"color": |kw2|}, ALL) assert-css: ("pre.rust .prelude-ty", {"color": |prelude_ty|}, ALL) diff --git a/tests/rustdoc-gui/item-decl-colors.goml b/tests/rustdoc-gui/item-decl-colors.goml index e68d206a5118..18545f035675 100644 --- a/tests/rustdoc-gui/item-decl-colors.goml +++ b/tests/rustdoc-gui/item-decl-colors.goml @@ -1,5 +1,7 @@ // This test ensures that the color of the items in the type decl are working as expected. +include: "utils.goml" + // We need to disable this check because `trait.impl/test_docs/trait.TraitWithoutGenerics.js` // doesn't exist. fail-on-request-error: false @@ -21,8 +23,8 @@ define-function: ( go-to: "file://" + |DOC_PATH| + "/test_docs/struct.WithGenerics.html" show-text: true - set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} - reload: + call-function: ("switch-theme", {"theme": |theme|}) + assert-css: (".item-decl .code-attribute", {"color": |attr_color|}, ALL) assert-css: (".item-decl .trait", {"color": |trait_color|}, ALL) // We need to add `code` here because otherwise it would select the parent too. diff --git a/tests/rustdoc-gui/item-decl-comment-highlighting.goml b/tests/rustdoc-gui/item-decl-comment-highlighting.goml index 056b6a5b1e81..3ffbbe1c40f0 100644 --- a/tests/rustdoc-gui/item-decl-comment-highlighting.goml +++ b/tests/rustdoc-gui/item-decl-comment-highlighting.goml @@ -1,4 +1,5 @@ // This test checks that comments in item declarations are highlighted. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/private/enum.Enum.html" show-text: true @@ -7,8 +8,7 @@ define-function: ( [theme, url, comment_color], block { go-to: |url| - set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} - reload: + call-function: ("switch-theme", {"theme": |theme|}) assert-css: (".item-decl .comment", {"color": |comment_color|}, ALL) } ) diff --git a/tests/rustdoc-gui/javascript-disabled.goml b/tests/rustdoc-gui/javascript-disabled.goml index a0872d553af7..a7579ef7ec14 100644 --- a/tests/rustdoc-gui/javascript-disabled.goml +++ b/tests/rustdoc-gui/javascript-disabled.goml @@ -3,4 +3,18 @@ javascript: false go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" +show-text: true assert-css: (".sub", {"display": "none"}) + +// Even though JS is disabled, we should still have themes applied. Links are never black-colored +// if styles are applied so we check that they are not. +assert-css-false: ("a.src", {"color": "#000"}) + +javascript: true +fail-on-request-error: false +block-network-request: "*.js" +reload: + +// JS is enabled but wasn't loaded, we should still have the light theme applied. Links are never +// black-colored if styles are applied so we check that they are not. +assert-css-false: ("a.src", {"color": "#000"}) diff --git a/tests/rustdoc-gui/jump-to-def-background.goml b/tests/rustdoc-gui/jump-to-def-background.goml index ae9c0c560cf3..71320360740c 100644 --- a/tests/rustdoc-gui/jump-to-def-background.goml +++ b/tests/rustdoc-gui/jump-to-def-background.goml @@ -1,14 +1,12 @@ // We check the background color on the jump to definition links in the src code page. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/src/link_to_definition/lib.rs.html" define-function: ( "check-background-color", [theme, background_color], block { - // Set the theme. - set-local-storage: { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false" } - // We reload the page so the local storage settings are being used. - reload: + call-function: ("switch-theme", {"theme": |theme|}) assert-css: ( "body.src .example-wrap pre.rust a", {"background-color": |background_color|}, diff --git a/tests/rustdoc-gui/links-color.goml b/tests/rustdoc-gui/links-color.goml index a1fb619a5d34..ad1b5e801ca3 100644 --- a/tests/rustdoc-gui/links-color.goml +++ b/tests/rustdoc-gui/links-color.goml @@ -1,4 +1,5 @@ // This test checks links colors. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" // This is needed so that the text color is computed. @@ -9,11 +10,7 @@ define-function: ( [theme, mod, macro, struct, enum, trait, fn, type, union, keyword, sidebar, sidebar_current, sidebar_current_background], block { - set-local-storage: { - "rustdoc-theme": |theme|, - "rustdoc-use-system-theme": "false", - } - reload: + call-function: ("switch-theme", {"theme": |theme|}) // Checking results colors. assert-css: (".item-table .mod", {"color": |mod|}, ALL) assert-css: (".item-table .macro", {"color": |macro|}, ALL) diff --git a/tests/rustdoc-gui/notable-trait.goml b/tests/rustdoc-gui/notable-trait.goml index 0b1c6622596a..34fafe9a1412 100644 --- a/tests/rustdoc-gui/notable-trait.goml +++ b/tests/rustdoc-gui/notable-trait.goml @@ -1,4 +1,5 @@ // This test checks the position of the `i` for the notable traits. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/struct.NotableStructWithLongName.html" show-text: true // We start with a wide screen. @@ -128,10 +129,7 @@ define-function: ( // This is needed to ensure that the text color is computed. show-text: true - // Setting the theme. - set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} - // We reload the page so the local storage settings are being used. - reload: + call-function: ("switch-theme", {"theme": |theme|}) assert-css: ( "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", diff --git a/tests/rustdoc-gui/pocket-menu.goml b/tests/rustdoc-gui/pocket-menu.goml index b16150cd0d36..ec31f492abe7 100644 --- a/tests/rustdoc-gui/pocket-menu.goml +++ b/tests/rustdoc-gui/pocket-menu.goml @@ -1,4 +1,5 @@ // This test ensures that the "pocket menus" are working as expected. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" // First we check that the help menu doesn't exist yet. assert-false: "#help-button .popover" @@ -33,11 +34,7 @@ define-function: ( "check-popover-colors", [theme, border_color], block { - set-local-storage: { - "rustdoc-theme": |theme|, - "rustdoc-use-system-theme": "false", - } - reload: + call-function: ("switch-theme", {"theme": |theme|}) click: "#help-button" assert-css: ( diff --git a/tests/rustdoc-gui/run-on-hover.goml b/tests/rustdoc-gui/run-on-hover.goml index 19b15afbac3c..087dd3374f80 100644 --- a/tests/rustdoc-gui/run-on-hover.goml +++ b/tests/rustdoc-gui/run-on-hover.goml @@ -2,6 +2,7 @@ // Playground. That button is hidden until the user hovers over the code block. // This test checks that it is hidden, and that it shows on hover. It also // checks for its color. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html" show-text: true @@ -9,8 +10,7 @@ define-function: ( "check-run-button", [theme, color, background, hover_color, hover_background], block { - set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} - reload: + call-function: ("switch-theme", {"theme": |theme|}) assert-css: (".test-arrow", {"visibility": "hidden"}) move-cursor-to: ".example-wrap" assert-css: (".test-arrow", { diff --git a/tests/rustdoc-gui/rust-logo.goml b/tests/rustdoc-gui/rust-logo.goml index a3b420e5eb92..7a999fa854c4 100644 --- a/tests/rustdoc-gui/rust-logo.goml +++ b/tests/rustdoc-gui/rust-logo.goml @@ -1,4 +1,5 @@ // This test ensures that the correct style is applied to the rust logo in the sidebar. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/staged_api/index.html" define-function: ( @@ -8,14 +9,12 @@ define-function: ( // Going to the doc page. go-to: "file://" + |DOC_PATH| + "/staged_api/index.html" // Changing theme. - set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} - reload: + call-function: ("switch-theme", {"theme": |theme|}) assert-css: (".rust-logo", {"filter": |filter|}) // Now we check that the non-rust logos don't have a CSS filter set. go-to: "file://" + |DOC_PATH| + "/huge_logo/index.html" // Changing theme on the new page (again...). - set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} - reload: + call-function: ("switch-theme", {"theme": |theme|}) // Check there is no rust logo assert-false: ".rust-logo" // Check there is no filter. diff --git a/tests/rustdoc-gui/scrape-examples-color.goml b/tests/rustdoc-gui/scrape-examples-color.goml index b1675a5f1fd7..588ba08a60c7 100644 --- a/tests/rustdoc-gui/scrape-examples-color.goml +++ b/tests/rustdoc-gui/scrape-examples-color.goml @@ -1,4 +1,5 @@ // Check that scrape example code blocks have the expected colors. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/scrape_examples/fn.test_many.html" show-text: true @@ -7,8 +8,7 @@ define-function: ( [theme, highlight, highlight_focus, help_border, help_color, help_hover_border, help_hover_color], block { - set-local-storage: { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false", } - reload: + call-function: ("switch-theme", {"theme": |theme|}) wait-for: ".more-examples-toggle" assert-css: (".scraped-example .example-wrap .rust span.highlight:not(.focus)", { "background-color": |highlight|, @@ -66,8 +66,7 @@ define-function: ( "check-background", [theme, background_color_start, background_color_end], block { - set-local-storage: { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false", } - reload: + call-function: ("switch-theme", {"theme": |theme|}) assert-css: (".scraped-example:not(.expanded) .code-wrapper::before", { "background-image": "linear-gradient(" + |background_color_start| + ", " + |background_color_end| + ")", diff --git a/tests/rustdoc-gui/scrape-examples-toggle.goml b/tests/rustdoc-gui/scrape-examples-toggle.goml index ea645d289244..a9d37048188c 100644 --- a/tests/rustdoc-gui/scrape-examples-toggle.goml +++ b/tests/rustdoc-gui/scrape-examples-toggle.goml @@ -1,4 +1,5 @@ // This tests checks that the "scraped examples" toggle is working as expected. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/scrape_examples/fn.test_many.html" // Checking the color of the toggle line. @@ -7,8 +8,7 @@ define-function: ( "check-color", [theme, toggle_line_color, toggle_line_hover_color], block { - set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} - reload: + call-function: ("switch-theme", {"theme": |theme|}) // Clicking "More examples..." will open additional examples assert-attribute-false: (".more-examples-toggle", {"open": ""}) diff --git a/tests/rustdoc-gui/search-error.goml b/tests/rustdoc-gui/search-error.goml index d3de77b5635c..4dc60669c7a5 100644 --- a/tests/rustdoc-gui/search-error.goml +++ b/tests/rustdoc-gui/search-error.goml @@ -1,4 +1,5 @@ // Checks that the crate search filtering is handled correctly and changes the results. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=sa'%3Bda'%3Bds" show-text: true @@ -6,11 +7,7 @@ define-function: ( "check-colors", [theme, error_background], block { - // Setting the theme. - set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} - // We reload the page so the local storage settings are being used. - reload: - + call-function: ("switch-theme", {"theme": |theme|}) wait-for: "#search .error code" assert-css: ("#search .error code", {"background-color": |error_background|}) } diff --git a/tests/rustdoc-gui/search-filter.goml b/tests/rustdoc-gui/search-filter.goml index 8c50322fcd4e..d6421599a207 100644 --- a/tests/rustdoc-gui/search-filter.goml +++ b/tests/rustdoc-gui/search-filter.goml @@ -1,4 +1,5 @@ // Checks that the crate search filtering is handled correctly and changes the results. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" show-text: true write-into: (".search-input", "test") @@ -59,8 +60,7 @@ assert-text: (".search-results-title", "Results in all crates", STARTS_WITH) // Checking the display of the crate filter. // We start with the light theme. -set-local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"} -reload: +call-function: ("switch-theme", {"theme": "light"}) set-timeout: 2000 wait-for: "#crate-search" diff --git a/tests/rustdoc-gui/search-form-elements.goml b/tests/rustdoc-gui/search-form-elements.goml index 2fc66259291c..63d2ceb3e7c1 100644 --- a/tests/rustdoc-gui/search-form-elements.goml +++ b/tests/rustdoc-gui/search-form-elements.goml @@ -1,4 +1,5 @@ // This test ensures that the elements in ".search-form" have the expected display. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" show-text: true @@ -9,11 +10,7 @@ define-function: ( menu_button_border, menu_button_a_color, menu_button_a_border_hover, menu_a_color, ], block { - set-local-storage: { - "rustdoc-theme": |theme|, - "rustdoc-use-system-theme": "false", - } - reload: + call-function: ("switch-theme", {"theme": |theme|}) assert-css: ( ".search-input", { diff --git a/tests/rustdoc-gui/search-no-result.goml b/tests/rustdoc-gui/search-no-result.goml index dda50ec3fb64..2e89278b46cb 100644 --- a/tests/rustdoc-gui/search-no-result.goml +++ b/tests/rustdoc-gui/search-no-result.goml @@ -1,4 +1,5 @@ // The goal of this test is to check the color of the "no result" links. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/lib2/index.html?search=sdkfskjfsdks" show-text: true @@ -6,9 +7,7 @@ define-function: ( "check-no-result", [theme, link, link_hover], block { - // Changing theme. - set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} - reload: + call-function: ("switch-theme", {"theme": |theme|}) wait-for: "#results" assert: ".search-failed.active" assert-css: ("#results a", {"color": |link|}, ALL) diff --git a/tests/rustdoc-gui/search-reexport.goml b/tests/rustdoc-gui/search-reexport.goml index 2e7c967d5c33..fa9eedeceac2 100644 --- a/tests/rustdoc-gui/search-reexport.goml +++ b/tests/rustdoc-gui/search-reexport.goml @@ -1,8 +1,8 @@ // Checks that the reexports are present in the search index, can have // doc aliases and are highligted when their ID is the hash of the page. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" -set-local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false"} -reload: +call-function: ("switch-theme", {"theme": "dark"}) // First we check that the reexport has the correct ID and no background color. assert-text: ("//*[@id='reexport.TheStdReexport']", "pub use ::std as TheStdReexport;") assert-css: ("//*[@id='reexport.TheStdReexport']", {"background-color": "rgba(0, 0, 0, 0)"}) diff --git a/tests/rustdoc-gui/search-result-color.goml b/tests/rustdoc-gui/search-result-color.goml index 1a19ea2d8432..d4da23fa156d 100644 --- a/tests/rustdoc-gui/search-result-color.goml +++ b/tests/rustdoc-gui/search-result-color.goml @@ -1,5 +1,6 @@ // The goal of this test is to ensure the color of the text is the one expected. +include: "utils.goml" define-function: ( "check-result-color", [result_kind, color, hover_color], @@ -43,11 +44,7 @@ go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=coo" show-text: true // Ayu theme -set-local-storage: { - "rustdoc-theme": "ayu", - "rustdoc-use-system-theme": "false", -} -reload: +call-function: ("switch-theme", {"theme": "ayu"}) // Waiting for the search results to appear... wait-for: "#search-tabs" @@ -155,11 +152,7 @@ assert-css: ( ) // Dark theme -set-local-storage: { - "rustdoc-theme": "dark", - "rustdoc-use-system-theme": "false", -} -reload: +call-function: ("switch-theme", {"theme": "dark"}) // Waiting for the search results to appear... wait-for: "#search-tabs" @@ -255,8 +248,7 @@ assert-css: ( ) // Light theme -set-local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"} -reload: +call-function: ("switch-theme", {"theme": "light"}) // Waiting for the search results to appear... wait-for: "#search-tabs" @@ -360,8 +352,7 @@ define-function: ( "check-alias", [theme, alias, grey], block { - set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} - reload: + call-function: ("switch-theme", {"theme": |theme|}) write-into: (".search-input", "thisisanalias") // To be SURE that the search will be run. press-key: 'Enter' diff --git a/tests/rustdoc-gui/search-result-display.goml b/tests/rustdoc-gui/search-result-display.goml index b1a5548808e0..3ca46f3c5693 100644 --- a/tests/rustdoc-gui/search-result-display.goml +++ b/tests/rustdoc-gui/search-result-display.goml @@ -1,5 +1,6 @@ // ignore-tidy-linelength // Checks that the search results have the expected width. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" set-window-size: (900, 1000) write-into: (".search-input", "test") @@ -71,8 +72,7 @@ define-function: ( "check-filter", [theme, border, filter, hover_border, hover_filter], block { - set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} - reload: + call-function: ("switch-theme", {"theme": |theme|}) wait-for: "#crate-search" assert-css: ("#crate-search", {"border": "1px solid " + |border|}) assert-css: ("#crate-search-div::after", {"filter": |filter|}) diff --git a/tests/rustdoc-gui/search-tab.goml b/tests/rustdoc-gui/search-tab.goml index c33866593c35..4329726398c1 100644 --- a/tests/rustdoc-gui/search-tab.goml +++ b/tests/rustdoc-gui/search-tab.goml @@ -1,4 +1,5 @@ // Checking the colors of the search tab headers. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html?search=foo" show-text: true @@ -8,9 +9,7 @@ define-function: ( border_bottom_selected, border_bottom_hover, border_top, border_top_selected, border_top_hover], block { - // Setting the theme. - set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} - reload: + call-function: ("switch-theme", {"theme": |theme|}) // These two commands are used to be sure the search will be run. focus: ".search-input" diff --git a/tests/rustdoc-gui/settings.goml b/tests/rustdoc-gui/settings.goml index 0bb21c28cb52..56d0f8624e8f 100644 --- a/tests/rustdoc-gui/settings.goml +++ b/tests/rustdoc-gui/settings.goml @@ -1,5 +1,6 @@ // This test ensures that the settings menu display is working as expected and that // the settings page is also rendered as expected. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" show-text: true // needed when we check for colors below. // First, we check that the settings page doesn't exist. @@ -35,8 +36,7 @@ wait-for: "#alternative-display #search" assert: "#main-content.hidden" // Now let's check the content of the settings menu. -set-local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false"} -reload: +call-function: ("switch-theme", {"theme": "dark"}) click: "#settings-menu" wait-for: "#settings" diff --git a/tests/rustdoc-gui/sidebar-links-color.goml b/tests/rustdoc-gui/sidebar-links-color.goml index 0edffc51a816..57c45555a76b 100644 --- a/tests/rustdoc-gui/sidebar-links-color.goml +++ b/tests/rustdoc-gui/sidebar-links-color.goml @@ -1,4 +1,5 @@ // This test checks links colors in sidebar before and after hover. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" // This is needed so that the text color is computed. @@ -13,8 +14,7 @@ define-function: ( type_hover_background, keyword, keyword_hover, keyword_hover_background, ], block { - set-local-storage: { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false" } - reload: + call-function: ("switch-theme", {"theme": |theme|}) // Struct assert-css: ( ".sidebar .block.struct li:not(.current) a", diff --git a/tests/rustdoc-gui/sidebar-mobile.goml b/tests/rustdoc-gui/sidebar-mobile.goml index 8843de8d7e94..b4ff483c1809 100644 --- a/tests/rustdoc-gui/sidebar-mobile.goml +++ b/tests/rustdoc-gui/sidebar-mobile.goml @@ -1,6 +1,7 @@ // This test ensure that the sidebar isn't "hidden" on mobile but instead moved out of the viewport. // This is especially important for devices for "text-first" content (like for users with // sight issues). +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" // Switching to "mobile view" by reducing the width to 600px. set-window-size: (600, 600) @@ -59,7 +60,7 @@ define-function: ( "check-colors", [theme, color, background], block { - set-local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": |theme|} + call-function: ("switch-theme", {"theme": |theme|}) reload: // Open the sidebar menu. diff --git a/tests/rustdoc-gui/sidebar-source-code-display.goml b/tests/rustdoc-gui/sidebar-source-code-display.goml index 41c8e45f4a6d..3bfbe820b8df 100644 --- a/tests/rustdoc-gui/sidebar-source-code-display.goml +++ b/tests/rustdoc-gui/sidebar-source-code-display.goml @@ -1,4 +1,5 @@ // This test ensures that the elements in the sidebar are displayed correctly. +include: "utils.goml" javascript: false go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html" // Since the javascript is disabled, there shouldn't be a toggle. @@ -34,8 +35,7 @@ define-function: ( theme, color, color_hover, background, background_hover, background_toggle, ], block { - set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} - reload: + call-function: ("switch-theme", {"theme": |theme|}) wait-for-css: (".src .sidebar > *", {"visibility": "visible"}) assert-css: ( "#src-sidebar details[open] > .files a.selected", diff --git a/tests/rustdoc-gui/sidebar-source-code.goml b/tests/rustdoc-gui/sidebar-source-code.goml index 3f7ef643d18e..ef0b5ab38b13 100644 --- a/tests/rustdoc-gui/sidebar-source-code.goml +++ b/tests/rustdoc-gui/sidebar-source-code.goml @@ -1,5 +1,6 @@ // The goal of this test is to ensure that the sidebar is working as expected in the source // code pages. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html" show-text: true @@ -8,11 +9,7 @@ define-function: ( "check-colors", [theme, color, background_color], block { - set-local-storage: { - "rustdoc-theme": |theme|, - "rustdoc-use-system-theme": "false", - } - reload: + call-function: ("switch-theme", {"theme": |theme|}) // Checking results colors. assert-css: (".src .sidebar", { "color": |color|, diff --git a/tests/rustdoc-gui/sidebar.goml b/tests/rustdoc-gui/sidebar.goml index 115b1eb323c4..452545958f96 100644 --- a/tests/rustdoc-gui/sidebar.goml +++ b/tests/rustdoc-gui/sidebar.goml @@ -1,4 +1,5 @@ // Checks multiple things on the sidebar display (width of its elements, colors, etc). +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" assert-property: (".sidebar", {"clientWidth": "200"}) show-text: true @@ -8,11 +9,7 @@ define-function: ( "check-colors", [theme, color, background_color], block { - set-local-storage: { - "rustdoc-theme": |theme|, - "rustdoc-use-system-theme": "false", - } - reload: + call-function: ("switch-theme", {"theme": |theme|}) // Checking results colors. assert-css: (".sidebar", { "color": |color|, @@ -46,9 +43,7 @@ call-function: ( } ) -set-local-storage: {"rustdoc-theme": "light"} -// We reload the page so the local storage settings are being used. -reload: +call-function: ("switch-theme", {"theme": "light"}) assert-text: (".sidebar > .sidebar-crate > h2 > a", "test_docs") // Crate root has no "location" element diff --git a/tests/rustdoc-gui/source-code-page.goml b/tests/rustdoc-gui/source-code-page.goml index e29d123d2270..619d2b37d8da 100644 --- a/tests/rustdoc-gui/source-code-page.goml +++ b/tests/rustdoc-gui/source-code-page.goml @@ -1,4 +1,5 @@ // Checks that the interactions with the source code pages are working as expected. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html" show-text: true // Check that we can click on the line number. @@ -23,8 +24,7 @@ define-function: ( "check-colors", [theme, color, background_color, highlight_color, highlight_background_color], block { - set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} - reload: + call-function: ("switch-theme", {"theme": |theme|}) assert-css: ( ".src-line-numbers > a:not(.line-highlighted)", {"color": |color|, "background-color": |background_color|}, diff --git a/tests/rustdoc-gui/stab-badge.goml b/tests/rustdoc-gui/stab-badge.goml index 46df0946c459..3568d7a3e48d 100644 --- a/tests/rustdoc-gui/stab-badge.goml +++ b/tests/rustdoc-gui/stab-badge.goml @@ -1,12 +1,13 @@ // All stability badges should have rounded corners and colored backgrounds. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" show-text: true define-function: ( "check-badge", [theme, background, color], block { - set-local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": |theme|} go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" + call-function: ("switch-theme", {"theme": |theme|}) assert: ".docblock .stab" assert: ".item-table .stab" assert-css: (".stab", { diff --git a/tests/rustdoc-gui/target.goml b/tests/rustdoc-gui/target.goml index 0f8f77093635..82bd34ed2746 100644 --- a/tests/rustdoc-gui/target.goml +++ b/tests/rustdoc-gui/target.goml @@ -1,4 +1,5 @@ // Check that the targeted element has the expected styles. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/lib2/struct.Foo.html#method.a_method" show-text: true @@ -9,8 +10,7 @@ define-function: ( "check-style", [theme, background, border], block { - set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} - reload: + call-function: ("switch-theme", {"theme": |theme|}) assert-css: ("#method\.a_method:target", { "background-color": |background|, "border-right": "3px solid " + |border|, diff --git a/tests/rustdoc-gui/theme-change.goml b/tests/rustdoc-gui/theme-change.goml index fdaf9d6289a3..589871105099 100644 --- a/tests/rustdoc-gui/theme-change.goml +++ b/tests/rustdoc-gui/theme-change.goml @@ -1,7 +1,7 @@ // Ensures that the theme change is working as expected. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" -set-local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "dark"} -reload: +call-function: ("switch-theme", {"theme": "dark"}) store-value: (background_light, "white") store-value: (background_dark, "#353535") @@ -68,8 +68,7 @@ assert: "#preferred-light-theme.setting-line.hidden" // Ensures that the custom theme feature is working as expected. go-to: "file://" + |DOC_PATH| + "/theme_css/index.html" -set-local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "dark"} -reload: +call-function: ("switch-theme", {"theme": "dark"}) store-value: (background_light, "white") store-value: (background_dark, "#353535") diff --git a/tests/rustdoc-gui/theme-in-history.goml b/tests/rustdoc-gui/theme-in-history.goml index 42c5b5e6e69e..71cc64ac6005 100644 --- a/tests/rustdoc-gui/theme-in-history.goml +++ b/tests/rustdoc-gui/theme-in-history.goml @@ -1,12 +1,10 @@ // Ensures that the theme is working when going back in history. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" + // Set the theme to dark. -set-local-storage: { - "rustdoc-theme": "dark", - "rustdoc-use-system-theme": "false", -} -// We reload the page so the local storage settings are being used. -reload: +call-function: ("switch-theme", {"theme": "dark"}) + assert-css: ("body", { "background-color": "#353535" }) assert-local-storage: { "rustdoc-theme": "dark" } diff --git a/tests/rustdoc-gui/toggle-docs.goml b/tests/rustdoc-gui/toggle-docs.goml index cfd18bd2e14f..1235ee4b754c 100644 --- a/tests/rustdoc-gui/toggle-docs.goml +++ b/tests/rustdoc-gui/toggle-docs.goml @@ -1,4 +1,5 @@ // Checks that the documentation toggles have the correct position, style and work as expected. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" assert-attribute: ("#main-content > details.top-doc", {"open": ""}) assert-text: ("#toggle-all-docs", "[−]") @@ -51,10 +52,7 @@ define-function: ( "check-color", [theme, filter], block { - // Setting the theme. - set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} - // We reload the page so the local storage settings are being used. - reload: + call-function: ("switch-theme", {"theme": |theme|}) assert-css: ("details.toggle > summary::before", { "opacity": "0.5", diff --git a/tests/rustdoc-gui/unsafe-fn.goml b/tests/rustdoc-gui/unsafe-fn.goml index 83503121a046..b8b2e1e27f52 100644 --- a/tests/rustdoc-gui/unsafe-fn.goml +++ b/tests/rustdoc-gui/unsafe-fn.goml @@ -1,4 +1,5 @@ // Check position and color of the `` for unsafe elements. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" // If the text isn't displayed, the browser doesn't compute color style correctly... show-text: true @@ -15,10 +16,7 @@ define-function: ( // `color` is the expected color of the `` element. [theme, color], block { - // Set the theme. - set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} - // We reload the page so the local storage settings are being used. - reload: + call-function: ("switch-theme", {"theme": |theme|}) assert-css: (".item-name sup", {"color": |color|}) }, ) diff --git a/tests/rustdoc-gui/utils.goml b/tests/rustdoc-gui/utils.goml new file mode 100644 index 000000000000..d9f8726ec531 --- /dev/null +++ b/tests/rustdoc-gui/utils.goml @@ -0,0 +1,11 @@ +// This file contains code to be re-used by other tests. +define-function: ( + "switch-theme", + [theme], + block { + // Set the theme. + set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} + // We reload the page so the local storage settings are being used. + reload: + }, +) diff --git a/tests/rustdoc-gui/warning-block.goml b/tests/rustdoc-gui/warning-block.goml index a5a47f868db2..34207ed58052 100644 --- a/tests/rustdoc-gui/warning-block.goml +++ b/tests/rustdoc-gui/warning-block.goml @@ -1,4 +1,5 @@ // Test to check that the "warning blocks" are displayed as expected. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" show-text: true @@ -7,8 +8,7 @@ define-function: ( "check-warning", [theme, color, border_color], block { - set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} - reload: + call-function: ("switch-theme", {"theme": |theme|}) // The IDs are added directly into the DOM to make writing this test easier. assert-css: ("#doc-warning-1", { diff --git a/tests/ui/async-await/async-closures/captures.rs b/tests/ui/async-await/async-closures/captures.rs index e3ab8713709d..0a9d0529bf54 100644 --- a/tests/ui/async-await/async-closures/captures.rs +++ b/tests/ui/async-await/async-closures/captures.rs @@ -79,4 +79,38 @@ async fn async_main() { }; call_once(c).await; } + + fn force_fnonce(f: impl async FnOnce() -> T) -> impl async FnOnce() -> T { + f + } + + // Capture something with `move`, but infer to `AsyncFnOnce` + { + let x = Hello(6); + let c = force_fnonce(async move || { + println!("{x:?}"); + }); + call_once(c).await; + + let x = &Hello(7); + let c = force_fnonce(async move || { + println!("{x:?}"); + }); + call_once(c).await; + } + + // Capture something by-ref, but infer to `AsyncFnOnce` + { + let x = Hello(8); + let c = force_fnonce(async || { + println!("{x:?}"); + }); + call_once(c).await; + + let x = &Hello(9); + let c = force_fnonce(async || { + println!("{x:?}"); + }); + call_once(c).await; + } } diff --git a/tests/ui/async-await/async-closures/captures.run.stdout b/tests/ui/async-await/async-closures/captures.run.stdout index a0db6d236fef..42a7999b2dcd 100644 --- a/tests/ui/async-await/async-closures/captures.run.stdout +++ b/tests/ui/async-await/async-closures/captures.run.stdout @@ -8,3 +8,7 @@ Hello(3) Hello(4) Hello(4) Hello(5) +Hello(6) +Hello(7) +Hello(8) +Hello(9) diff --git a/tests/ui/async-await/async-closures/wrong-fn-kind.rs b/tests/ui/async-await/async-closures/wrong-fn-kind.rs index 8502bb6e2d45..3d6f856874f2 100644 --- a/tests/ui/async-await/async-closures/wrong-fn-kind.rs +++ b/tests/ui/async-await/async-closures/wrong-fn-kind.rs @@ -2,18 +2,22 @@ #![feature(async_closure)] -fn main() { - fn needs_async_fn(_: impl async Fn()) {} +fn needs_async_fn(_: impl async Fn()) {} +fn a() { let mut x = 1; needs_async_fn(async || { - //~^ ERROR expected a closure that implements the `async Fn` trait, but this closure only implements `async FnMut` + //~^ ERROR cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure x += 1; }); +} +fn b() { let x = String::new(); needs_async_fn(move || async move { //~^ ERROR expected a closure that implements the `async Fn` trait, but this closure only implements `async FnOnce` println!("{x}"); }); } + +fn main() {} diff --git a/tests/ui/async-await/async-closures/wrong-fn-kind.stderr b/tests/ui/async-await/async-closures/wrong-fn-kind.stderr index d0f1948e48f8..e56389b32027 100644 --- a/tests/ui/async-await/async-closures/wrong-fn-kind.stderr +++ b/tests/ui/async-await/async-closures/wrong-fn-kind.stderr @@ -1,26 +1,5 @@ -error[E0525]: expected a closure that implements the `async Fn` trait, but this closure only implements `async FnMut` - --> $DIR/wrong-fn-kind.rs:9:20 - | -LL | needs_async_fn(async || { - | -------------- -^^^^^^^ - | | | - | _____|______________this closure implements `async FnMut`, not `async Fn` - | | | - | | required by a bound introduced by this call -LL | | -LL | | x += 1; - | | - closure is `async FnMut` because it mutates the variable `x` here -LL | | }); - | |_____- the requirement to implement `async Fn` derives from here - | -note: required by a bound in `needs_async_fn` - --> $DIR/wrong-fn-kind.rs:6:31 - | -LL | fn needs_async_fn(_: impl async Fn()) {} - | ^^^^^^^^^^ required by this bound in `needs_async_fn` - error[E0525]: expected a closure that implements the `async Fn` trait, but this closure only implements `async FnOnce` - --> $DIR/wrong-fn-kind.rs:15:20 + --> $DIR/wrong-fn-kind.rs:17:20 | LL | needs_async_fn(move || async move { | -------------- -^^^^^^ @@ -35,11 +14,29 @@ LL | | }); | |_____- the requirement to implement `async Fn` derives from here | note: required by a bound in `needs_async_fn` - --> $DIR/wrong-fn-kind.rs:6:31 + --> $DIR/wrong-fn-kind.rs:5:27 | -LL | fn needs_async_fn(_: impl async Fn()) {} - | ^^^^^^^^^^ required by this bound in `needs_async_fn` +LL | fn needs_async_fn(_: impl async Fn()) {} + | ^^^^^^^^^^ required by this bound in `needs_async_fn` + +error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure + --> $DIR/wrong-fn-kind.rs:9:29 + | +LL | fn needs_async_fn(_: impl async Fn()) {} + | --------------- change this to accept `FnMut` instead of `Fn` +... +LL | needs_async_fn(async || { + | _____--------------_--------_^ + | | | | + | | | in this closure + | | expects `Fn` instead of `FnMut` +LL | | +LL | | x += 1; + | | - mutable borrow occurs due to use of `x` in closure +LL | | }); + | |_____^ cannot borrow as mutable error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0525`. +Some errors have detailed explanations: E0525, E0596. +For more information about an error, try `rustc --explain E0525`. diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index cf18503b74bb..31553371101f 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -190,7 +190,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_os = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, `zkvm` + = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, `zkvm` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` @@ -263,7 +263,7 @@ LL | #[cfg(target_os = "linuz")] // testing that we suggest `linux` | | | help: there is a expected value with a similar name: `"linux"` | - = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, `zkvm` + = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, `zkvm` = note: see for more information about checking conditional configuration warning: 27 warnings emitted diff --git a/tests/ui/coherence/skip-reporting-if-references-err.current.stderr b/tests/ui/coherence/skip-reporting-if-references-err.current.stderr new file mode 100644 index 000000000000..5eef3256b2c3 --- /dev/null +++ b/tests/ui/coherence/skip-reporting-if-references-err.current.stderr @@ -0,0 +1,27 @@ +error[E0726]: implicit elided lifetime not allowed here + --> $DIR/skip-reporting-if-references-err.rs:10:9 + | +LL | impl ToUnit for T {} + | ^^^^^^ expected lifetime parameter + | +help: indicate the anonymous lifetime + | +LL | impl ToUnit<'_> for T {} + | ++++ + +error[E0277]: the trait bound `for<'a> (): ToUnit<'a>` is not satisfied + --> $DIR/skip-reporting-if-references-err.rs:15:29 + | +LL | impl Overlap for for<'a> fn(<() as ToUnit<'a>>::Unit) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> ToUnit<'a>` is not implemented for `()` + +error[E0277]: the trait bound `for<'a> (): ToUnit<'a>` is not satisfied + --> $DIR/skip-reporting-if-references-err.rs:15:18 + | +LL | impl Overlap for for<'a> fn(<() as ToUnit<'a>>::Unit) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> ToUnit<'a>` is not implemented for `()` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0277, E0726. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/coherence/skip-reporting-if-references-err.next.stderr b/tests/ui/coherence/skip-reporting-if-references-err.next.stderr new file mode 100644 index 000000000000..5de4cf626e48 --- /dev/null +++ b/tests/ui/coherence/skip-reporting-if-references-err.next.stderr @@ -0,0 +1,14 @@ +error[E0726]: implicit elided lifetime not allowed here + --> $DIR/skip-reporting-if-references-err.rs:10:9 + | +LL | impl ToUnit for T {} + | ^^^^^^ expected lifetime parameter + | +help: indicate the anonymous lifetime + | +LL | impl ToUnit<'_> for T {} + | ++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0726`. diff --git a/tests/ui/coherence/skip-reporting-if-references-err.rs b/tests/ui/coherence/skip-reporting-if-references-err.rs new file mode 100644 index 000000000000..f9eaa498232d --- /dev/null +++ b/tests/ui/coherence/skip-reporting-if-references-err.rs @@ -0,0 +1,19 @@ +// Regression test for #121006. +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +trait ToUnit<'a> { + type Unit; +} + +impl ToUnit for T {} +//~^ ERROR implicit elided lifetime not allowed here + +trait Overlap {} +impl Overlap for fn(U) {} +impl Overlap for for<'a> fn(<() as ToUnit<'a>>::Unit) {} +//[current]~^ ERROR the trait bound `for<'a> (): ToUnit<'a>` is not satisfied +//[current]~| ERROR the trait bound `for<'a> (): ToUnit<'a>` is not satisfied + +fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/opaque_type.rs b/tests/ui/const-generics/generic_const_exprs/opaque_type.rs new file mode 100644 index 000000000000..56b8acbf88cd --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/opaque_type.rs @@ -0,0 +1,18 @@ +#![feature(generic_const_exprs, type_alias_impl_trait)] +#![allow(incomplete_features)] + +type Foo = impl Sized; + +fn with_bound() -> Foo +where + [u8; (N / 2) as usize]: Sized, +{ + let _: [u8; (N / 2) as Foo] = [0; (N / 2) as usize]; + //~^ ERROR mismatched types + //~| ERROR non-primitive cast: `usize` as `Foo` + todo!() +} + +fn main() { + with_bound::<4>(); +} diff --git a/tests/ui/const-generics/generic_const_exprs/opaque_type.stderr b/tests/ui/const-generics/generic_const_exprs/opaque_type.stderr new file mode 100644 index 000000000000..e9fb8c0f403a --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/opaque_type.stderr @@ -0,0 +1,22 @@ +error[E0308]: mismatched types + --> $DIR/opaque_type.rs:10:17 + | +LL | type Foo = impl Sized; + | ---------- the found opaque type +... +LL | let _: [u8; (N / 2) as Foo] = [0; (N / 2) as usize]; + | ^^^^^^^^^^^^^^ expected `usize`, found opaque type + | + = note: expected type `usize` + found opaque type `Foo` + +error[E0605]: non-primitive cast: `usize` as `Foo` + --> $DIR/opaque_type.rs:10:17 + | +LL | let _: [u8; (N / 2) as Foo] = [0; (N / 2) as usize]; + | ^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0308, E0605. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/opaque_types.rs b/tests/ui/const-generics/opaque_types.rs new file mode 100644 index 000000000000..ccf70f4fb37b --- /dev/null +++ b/tests/ui/const-generics/opaque_types.rs @@ -0,0 +1,13 @@ +#![feature(type_alias_impl_trait)] + +type Foo = impl Sized; +//~^ ERROR: cycle +//~| ERROR: cycle + +fn foo() {} +//~^ ERROR: `Foo` is forbidden as the type of a const generic parameter + +fn main() { + foo::<42>(); + //~^ ERROR: mismatched types +} diff --git a/tests/ui/const-generics/opaque_types.stderr b/tests/ui/const-generics/opaque_types.stderr new file mode 100644 index 000000000000..f03bca69a8bb --- /dev/null +++ b/tests/ui/const-generics/opaque_types.stderr @@ -0,0 +1,125 @@ +error[E0308]: mismatched types + --> $DIR/opaque_types.rs:11:11 + | +LL | type Foo = impl Sized; + | ---------- the expected opaque type +... +LL | foo::<42>(); + | ^^ expected opaque type, found integer + | + = note: expected opaque type `Foo` + found type `{integer}` + +error[E0391]: cycle detected when computing type of `Foo::{opaque#0}` + --> $DIR/opaque_types.rs:3:12 + | +LL | type Foo = impl Sized; + | ^^^^^^^^^^ + | +note: ...which requires computing type of opaque `Foo::{opaque#0}`... + --> $DIR/opaque_types.rs:3:12 + | +LL | type Foo = impl Sized; + | ^^^^^^^^^^ +note: ...which requires type-checking `main`... + --> $DIR/opaque_types.rs:10:1 + | +LL | fn main() { + | ^^^^^^^^^ +note: ...which requires evaluating type-level constant... + --> $DIR/opaque_types.rs:11:11 + | +LL | foo::<42>(); + | ^^ +note: ...which requires const-evaluating + checking `main::{constant#0}`... + --> $DIR/opaque_types.rs:11:11 + | +LL | foo::<42>(); + | ^^ +note: ...which requires caching mir of `main::{constant#0}` for CTFE... + --> $DIR/opaque_types.rs:11:11 + | +LL | foo::<42>(); + | ^^ +note: ...which requires elaborating drops for `main::{constant#0}`... + --> $DIR/opaque_types.rs:11:11 + | +LL | foo::<42>(); + | ^^ + = note: ...which requires normalizing `Foo`... + = note: ...which again requires computing type of `Foo::{opaque#0}`, completing the cycle +note: cycle used when checking that `Foo::{opaque#0}` is well-formed + --> $DIR/opaque_types.rs:3:12 + | +LL | type Foo = impl Sized; + | ^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: `Foo` is forbidden as the type of a const generic parameter + --> $DIR/opaque_types.rs:7:17 + | +LL | fn foo() {} + | ^^^ + | + = note: the only supported types are integers, `bool` and `char` + +error[E0391]: cycle detected when computing type of opaque `Foo::{opaque#0}` + --> $DIR/opaque_types.rs:3:12 + | +LL | type Foo = impl Sized; + | ^^^^^^^^^^ + | +note: ...which requires type-checking `main`... + --> $DIR/opaque_types.rs:10:1 + | +LL | fn main() { + | ^^^^^^^^^ +note: ...which requires evaluating type-level constant... + --> $DIR/opaque_types.rs:11:11 + | +LL | foo::<42>(); + | ^^ +note: ...which requires const-evaluating + checking `main::{constant#0}`... + --> $DIR/opaque_types.rs:11:11 + | +LL | foo::<42>(); + | ^^ +note: ...which requires caching mir of `main::{constant#0}` for CTFE... + --> $DIR/opaque_types.rs:11:11 + | +LL | foo::<42>(); + | ^^ +note: ...which requires elaborating drops for `main::{constant#0}`... + --> $DIR/opaque_types.rs:11:11 + | +LL | foo::<42>(); + | ^^ +note: ...which requires borrow-checking `main::{constant#0}`... + --> $DIR/opaque_types.rs:11:11 + | +LL | foo::<42>(); + | ^^ +note: ...which requires promoting constants in MIR for `main::{constant#0}`... + --> $DIR/opaque_types.rs:11:11 + | +LL | foo::<42>(); + | ^^ +note: ...which requires const checking `main::{constant#0}`... + --> $DIR/opaque_types.rs:11:11 + | +LL | foo::<42>(); + | ^^ + = note: ...which requires computing whether `Foo` is freeze... + = note: ...which requires evaluating trait selection obligation `Foo: core::marker::Freeze`... + = note: ...which again requires computing type of opaque `Foo::{opaque#0}`, completing the cycle +note: cycle used when computing type of `Foo::{opaque#0}` + --> $DIR/opaque_types.rs:3:12 + | +LL | type Foo = impl Sized; + | ^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0308, E0391. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/opaque_types2.rs b/tests/ui/const-generics/opaque_types2.rs new file mode 100644 index 000000000000..fd57438bb617 --- /dev/null +++ b/tests/ui/const-generics/opaque_types2.rs @@ -0,0 +1,17 @@ +#![feature(type_alias_impl_trait)] + +type Foo = impl Sized; + +fn foo() {} + +const C: Foo = 42; + +fn bar() +where + Foo:, +{ + foo::(); + //~^ ERROR: mismatched types +} + +fn main() {} diff --git a/tests/ui/const-generics/opaque_types2.stderr b/tests/ui/const-generics/opaque_types2.stderr new file mode 100644 index 000000000000..2fb1669b7bfa --- /dev/null +++ b/tests/ui/const-generics/opaque_types2.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> $DIR/opaque_types2.rs:13:11 + | +LL | type Foo = impl Sized; + | ---------- the found opaque type +... +LL | foo::(); + | ^ expected `u32`, found opaque type + | + = note: expected type `u32` + found opaque type `Foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/extern/issue-95829.stderr b/tests/ui/extern/issue-95829.stderr index b902f0ef8f5c..16504d1f0c9d 100644 --- a/tests/ui/extern/issue-95829.stderr +++ b/tests/ui/extern/issue-95829.stderr @@ -16,17 +16,12 @@ LL | | } = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html error: functions in `extern` blocks cannot have qualifiers - --> $DIR/issue-95829.rs:4:14 + --> $DIR/issue-95829.rs:4:5 | LL | extern { | ------ in this `extern` block LL | async fn L() { - | ^ - | -help: remove the qualifiers - | -LL | fn L() { - | ~~ + | ^^^^^ help: remove this qualifier error: aborting due to 2 previous errors diff --git a/tests/ui/feature-gates/feature-gate-f128.stderr b/tests/ui/feature-gates/feature-gate-f128.e2015.stderr similarity index 91% rename from tests/ui/feature-gates/feature-gate-f128.stderr rename to tests/ui/feature-gates/feature-gate-f128.e2015.stderr index 299375c9aed9..771aee79dce1 100644 --- a/tests/ui/feature-gates/feature-gate-f128.stderr +++ b/tests/ui/feature-gates/feature-gate-f128.e2015.stderr @@ -1,5 +1,5 @@ error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:3:10 + --> $DIR/feature-gate-f128.rs:7:10 | LL | const A: f128 = 10.0; | ^^^^ @@ -9,7 +9,7 @@ LL | const A: f128 = 10.0; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:6:12 + --> $DIR/feature-gate-f128.rs:10:12 | LL | let a: f128 = 100.0; | ^^^^ @@ -19,7 +19,7 @@ LL | let a: f128 = 100.0; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:11:11 + --> $DIR/feature-gate-f128.rs:15:11 | LL | fn foo(a: f128) {} | ^^^^ @@ -29,7 +29,7 @@ LL | fn foo(a: f128) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:14:8 + --> $DIR/feature-gate-f128.rs:18:8 | LL | a: f128, | ^^^^ @@ -39,7 +39,7 @@ LL | a: f128, = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:7:13 + --> $DIR/feature-gate-f128.rs:11:13 | LL | let b = 0.0f128; | ^^^^^^^ diff --git a/tests/ui/feature-gates/feature-gate-f128.e2018.stderr b/tests/ui/feature-gates/feature-gate-f128.e2018.stderr new file mode 100644 index 000000000000..771aee79dce1 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-f128.e2018.stderr @@ -0,0 +1,53 @@ +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:7:10 + | +LL | const A: f128 = 10.0; + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:10:12 + | +LL | let a: f128 = 100.0; + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:15:11 + | +LL | fn foo(a: f128) {} + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:18:8 + | +LL | a: f128, + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:11:13 + | +LL | let b = 0.0f128; + | ^^^^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-f128.rs b/tests/ui/feature-gates/feature-gate-f128.rs index 7f60fb6afa08..d25b6dde4ee4 100644 --- a/tests/ui/feature-gates/feature-gate-f128.rs +++ b/tests/ui/feature-gates/feature-gate-f128.rs @@ -1,3 +1,7 @@ +//@ revisions: e2015 e2018 +// +//@[e2018] edition:2018 + #![allow(unused)] const A: f128 = 10.0; //~ ERROR the type `f128` is unstable diff --git a/tests/ui/feature-gates/feature-gate-f16.stderr b/tests/ui/feature-gates/feature-gate-f16.e2015.stderr similarity index 91% rename from tests/ui/feature-gates/feature-gate-f16.stderr rename to tests/ui/feature-gates/feature-gate-f16.e2015.stderr index e54b54a47bde..2bb3b59465a0 100644 --- a/tests/ui/feature-gates/feature-gate-f16.stderr +++ b/tests/ui/feature-gates/feature-gate-f16.e2015.stderr @@ -1,5 +1,5 @@ error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:3:10 + --> $DIR/feature-gate-f16.rs:7:10 | LL | const A: f16 = 10.0; | ^^^ @@ -9,7 +9,7 @@ LL | const A: f16 = 10.0; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:6:12 + --> $DIR/feature-gate-f16.rs:10:12 | LL | let a: f16 = 100.0; | ^^^ @@ -19,7 +19,7 @@ LL | let a: f16 = 100.0; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:11:11 + --> $DIR/feature-gate-f16.rs:15:11 | LL | fn foo(a: f16) {} | ^^^ @@ -29,7 +29,7 @@ LL | fn foo(a: f16) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:14:8 + --> $DIR/feature-gate-f16.rs:18:8 | LL | a: f16, | ^^^ @@ -39,7 +39,7 @@ LL | a: f16, = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:7:13 + --> $DIR/feature-gate-f16.rs:11:13 | LL | let b = 0.0f16; | ^^^^^^ diff --git a/tests/ui/feature-gates/feature-gate-f16.e2018.stderr b/tests/ui/feature-gates/feature-gate-f16.e2018.stderr new file mode 100644 index 000000000000..2bb3b59465a0 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-f16.e2018.stderr @@ -0,0 +1,53 @@ +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:7:10 + | +LL | const A: f16 = 10.0; + | ^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:10:12 + | +LL | let a: f16 = 100.0; + | ^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:15:11 + | +LL | fn foo(a: f16) {} + | ^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:18:8 + | +LL | a: f16, + | ^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:11:13 + | +LL | let b = 0.0f16; + | ^^^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-f16.rs b/tests/ui/feature-gates/feature-gate-f16.rs index 31d8f87f3ba6..af906d71f5fe 100644 --- a/tests/ui/feature-gates/feature-gate-f16.rs +++ b/tests/ui/feature-gates/feature-gate-f16.rs @@ -1,3 +1,7 @@ +//@ revisions: e2015 e2018 +// +//@[e2018] edition:2018 + #![allow(unused)] const A: f16 = 10.0; //~ ERROR the type `f16` is unstable diff --git a/tests/ui/feature-gates/feature-gate-proc_macro_byte_character.rs b/tests/ui/feature-gates/feature-gate-proc_macro_byte_character.rs deleted file mode 100644 index 03071c351a44..000000000000 --- a/tests/ui/feature-gates/feature-gate-proc_macro_byte_character.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ force-host -#![crate_type = "proc-macro"] - -extern crate proc_macro; - -use proc_macro::Literal; - -fn test() { - Literal::byte_character(b'a'); //~ ERROR use of unstable library feature 'proc_macro_byte_character' -} diff --git a/tests/ui/feature-gates/feature-gate-proc_macro_byte_character.stderr b/tests/ui/feature-gates/feature-gate-proc_macro_byte_character.stderr deleted file mode 100644 index c14d19381c8b..000000000000 --- a/tests/ui/feature-gates/feature-gate-proc_macro_byte_character.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0658]: use of unstable library feature 'proc_macro_byte_character' - --> $DIR/feature-gate-proc_macro_byte_character.rs:9:5 - | -LL | Literal::byte_character(b'a'); - | ^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #115268 for more information - = help: add `#![feature(proc_macro_byte_character)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-proc_macro_c_str_literals.rs b/tests/ui/feature-gates/feature-gate-proc_macro_c_str_literals.rs deleted file mode 100644 index 1750fe952f56..000000000000 --- a/tests/ui/feature-gates/feature-gate-proc_macro_c_str_literals.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ edition: 2021 -//@ force-host -#![crate_type = "proc-macro"] - -extern crate proc_macro; - -use proc_macro::Literal; - -fn test() { - Literal::c_string(c"a"); //~ ERROR use of unstable library feature 'proc_macro_c_str_literals' -} diff --git a/tests/ui/feature-gates/feature-gate-proc_macro_c_str_literals.stderr b/tests/ui/feature-gates/feature-gate-proc_macro_c_str_literals.stderr deleted file mode 100644 index 9bba1d50ce36..000000000000 --- a/tests/ui/feature-gates/feature-gate-proc_macro_c_str_literals.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0658]: use of unstable library feature 'proc_macro_c_str_literals' - --> $DIR/feature-gate-proc_macro_c_str_literals.rs:10:5 - | -LL | Literal::c_string(c"a"); - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #119750 for more information - = help: add `#![feature(proc_macro_c_str_literals)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-ref_pat_everywhere.rs b/tests/ui/feature-gates/feature-gate-ref_pat_everywhere.rs new file mode 100644 index 000000000000..ed5db56e0e83 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-ref_pat_everywhere.rs @@ -0,0 +1,14 @@ +pub fn main() { + if let Some(Some(&x)) = &Some(&Some(0)) { + //~^ ERROR: mismatched types [E0308] + let _: u32 = x; + } + if let Some(&Some(x)) = &Some(Some(0)) { + //~^ ERROR: mismatched types [E0308] + let _: u32 = x; + } + if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { + //~^ ERROR: mismatched types [E0308] + let _: u32 = x; + } +} diff --git a/tests/ui/feature-gates/feature-gate-ref_pat_everywhere.stderr b/tests/ui/feature-gates/feature-gate-ref_pat_everywhere.stderr new file mode 100644 index 000000000000..0f0051325cdf --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-ref_pat_everywhere.stderr @@ -0,0 +1,49 @@ +error[E0308]: mismatched types + --> $DIR/feature-gate-ref_pat_everywhere.rs:2:22 + | +LL | if let Some(Some(&x)) = &Some(&Some(0)) { + | ^^ --------------- this expression has type `&Option<&Option<{integer}>>` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL | if let Some(Some(x)) = &Some(&Some(0)) { + | ~ + +error[E0308]: mismatched types + --> $DIR/feature-gate-ref_pat_everywhere.rs:6:17 + | +LL | if let Some(&Some(x)) = &Some(Some(0)) { + | ^^^^^^^^ -------------- this expression has type `&Option>` + | | + | expected `Option<{integer}>`, found `&_` + | + = note: expected enum `Option<{integer}>` + found reference `&_` + +error[E0308]: mismatched types + --> $DIR/feature-gate-ref_pat_everywhere.rs:10:22 + | +LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { + | ^^^^^^ ----------------------- this expression has type `&mut Option<&mut Option<{integer}>>` + | | + | expected integer, found `&mut _` + | + = note: expected type `{integer}` + found mutable reference `&mut _` +note: to declare a mutable binding use: `mut x` + --> $DIR/feature-gate-ref_pat_everywhere.rs:10:22 + | +LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { + | ^^^^^^ +help: consider removing `&mut` from the pattern + | +LL | if let Some(Some(x)) = &mut Some(&mut Some(0)) { + | ~ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/fn/fn-item-lifetime-bounds.rs b/tests/ui/fn/fn-item-lifetime-bounds.rs deleted file mode 100644 index b80b7eade23d..000000000000 --- a/tests/ui/fn/fn-item-lifetime-bounds.rs +++ /dev/null @@ -1,37 +0,0 @@ -//@ check-pass -//@ known-bug: #84533 - -// Should fail. Lifetimes are checked correctly when `foo` is called, but NOT -// when only the lifetime parameters are instantiated. - -use std::marker::PhantomData; - -#[allow(dead_code)] -fn foo<'b, 'a>() -> PhantomData<&'b &'a ()> { - PhantomData -} - -#[allow(dead_code)] -#[allow(path_statements)] -fn caller<'b, 'a>() { - foo::<'b, 'a>; -} - -// In contrast to above, below code correctly does NOT compile. -// fn caller<'b, 'a>() { -// foo::<'b, 'a>(); -// } - -// error: lifetime may not live long enough -// --> src/main.rs:22:5 -// | -// 21 | fn caller<'b, 'a>() { -// | -- -- lifetime `'a` defined here -// | | -// | lifetime `'b` defined here -// 22 | foo::<'b, 'a>(); -// | ^^^^^^^^^^^^^^^ requires that `'a` must outlive `'b` -// | -// = help: consider adding the following bound: `'a: 'b` - -fn main() {} diff --git a/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.next.stderr b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.next.stderr index 06ffff057f90..d913b2e91ca0 100644 --- a/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.next.stderr +++ b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.next.stderr @@ -6,7 +6,7 @@ LL | cmp_eq | = note: cannot satisfy `_: Scalar` note: required by a bound in `cmp_eq` - --> $DIR/ambig-hr-projection-issue-93340.rs:9:22 + --> $DIR/ambig-hr-projection-issue-93340.rs:10:22 | LL | fn cmp_eq<'a, 'b, A: Scalar, B: Scalar, O: Scalar>(a: A::RefType<'a>, b: B::RefType<'b>) -> O { | ^^^^^^ required by this bound in `cmp_eq` @@ -15,34 +15,6 @@ help: consider specifying the generic arguments LL | cmp_eq:: | +++++++++++ -error[E0275]: overflow evaluating the requirement `impl for<'a, 'b> Fn(::RefType<'a>, ::RefType<'b>) -> O == for<'a, 'b> fn(..., ...) -> ... {cmp_eq::<..., ..., ...>}` - --> $DIR/ambig-hr-projection-issue-93340.rs:16:5 - | -LL | cmp_eq - | ^^^^^^ +error: aborting due to 1 previous error -error[E0275]: overflow evaluating the requirement `impl for<'a, 'b> Fn(::RefType<'a>, ::RefType<'b>) -> O == for<'a, 'b> fn(..., ...) -> ... {cmp_eq::<..., ..., ...>}` - --> $DIR/ambig-hr-projection-issue-93340.rs:16:5 - | -LL | cmp_eq - | ^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0275]: overflow evaluating the requirement `for<'a, 'b> fn(::RefType<'a>, <_ as Scalar>::RefType<'b>) -> _ {cmp_eq::} <: ...` - --> $DIR/ambig-hr-projection-issue-93340.rs:14:51 - | -LL | ) -> impl Fn(A::RefType<'_>, B::RefType<'_>) -> O { - | ___________________________________________________^ -LL | | -LL | | cmp_eq -LL | | -LL | | -LL | | -LL | | } - | |_^ - -error: aborting due to 4 previous errors - -Some errors have detailed explanations: E0275, E0283. -For more information about an error, try `rustc --explain E0275`. +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.old.stderr b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.old.stderr index df2ec4ab182a..d913b2e91ca0 100644 --- a/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.old.stderr +++ b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.old.stderr @@ -6,7 +6,7 @@ LL | cmp_eq | = note: cannot satisfy `_: Scalar` note: required by a bound in `cmp_eq` - --> $DIR/ambig-hr-projection-issue-93340.rs:9:22 + --> $DIR/ambig-hr-projection-issue-93340.rs:10:22 | LL | fn cmp_eq<'a, 'b, A: Scalar, B: Scalar, O: Scalar>(a: A::RefType<'a>, b: B::RefType<'b>) -> O { | ^^^^^^ required by this bound in `cmp_eq` diff --git a/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.rs b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.rs index 4d8ea9d8d481..acfebad38db0 100644 --- a/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.rs +++ b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.rs @@ -1,4 +1,5 @@ //@ revisions: old next +//@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver pub trait Scalar: 'static { type RefType<'a>: ScalarRef<'a>; @@ -12,11 +13,8 @@ fn cmp_eq<'a, 'b, A: Scalar, B: Scalar, O: Scalar>(a: A::RefType<'a>, b: B::RefT fn build_expression( ) -> impl Fn(A::RefType<'_>, B::RefType<'_>) -> O { - //[next]~^ ERROR overflow evaluating the requirement cmp_eq //~^ ERROR type annotations needed - //[next]~| ERROR overflow evaluating the requirement - //[next]~| ERROR overflow evaluating the requirement } fn main() {} diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-1.rs b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-1.rs new file mode 100644 index 000000000000..b448f0bdc777 --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-1.rs @@ -0,0 +1,28 @@ +// cc #119820 + +trait Trait {} + +impl Trait for &T {} +impl Trait for u32 {} + +fn hr_bound() +where + for<'a> &'a T: Trait, +{ +} + +fn foo() +where + T: Trait, + for<'a> &'a &'a T: Trait, +{ + // We get a universe error when using the `param_env` candidate + // but are able to successfully use the impl candidate. Without + // the leak check both candidates may apply and we prefer the + // `param_env` candidate in winnowing. + hr_bound::<&T>(); + //~^ ERROR the parameter type `T` may not live long enough + //~| ERROR implementation of `Trait` is not general enough +} + +fn main() {} diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-1.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-1.stderr new file mode 100644 index 000000000000..febe252d7d1d --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-1.stderr @@ -0,0 +1,26 @@ +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/candidate-from-env-universe-err-1.rs:23:5 + | +LL | hr_bound::<&T>(); + | ^^^^^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | T: Trait + 'static, + | +++++++++ + +error: implementation of `Trait` is not general enough + --> $DIR/candidate-from-env-universe-err-1.rs:23:5 + | +LL | hr_bound::<&T>(); + | ^^^^^^^^^^^^^^ implementation of `Trait` is not general enough + | + = note: `Trait` would have to be implemented for the type `&'0 &T`, for any lifetime `'0`... + = note: ...but `Trait` is actually implemented for the type `&'1 &'1 T`, for some specific lifetime `'1` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0310`. diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.current.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.current.stderr new file mode 100644 index 000000000000..22ce87c02486 --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.current.stderr @@ -0,0 +1,25 @@ +error: lifetime may not live long enough + --> $DIR/candidate-from-env-universe-err-2.rs:14:5 + | +LL | fn not_hr<'a, T: for<'b> Trait<'a, 'b> + OtherTrait<'static>>() { + | -- lifetime `'a` defined here +LL | impl_hr::(); + | ^^^^^^^^^^^^ requires that `'a` must outlive `'static` + | +note: due to current limitations in the borrow checker, this implies a `'static` lifetime + --> $DIR/candidate-from-env-universe-err-2.rs:11:19 + | +LL | fn impl_hr<'b, T: for<'a> Trait<'a, 'b>>() {} + | ^^^^^^^^^^^^^^^^^^^^^ + +error: implementation of `Trait` is not general enough + --> $DIR/candidate-from-env-universe-err-2.rs:14:5 + | +LL | impl_hr::(); + | ^^^^^^^^^^^^ implementation of `Trait` is not general enough + | + = note: `T` must implement `Trait<'0, '_>`, for any lifetime `'0`... + = note: ...but it actually implements `Trait<'1, '_>`, for some specific lifetime `'1` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.next.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.next.stderr new file mode 100644 index 000000000000..a61bc748bea2 --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.next.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `for<'a> T: Trait<'a, '_>` is not satisfied + --> $DIR/candidate-from-env-universe-err-2.rs:14:5 + | +LL | impl_hr::(); + | ^^^^^^^^^^^^^^ the trait `for<'a> Trait<'a, '_>` is not implemented for `T` + | +note: required by a bound in `impl_hr` + --> $DIR/candidate-from-env-universe-err-2.rs:11:19 + | +LL | fn impl_hr<'b, T: for<'a> Trait<'a, 'b>>() {} + | ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impl_hr` +help: consider further restricting this bound + | +LL | fn not_hr<'a, T: for<'b> Trait<'a, 'b> + OtherTrait<'static> + for<'a> Trait<'a, '_>>() { + | +++++++++++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.old.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.old.stderr new file mode 100644 index 000000000000..29a72b1c1b64 --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.old.stderr @@ -0,0 +1,26 @@ +error: lifetime may not live long enough + --> $DIR/candidate-from-env-universe-err-2.rs:14:5 + | +LL | fn not_hr<'a, T: for<'b> Trait<'a, 'b> + OtherTrait<'static>>() { + | -- lifetime `'a` defined here +LL | impl_hr::(); + | ^^^^^^^^^^^^ requires that `'a` must outlive `'static` + | +note: due to current limitations in the borrow checker, this implies a `'static` lifetime + --> $DIR/candidate-from-env-universe-err-2.rs:11:19 + | +LL | fn impl_hr<'b, T: for<'a> Trait<'a, 'b>>() {} + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/candidate-from-env-universe-err-2.rs:14:5 + | +LL | impl_hr::(); + | ^^^^^^^^^^^^ one type is more general than the other + | + = note: expected trait `for<'a> Trait<'a, '_>` + found trait `for<'b> Trait<'_, 'b>` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.rs b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.rs new file mode 100644 index 000000000000..56fa70469ccf --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.rs @@ -0,0 +1,20 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver + +// cc #119820 + +trait Trait<'a, 'b> {} + +trait OtherTrait<'b> {} +impl<'a, 'b, T: OtherTrait<'b>> Trait<'a, 'b> for T {} + +fn impl_hr<'b, T: for<'a> Trait<'a, 'b>>() {} + +fn not_hr<'a, T: for<'b> Trait<'a, 'b> + OtherTrait<'static>>() { + impl_hr::(); + //[next]~^ ERROR the trait bound `for<'a> T: Trait<'a, '_>` is not satisfied + //[current]~^^ERROR lifetime may not live long enough + //[current]~| ERROR implementation of `Trait` is not general enough +} + +fn main() {} diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.current.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.current.stderr new file mode 100644 index 000000000000..bb0b2de788e8 --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.current.stderr @@ -0,0 +1,54 @@ +error: implementation of `Trait` is not general enough + --> $DIR/candidate-from-env-universe-err-project.rs:28:5 + | +LL | trait_bound::(); + | ^^^^^^^^^^^^^^^^^^ implementation of `Trait` is not general enough + | + = note: `T` must implement `Trait<'0>`, for any lifetime `'0`... + = note: ...but it actually implements `Trait<'static>` + +error: implementation of `Trait` is not general enough + --> $DIR/candidate-from-env-universe-err-project.rs:39:5 + | +LL | projection_bound::(); + | ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Trait` is not general enough + | + = note: `T` must implement `Trait<'0>`, for any lifetime `'0`... + = note: ...but it actually implements `Trait<'static>` + +error[E0308]: mismatched types + --> $DIR/candidate-from-env-universe-err-project.rs:39:5 + | +LL | projection_bound::(); + | ^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other + | + = note: expected associated type `>::Assoc` + found associated type `>::Assoc` +note: the lifetime requirement is introduced here + --> $DIR/candidate-from-env-universe-err-project.rs:18:42 + | +LL | fn projection_bound Trait<'a, Assoc = usize>>() {} + | ^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/candidate-from-env-universe-err-project.rs:55:30 + | +LL | let _higher_ranked_norm: for<'a> fn(>::Assoc) = |_| (); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other + | + = note: expected associated type `>::Assoc` + found associated type `>::Assoc` + +error[E0308]: mismatched types + --> $DIR/candidate-from-env-universe-err-project.rs:55:30 + | +LL | let _higher_ranked_norm: for<'a> fn(>::Assoc) = |_| (); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other + | + = note: expected associated type `>::Assoc` + found associated type `>::Assoc` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr new file mode 100644 index 000000000000..2804d5bbe940 --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr @@ -0,0 +1,67 @@ +error[E0277]: the trait bound `for<'a> T: Trait<'a>` is not satisfied + --> $DIR/candidate-from-env-universe-err-project.rs:28:19 + | +LL | trait_bound::(); + | ^ the trait `for<'a> Trait<'a>` is not implemented for `T` + | +note: required by a bound in `trait_bound` + --> $DIR/candidate-from-env-universe-err-project.rs:17:19 + | +LL | fn trait_bound Trait<'a>>() {} + | ^^^^^^^^^^^^^^^^^ required by this bound in `trait_bound` +help: consider further restricting this bound + | +LL | fn function1 + for<'a> Trait<'a>>() { + | +++++++++++++++++++ + +error[E0277]: the trait bound `for<'a> T: Trait<'a>` is not satisfied + --> $DIR/candidate-from-env-universe-err-project.rs:39:24 + | +LL | projection_bound::(); + | ^ the trait `for<'a> Trait<'a>` is not implemented for `T` + | +note: required by a bound in `projection_bound` + --> $DIR/candidate-from-env-universe-err-project.rs:18:24 + | +LL | fn projection_bound Trait<'a, Assoc = usize>>() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `projection_bound` +help: consider further restricting this bound + | +LL | fn function2 + for<'a> Trait<'a>>() { + | +++++++++++++++++++ + +error[E0271]: type mismatch resolving `>::Assoc == usize` + --> $DIR/candidate-from-env-universe-err-project.rs:39:24 + | +LL | projection_bound::(); + | ^ type mismatch resolving `>::Assoc == usize` + | +note: types differ + --> $DIR/candidate-from-env-universe-err-project.rs:14:18 + | +LL | type Assoc = usize; + | ^^^^^ +note: required by a bound in `projection_bound` + --> $DIR/candidate-from-env-universe-err-project.rs:18:42 + | +LL | fn projection_bound Trait<'a, Assoc = usize>>() {} + | ^^^^^^^^^^^^^ required by this bound in `projection_bound` + +error: higher-ranked subtype error + --> $DIR/candidate-from-env-universe-err-project.rs:55:30 + | +LL | let _higher_ranked_norm: for<'a> fn(>::Assoc) = |_| (); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: higher-ranked subtype error + --> $DIR/candidate-from-env-universe-err-project.rs:55:30 + | +LL | let _higher_ranked_norm: for<'a> fn(>::Assoc) = |_| (); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0271, E0277. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs new file mode 100644 index 000000000000..2f53bd019b78 --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs @@ -0,0 +1,62 @@ +//@ revisions: next current +//@[next] compile-flags: -Znext-solver + +// cc #119820 the previous behavior here was inconsistent as we discarded +// the where-bound candidate for trait goals due to the leak check, but did +// not do so for projection candidates and during normalization. +// +// This results in an inconsistency between `Trait` and `Projection` goals as +// normalizing always constraints the normalized-to term. +trait Trait<'a> { + type Assoc; +} +impl<'a, T> Trait<'a> for T { + type Assoc = usize; +} + +fn trait_bound Trait<'a>>() {} +fn projection_bound Trait<'a, Assoc = usize>>() {} + +// We use a function with a trivial where-bound which is more +// restrictive than the impl. +fn function1>() { + // err + // + // Proving `for<'a> T: Trait<'a>` using the where-bound does not + // result in a leak check failure even though it does not apply. + // We prefer env candidates over impl candidatescausing this to succeed. + trait_bound::(); + //[next]~^ ERROR the trait bound `for<'a> T: Trait<'a>` is not satisfied + //[current]~^^ ERROR implementation of `Trait` is not general enough +} + +fn function2>() { + // err + // + // Proving the `Projection` goal `for<'a> T: Trait<'a, Assoc = usize>` + // does not use the leak check when trying the where-bound, causing us + // to prefer it over the impl, resulting in a placeholder error. + projection_bound::(); + //[next]~^ ERROR type mismatch resolving `>::Assoc == usize` + //[next]~| ERROR the trait bound `for<'a> T: Trait<'a>` is not satisfied + //[current]~^^^ ERROR implementation of `Trait` is not general enough + //[current]~| ERROR mismatched types +} + +fn function3>() { + // err + // + // Trying to normalize the type `for<'a> fn(>::Assoc)` + // only gets to `>::Assoc` once `'a` has been already + // instantiated, causing us to prefer the where-bound over the impl + // resulting in a placeholder error. Even if were were to also use the + // leak check during candidate selection for normalization, this + // case would still not compile. + let _higher_ranked_norm: for<'a> fn(>::Assoc) = |_| (); + //[next]~^ ERROR higher-ranked subtype error + //[next]~| ERROR higher-ranked subtype error + //[current]~^^^ ERROR mismatched types + //[current]~| ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/higher-ranked/leak-check-in-selection.rs b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-1.rs similarity index 100% rename from tests/ui/higher-ranked/leak-check-in-selection.rs rename to tests/ui/higher-ranked/leak-check/leak-check-in-selection-1.rs diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.next.stderr b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.next.stderr new file mode 100644 index 000000000000..a840304e49c1 --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.next.stderr @@ -0,0 +1,23 @@ +error[E0283]: type annotations needed + --> $DIR/leak-check-in-selection-2.rs:16:5 + | +LL | impls_trait::<(), _>(); + | ^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `impls_trait` + | +note: multiple `impl`s satisfying `for<'a> (): Trait<&'a str, _>` found + --> $DIR/leak-check-in-selection-2.rs:9:1 + | +LL | impl<'a> Trait<&'a str, &'a str> for () {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | impl<'a> Trait<&'a str, String> for () {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `impls_trait` + --> $DIR/leak-check-in-selection-2.rs:13:19 + | +LL | fn impls_trait Trait<&'a str, U>, U>() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impls_trait` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.old.stderr b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.old.stderr new file mode 100644 index 000000000000..a840304e49c1 --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.old.stderr @@ -0,0 +1,23 @@ +error[E0283]: type annotations needed + --> $DIR/leak-check-in-selection-2.rs:16:5 + | +LL | impls_trait::<(), _>(); + | ^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `impls_trait` + | +note: multiple `impl`s satisfying `for<'a> (): Trait<&'a str, _>` found + --> $DIR/leak-check-in-selection-2.rs:9:1 + | +LL | impl<'a> Trait<&'a str, &'a str> for () {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | impl<'a> Trait<&'a str, String> for () {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `impls_trait` + --> $DIR/leak-check-in-selection-2.rs:13:19 + | +LL | fn impls_trait Trait<&'a str, U>, U>() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impls_trait` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.rs b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.rs new file mode 100644 index 000000000000..48dd569f201b --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.rs @@ -0,0 +1,18 @@ +//@ revisions: old next +//@[next] compile-flags: -Znext-solver + +// cc #119820 + +trait Trait {} + +// using this impl results in a higher-ranked region error. +impl<'a> Trait<&'a str, &'a str> for () {} + +impl<'a> Trait<&'a str, String> for () {} + +fn impls_trait Trait<&'a str, U>, U>() {} + +fn main() { + impls_trait::<(), _>(); + //~^ ERROR type annotations needed +} diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.next.stderr b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.next.stderr new file mode 100644 index 000000000000..8a8118dea859 --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.next.stderr @@ -0,0 +1,35 @@ +error[E0283]: type annotations needed + --> $DIR/leak-check-in-selection-3.rs:18:5 + | +LL | impls_leak::>(); + | ^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls_leak` + | +note: multiple `impl`s satisfying `for<'a> Box<_>: Leak<'a>` found + --> $DIR/leak-check-in-selection-3.rs:9:1 + | +LL | impl Leak<'_> for Box {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl Leak<'static> for Box {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `impls_leak` + --> $DIR/leak-check-in-selection-3.rs:12:18 + | +LL | fn impls_leak Leak<'a>>() {} + | ^^^^^^^^^^^^^^^^ required by this bound in `impls_leak` + +error[E0283]: type annotations needed + --> $DIR/leak-check-in-selection-3.rs:35:5 + | +LL | impls_indirect_leak::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls_indirect_leak` + | + = note: cannot satisfy `for<'a> Box<_>: IndirectLeak<'a>` +note: required by a bound in `impls_indirect_leak` + --> $DIR/leak-check-in-selection-3.rs:25:27 + | +LL | fn impls_indirect_leak IndirectLeak<'a>>() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impls_indirect_leak` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.old.stderr b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.old.stderr new file mode 100644 index 000000000000..662a06537401 --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.old.stderr @@ -0,0 +1,48 @@ +error[E0283]: type annotations needed + --> $DIR/leak-check-in-selection-3.rs:18:5 + | +LL | impls_leak::>(); + | ^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls_leak` + | +note: multiple `impl`s satisfying `for<'a> Box<_>: Leak<'a>` found + --> $DIR/leak-check-in-selection-3.rs:9:1 + | +LL | impl Leak<'_> for Box {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl Leak<'static> for Box {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `impls_leak` + --> $DIR/leak-check-in-selection-3.rs:12:18 + | +LL | fn impls_leak Leak<'a>>() {} + | ^^^^^^^^^^^^^^^^ required by this bound in `impls_leak` + +error[E0283]: type annotations needed + --> $DIR/leak-check-in-selection-3.rs:35:5 + | +LL | impls_indirect_leak::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls_indirect_leak` + | +note: multiple `impl`s satisfying `Box<_>: Leak<'_>` found + --> $DIR/leak-check-in-selection-3.rs:9:1 + | +LL | impl Leak<'_> for Box {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl Leak<'static> for Box {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required for `Box<_>` to implement `for<'a> IndirectLeak<'a>` + --> $DIR/leak-check-in-selection-3.rs:23:23 + | +LL | impl<'a, T: Leak<'a>> IndirectLeak<'a> for T {} + | -------- ^^^^^^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here +note: required by a bound in `impls_indirect_leak` + --> $DIR/leak-check-in-selection-3.rs:25:27 + | +LL | fn impls_indirect_leak IndirectLeak<'a>>() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impls_indirect_leak` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.rs b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.rs new file mode 100644 index 000000000000..9e99b6c527d9 --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.rs @@ -0,0 +1,39 @@ +//@ revisions: old next +//@[next] compile-flags: -Znext-solver + +// cc #119820, the previous behavior here was inconsistent, +// using the leak check to guide inference for `for<'a> Box<_>: Leak<'a>` +// but not for `for<'a> Box<_>: IndirectLeak<'a>` + +trait Leak<'a> {} +impl Leak<'_> for Box {} +impl Leak<'static> for Box {} + +fn impls_leak Leak<'a>>() {} +fn direct() { + // ok + // + // The `Box` impls fails the leak check, + // meaning that we apply the `Box` impl. + impls_leak::>(); + //~^ ERROR type annotations needed +} + +trait IndirectLeak<'a> {} +impl<'a, T: Leak<'a>> IndirectLeak<'a> for T {} + +fn impls_indirect_leak IndirectLeak<'a>>() {} +fn indirect() { + // error: type annotations needed + // + // While the `Box` impl would fail the leak check + // we have already instantiated the binder while applying + // the generic `IndirectLeak` impl, so during candidate + // selection of `Leak` we do not detect the placeholder error. + // Evaluation of `Box<_>: Leak<'!a>` is therefore ambiguous, + // resulting in `for<'a> Box<_>: Leak<'a>` also being ambiguous. + impls_indirect_leak::>(); + //~^ ERROR type annotations needed +} + +fn main() {} diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-4-hr-nested.rs b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-4-hr-nested.rs new file mode 100644 index 000000000000..8d87bdd064a0 --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-4-hr-nested.rs @@ -0,0 +1,29 @@ +//@ revisions: old next +//@[next] compile-flags: -Znext-solver +//@ check-pass + +// cc #119820. While the leak check does not consider the binder +// of the current goal, leaks from higher-ranked nested goals are +// considered. +// +// We enter and exit the binder of the nested goal while evaluating +// the candidate. + +trait LeakCheckFailure<'a> {} +impl LeakCheckFailure<'static> for () {} + +trait Trait {} +impl Trait for () where for<'a> (): LeakCheckFailure<'a> {} +impl Trait for () {} +fn impls_trait, U>() {} +fn main() { + // ok + // + // It does not matter whether candidate assembly + // considers the placeholders from higher-ranked goal. + // + // Either `for<'a> (): LeakCheckFailure<'a>` has no applicable + // candidate or it has a single applicable candidate which then later + // results in an error. This allows us to infer `U` to `u16`. + impls_trait::<(), _>() +} diff --git a/tests/ui/higher-ranked/trait-bounds/issue-30786.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-1.rs similarity index 86% rename from tests/ui/higher-ranked/trait-bounds/issue-30786.rs rename to tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-1.rs index ffb2b306ae76..799df8cae9fd 100644 --- a/tests/ui/higher-ranked/trait-bounds/issue-30786.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-1.rs @@ -1,6 +1,6 @@ //@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash" -// rust-lang/rust#30786: the use of `for<'b> &'b mut A: Stream &'b mut A: Stream` // should act as assertion that item does not borrow from its stream; // but an earlier buggy rustc allowed `.map(|x: &_| x)` which does // have such an item. @@ -97,10 +97,6 @@ where impl StreamExt for T where for<'a> &'a mut T: Stream {} -fn identity(x: &T) -> &T { - x -} - fn variant1() { let source = Repeat(10); @@ -118,19 +114,7 @@ fn variant1() { // guess. let map = source.mapx(|x: &_| x); let filter = map.filterx(|x: &_| true); - //~^ ERROR the method -} - -fn variant2() { - let source = Repeat(10); - - // Here, we use a function, which is not subject to the vagaries - // of closure signature inference. In this case, we get the error - // on `countx` as, I think, the test originally expected. - let map = source.mapx(identity); - let filter = map.filterx(|x: &_| true); - let count = filter.countx(); - //~^ ERROR the method + //~^ ERROR the method `filterx` exists for struct } fn main() {} diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-1.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-1.stderr new file mode 100644 index 000000000000..ae364de8cc06 --- /dev/null +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-1.stderr @@ -0,0 +1,27 @@ +error[E0599]: the method `filterx` exists for struct `Map`, but its trait bounds were not satisfied + --> $DIR/hrtb-doesnt-borrow-self-1.rs:116:22 + | +LL | pub struct Map { + | -------------------- method `filterx` not found for this struct because it doesn't satisfy `_: StreamExt` +... +LL | let filter = map.filterx(|x: &_| true); + | ^^^^^^^ method cannot be called due to unsatisfied trait bounds + | +note: the following trait bounds were not satisfied: + `&'a mut &Map: Stream` + `&'a mut &mut Map: Stream` + `&'a mut Map: Stream` + --> $DIR/hrtb-doesnt-borrow-self-1.rs:98:50 + | +LL | impl StreamExt for T where for<'a> &'a mut T: Stream {} + | --------- - ^^^^^^ unsatisfied trait bound introduced here + = help: items from traits can only be used if the trait is implemented and in scope +note: `StreamExt` defines an item `filterx`, perhaps you need to implement it + --> $DIR/hrtb-doesnt-borrow-self-1.rs:66:1 + | +LL | pub trait StreamExt + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.rs new file mode 100644 index 000000000000..92e2e7f796ea --- /dev/null +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.rs @@ -0,0 +1,116 @@ +//@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash" + +// rust-lang/rust#30786: the use of `for<'b> &'b mut A: Stream Option; +} + +// Example stream +pub struct Repeat(u64); + +impl<'a> Stream for &'a mut Repeat { + type Item = &'a u64; + fn next(self) -> Option { + Some(&self.0) + } +} + +pub struct Map { + stream: S, + func: F, +} + +impl<'a, A, F, T> Stream for &'a mut Map +where + &'a mut A: Stream, + F: FnMut(<&'a mut A as Stream>::Item) -> T, +{ + type Item = T; + fn next(self) -> Option { + match self.stream.next() { + Some(item) => Some((self.func)(item)), + None => None, + } + } +} + +pub struct Filter { + stream: S, + func: F, +} + +impl<'a, A, F, T> Stream for &'a mut Filter +where + for<'b> &'b mut A: Stream, // <---- BAD + F: FnMut(&T) -> bool, +{ + type Item = <&'a mut A as Stream>::Item; + fn next(self) -> Option { + while let Some(item) = self.stream.next() { + if (self.func)(&item) { + return Some(item); + } + } + None + } +} + +pub trait StreamExt +where + for<'b> &'b mut Self: Stream, +{ + fn mapx(self, func: F) -> Map + where + Self: Sized, + for<'a> &'a mut Map: Stream, + { + Map { func: func, stream: self } + } + + fn filterx(self, func: F) -> Filter + where + Self: Sized, + for<'a> &'a mut Filter: Stream, + { + Filter { func: func, stream: self } + } + + fn countx(mut self) -> usize + where + Self: Sized, + { + let mut count = 0; + while let Some(_) = self.next() { + count += 1; + } + count + } +} + +impl StreamExt for T where for<'a> &'a mut T: Stream {} + +fn identity(x: &T) -> &T { + x +} + +fn variant2() { + let source = Repeat(10); + + // Here, we use a function, which is not subject to the vagaries + // of closure signature inference. In this case, we get the error + // on `countx` as, I think, the test originally expected. + let map = source.mapx(identity); + let filter = map.filterx(|x: &_| true); + let count = filter.countx(); + //~^ ERROR the method +} + +fn main() {} diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.stderr new file mode 100644 index 000000000000..eeb4e12fa8b3 --- /dev/null +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.stderr @@ -0,0 +1,27 @@ +error[E0599]: the method `countx` exists for struct `Filter &u64 {identity::}>, {closure@hrtb-doesnt-borrow-self-2.rs:111:30}>`, but its trait bounds were not satisfied + --> $DIR/hrtb-doesnt-borrow-self-2.rs:112:24 + | +LL | pub struct Filter { + | ----------------------- method `countx` not found for this struct because it doesn't satisfy `_: StreamExt` +... +LL | let count = filter.countx(); + | ^^^^^^ method cannot be called due to unsatisfied trait bounds + | +note: the following trait bounds were not satisfied: + `&'a mut &Filter fn(&'a u64) -> &'a u64 {identity::}>, {closure@$DIR/hrtb-doesnt-borrow-self-2.rs:111:30: 111:37}>: Stream` + `&'a mut &mut Filter fn(&'a u64) -> &'a u64 {identity::}>, {closure@$DIR/hrtb-doesnt-borrow-self-2.rs:111:30: 111:37}>: Stream` + `&'a mut Filter fn(&'a u64) -> &'a u64 {identity::}>, {closure@$DIR/hrtb-doesnt-borrow-self-2.rs:111:30: 111:37}>: Stream` + --> $DIR/hrtb-doesnt-borrow-self-2.rs:98:50 + | +LL | impl StreamExt for T where for<'a> &'a mut T: Stream {} + | --------- - ^^^^^^ unsatisfied trait bound introduced here + = help: items from traits can only be used if the trait is implemented and in scope +note: `StreamExt` defines an item `countx`, perhaps you need to implement it + --> $DIR/hrtb-doesnt-borrow-self-2.rs:66:1 + | +LL | pub trait StreamExt + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr index e10da26665eb..be19bf85bd2f 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr @@ -1,23 +1,11 @@ -error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied - --> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:47:26 +error: implementation of `Bar` is not general enough + --> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:47:5 | LL | want_bar_for_any_ccx(b); - | -------------------- ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B` - | | - | required by a bound introduced by this call + | ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Bar` is not general enough | -note: required by a bound in `want_bar_for_any_ccx` - --> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:32:15 - | -LL | fn want_bar_for_any_ccx(b: &B) - | -------------------- required by a bound in this function -LL | where B : for<'ccx> Bar<'ccx> - | ^^^^^^^^^^^^^^^^^^^ required by this bound in `want_bar_for_any_ccx` -help: consider further restricting this bound - | -LL | where B : Qux + for<'ccx> Bar<'ccx> - | +++++++++++++++++++++ + = note: `B` must implement `Bar<'0>`, for any lifetime `'0`... + = note: ...but it actually implements `Bar<'static>` error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.rs index 33e0ec4635b6..70ce580258d4 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.rs @@ -1,43 +1,37 @@ // Test a trait (`Bar`) with a higher-ranked supertrait. +#![allow(unconditional_recursion)] -trait Foo<'tcx> -{ +trait Foo<'tcx> { fn foo(&'tcx self) -> &'tcx isize; } -trait Bar<'ccx> - : for<'tcx> Foo<'tcx> -{ +trait Bar<'ccx>: for<'tcx> Foo<'tcx> { fn bar(&'ccx self) -> &'ccx isize; } -fn want_foo_for_some_tcx<'x,F>(f: &'x F) - where F : Foo<'x> -{ +fn want_foo_for_some_tcx<'x, F: Foo<'x>>(f: &'x F) { want_foo_for_some_tcx(f); - want_foo_for_any_tcx(f); //~ ERROR not satisfied + want_foo_for_any_tcx(f); + //~^ ERROR lifetime may not live long enough + //~| ERROR implementation of `Foo` is not general enough } -fn want_foo_for_any_tcx(f: &F) //~ WARN cannot return without recursing - where F : for<'tcx> Foo<'tcx> -{ +fn want_foo_for_any_tcx Foo<'tcx>>(f: &F) { want_foo_for_some_tcx(f); want_foo_for_any_tcx(f); } -fn want_bar_for_some_ccx<'x,B>(b: &B) - where B : Bar<'x> -{ +fn want_bar_for_some_ccx<'x, B: Bar<'x>>(b: &B) { want_foo_for_some_tcx(b); want_foo_for_any_tcx(b); want_bar_for_some_ccx(b); - want_bar_for_any_ccx(b); //~ ERROR not satisfied + want_bar_for_any_ccx(b); + //~^ ERROR lifetime may not live long enough + //~| ERROR implementation of `Bar` is not general enough } -fn want_bar_for_any_ccx(b: &B) //~ WARN cannot return without recursing - where B : for<'ccx> Bar<'ccx> -{ +fn want_bar_for_any_ccx Bar<'ccx>>(b: &B) { want_foo_for_some_tcx(b); want_foo_for_any_tcx(b); diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.stderr index f220ba6f3389..dd760926ea11 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.stderr @@ -1,68 +1,50 @@ -error[E0277]: the trait bound `for<'tcx> F: Foo<'tcx>` is not satisfied - --> $DIR/hrtb-higher-ranker-supertraits.rs:18:26 +error: lifetime may not live long enough + --> $DIR/hrtb-higher-ranker-supertraits.rs:14:5 + | +LL | fn want_foo_for_some_tcx<'x, F: Foo<'x>>(f: &'x F) { + | -- lifetime `'x` defined here +LL | want_foo_for_some_tcx(f); +LL | want_foo_for_any_tcx(f); + | ^^^^^^^^^^^^^^^^^^^^^^^ requires that `'x` must outlive `'static` + | +note: due to current limitations in the borrow checker, this implies a `'static` lifetime + --> $DIR/hrtb-higher-ranker-supertraits.rs:19:28 + | +LL | fn want_foo_for_any_tcx Foo<'tcx>>(f: &F) { + | ^^^^^^^^^^^^^^^^^^^ + +error: implementation of `Foo` is not general enough + --> $DIR/hrtb-higher-ranker-supertraits.rs:14:5 | LL | want_foo_for_any_tcx(f); - | -------------------- ^ the trait `for<'tcx> Foo<'tcx>` is not implemented for `F` - | | - | required by a bound introduced by this call + | ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough | -note: required by a bound in `want_foo_for_any_tcx` - --> $DIR/hrtb-higher-ranker-supertraits.rs:22:15 - | -LL | fn want_foo_for_any_tcx(f: &F) - | -------------------- required by a bound in this function -LL | where F : for<'tcx> Foo<'tcx> - | ^^^^^^^^^^^^^^^^^^^ required by this bound in `want_foo_for_any_tcx` -help: consider further restricting this bound - | -LL | where F : Foo<'x> + for<'tcx> Foo<'tcx> - | +++++++++++++++++++++ + = note: `F` must implement `Foo<'0>`, for any lifetime `'0`... + = note: ...but it actually implements `Foo<'1>`, for some specific lifetime `'1` -error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied - --> $DIR/hrtb-higher-ranker-supertraits.rs:35:26 +error: lifetime may not live long enough + --> $DIR/hrtb-higher-ranker-supertraits.rs:29:5 + | +LL | fn want_bar_for_some_ccx<'x, B: Bar<'x>>(b: &B) { + | -- lifetime `'x` defined here +... +LL | want_bar_for_any_ccx(b); + | ^^^^^^^^^^^^^^^^^^^^^^^ requires that `'x` must outlive `'static` + | +note: due to current limitations in the borrow checker, this implies a `'static` lifetime + --> $DIR/hrtb-higher-ranker-supertraits.rs:34:28 + | +LL | fn want_bar_for_any_ccx Bar<'ccx>>(b: &B) { + | ^^^^^^^^^^^^^^^^^^^ + +error: implementation of `Bar` is not general enough + --> $DIR/hrtb-higher-ranker-supertraits.rs:29:5 | LL | want_bar_for_any_ccx(b); - | -------------------- ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B` - | | - | required by a bound introduced by this call + | ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Bar` is not general enough | -note: required by a bound in `want_bar_for_any_ccx` - --> $DIR/hrtb-higher-ranker-supertraits.rs:39:15 - | -LL | fn want_bar_for_any_ccx(b: &B) - | -------------------- required by a bound in this function -LL | where B : for<'ccx> Bar<'ccx> - | ^^^^^^^^^^^^^^^^^^^ required by this bound in `want_bar_for_any_ccx` -help: consider further restricting this bound - | -LL | where B : Bar<'x> + for<'ccx> Bar<'ccx> - | +++++++++++++++++++++ + = note: `B` must implement `Bar<'0>`, for any lifetime `'0`... + = note: ...but it actually implements `Bar<'1>`, for some specific lifetime `'1` -warning: function cannot return without recursing - --> $DIR/hrtb-higher-ranker-supertraits.rs:21:1 - | -LL | / fn want_foo_for_any_tcx(f: &F) -LL | | where F : for<'tcx> Foo<'tcx> - | |_________________________________^ cannot return without recursing -... -LL | want_foo_for_any_tcx(f); - | ----------------------- recursive call site - | - = help: a `loop` may express intention better if this is on purpose - = note: `#[warn(unconditional_recursion)]` on by default +error: aborting due to 4 previous errors -warning: function cannot return without recursing - --> $DIR/hrtb-higher-ranker-supertraits.rs:38:1 - | -LL | / fn want_bar_for_any_ccx(b: &B) -LL | | where B : for<'ccx> Bar<'ccx> - | |_________________________________^ cannot return without recursing -... -LL | want_bar_for_any_ccx(b); - | ----------------------- recursive call site - | - = help: a `loop` may express intention better if this is on purpose - -error: aborting due to 2 previous errors; 2 warnings emitted - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr b/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr deleted file mode 100644 index 699a4ecc42bb..000000000000 --- a/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr +++ /dev/null @@ -1,51 +0,0 @@ -error[E0599]: the method `filterx` exists for struct `Map`, but its trait bounds were not satisfied - --> $DIR/issue-30786.rs:120:22 - | -LL | pub struct Map { - | -------------------- method `filterx` not found for this struct because it doesn't satisfy `_: StreamExt` -... -LL | let filter = map.filterx(|x: &_| true); - | ^^^^^^^ method cannot be called on `Map` due to unsatisfied trait bounds - | -note: the following trait bounds were not satisfied: - `&'a mut &Map: Stream` - `&'a mut &mut Map: Stream` - `&'a mut Map: Stream` - --> $DIR/issue-30786.rs:98:50 - | -LL | impl StreamExt for T where for<'a> &'a mut T: Stream {} - | --------- - ^^^^^^ unsatisfied trait bound introduced here - = help: items from traits can only be used if the trait is implemented and in scope -note: `StreamExt` defines an item `filterx`, perhaps you need to implement it - --> $DIR/issue-30786.rs:66:1 - | -LL | pub trait StreamExt - | ^^^^^^^^^^^^^^^^^^^ - -error[E0599]: the method `countx` exists for struct `Filter &u64 {identity::}>, {closure@issue-30786.rs:131:30}>`, but its trait bounds were not satisfied - --> $DIR/issue-30786.rs:132:24 - | -LL | pub struct Filter { - | ----------------------- method `countx` not found for this struct because it doesn't satisfy `_: StreamExt` -... -LL | let count = filter.countx(); - | ^^^^^^ method cannot be called due to unsatisfied trait bounds - | -note: the following trait bounds were not satisfied: - `&'a mut &Filter fn(&'a u64) -> &'a u64 {identity::}>, {closure@$DIR/issue-30786.rs:131:30: 131:37}>: Stream` - `&'a mut &mut Filter fn(&'a u64) -> &'a u64 {identity::}>, {closure@$DIR/issue-30786.rs:131:30: 131:37}>: Stream` - `&'a mut Filter fn(&'a u64) -> &'a u64 {identity::}>, {closure@$DIR/issue-30786.rs:131:30: 131:37}>: Stream` - --> $DIR/issue-30786.rs:98:50 - | -LL | impl StreamExt for T where for<'a> &'a mut T: Stream {} - | --------- - ^^^^^^ unsatisfied trait bound introduced here - = help: items from traits can only be used if the trait is implemented and in scope -note: `StreamExt` defines an item `countx`, perhaps you need to implement it - --> $DIR/issue-30786.rs:66:1 - | -LL | pub trait StreamExt - | ^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.rs b/tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.rs new file mode 100644 index 000000000000..0e07d21b2f5b --- /dev/null +++ b/tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.rs @@ -0,0 +1,11 @@ +// Don't panic when iterating through the `hir::Map::parent_iter` of an RPITIT. + +pub trait Foo { + fn demo() -> impl Foo + //~^ ERROR the trait bound `String: Copy` is not satisfied + where + String: Copy; + //~^ ERROR the trait bound `String: Copy` is not satisfied +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.stderr b/tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.stderr new file mode 100644 index 000000000000..8ff8f12cdf46 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/synthetic-hir-has-parent.stderr @@ -0,0 +1,27 @@ +error[E0277]: the trait bound `String: Copy` is not satisfied + --> $DIR/synthetic-hir-has-parent.rs:7:9 + | +LL | String: Copy; + | ^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` + | + = help: see issue #48214 +help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + | +LL + #![feature(trivial_bounds)] + | + +error[E0277]: the trait bound `String: Copy` is not satisfied + --> $DIR/synthetic-hir-has-parent.rs:4:18 + | +LL | fn demo() -> impl Foo + | ^^^^^^^^ the trait `Copy` is not implemented for `String` + | + = help: see issue #48214 +help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + | +LL + #![feature(trivial_bounds)] + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/nested_impl_trait.rs b/tests/ui/impl-trait/nested_impl_trait.rs index 760102794c34..502b2af2bc66 100644 --- a/tests/ui/impl-trait/nested_impl_trait.rs +++ b/tests/ui/impl-trait/nested_impl_trait.rs @@ -5,7 +5,7 @@ fn fine(x: impl Into) -> impl Into { x } fn bad_in_ret_position(x: impl Into) -> impl Into { x } //~^ ERROR nested `impl Trait` is not allowed -//~| ERROR the trait bound `impl Debug: From>` is not satisfied +//~| ERROR the trait bound `impl Into: Into` is not satisfied fn bad_in_fn_syntax(x: fn() -> impl Into) {} //~^ ERROR nested `impl Trait` is not allowed @@ -18,7 +18,7 @@ struct X; impl X { fn bad(x: impl Into) -> impl Into { x } //~^ ERROR nested `impl Trait` is not allowed - //~| ERROR the trait bound `impl Debug: From>` is not satisfied + //~| ERROR the trait bound `impl Into: Into` is not satisfied } fn allowed_in_assoc_type() -> impl Iterator { diff --git a/tests/ui/impl-trait/nested_impl_trait.stderr b/tests/ui/impl-trait/nested_impl_trait.stderr index 83d1347aff43..1f9a2a5e9d60 100644 --- a/tests/ui/impl-trait/nested_impl_trait.stderr +++ b/tests/ui/impl-trait/nested_impl_trait.stderr @@ -42,20 +42,20 @@ LL | fn bad_in_fn_syntax(x: fn() -> impl Into) {} | = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0277]: the trait bound `impl Debug: From>` is not satisfied +error[E0277]: the trait bound `impl Into: Into` is not satisfied --> $DIR/nested_impl_trait.rs:6:46 | LL | fn bad_in_ret_position(x: impl Into) -> impl Into { x } - | ^^^^^^^^^^^^^^^^^^^^^ the trait `From>` is not implemented for `impl Debug`, which is required by `impl Into: Into` + | ^^^^^^^^^^^^^^^^^^^^^ the trait `From>` is not implemented for `impl Into`, which is required by `impl Into: Into` | = help: the trait `Into` is implemented for `T` = note: required for `impl Into` to implement `Into` -error[E0277]: the trait bound `impl Debug: From>` is not satisfied +error[E0277]: the trait bound `impl Into: Into` is not satisfied --> $DIR/nested_impl_trait.rs:19:34 | LL | fn bad(x: impl Into) -> impl Into { x } - | ^^^^^^^^^^^^^^^^^^^^^ the trait `From>` is not implemented for `impl Debug`, which is required by `impl Into: Into` + | ^^^^^^^^^^^^^^^^^^^^^ the trait `From>` is not implemented for `impl Into`, which is required by `impl Into: Into` | = help: the trait `Into` is implemented for `T` = note: required for `impl Into` to implement `Into` diff --git a/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr b/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr index 755d12d74482..c0b399746eaf 100644 --- a/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr +++ b/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/recursive-coroutine-boxed.rs:12:23 + --> $DIR/recursive-coroutine-boxed.rs:14:23 | LL | let mut gen = Box::pin(foo()); | ^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Box` @@ -12,12 +12,28 @@ help: consider specifying the generic argument LL | let mut gen = Box::::pin(foo()); | +++++ -error[E0282]: type annotations needed - --> $DIR/recursive-coroutine-boxed.rs:9:13 +error[E0308]: mismatched types + --> $DIR/recursive-coroutine-boxed.rs:13:5 | -LL | fn foo() -> impl Coroutine { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for opaque type `impl Coroutine` +LL | fn foo() -> impl Coroutine { + | --------------------------------------- + | | + | the expected opaque type + | expected `impl Coroutine` because of return type +... +LL | / || { +LL | | let mut gen = Box::pin(foo()); +LL | | +LL | | let mut r = gen.as_mut().resume(()); +... | +LL | | } +LL | | } + | |_____^ types differ + | + = note: expected opaque type `impl Coroutine` + found coroutine `{coroutine@$DIR/recursive-coroutine-boxed.rs:13:5: 13:7}` error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0282`. +Some errors have detailed explanations: E0282, E0308. +For more information about an error, try `rustc --explain E0282`. diff --git a/tests/ui/impl-trait/recursive-coroutine-boxed.rs b/tests/ui/impl-trait/recursive-coroutine-boxed.rs index 3b8ffb920908..02c75be0f3aa 100644 --- a/tests/ui/impl-trait/recursive-coroutine-boxed.rs +++ b/tests/ui/impl-trait/recursive-coroutine-boxed.rs @@ -7,8 +7,10 @@ use std::ops::{Coroutine, CoroutineState}; fn foo() -> impl Coroutine { - //[next]~^ ERROR type annotations needed - || { + // FIXME(-Znext-solver): this fails with a mismatched types as the + // hidden type of the opaque ends up as {type error}. We should not + // emit errors for such goals. + || { //[next]~ ERROR mismatched types let mut gen = Box::pin(foo()); //[next]~^ ERROR type annotations needed let mut r = gen.as_mut().resume(()); diff --git a/tests/ui/implied-bounds/issue-100690.rs b/tests/ui/implied-bounds/issue-100690.rs index ea33c9f423b7..041c687ec943 100644 --- a/tests/ui/implied-bounds/issue-100690.rs +++ b/tests/ui/implied-bounds/issue-100690.rs @@ -4,11 +4,8 @@ use std::io; fn real_dispatch(f: F) -> Result<(), io::Error> -//~^ NOTE required by a bound in this where F: FnOnce(&mut UIView) -> Result<(), io::Error> + Send + 'static, - //~^ NOTE required by this bound in `real_dispatch` - //~| NOTE required by a bound in `real_dispatch` { todo!() } @@ -35,10 +32,10 @@ impl<'a, T: 'a> Handle<'a, T, UIView<'a, T>, Result<(), io::Error>> for TUIHandl F: FnOnce(&mut UIView<'a, T>) -> Result<(), io::Error> + Send + 'static, { real_dispatch(f) - //~^ ERROR expected a `FnOnce(&mut UIView<'_, T>)` closure, found `F` - //~| NOTE expected an `FnOnce(&mut UIView<'_, T>)` closure, found `F` - //~| NOTE expected a closure with arguments - //~| NOTE required by a bound introduced by this call + //~^ ERROR lifetime may not live long enough + //~| ERROR implementation of `FnOnce` is not general enough + //~| ERROR mismatched types + // } } diff --git a/tests/ui/implied-bounds/issue-100690.stderr b/tests/ui/implied-bounds/issue-100690.stderr index df069d875ceb..2cfd028f2559 100644 --- a/tests/ui/implied-bounds/issue-100690.stderr +++ b/tests/ui/implied-bounds/issue-100690.stderr @@ -1,22 +1,41 @@ -error[E0277]: expected a `FnOnce(&mut UIView<'_, T>)` closure, found `F` - --> $DIR/issue-100690.rs:37:23 +error: lifetime may not live long enough + --> $DIR/issue-100690.rs:34:9 + | +LL | impl<'a, T: 'a> Handle<'a, T, UIView<'a, T>, Result<(), io::Error>> for TUIHandle { + | -- lifetime `'a` defined here +... +LL | real_dispatch(f) + | ^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + | +note: due to current limitations in the borrow checker, this implies a `'static` lifetime + --> $DIR/issue-100690.rs:8:8 + | +LL | F: FnOnce(&mut UIView) -> Result<(), io::Error> + Send + 'static, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: implementation of `FnOnce` is not general enough + --> $DIR/issue-100690.rs:34:9 | LL | real_dispatch(f) - | ------------- ^ expected an `FnOnce(&mut UIView<'_, T>)` closure, found `F` - | | - | required by a bound introduced by this call + | ^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough | - = note: expected a closure with arguments `(&mut UIView<'a, _>,)` - found a closure with arguments `(&mut UIView<'_, _>,)` -note: required by a bound in `real_dispatch` - --> $DIR/issue-100690.rs:9:8 + = note: `F` must implement `FnOnce<(&mut UIView<'0, T>,)>`, for any lifetime `'0`... + = note: ...but it actually implements `FnOnce<(&mut UIView<'1, T>,)>`, for some specific lifetime `'1` + +error[E0308]: mismatched types + --> $DIR/issue-100690.rs:34:9 + | +LL | real_dispatch(f) + | ^^^^^^^^^^^^^^^^ one type is more general than the other + | + = note: expected associated type `,)>>::Output` + found associated type `,)>>::Output` +note: the lifetime requirement is introduced here + --> $DIR/issue-100690.rs:8:34 | -LL | fn real_dispatch(f: F) -> Result<(), io::Error> - | ------------- required by a bound in this function -... LL | F: FnOnce(&mut UIView) -> Result<(), io::Error> + Send + 'static, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `real_dispatch` + | ^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 1 previous error +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/layout/ice-non-last-unsized-field-issue-121473.rs b/tests/ui/layout/ice-non-last-unsized-field-issue-121473.rs new file mode 100644 index 000000000000..737a7ffbc296 --- /dev/null +++ b/tests/ui/layout/ice-non-last-unsized-field-issue-121473.rs @@ -0,0 +1,79 @@ +// Regression test for #121473 +// Checks that no ICE occurs when `size_of` +// is applied to a struct that has an unsized +// field which is not its last field + +use std::mem::size_of; + +pub struct BadStruct { + pub field1: i32, + pub field2: str, // Unsized field that is not the last field + //~^ ERROR the size for values of type `str` cannot be known at compilation time + pub field3: [u8; 16], +} + +enum BadEnum1 { + Variant1 { + field1: i32, + field2: str, // Unsized + //~^ ERROR the size for values of type `str` cannot be known at compilation time + field3: [u8; 16], + }, +} + +enum BadEnum2 { + Variant1( + i32, + str, // Unsized + //~^ ERROR the size for values of type `str` cannot be known at compilation time + [u8; 16] + ), +} + +enum BadEnumMultiVariant { + Variant1(i32), + Variant2 { + field1: i32, + field2: str, // Unsized + //~^ ERROR the size for values of type `str` cannot be known at compilation time + field3: [u8; 16], + }, + Variant3 +} + +union BadUnion { + field1: i32, + field2: str, // Unsized + //~^ ERROR the size for values of type `str` cannot be known at compilation time + //~| ERROR field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union + field3: [u8; 16], +} + +// Used to test that projection type fields that normalize +// to a sized type do not cause problems +struct StructWithProjections<'a> +{ + field1: <&'a [i32] as IntoIterator>::IntoIter, + field2: i32 +} + +pub fn main() { + let _a = &size_of::(); + assert_eq!(size_of::(), 21); + + let _a = &size_of::(); + assert_eq!(size_of::(), 21); + + let _a = &size_of::(); + assert_eq!(size_of::(), 21); + + let _a = &size_of::(); + assert_eq!(size_of::(), 21); + + let _a = &size_of::(); + assert_eq!(size_of::(), 21); + + let _a = &size_of::(); + assert_eq!(size_of::(), 21); + let _a = StructWithProjections { field1: [1, 3].iter(), field2: 3 }; +} diff --git a/tests/ui/layout/ice-non-last-unsized-field-issue-121473.stderr b/tests/ui/layout/ice-non-last-unsized-field-issue-121473.stderr new file mode 100644 index 000000000000..626be7ac2836 --- /dev/null +++ b/tests/ui/layout/ice-non-last-unsized-field-issue-121473.stderr @@ -0,0 +1,106 @@ +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/ice-non-last-unsized-field-issue-121473.rs:10:17 + | +LL | pub field2: str, // Unsized field that is not the last field + | ^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` + = note: only the last field of a struct may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | pub field2: &str, // Unsized field that is not the last field + | + +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | pub field2: Box, // Unsized field that is not the last field + | ++++ + + +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/ice-non-last-unsized-field-issue-121473.rs:18:17 + | +LL | field2: str, // Unsized + | ^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` + = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | field2: &str, // Unsized + | + +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | field2: Box, // Unsized + | ++++ + + +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/ice-non-last-unsized-field-issue-121473.rs:27:9 + | +LL | str, // Unsized + | ^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` + = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | &str, // Unsized + | + +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | Box, // Unsized + | ++++ + + +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/ice-non-last-unsized-field-issue-121473.rs:37:17 + | +LL | field2: str, // Unsized + | ^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` + = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | field2: &str, // Unsized + | + +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | field2: Box, // Unsized + | ++++ + + +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/ice-non-last-unsized-field-issue-121473.rs:46:13 + | +LL | field2: str, // Unsized + | ^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` + = note: no field of a union may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | field2: &str, // Unsized + | + +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | field2: Box, // Unsized + | ++++ + + +error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union + --> $DIR/ice-non-last-unsized-field-issue-121473.rs:46:5 + | +LL | field2: str, // Unsized + | ^^^^^^^^^^^ + | + = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>` +help: wrap the field type in `ManuallyDrop<...>` + | +LL | field2: std::mem::ManuallyDrop, // Unsized + | +++++++++++++++++++++++ + + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0277, E0740. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/lint/non_local_definitions.rs b/tests/ui/lint/non_local_definitions.rs index eee582a6f11b..0b43e19d1e96 100644 --- a/tests/ui/lint/non_local_definitions.rs +++ b/tests/ui/lint/non_local_definitions.rs @@ -4,7 +4,6 @@ //@ rustc-env:CARGO_CRATE_NAME=non_local_def #![feature(inline_const)] -#![warn(non_local_definitions)] extern crate non_local_macro; @@ -282,7 +281,6 @@ struct Cat; fn meow() { impl From for () { - //~^ WARN non-local `impl` definition fn from(_: Cat) -> () { todo!() } @@ -374,6 +372,72 @@ fn rawr() { todo!() } } + + #[derive(Debug)] + struct Elephant; + + impl From>> for () { + //~^ WARN non-local `impl` definition + fn from(_: Wrap>) -> Self { + todo!() + } + } +} + +pub trait StillNonLocal {} + +impl StillNonLocal for &str {} + +fn only_global() { + struct Foo; + impl StillNonLocal for &Foo {} + //~^ WARN non-local `impl` definition +} + +struct GlobalSameFunction; + +fn same_function() { + struct Local1(GlobalSameFunction); + impl From for GlobalSameFunction { + //~^ WARN non-local `impl` definition + fn from(x: Local1) -> GlobalSameFunction { + x.0 + } + } + + struct Local2(GlobalSameFunction); + impl From for GlobalSameFunction { + //~^ WARN non-local `impl` definition + fn from(x: Local2) -> GlobalSameFunction { + x.0 + } + } +} + +struct GlobalDifferentFunction; + +fn diff_foo() { + struct Local(GlobalDifferentFunction); + + impl From for GlobalDifferentFunction { + // FIXME(Urgau): Should warn but doesn't since we currently consider + // the other impl to be "global", but that's not the case for the type-system + fn from(x: Local) -> GlobalDifferentFunction { + x.0 + } + } +} + +fn diff_bar() { + struct Local(GlobalDifferentFunction); + + impl From for GlobalDifferentFunction { + // FIXME(Urgau): Should warn but doesn't since we currently consider + // the other impl to be "global", but that's not the case for the type-system + fn from(x: Local) -> GlobalDifferentFunction { + x.0 + } + } } macro_rules! m { @@ -404,3 +468,24 @@ fn bitflags() { impl Flags {} }; } + +// https://github.com/rust-lang/rust/issues/121621#issuecomment-1976826895 +fn commonly_reported() { + struct Local(u8); + impl From for u8 { + fn from(x: Local) -> u8 { + x.0 + } + } +} + +// https://github.com/rust-lang/rust/issues/121621#issue-2153187542 +pub trait Serde {} + +impl Serde for &[u8] {} +impl Serde for &str {} + +fn serde() { + struct Thing; + impl Serde for &Thing {} +} diff --git a/tests/ui/lint/non_local_definitions.stderr b/tests/ui/lint/non_local_definitions.stderr index ef74e262f9db..8ae04f2c2e8e 100644 --- a/tests/ui/lint/non_local_definitions.stderr +++ b/tests/ui/lint/non_local_definitions.stderr @@ -1,5 +1,5 @@ warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:37:5 + --> $DIR/non_local_definitions.rs:36:5 | LL | const Z: () = { | - help: use a const-anon item to suppress this lint: `_` @@ -8,61 +8,57 @@ LL | impl Uto for &Test {} | ^^^^^^^^^^^^^^^^^^^^^ | = help: move this `impl` block outside the of the current constant `Z` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -note: the lint level is defined here - --> $DIR/non_local_definitions.rs:7:9 - | -LL | #![warn(non_local_definitions)] - | ^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(non_local_definitions)]` on by default warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:47:5 + --> $DIR/non_local_definitions.rs:46:5 | LL | impl Uto for *mut Test {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: move this `impl` block outside the of the current constant expression `` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:55:9 + --> $DIR/non_local_definitions.rs:54:9 | LL | impl Uto for Test {} | ^^^^^^^^^^^^^^^^^^^^ | = help: move this `impl` block outside the of the current constant expression `` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:64:5 + --> $DIR/non_local_definitions.rs:63:5 | LL | impl Uto2 for Test {} | ^^^^^^^^^^^^^^^^^^^^^ | = help: move this `impl` block outside the of the current static `A` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:72:5 + --> $DIR/non_local_definitions.rs:71:5 | LL | impl Uto3 for Test {} | ^^^^^^^^^^^^^^^^^^^^^ | = help: move this `impl` block outside the of the current constant `B` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:76:5 + --> $DIR/non_local_definitions.rs:75:5 | LL | macro_rules! m0 { () => { } }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +69,7 @@ LL | macro_rules! m0 { () => { } }; = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:88:5 + --> $DIR/non_local_definitions.rs:87:5 | LL | macro_rules! m { () => { } }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -84,7 +80,7 @@ LL | macro_rules! m { () => { } }; = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:91:5 + --> $DIR/non_local_definitions.rs:90:5 | LL | / impl Test { LL | | @@ -93,12 +89,12 @@ LL | | } | |_____^ | = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:97:9 + --> $DIR/non_local_definitions.rs:96:9 | LL | / impl Test { LL | | @@ -107,12 +103,12 @@ LL | | } | |_________^ | = help: move this `impl` block outside the of the current constant expression `` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:106:9 + --> $DIR/non_local_definitions.rs:105:9 | LL | / impl Test { LL | | @@ -121,12 +117,12 @@ LL | | } | |_________^ | = help: move this `impl` block outside the of the current inline constant `` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:115:9 + --> $DIR/non_local_definitions.rs:114:9 | LL | / impl Test { LL | | @@ -135,12 +131,12 @@ LL | | } | |_________^ | = help: move this `impl` block outside the of the current constant `_` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:123:5 + --> $DIR/non_local_definitions.rs:122:5 | LL | / impl Display for Test { LL | | @@ -151,221 +147,221 @@ LL | | } | |_____^ | = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:130:5 + --> $DIR/non_local_definitions.rs:129:5 | LL | impl dyn Uto5 {} | ^^^^^^^^^^^^^^^^ | = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:133:5 + --> $DIR/non_local_definitions.rs:132:5 | LL | impl Uto5 for Vec { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:136:5 + --> $DIR/non_local_definitions.rs:135:5 | LL | impl Uto5 for &dyn Uto5 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:139:5 + --> $DIR/non_local_definitions.rs:138:5 | LL | impl Uto5 for *mut Test {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:142:5 + --> $DIR/non_local_definitions.rs:141:5 | LL | impl Uto5 for *mut [Test] {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:145:5 + --> $DIR/non_local_definitions.rs:144:5 | LL | impl Uto5 for [Test; 8] {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:148:5 + --> $DIR/non_local_definitions.rs:147:5 | LL | impl Uto5 for (Test,) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ | = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:151:5 + --> $DIR/non_local_definitions.rs:150:5 | LL | impl Uto5 for fn(Test) -> () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:154:5 + --> $DIR/non_local_definitions.rs:153:5 | LL | impl Uto5 for fn() -> Test {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:158:9 + --> $DIR/non_local_definitions.rs:157:9 | LL | impl Uto5 for Test {} | ^^^^^^^^^^^^^^^^^^^^^ | = help: move this `impl` block outside the of the current closure `` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:165:9 + --> $DIR/non_local_definitions.rs:164:9 | LL | impl Uto5 for &Test {} | ^^^^^^^^^^^^^^^^^^^^^^ | = help: move this `impl` block outside the of the current constant expression `` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:172:9 + --> $DIR/non_local_definitions.rs:171:9 | LL | impl Uto5 for &(Test,) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: move this `impl` block outside the of the current constant expression `` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:179:9 + --> $DIR/non_local_definitions.rs:178:9 | LL | impl Uto5 for &(Test,Test) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: move this `impl` block outside the of the current constant expression `` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:187:5 + --> $DIR/non_local_definitions.rs:186:5 | LL | impl Uto5 for *mut InsideMain {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:189:5 + --> $DIR/non_local_definitions.rs:188:5 | LL | impl Uto5 for *mut [InsideMain] {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:191:5 + --> $DIR/non_local_definitions.rs:190:5 | LL | impl Uto5 for [InsideMain; 8] {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:193:5 + --> $DIR/non_local_definitions.rs:192:5 | LL | impl Uto5 for (InsideMain,) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:195:5 + --> $DIR/non_local_definitions.rs:194:5 | LL | impl Uto5 for fn(InsideMain) -> () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:197:5 + --> $DIR/non_local_definitions.rs:196:5 | LL | impl Uto5 for fn() -> InsideMain {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:211:9 + --> $DIR/non_local_definitions.rs:210:9 | LL | / impl Display for InsideMain { LL | | @@ -376,12 +372,12 @@ LL | | } | |_________^ | = help: move this `impl` block outside the of the current function `inside_inside` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:218:9 + --> $DIR/non_local_definitions.rs:217:9 | LL | / impl InsideMain { LL | | @@ -393,12 +389,12 @@ LL | | } | |_________^ | = help: move this `impl` block outside the of the current function `inside_inside` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:222:17 + --> $DIR/non_local_definitions.rs:221:17 | LL | macro_rules! m2 { () => { } }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -409,62 +405,62 @@ LL | macro_rules! m2 { () => { } }; = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:232:5 + --> $DIR/non_local_definitions.rs:231:5 | LL | impl Uto3 for Vec { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:241:5 + --> $DIR/non_local_definitions.rs:240:5 | LL | impl Uto7 for Test where Local: std::any::Any {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: move this `impl` block outside the of the current function `bad` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:244:5 + --> $DIR/non_local_definitions.rs:243:5 | LL | impl Uto8 for T {} | ^^^^^^^^^^^^^^^^^^^^^ | = help: move this `impl` block outside the of the current function `bad` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:252:9 + --> $DIR/non_local_definitions.rs:251:9 | LL | impl Uto9 for Test {} | ^^^^^^^^^^^^^^^^^^^^^ | = help: move this `impl` block outside the of the current closure `` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:259:9 + --> $DIR/non_local_definitions.rs:258:9 | LL | impl Uto10 for Test {} | ^^^^^^^^^^^^^^^^^^^^^^ | = help: move this `impl` block outside the of the current constant expression `` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:273:5 + --> $DIR/non_local_definitions.rs:272:5 | LL | / impl Default for UwU { LL | | @@ -475,28 +471,12 @@ LL | | } | |_____^ | = help: move this `impl` block outside the of the current function `fun` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:284:5 - | -LL | / impl From for () { -LL | | -LL | | fn from(_: Cat) -> () { -LL | | todo!() -LL | | } -LL | | } - | |_____^ - | - = help: move this `impl` block outside the of the current function `meow` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:293:5 + --> $DIR/non_local_definitions.rs:291:5 | LL | / impl AsRef for () { LL | | @@ -505,12 +485,12 @@ LL | | } | |_____^ | = help: move this `impl` block outside the of the current function `meow` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:304:5 + --> $DIR/non_local_definitions.rs:302:5 | LL | / impl PartialEq for G { LL | | @@ -521,12 +501,12 @@ LL | | } | |_____^ | = help: move this `impl` block outside the of the current function `fun2` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:321:5 + --> $DIR/non_local_definitions.rs:319:5 | LL | / impl PartialEq for &Dog { LL | | @@ -537,12 +517,12 @@ LL | | } | |_____^ | = help: move this `impl` block outside the of the current function `woof` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:328:5 + --> $DIR/non_local_definitions.rs:326:5 | LL | / impl PartialEq<()> for Dog { LL | | @@ -553,12 +533,12 @@ LL | | } | |_____^ | = help: move this `impl` block outside the of the current function `woof` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:335:5 + --> $DIR/non_local_definitions.rs:333:5 | LL | / impl PartialEq<()> for &Dog { LL | | @@ -569,12 +549,12 @@ LL | | } | |_____^ | = help: move this `impl` block outside the of the current function `woof` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:342:5 + --> $DIR/non_local_definitions.rs:340:5 | LL | / impl PartialEq for () { LL | | @@ -585,12 +565,12 @@ LL | | } | |_____^ | = help: move this `impl` block outside the of the current function `woof` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:364:5 + --> $DIR/non_local_definitions.rs:362:5 | LL | / impl From>> for () { LL | | @@ -601,12 +581,12 @@ LL | | } | |_____^ | = help: move this `impl` block outside the of the current function `rawr` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:371:5 + --> $DIR/non_local_definitions.rs:369:5 | LL | / impl From<()> for Wrap { LL | | @@ -617,12 +597,71 @@ LL | | } | |_____^ | = help: move this `impl` block outside the of the current function `rawr` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:384:13 + --> $DIR/non_local_definitions.rs:379:5 + | +LL | / impl From>> for () { +LL | | +LL | | fn from(_: Wrap>) -> Self { +LL | | todo!() +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `rawr` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:393:5 + | +LL | impl StillNonLocal for &Foo {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `only_global` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:401:5 + | +LL | / impl From for GlobalSameFunction { +LL | | +LL | | fn from(x: Local1) -> GlobalSameFunction { +LL | | x.0 +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `same_function` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:409:5 + | +LL | / impl From for GlobalSameFunction { +LL | | +LL | | fn from(x: Local2) -> GlobalSameFunction { +LL | | x.0 +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `same_function` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/non_local_definitions.rs:448:13 | LL | impl MacroTrait for OutsideStruct {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -631,26 +670,26 @@ LL | m!(); | ---- in this macro invocation | = help: move this `impl` block outside the of the current function `my_func` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue = note: this warning originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:394:1 + --> $DIR/non_local_definitions.rs:458:1 | LL | non_local_macro::non_local_impl!(CargoUpdate); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: move this `impl` block outside the of the current constant `_IMPL_DEBUG` - = note: an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue = note: the macro `non_local_macro::non_local_impl` may come from an old version of the `non_local_macro` crate, try updating your dependency with `cargo update -p non_local_macro` = note: this warning originates in the macro `non_local_macro::non_local_impl` (in Nightly builds, run with -Z macro-backtrace for more info) warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:397:1 + --> $DIR/non_local_definitions.rs:461:1 | LL | non_local_macro::non_local_macro_rules!(my_macro); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -662,5 +701,5 @@ LL | non_local_macro::non_local_macro_rules!(my_macro); = note: the macro `non_local_macro::non_local_macro_rules` may come from an old version of the `non_local_macro` crate, try updating your dependency with `cargo update -p non_local_macro` = note: this warning originates in the macro `non_local_macro::non_local_macro_rules` (in Nightly builds, run with -Z macro-backtrace for more info) -warning: 52 warnings emitted +warning: 55 warnings emitted diff --git a/tests/ui/match/ref_pat_everywhere-mutability-mismatch.rs b/tests/ui/match/ref_pat_everywhere-mutability-mismatch.rs new file mode 100644 index 000000000000..9dd7a7893ec7 --- /dev/null +++ b/tests/ui/match/ref_pat_everywhere-mutability-mismatch.rs @@ -0,0 +1,16 @@ +#![allow(incomplete_features)] +#![feature(ref_pat_everywhere)] +pub fn main() { + if let Some(&x) = Some(0) { + //~^ ERROR: mismatched types [E0308] + let _: u32 = x; + } + if let &Some(x) = &mut Some(0) { + //~^ ERROR: mismatched types [E0308] + let _: u32 = x; + } + if let Some(&x) = &mut Some(0) { + //~^ ERROR: mismatched types [E0308] + let _: u32 = x; + } +} diff --git a/tests/ui/match/ref_pat_everywhere-mutability-mismatch.stderr b/tests/ui/match/ref_pat_everywhere-mutability-mismatch.stderr new file mode 100644 index 000000000000..d512ea5f957d --- /dev/null +++ b/tests/ui/match/ref_pat_everywhere-mutability-mismatch.stderr @@ -0,0 +1,44 @@ +error[E0308]: mismatched types + --> $DIR/ref_pat_everywhere-mutability-mismatch.rs:4:17 + | +LL | if let Some(&x) = Some(0) { + | ^^ ------- this expression has type `Option<{integer}>` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL | if let Some(x) = Some(0) { + | ~ + +error[E0308]: mismatched types + --> $DIR/ref_pat_everywhere-mutability-mismatch.rs:8:12 + | +LL | if let &Some(x) = &mut Some(0) { + | ^^^^^^^^ ------------ this expression has type `&mut Option<{integer}>` + | | + | types differ in mutability + | + = note: expected mutable reference `&mut Option<{integer}>` + found reference `&_` + +error[E0308]: mismatched types + --> $DIR/ref_pat_everywhere-mutability-mismatch.rs:12:17 + | +LL | if let Some(&x) = &mut Some(0) { + | ^^ ------------ this expression has type `&mut Option<{integer}>` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL | if let Some(x) = &mut Some(0) { + | ~ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/match/ref_pat_everywhere.rs b/tests/ui/match/ref_pat_everywhere.rs new file mode 100644 index 000000000000..b3daca484092 --- /dev/null +++ b/tests/ui/match/ref_pat_everywhere.rs @@ -0,0 +1,18 @@ +//@ run-pass +#![allow(incomplete_features)] +#![feature(ref_pat_everywhere)] + +pub fn main() { + if let Some(Some(&x)) = &Some(&Some(0)) { + let _: u32 = x; + } + if let Some(&Some(x)) = &Some(Some(0)) { + let _: u32 = x; + } + if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { + let _: u32 = x; + } + if let Some(Some(&x)) = &Some(&mut Some(0)) { + let _: u32 = x; + } +} diff --git a/tests/ui/methods/opaque_param_in_ufc.rs b/tests/ui/methods/opaque_param_in_ufc.rs new file mode 100644 index 000000000000..a4b27a0131fd --- /dev/null +++ b/tests/ui/methods/opaque_param_in_ufc.rs @@ -0,0 +1,30 @@ +#![feature(type_alias_impl_trait)] +struct Foo(T); + +impl Foo { + fn method() {} + fn method2(self) {} +} + +type Bar = impl Sized; + +fn bar() -> Bar { + 42_u32 +} + +impl Foo { + fn foo() -> Bar { + Self::method(); + //~^ ERROR: no function or associated item named `method` found for struct `Foo` + Foo::::method(); + //~^ ERROR: no function or associated item named `method` found for struct `Foo` + let x = Foo(bar()); + Foo::method2(x); + let x = Self(bar()); + Self::method2(x); + //~^ ERROR: no function or associated item named `method2` found for struct `Foo` + todo!() + } +} + +fn main() {} diff --git a/tests/ui/methods/opaque_param_in_ufc.stderr b/tests/ui/methods/opaque_param_in_ufc.stderr new file mode 100644 index 000000000000..7e5bbbac8a9a --- /dev/null +++ b/tests/ui/methods/opaque_param_in_ufc.stderr @@ -0,0 +1,36 @@ +error[E0599]: no function or associated item named `method` found for struct `Foo` in the current scope + --> $DIR/opaque_param_in_ufc.rs:17:15 + | +LL | struct Foo(T); + | ------------- function or associated item `method` not found for this struct +... +LL | Self::method(); + | ^^^^^^ function or associated item not found in `Foo` + | + = note: the function or associated item was found for + - `Foo` + +error[E0599]: no function or associated item named `method` found for struct `Foo` in the current scope + --> $DIR/opaque_param_in_ufc.rs:19:21 + | +LL | struct Foo(T); + | ------------- function or associated item `method` not found for this struct +... +LL | Foo::::method(); + | ^^^^^^ function or associated item not found in `Foo` + | + = note: the function or associated item was found for + - `Foo` + +error[E0599]: no function or associated item named `method2` found for struct `Foo` in the current scope + --> $DIR/opaque_param_in_ufc.rs:24:15 + | +LL | struct Foo(T); + | ------------- function or associated item `method2` not found for this struct +... +LL | Self::method2(x); + | ^^^^^^^ function or associated item not found in `Foo` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/nll/match-cfg-fake-edges.rs b/tests/ui/nll/match-cfg-fake-edges.rs index 1afc7931a6b6..e349c2c8e2a5 100644 --- a/tests/ui/nll/match-cfg-fake-edges.rs +++ b/tests/ui/nll/match-cfg-fake-edges.rs @@ -3,15 +3,57 @@ #![feature(if_let_guard)] +#[rustfmt::skip] +fn all_patterns_are_tested() { + // Even though `x` is never actually moved out of, we don't want borrowck results to be based on + // whether MIR lowering reveals which patterns are unreachable. + let x = String::new(); + match true { + _ => {}, + _ => drop(x), + } + // Borrowck must not know the second arm is never run. + drop(x); //~ ERROR use of moved value + + let x = String::new(); + if let _ = true { //~ WARN irrefutable + } else { + drop(x) + } + // Borrowck must not know the else branch is never run. + drop(x); //~ ERROR use of moved value + + let x = (String::new(), String::new()); + match x { + (y, _) | (_, y) => (), + } + &x.0; //~ ERROR borrow of moved value + // Borrowck must not know the second pattern never matches. + &x.1; //~ ERROR borrow of moved value + + let x = (String::new(), String::new()); + let ((y, _) | (_, y)) = x; + &x.0; //~ ERROR borrow of moved value + // Borrowck must not know the second pattern never matches. + &x.1; //~ ERROR borrow of moved value +} + +#[rustfmt::skip] fn guard_always_precedes_arm(y: i32) { - let mut x; // x should always be initialized, as the only way to reach the arm is // through the guard. + let mut x; match y { 0 | 2 if { x = 2; true } => x, _ => 2, }; + let mut x; + match y { + _ => 2, + 0 | 2 if { x = 2; true } => x, + }; + let mut x; match y { 0 | 2 if let Some(()) = { x = 2; Some(()) } => x, @@ -19,51 +61,58 @@ fn guard_always_precedes_arm(y: i32) { }; } +#[rustfmt::skip] fn guard_may_be_skipped(y: i32) { + // Even though x *is* always initialized, we don't want to have borrowck results be based on + // whether MIR lowering reveals which patterns are exhaustive. + let x; + match y { + _ if { x = 2; true } => {}, + // Borrowck must not know the guard is always run. + _ => drop(x), //~ ERROR used binding `x` is possibly-uninitialized + }; + let x; - // Even though x *is* always initialized, we don't want to have borrowck - // results be based on whether patterns are exhaustive. match y { _ if { x = 2; true } => 1, - _ if { - x; //~ ERROR E0381 - false - } => 2, + // Borrowck must not know the guard is always run. + _ if { x; false } => 2, //~ ERROR used binding `x` isn't initialized _ => 3, }; let x; match y { _ if let Some(()) = { x = 2; Some(()) } => 1, - _ if let Some(()) = { - x; //~ ERROR E0381 - None - } => 2, + _ if let Some(()) = { x; None } => 2, //~ ERROR used binding `x` isn't initialized _ => 3, }; } +#[rustfmt::skip] fn guard_may_be_taken(y: bool) { - let x = String::new(); // Even though x *is* never moved before the use, we don't want to have // borrowck results be based on whether patterns are disjoint. + let x = String::new(); match y { - false if { drop(x); true } => 1, - true => { - x; //~ ERROR use of moved value: `x` - 2 - } - false => 3, + false if { drop(x); true } => {}, + // Borrowck must not know the guard is not run in the `true` case. + true => drop(x), //~ ERROR use of moved value: `x` + false => {}, + }; + + // Fine in the other order. + let x = String::new(); + match y { + true => drop(x), + false if { drop(x); true } => {}, + false => {}, }; let x = String::new(); match y { - false if let Some(()) = { drop(x); Some(()) } => 1, - true => { - x; //~ ERROR use of moved value: `x` - 2 - } - false => 3, + false if let Some(()) = { drop(x); Some(()) } => {}, + true => drop(x), //~ ERROR use of moved value: `x` + false => {}, }; } diff --git a/tests/ui/nll/match-cfg-fake-edges.stderr b/tests/ui/nll/match-cfg-fake-edges.stderr index a6261345ceac..d692ded36fa4 100644 --- a/tests/ui/nll/match-cfg-fake-edges.stderr +++ b/tests/ui/nll/match-cfg-fake-edges.stderr @@ -1,14 +1,128 @@ -error[E0381]: used binding `x` isn't initialized - --> $DIR/match-cfg-fake-edges.rs:29:13 +warning: irrefutable `if let` pattern + --> $DIR/match-cfg-fake-edges.rs:19:8 + | +LL | if let _ = true { + | ^^^^^^^^^^^^ + | + = note: this pattern will always match, so the `if let` is useless + = help: consider replacing the `if let` with a `let` + = note: `#[warn(irrefutable_let_patterns)]` on by default + +error[E0382]: use of moved value: `x` + --> $DIR/match-cfg-fake-edges.rs:16:10 + | +LL | let x = String::new(); + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait +... +LL | _ => drop(x), + | - value moved here +... +LL | drop(x); + | ^ value used here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | _ => drop(x.clone()), + | ++++++++ + +error[E0382]: use of moved value: `x` + --> $DIR/match-cfg-fake-edges.rs:24:10 + | +LL | let x = String::new(); + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait +... +LL | drop(x) + | - value moved here +... +LL | drop(x); + | ^ value used here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | drop(x.clone()) + | ++++++++ + +error[E0382]: borrow of moved value: `x.0` + --> $DIR/match-cfg-fake-edges.rs:30:5 + | +LL | (y, _) | (_, y) => (), + | - value moved here +LL | } +LL | &x.0; + | ^^^^ value borrowed here after move + | + = note: move occurs because `x.0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | (ref y, _) | (_, y) => (), + | +++ + +error[E0382]: borrow of moved value: `x.1` + --> $DIR/match-cfg-fake-edges.rs:32:5 + | +LL | (y, _) | (_, y) => (), + | - value moved here +... +LL | &x.1; + | ^^^^ value borrowed here after move + | + = note: move occurs because `x.1` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | (y, _) | (_, ref y) => (), + | +++ + +error[E0382]: borrow of moved value: `x.0` + --> $DIR/match-cfg-fake-edges.rs:36:5 + | +LL | let ((y, _) | (_, y)) = x; + | - value moved here +LL | &x.0; + | ^^^^ value borrowed here after move + | + = note: move occurs because `x.0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let ((ref y, _) | (_, y)) = x; + | +++ + +error[E0382]: borrow of moved value: `x.1` + --> $DIR/match-cfg-fake-edges.rs:38:5 + | +LL | let ((y, _) | (_, y)) = x; + | - value moved here +... +LL | &x.1; + | ^^^^ value borrowed here after move + | + = note: move occurs because `x.1` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let ((y, _) | (_, ref y)) = x; + | +++ + +error[E0381]: used binding `x` is possibly-uninitialized + --> $DIR/match-cfg-fake-edges.rs:72:19 | LL | let x; | - binding declared here but left uninitialized ... +LL | _ => drop(x), + | - ^ `x` used here but it is possibly-uninitialized + | | + | if this pattern is matched, `x` is not initialized + +error[E0381]: used binding `x` isn't initialized + --> $DIR/match-cfg-fake-edges.rs:79:16 + | +LL | let x; + | - binding declared here but left uninitialized +LL | match y { LL | _ if { x = 2; true } => 1, | ----- binding initialized here in some conditions -LL | _ if { -LL | x; - | ^ `x` used here but it isn't initialized +LL | // Borrowck must not know the guard is always run. +LL | _ if { x; false } => 2, + | ^ `x` used here but it isn't initialized | help: consider assigning a value | @@ -16,16 +130,15 @@ LL | let x = 0; | +++ error[E0381]: used binding `x` isn't initialized - --> $DIR/match-cfg-fake-edges.rs:39:13 + --> $DIR/match-cfg-fake-edges.rs:86:31 | LL | let x; | - binding declared here but left uninitialized LL | match y { LL | _ if let Some(()) = { x = 2; Some(()) } => 1, | ----- binding initialized here in some conditions -LL | _ if let Some(()) = { -LL | x; - | ^ `x` used here but it isn't initialized +LL | _ if let Some(()) = { x; None } => 2, + | ^ `x` used here but it isn't initialized | help: consider assigning a value | @@ -33,40 +146,39 @@ LL | let x = 0; | +++ error[E0382]: use of moved value: `x` - --> $DIR/match-cfg-fake-edges.rs:53:13 - | -LL | let x = String::new(); - | - move occurs because `x` has type `String`, which does not implement the `Copy` trait -... -LL | false if { drop(x); true } => 1, - | - value moved here -LL | true => { -LL | x; - | ^ value used here after move - | -help: consider cloning the value if the performance cost is acceptable - | -LL | false if { drop(x.clone()); true } => 1, - | ++++++++ - -error[E0382]: use of moved value: `x` - --> $DIR/match-cfg-fake-edges.rs:63:13 + --> $DIR/match-cfg-fake-edges.rs:99:22 | LL | let x = String::new(); | - move occurs because `x` has type `String`, which does not implement the `Copy` trait LL | match y { -LL | false if let Some(()) = { drop(x); Some(()) } => 1, - | - value moved here -LL | true => { -LL | x; - | ^ value used here after move +LL | false if { drop(x); true } => {}, + | - value moved here +LL | // Borrowck must not know the guard is not run in the `true` case. +LL | true => drop(x), + | ^ value used here after move | help: consider cloning the value if the performance cost is acceptable | -LL | false if let Some(()) = { drop(x.clone()); Some(()) } => 1, +LL | false if { drop(x.clone()); true } => {}, + | ++++++++ + +error[E0382]: use of moved value: `x` + --> $DIR/match-cfg-fake-edges.rs:114:22 + | +LL | let x = String::new(); + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait +LL | match y { +LL | false if let Some(()) = { drop(x); Some(()) } => {}, + | - value moved here +LL | true => drop(x), + | ^ value used here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | false if let Some(()) = { drop(x.clone()); Some(()) } => {}, | ++++++++ -error: aborting due to 4 previous errors +error: aborting due to 11 previous errors; 1 warning emitted Some errors have detailed explanations: E0381, E0382. For more information about an error, try `rustc --explain E0381`. diff --git a/tests/ui/nll/match-cfg-fake-edges2.rs b/tests/ui/nll/match-cfg-fake-edges2.rs index 48f95e03b78c..ac90fb9cd1e7 100644 --- a/tests/ui/nll/match-cfg-fake-edges2.rs +++ b/tests/ui/nll/match-cfg-fake-edges2.rs @@ -5,13 +5,20 @@ fn all_previous_tests_may_be_done(y: &mut (bool, bool)) { let r = &mut y.1; // We don't actually test y.1 to select the second arm, but we don't want // borrowck results to be based on the order we match patterns. - match y { //~ ERROR cannot use `y.1` because it was mutably borrowed - (false, true) => 1, - (true, _) => { - r; - 2 - } - (false, _) => 3, + match y { + //~^ ERROR cannot use `y.1` because it was mutably borrowed + (false, true) => {} + // Borrowck must not know we don't test `y.1` when `y.0` is `true`. + (true, _) => drop(r), + (false, _) => {} + }; + + // Fine in the other order. + let r = &mut y.1; + match y { + (true, _) => drop(r), + (false, true) => {} + (false, _) => {} }; } diff --git a/tests/ui/nll/match-cfg-fake-edges2.stderr b/tests/ui/nll/match-cfg-fake-edges2.stderr index 639cba1406ae..0a228d62b923 100644 --- a/tests/ui/nll/match-cfg-fake-edges2.stderr +++ b/tests/ui/nll/match-cfg-fake-edges2.stderr @@ -7,8 +7,8 @@ LL | let r = &mut y.1; LL | match y { | ^^^^^^^ use of borrowed `y.1` ... -LL | r; - | - borrow later used here +LL | (true, _) => drop(r), + | - borrow later used here error: aborting due to 1 previous error diff --git a/tests/ui/parser/fn-header-semantic-fail.rs b/tests/ui/parser/fn-header-semantic-fail.rs index 25d7c3f35fca..6ed173b6854d 100644 --- a/tests/ui/parser/fn-header-semantic-fail.rs +++ b/tests/ui/parser/fn-header-semantic-fail.rs @@ -48,6 +48,9 @@ fn main() { const fn fe3(); //~ ERROR functions in `extern` blocks cannot have qualifiers extern "C" fn fe4(); //~ ERROR functions in `extern` blocks cannot have qualifiers const async unsafe extern "C" fn fe5(); //~ ERROR functions in `extern` blocks - //~^ ERROR functions cannot be both `const` and `async` + //~| ERROR functions in `extern` blocks + //~| ERROR functions in `extern` blocks + //~| ERROR functions in `extern` blocks + //~| ERROR functions cannot be both `const` and `async` } } diff --git a/tests/ui/parser/fn-header-semantic-fail.stderr b/tests/ui/parser/fn-header-semantic-fail.stderr index 696d8e01b638..cfc54839eb75 100644 --- a/tests/ui/parser/fn-header-semantic-fail.stderr +++ b/tests/ui/parser/fn-header-semantic-fail.stderr @@ -71,73 +71,75 @@ LL | const async unsafe extern "C" fn fi5() {} | `const` because of this error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:46:18 + --> $DIR/fn-header-semantic-fail.rs:46:9 | LL | extern "C" { | ---------- in this `extern` block LL | async fn fe1(); - | ^^^ - | -help: remove the qualifiers - | -LL | fn fe1(); - | ~~ + | ^^^^^ help: remove this qualifier error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:47:19 + --> $DIR/fn-header-semantic-fail.rs:47:9 | LL | extern "C" { | ---------- in this `extern` block LL | async fn fe1(); LL | unsafe fn fe2(); - | ^^^ - | -help: remove the qualifiers - | -LL | fn fe2(); - | ~~ + | ^^^^^^ help: remove this qualifier error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:48:18 + --> $DIR/fn-header-semantic-fail.rs:48:9 | LL | extern "C" { | ---------- in this `extern` block ... LL | const fn fe3(); - | ^^^ - | -help: remove the qualifiers - | -LL | fn fe3(); - | ~~ + | ^^^^^ help: remove this qualifier error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:49:23 + --> $DIR/fn-header-semantic-fail.rs:49:9 | LL | extern "C" { | ---------- in this `extern` block ... LL | extern "C" fn fe4(); - | ^^^ - | -help: remove the qualifiers - | -LL | fn fe4(); - | ~~ + | ^^^^^^^^^^ help: remove this qualifier error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:50:42 + --> $DIR/fn-header-semantic-fail.rs:50:21 | LL | extern "C" { | ---------- in this `extern` block ... LL | const async unsafe extern "C" fn fe5(); - | ^^^ + | ^^^^^^ help: remove this qualifier + +error: functions in `extern` blocks cannot have qualifiers + --> $DIR/fn-header-semantic-fail.rs:50:15 | -help: remove the qualifiers +LL | extern "C" { + | ---------- in this `extern` block +... +LL | const async unsafe extern "C" fn fe5(); + | ^^^^^ help: remove this qualifier + +error: functions in `extern` blocks cannot have qualifiers + --> $DIR/fn-header-semantic-fail.rs:50:9 | -LL | fn fe5(); - | ~~ +LL | extern "C" { + | ---------- in this `extern` block +... +LL | const async unsafe extern "C" fn fe5(); + | ^^^^^ help: remove this qualifier + +error: functions in `extern` blocks cannot have qualifiers + --> $DIR/fn-header-semantic-fail.rs:50:28 + | +LL | extern "C" { + | ---------- in this `extern` block +... +LL | const async unsafe extern "C" fn fe5(); + | ^^^^^^^^^^ help: remove this qualifier error: functions cannot be both `const` and `async` --> $DIR/fn-header-semantic-fail.rs:50:9 @@ -148,6 +150,6 @@ LL | const async unsafe extern "C" fn fe5(); | | `async` because of this | `const` because of this -error: aborting due to 14 previous errors +error: aborting due to 17 previous errors For more information about this error, try `rustc --explain E0379`. diff --git a/tests/ui/parser/no-const-fn-in-extern-block.rs b/tests/ui/parser/no-const-fn-in-extern-block.rs index 1993124edc39..d6c578681ccc 100644 --- a/tests/ui/parser/no-const-fn-in-extern-block.rs +++ b/tests/ui/parser/no-const-fn-in-extern-block.rs @@ -3,6 +3,7 @@ extern "C" { //~^ ERROR functions in `extern` blocks cannot have qualifiers const unsafe fn bar(); //~^ ERROR functions in `extern` blocks cannot have qualifiers + //~| ERROR functions in `extern` blocks cannot have qualifiers } fn main() {} diff --git a/tests/ui/parser/no-const-fn-in-extern-block.stderr b/tests/ui/parser/no-const-fn-in-extern-block.stderr index 4ac0e265501f..948ce669112c 100644 --- a/tests/ui/parser/no-const-fn-in-extern-block.stderr +++ b/tests/ui/parser/no-const-fn-in-extern-block.stderr @@ -1,29 +1,28 @@ error: functions in `extern` blocks cannot have qualifiers - --> $DIR/no-const-fn-in-extern-block.rs:2:14 + --> $DIR/no-const-fn-in-extern-block.rs:2:5 | LL | extern "C" { | ---------- in this `extern` block LL | const fn foo(); - | ^^^ - | -help: remove the qualifiers - | -LL | fn foo(); - | ~~ + | ^^^^^ help: remove this qualifier error: functions in `extern` blocks cannot have qualifiers - --> $DIR/no-const-fn-in-extern-block.rs:4:21 + --> $DIR/no-const-fn-in-extern-block.rs:4:11 | LL | extern "C" { | ---------- in this `extern` block ... LL | const unsafe fn bar(); - | ^^^ - | -help: remove the qualifiers - | -LL | fn bar(); - | ~~ + | ^^^^^^ help: remove this qualifier -error: aborting due to 2 previous errors +error: functions in `extern` blocks cannot have qualifiers + --> $DIR/no-const-fn-in-extern-block.rs:4:5 + | +LL | extern "C" { + | ---------- in this `extern` block +... +LL | const unsafe fn bar(); + | ^^^^^ help: remove this qualifier + +error: aborting due to 3 previous errors diff --git a/tests/ui/parser/unsafe-foreign-mod-2.stderr b/tests/ui/parser/unsafe-foreign-mod-2.stderr index 7cc2de141ae1..fc05184f018f 100644 --- a/tests/ui/parser/unsafe-foreign-mod-2.stderr +++ b/tests/ui/parser/unsafe-foreign-mod-2.stderr @@ -11,18 +11,13 @@ LL | extern "C" unsafe { | ^^^^^^ error: functions in `extern` blocks cannot have qualifiers - --> $DIR/unsafe-foreign-mod-2.rs:4:15 + --> $DIR/unsafe-foreign-mod-2.rs:4:5 | LL | extern "C" unsafe { | ----------------- in this `extern` block ... LL | unsafe fn foo(); - | ^^^ - | -help: remove the qualifiers - | -LL | fn foo(); - | ~~ + | ^^^^^^ help: remove this qualifier error: aborting due to 3 previous errors diff --git a/tests/ui/privacy/generic_struct_field_projection.rs b/tests/ui/privacy/generic_struct_field_projection.rs new file mode 100644 index 000000000000..c5bb1233c27b --- /dev/null +++ b/tests/ui/privacy/generic_struct_field_projection.rs @@ -0,0 +1,38 @@ +//! To determine all the types that need to be private when looking at `Struct`, we +//! used to invoke `predicates_of` to also look at types in `where` bounds. +//! Unfortunately this also computes the inferred outlives bounds, which means for +//! every field we check that if it is of type `&'a T` then `T: 'a` and if it is of +//! struct type, we check that the struct satisfies its lifetime parameters by looking +//! at its inferred outlives bounds. This means we end up with a `::Assoc: 'a` +//! in the outlives bounds of `Struct`. While this is trivially provable, privacy +//! only sees `Foo` and `Trait` and determines that `Foo` is private and then errors. +//! So now we invoke `explicit_predicates_of` to make sure we only care about user-written +//! predicates. + +//@ check-pass + +mod baz { + struct Foo; + + pub trait Trait { + type Assoc; + } + + impl Trait for Foo { + type Assoc = (); + } + + pub struct Bar<'a, T: Trait> { + source: &'a T::Assoc, + } + + pub struct Baz<'a> { + mode: Bar<'a, Foo>, + } +} + +pub struct Struct<'a> { + lexer: baz::Baz<'a>, +} + +fn main() {} diff --git a/tests/ui/proc-macro/auxiliary/api/mod.rs b/tests/ui/proc-macro/auxiliary/api/mod.rs index 199d097336af..45ef6922d283 100644 --- a/tests/ui/proc-macro/auxiliary/api/mod.rs +++ b/tests/ui/proc-macro/auxiliary/api/mod.rs @@ -5,8 +5,6 @@ #![crate_type = "proc-macro"] #![crate_name = "proc_macro_api_tests"] #![feature(proc_macro_span)] -#![feature(proc_macro_byte_character)] -#![feature(proc_macro_c_str_literals)] #![deny(dead_code)] // catch if a test function is never called extern crate proc_macro; diff --git a/tests/ui/proc-macro/bad-projection.rs b/tests/ui/proc-macro/bad-projection.rs index e633191bd310..0769a7f08c12 100644 --- a/tests/ui/proc-macro/bad-projection.rs +++ b/tests/ui/proc-macro/bad-projection.rs @@ -15,4 +15,5 @@ pub fn uwu() -> <() as Project>::Assoc {} //~^ ERROR the trait bound `(): Project` is not satisfied //~| ERROR the trait bound `(): Project` is not satisfied //~| ERROR the trait bound `(): Project` is not satisfied +//~| ERROR the trait bound `(): Project` is not satisfied //~| ERROR function is expected to take 1 argument, but it takes 0 arguments diff --git a/tests/ui/proc-macro/bad-projection.stderr b/tests/ui/proc-macro/bad-projection.stderr index 8e0d8461849b..2e8668f60de7 100644 --- a/tests/ui/proc-macro/bad-projection.stderr +++ b/tests/ui/proc-macro/bad-projection.stderr @@ -35,6 +35,18 @@ help: this trait has no implementations, consider adding one LL | trait Project { | ^^^^^^^^^^^^^ +error[E0277]: the trait bound `(): Project` is not satisfied + --> $DIR/bad-projection.rs:14:1 + | +LL | pub fn uwu() -> <() as Project>::Assoc {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Project` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/bad-projection.rs:9:1 + | +LL | trait Project { + | ^^^^^^^^^^^^^ + error[E0277]: the trait bound `(): Project` is not satisfied --> $DIR/bad-projection.rs:14:40 | @@ -47,7 +59,7 @@ help: this trait has no implementations, consider adding one LL | trait Project { | ^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors Some errors have detailed explanations: E0277, E0593. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/resolve/primitive-f16-f128-shadowed-mod.rs b/tests/ui/resolve/primitive-f16-f128-shadowed-mod.rs new file mode 100644 index 000000000000..93f518201013 --- /dev/null +++ b/tests/ui/resolve/primitive-f16-f128-shadowed-mod.rs @@ -0,0 +1,19 @@ +//@ compile-flags: --crate-type=lib +//@ check-pass +//@ revisions: e2015 e2018 +// +//@[e2018] edition:2018 + +// Verify that gates for the `f16` and `f128` features do not apply to user modules +// See + +mod f16 { + pub fn a16() {} +} + +mod f128 { + pub fn a128() {} +} + +pub use f128::a128; +pub use f16::a16; diff --git a/tests/ui/resolve/primitive-f16-f128-shadowed.rs b/tests/ui/resolve/primitive-f16-f128-shadowed.rs index ed3fb44b256d..38c7e15bf5a2 100644 --- a/tests/ui/resolve/primitive-f16-f128-shadowed.rs +++ b/tests/ui/resolve/primitive-f16-f128-shadowed.rs @@ -1,5 +1,8 @@ //@ compile-flags: --crate-type=lib //@ check-pass +//@ revisions: e2015 e2018 +// +//@[e2018] edition:2018 // Verify that gates for the `f16` and `f128` features do not apply to user types diff --git a/tests/ui/sanitizer/cfi-closures.rs b/tests/ui/sanitizer/cfi-closures.rs index 54f1cc035bc5..9f9002da674f 100644 --- a/tests/ui/sanitizer/cfi-closures.rs +++ b/tests/ui/sanitizer/cfi-closures.rs @@ -15,7 +15,6 @@ #![feature(fn_traits)] #![feature(unboxed_closures)] -#![feature(cfg_sanitize)] fn foo<'a, T>() -> Box &'a T> { Box::new(|x| x) @@ -72,12 +71,20 @@ fn use_closure(call: extern "rust-call" fn(&C, ()) -> i32, f: &C) -> i32 { } #[test] -// FIXME after KCFI reify support is added, remove this -// It will appear to work if you test locally, set -C opt-level=0 to see it fail. -#[cfg_attr(sanitize = "kcfi", ignore)] fn closure_addr_taken() { let x = 3i32; let f = || x; let call = Fn::<()>::call; use_closure(call, &f); } + +fn use_closure_once(call: extern "rust-call" fn(C, ()) -> i32, f: C) -> i32 { + call(f, ()) +} + +#[test] +fn closure_once_addr_taken() { + let g = || 3; + let call2 = FnOnce::<()>::call_once; + use_closure_once(call2, g); +} diff --git a/tests/ui/sanitizer/cfi-method-fn-ptr-cast.rs b/tests/ui/sanitizer/cfi-method-fn-ptr-cast.rs index 273b8785faee..8f79de117488 100644 --- a/tests/ui/sanitizer/cfi-method-fn-ptr-cast.rs +++ b/tests/ui/sanitizer/cfi-method-fn-ptr-cast.rs @@ -1,11 +1,41 @@ // Verifies that casting a method to a function pointer works. -// -// FIXME(#122848): Remove only-linux when fixed. + +//@ revisions: cfi kcfi +// FIXME(#122848) Remove only-linux once OSX CFI binaries work //@ only-linux -//@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Copt-level=0 -Cprefer-dynamic=off -Ctarget-feature=-crt-static -Zsanitizer=cfi +//@ [cfi] needs-sanitizer-cfi +//@ [kcfi] needs-sanitizer-kcfi +//@ compile-flags: -C target-feature=-crt-static +//@ [cfi] compile-flags: -C opt-level=0 -C codegen-units=1 -C lto +//@ [cfi] compile-flags: -C prefer-dynamic=off +//@ [cfi] compile-flags: -Z sanitizer=cfi +//@ [kcfi] compile-flags: -Z sanitizer=kcfi +//@ [kcfi] compile-flags: -C panic=abort -C prefer-dynamic=off //@ run-pass +trait Foo { + fn foo(&self); + fn bar(&self); +} + +struct S; + +impl Foo for S { + fn foo(&self) {} + #[track_caller] + fn bar(&self) {} +} + +struct S2 { + f: fn(&S) +} + +impl S2 { + fn foo(&self, s: &S) { + (self.f)(s) + } +} + trait Trait1 { fn foo(&self); } @@ -20,4 +50,8 @@ fn main() { let type1 = Type1 {}; let f = ::foo; f(&type1); + // Check again with different optimization barriers + S2 { f: ::foo }.foo(&S); + // Check mismatched #[track_caller] + S2 { f: ::bar }.foo(&S) } diff --git a/tests/ui/self/arbitrary-self-opaque.rs b/tests/ui/self/arbitrary-self-opaque.rs new file mode 100644 index 000000000000..99357dde3e14 --- /dev/null +++ b/tests/ui/self/arbitrary-self-opaque.rs @@ -0,0 +1,12 @@ +#![feature(type_alias_impl_trait)] +struct Foo; + +type Bar = impl Sized; +//~^ ERROR unconstrained opaque type + +impl Foo { + fn foo(self: Bar) {} + //~^ ERROR: invalid `self` parameter type: Bar +} + +fn main() {} diff --git a/tests/ui/self/arbitrary-self-opaque.stderr b/tests/ui/self/arbitrary-self-opaque.stderr new file mode 100644 index 000000000000..6b5db8d84932 --- /dev/null +++ b/tests/ui/self/arbitrary-self-opaque.stderr @@ -0,0 +1,20 @@ +error: unconstrained opaque type + --> $DIR/arbitrary-self-opaque.rs:4:12 + | +LL | type Bar = impl Sized; + | ^^^^^^^^^^ + | + = note: `Bar` must be used in combination with a concrete type within the same module + +error[E0307]: invalid `self` parameter type: Bar + --> $DIR/arbitrary-self-opaque.rs:8:18 + | +LL | fn foo(self: Bar) {} + | ^^^ + | + = note: type of `self` must be `Self` or a type that dereferences to it + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0307`. diff --git a/tests/ui/specialization/min_specialization/impl-on-opaque.rs b/tests/ui/specialization/min_specialization/impl-on-opaque.rs new file mode 100644 index 000000000000..7531dcaccf23 --- /dev/null +++ b/tests/ui/specialization/min_specialization/impl-on-opaque.rs @@ -0,0 +1,31 @@ +// Test that specializing on opaque types is allowed + +//@ check-pass + +#![feature(min_specialization, type_alias_impl_trait)] + +trait SpecTrait { + fn f(); +} + +impl SpecTrait for () { + default fn f() {} +} + +type Opaque = impl Tuple; + +trait Tuple {} + +impl Tuple for () {} + +impl SpecTrait for () { + fn f() {} +} + +impl SpecTrait for () { + fn f() {} +} + +fn foo() -> Opaque {} + +fn main() {} diff --git a/tests/ui/specialization/min_specialization/impl-on-opaque2.rs b/tests/ui/specialization/min_specialization/impl-on-opaque2.rs new file mode 100644 index 000000000000..0cd8be84ed37 --- /dev/null +++ b/tests/ui/specialization/min_specialization/impl-on-opaque2.rs @@ -0,0 +1,28 @@ +// Test that specializing on opaque types is allowed + +#![feature(min_specialization, type_alias_impl_trait)] + +trait SpecTrait { + fn f(); +} + +impl SpecTrait for () { + default fn f() {} +} + +type Opaque = impl Tuple; + +trait Tuple {} + +impl Tuple for () {} + +// FIXME: this passes if we use `<(), ()>` here instead of `<(), Opaque>`, +// even though there can't be more overlap from the opaque version +impl SpecTrait<(), Opaque> for () { + //~^ ERROR: conflicting implementations + fn f() {} +} + +fn foo() -> Opaque {} + +fn main() {} diff --git a/tests/ui/specialization/min_specialization/impl-on-opaque2.stderr b/tests/ui/specialization/min_specialization/impl-on-opaque2.stderr new file mode 100644 index 000000000000..3c0bc8f8f835 --- /dev/null +++ b/tests/ui/specialization/min_specialization/impl-on-opaque2.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `SpecTrait<(), ()>` for type `()` + --> $DIR/impl-on-opaque2.rs:21:1 + | +LL | impl SpecTrait for () { + | ------------------------------- first implementation here +... +LL | impl SpecTrait<(), Opaque> for () { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.current.stderr b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.current.stderr new file mode 100644 index 000000000000..c54a1c42badd --- /dev/null +++ b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.current.stderr @@ -0,0 +1,17 @@ +error[E0308]: mismatched types + --> $DIR/illegal-upcast-from-impl-opaque.rs:26:5 + | +LL | type Foo = impl Sized; + | ---------- the found opaque type +LL | +LL | fn illegal(x: &dyn Sub) -> &dyn Super { + | ----------------------- expected `&dyn Super` because of return type +LL | x + | ^ expected trait `Super`, found trait `Sub` + | + = note: expected reference `&dyn Super` + found reference `&dyn Sub` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.next.stderr b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.next.stderr new file mode 100644 index 000000000000..3c2bc0b91906 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.next.stderr @@ -0,0 +1,14 @@ +error: internal compiler error: error performing operation: query type op + --> $DIR/illegal-upcast-from-impl-opaque.rs:25:1 + | +LL | fn illegal(x: &dyn Sub) -> &dyn Super { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: + --> $DIR/illegal-upcast-from-impl-opaque.rs:25:1 + | +LL | fn illegal(x: &dyn Sub) -> &dyn Super { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +query stack during panic: +end of query stack diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.rs b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.rs new file mode 100644 index 000000000000..f344474054a2 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.rs @@ -0,0 +1,29 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@[next] failure-status: 101 +//@[next] known-bug: unknown +//@[next] normalize-stderr-test "note: .*\n\n" -> "" +//@[next] normalize-stderr-test "thread 'rustc' panicked.*\n.*\n" -> "" +//@[next] normalize-stderr-test "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: " +//@[next] normalize-stderr-test "delayed at .*" -> "" +//@[next] rustc-env:RUST_BACKTRACE=0 + +#![feature(trait_upcasting, type_alias_impl_trait)] + +trait Super { + type Assoc; +} + +trait Sub: Super {} + +impl Super for T { + type Assoc = i32; +} + +type Foo = impl Sized; + +fn illegal(x: &dyn Sub) -> &dyn Super { + x //[current]~ mismatched types +} + +fn main() {} diff --git a/tests/ui/unpretty/hir-tree.rs b/tests/ui/unpretty/hir-tree.rs new file mode 100644 index 000000000000..3388c60c4253 --- /dev/null +++ b/tests/ui/unpretty/hir-tree.rs @@ -0,0 +1,10 @@ +//@ build-pass +//@ compile-flags: -o - -Zunpretty=hir-tree +//@ check-stdout +//@ dont-check-compiler-stdout +//@ dont-check-compiler-stderr +//@ regex-error-pattern: Hello, Rustaceans! + +fn main() { + println!("Hello, Rustaceans!"); +} diff --git a/tests/ui/wf/wf-fn-def-check-sig-1.rs b/tests/ui/wf/wf-fn-def-check-sig-1.rs new file mode 100644 index 000000000000..6d9e1f38f8d3 --- /dev/null +++ b/tests/ui/wf/wf-fn-def-check-sig-1.rs @@ -0,0 +1,44 @@ +// Regression test for #84533. + +use std::marker::PhantomData; + +fn foo<'b, 'a>() -> PhantomData<&'b &'a ()> { + PhantomData +} + +fn extend_lifetime<'a, 'b, T: ?Sized>(x: &'a T) -> &'b T { + let f = foo::<'b, 'a>; + f.baz(x) + //~^ ERROR lifetime may not live long enough +} + +trait Foo<'a, 'b, T: ?Sized> { + fn baz(self, s: &'a T) -> &'b T; +} +impl<'a, 'b, R, F, T: ?Sized> Foo<'a, 'b, T> for F +where + F: Fn() -> R, + R: ProofForConversion<'a, 'b, T>, +{ + fn baz(self, s: &'a T) -> &'b T { + self().convert(s) + } +} + +trait ProofForConversion<'a, 'b, T: ?Sized> { + fn convert(self, s: &'a T) -> &'b T; +} +impl<'a, 'b, T: ?Sized> ProofForConversion<'a, 'b, T> for PhantomData<&'b &'a ()> { + fn convert(self, s: &'a T) -> &'b T { + s + } +} + +fn main() { + let d; + { + let x = "Hello World".to_string(); + d = extend_lifetime(&x); + } + println!("{}", d); +} diff --git a/tests/ui/wf/wf-fn-def-check-sig-1.stderr b/tests/ui/wf/wf-fn-def-check-sig-1.stderr new file mode 100644 index 000000000000..a93449ad3c63 --- /dev/null +++ b/tests/ui/wf/wf-fn-def-check-sig-1.stderr @@ -0,0 +1,15 @@ +error: lifetime may not live long enough + --> $DIR/wf-fn-def-check-sig-1.rs:11:5 + | +LL | fn extend_lifetime<'a, 'b, T: ?Sized>(x: &'a T) -> &'b T { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | let f = foo::<'b, 'a>; +LL | f.baz(x) + | ^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + | + = help: consider adding the following bound: `'a: 'b` + +error: aborting due to 1 previous error + diff --git a/tests/ui/wf/wf-fn-def-check-sig-2.rs b/tests/ui/wf/wf-fn-def-check-sig-2.rs new file mode 100644 index 000000000000..51740dca8e9b --- /dev/null +++ b/tests/ui/wf/wf-fn-def-check-sig-2.rs @@ -0,0 +1,44 @@ +// Regression test for #84533 involving higher-ranked regions +// in the return type. +use std::marker::PhantomData; + +fn foo<'c, 'b, 'a>(_: &'c ()) -> (&'c (), PhantomData<&'b &'a ()>) { + (&(), PhantomData) +} + +fn extend_lifetime<'a, 'b, T: ?Sized>(x: &'a T) -> &'b T { + let f = foo; + f.baz(x) + //~^ ERROR lifetime may not live long enough +} + +trait Foo<'a, 'b, T: ?Sized> { + fn baz(self, s: &'a T) -> &'b T; +} +impl<'a, 'b, R, F, T: ?Sized> Foo<'a, 'b, T> for F +where + F: for<'c> Fn(&'c ()) -> (&'c (), R), + R: ProofForConversion<'a, 'b, T>, +{ + fn baz(self, s: &'a T) -> &'b T { + self(&()).1.convert(s) + } +} + +trait ProofForConversion<'a, 'b, T: ?Sized> { + fn convert(self, s: &'a T) -> &'b T; +} +impl<'a, 'b, T: ?Sized> ProofForConversion<'a, 'b, T> for PhantomData<&'b &'a ()> { + fn convert(self, s: &'a T) -> &'b T { + s + } +} + +fn main() { + let d; + { + let x = "Hello World".to_string(); + d = extend_lifetime(&x); + } + println!("{}", d); +} diff --git a/tests/ui/wf/wf-fn-def-check-sig-2.stderr b/tests/ui/wf/wf-fn-def-check-sig-2.stderr new file mode 100644 index 000000000000..404d3cc4513b --- /dev/null +++ b/tests/ui/wf/wf-fn-def-check-sig-2.stderr @@ -0,0 +1,15 @@ +error: lifetime may not live long enough + --> $DIR/wf-fn-def-check-sig-2.rs:11:5 + | +LL | fn extend_lifetime<'a, 'b, T: ?Sized>(x: &'a T) -> &'b T { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | let f = foo; +LL | f.baz(x) + | ^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + | + = help: consider adding the following bound: `'a: 'b` + +error: aborting due to 1 previous error + diff --git a/triagebot.toml b/triagebot.toml index 55f0d32398ff..927852f0ca2e 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -286,6 +286,11 @@ trigger_files = [ "library/std/src/os/windows" ] +[autolabel."O-visionos"] +trigger_files = [ + "library/std/src/os/visionos" +] + [autolabel."T-bootstrap"] trigger_files = [ "x.py", @@ -469,11 +474,11 @@ message = "Some changes occurred in need_type_info.rs" cc = ["@lcnr"] [mentions."compiler/rustc_middle/src/ty/relate.rs"] -message = "Type relation code was changed" +message = "changes to the core type system" cc = ["@compiler-errors", "@lcnr"] [mentions."compiler/rustc_infer/src/infer/relate"] -message = "Type relation code was changed" +message = "changes to the core type system" cc = ["@compiler-errors", "@lcnr"] [mentions."compiler/rustc_middle/src/mir/interpret"] @@ -484,6 +489,10 @@ cc = ["@rust-lang/miri"] message = "Some changes occurred to MIR optimizations" cc = ["@rust-lang/wg-mir-opt"] +[mentions."compiler/rustc_trait_selection/src/traits/wf.rs"] +message = "changes to the core type system" +cc = ["@compiler-errors", "@lcnr"] + [mentions."compiler/rustc_trait_selection/src/traits/const_evaluatable.rs"] message = "Some changes occurred in `const_evaluatable.rs`" cc = ["@BoxyUwU"] @@ -789,6 +798,7 @@ compiler-team-contributors = [ "@fmease", "@fee1-dead", "@BoxyUwU", + "@jieyouxu", ] compiler = [ "compiler-team", @@ -969,10 +979,12 @@ project-exploit-mitigations = [ "/src/llvm-project" = ["@cuviper"] "/src/rustdoc-json-types" = ["rustdoc"] "/src/stage0.json" = ["bootstrap"] +"/tests/run-make" = ["@jieyouxu"] "/tests/ui" = ["compiler"] "/src/tools/cargo" = ["@ehuss"] -"/src/tools/compiletest" = ["bootstrap", "@wesleywiser", "@oli-obk", "@compiler-errors"] +"/src/tools/compiletest" = ["bootstrap", "@wesleywiser", "@oli-obk", "@compiler-errors", "@jieyouxu"] "/src/tools/linkchecker" = ["@ehuss"] +"/src/tools/run-make-support" = ["@jieyouxu"] "/src/tools/rust-installer" = ["bootstrap"] "/src/tools/rustbook" = ["@ehuss"] "/src/tools/rustdoc" = ["rustdoc"]